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 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
434 video.window_width = window_scaling_factor * width;
435 video.window_height = window_scaling_factor * height;
438 printf("::: use window scaling factor %f\n", screen_scaling_factor);
441 if ((*backbuffer)->surface)
443 SDL_FreeSurface((*backbuffer)->surface);
444 (*backbuffer)->surface = NULL;
449 SDL_DestroyTexture(sdl_texture);
453 if (!(fullscreen && fullscreen_enabled))
457 SDL_DestroyRenderer(sdl_renderer);
463 SDL_DestroyWindow(sdl_window);
469 Error(ERR_INFO, "::: checking 'sdl_window' ...");
471 if (sdl_window == NULL)
472 Error(ERR_INFO, "::: calling SDL_CreateWindow() [%d, %d, %d] ...",
473 setup.fullscreen, fullscreen, fullscreen_enabled);
476 if (sdl_window == NULL)
477 sdl_window = SDL_CreateWindow(program.window_title,
478 SDL_WINDOWPOS_CENTERED,
479 SDL_WINDOWPOS_CENTERED,
480 #if USE_DESKTOP_FULLSCREEN
484 (int)(screen_scaling_factor * width),
485 (int)(screen_scaling_factor * height),
489 if (sdl_window != NULL)
491 if (sdl_renderer == NULL)
492 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
494 if (sdl_renderer != NULL)
496 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
497 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
499 sdl_texture = SDL_CreateTexture(sdl_renderer,
500 SDL_PIXELFORMAT_ARGB8888,
501 SDL_TEXTUREACCESS_STREAMING,
504 if (sdl_texture != NULL)
507 // (do not use alpha channel)
508 new_surface = SDL_CreateRGBSurface(0, width, height, 32,
514 // (this uses an alpha channel, which we don't want here)
515 new_surface = SDL_CreateRGBSurface(0, width, height, 32,
522 if (new_surface == NULL)
523 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
528 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
533 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
538 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
544 SDL_DestroyWindow(sdl_window);
546 sdl_window = SDL_CreateWindow(program.window_title,
547 SDL_WINDOWPOS_CENTERED,
548 SDL_WINDOWPOS_CENTERED,
552 if (sdl_window != NULL)
553 new_surface = SDL_GetWindowSurface(sdl_window);
557 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
560 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
561 if (new_surface != NULL)
562 fullscreen_enabled = fullscreen;
567 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
569 boolean success = TRUE;
572 #if defined(TARGET_SDL2)
573 // int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
574 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
575 int surface_flags_window = SURFACE_FLAGS;
577 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
578 int surface_flags_window = SURFACE_FLAGS;
581 SDL_Surface *new_surface = NULL;
583 if (*backbuffer == NULL)
584 *backbuffer = CreateBitmapStruct();
586 /* (real bitmap might be larger in fullscreen mode with video offsets) */
587 (*backbuffer)->width = video.width;
588 (*backbuffer)->height = video.height;
590 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
592 setFullscreenParameters(setup.fullscreen_mode);
594 video_xoffset = fullscreen_xoffset;
595 video_yoffset = fullscreen_yoffset;
597 /* switch display to fullscreen mode, if available */
599 new_surface = SDLCreateScreen(backbuffer, TRUE);
602 #if defined(TARGET_SDL2)
603 sdl_window = SDL_CreateWindow(program.window_title,
604 SDL_WINDOWPOS_CENTERED,
605 SDL_WINDOWPOS_CENTERED,
606 fullscreen_width, fullscreen_height,
607 surface_flags_fullscreen);
608 if (sdl_window != NULL)
610 new_surface = SDL_GetWindowSurface(sdl_window);
612 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
613 // UpdateScreen(NULL); // immediately map window
616 new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
617 video.depth, surface_flags_fullscreen);
621 if (new_surface == NULL)
623 /* switching display to fullscreen mode failed */
624 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
626 /* do not try it again */
627 video.fullscreen_available = FALSE;
633 (*backbuffer)->surface = new_surface;
635 video.fullscreen_enabled = TRUE;
636 video.fullscreen_mode_current = setup.fullscreen_mode;
642 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
647 /* switch display to window mode */
649 new_surface = SDLCreateScreen(backbuffer, FALSE);
652 #if defined(TARGET_SDL2)
655 float screen_scaling_factor = 1.2;
656 int test_fullscreen = 0;
657 int surface_flags = (test_fullscreen ? surface_flags_fullscreen :
658 surface_flags_window);
660 if ((*backbuffer)->surface)
661 SDL_FreeSurface((*backbuffer)->surface);
664 SDL_DestroyTexture(sdl_texture);
667 SDL_DestroyRenderer(sdl_renderer);
670 SDL_DestroyWindow(sdl_window);
672 sdl_window = SDL_CreateWindow(program.window_title,
673 SDL_WINDOWPOS_CENTERED,
674 SDL_WINDOWPOS_CENTERED,
675 (int)(screen_scaling_factor * video.width),
676 (int)(screen_scaling_factor * video.height),
679 if (sdl_window != NULL)
681 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
683 if (sdl_renderer != NULL)
685 SDL_RenderSetLogicalSize(sdl_renderer, video.width, video.height);
686 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
688 sdl_texture = SDL_CreateTexture(sdl_renderer,
689 SDL_PIXELFORMAT_ARGB8888,
690 SDL_TEXTUREACCESS_STREAMING,
691 video.width, video.height);
693 if (sdl_texture != NULL)
696 // (do not use alpha channel)
697 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
703 // (this uses an alpha channel, which we don't want here)
704 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
711 if (new_surface == NULL)
712 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
717 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
722 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
727 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
733 SDL_DestroyWindow(sdl_window);
735 sdl_window = SDL_CreateWindow(program.window_title,
736 SDL_WINDOWPOS_CENTERED,
737 SDL_WINDOWPOS_CENTERED,
738 video.width, video.height,
739 surface_flags_window);
741 if (sdl_window != NULL)
743 new_surface = SDL_GetWindowSurface(sdl_window);
745 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
746 // UpdateScreen(NULL); // immediately map window
751 new_surface = SDL_SetVideoMode(video.width, video.height,
752 video.depth, surface_flags_window);
756 if (new_surface == NULL)
758 /* switching display to window mode failed -- should not happen */
759 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
765 (*backbuffer)->surface = new_surface;
767 video.fullscreen_enabled = FALSE;
768 video.window_scaling_percent = setup.window_scaling_percent;
774 #if defined(TARGET_SDL2)
775 SDLRedrawWindow(); // map window
776 // UpdateScreen(NULL); // map window
780 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
782 #if defined(PLATFORM_WIN32)
784 SDL_SysWMinfo wminfo;
787 SDL_VERSION(&wminfo.version);
788 SDL_GetWMInfo(&wminfo);
790 hwnd = wminfo.window;
792 DragAcceptFiles(hwnd, TRUE);
800 #if defined(TARGET_SDL2)
801 void SDLSetWindowScaling(int window_scaling_percent)
803 if (sdl_window == NULL)
806 float window_scaling_factor = (float)window_scaling_percent / 100;
807 int new_window_width = (int)(window_scaling_factor * video.width);
808 int new_window_height = (int)(window_scaling_factor * video.height);
811 Error(ERR_DEBUG, "::: SDLSetWindowScaling(%d) ...", window_scaling_percent);
814 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
816 video.window_scaling_percent = window_scaling_percent;
817 video.window_width = new_window_width;
818 video.window_height = new_window_height;
821 void SDLSetWindowFullscreen(boolean fullscreen)
823 if (sdl_window == NULL)
826 #if USE_DESKTOP_FULLSCREEN
827 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
829 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
833 Error(ERR_DEBUG, "::: SDL_SetWindowFullscreen(%d) ...", fullscreen);
836 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
837 video.fullscreen_enabled = fullscreen;
840 printf("::: SDLSetWindowFullscreen: %d, %d\n",
841 fullscreen, video.fullscreen_initial);
845 // if game started in fullscreen mode, window will also get fullscreen size
846 if (!fullscreen && video.fullscreen_initial)
848 SDLSetWindowScaling(setup.window_scaling_percent);
849 SDL_SetWindowPosition(sdl_window,
850 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
852 video.fullscreen_initial = FALSE;
857 void SDLRedrawWindow()
863 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
866 SDL_Surface *surface_tmp, *surface_native;
868 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
871 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
873 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
874 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
876 SDL_FreeSurface(surface_tmp);
878 new_bitmap->surface = surface_native;
881 void SDLFreeBitmapPointers(Bitmap *bitmap)
884 SDL_FreeSurface(bitmap->surface);
885 if (bitmap->surface_masked)
886 SDL_FreeSurface(bitmap->surface_masked);
887 bitmap->surface = NULL;
888 bitmap->surface_masked = NULL;
891 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
892 int src_x, int src_y, int width, int height,
893 int dst_x, int dst_y, int mask_mode)
895 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
896 SDL_Rect src_rect, dst_rect;
898 if (src_bitmap == backbuffer)
900 src_x += video_xoffset;
901 src_y += video_yoffset;
909 if (dst_bitmap == backbuffer || dst_bitmap == window)
911 dst_x += video_xoffset;
912 dst_y += video_yoffset;
920 // if (src_bitmap != backbuffer || dst_bitmap != window)
921 if (!(src_bitmap == backbuffer && dst_bitmap == window))
922 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
923 src_bitmap->surface_masked : src_bitmap->surface),
924 &src_rect, real_dst_bitmap->surface, &dst_rect);
926 #if defined(TARGET_SDL2)
927 if (dst_bitmap == window)
929 // SDL_UpdateWindowSurface(sdl_window);
930 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
931 UpdateScreen(&dst_rect);
934 if (dst_bitmap == window)
935 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
939 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
942 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
945 if (dst_bitmap == backbuffer || dst_bitmap == window)
956 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
958 #if defined(TARGET_SDL2)
959 if (dst_bitmap == window)
961 // SDL_UpdateWindowSurface(sdl_window);
962 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
966 if (dst_bitmap == window)
967 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
971 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
972 int fade_mode, int fade_delay, int post_delay,
973 void (*draw_border_function)(void))
975 static boolean initialization_needed = TRUE;
976 static SDL_Surface *surface_source = NULL;
977 static SDL_Surface *surface_target = NULL;
978 static SDL_Surface *surface_black = NULL;
979 SDL_Surface *surface_screen = backbuffer->surface;
980 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
981 SDL_Rect src_rect, dst_rect;
982 #if defined(TARGET_SDL2)
985 int src_x = x, src_y = y;
986 int dst_x = x, dst_y = y;
987 unsigned int time_last, time_current;
989 /* check if screen size has changed */
990 if (surface_source != NULL && (video.width != surface_source->w ||
991 video.height != surface_source->h))
993 SDL_FreeSurface(surface_source);
994 SDL_FreeSurface(surface_target);
995 SDL_FreeSurface(surface_black);
997 initialization_needed = TRUE;
1003 src_rect.h = height;
1005 dst_x += video_xoffset;
1006 dst_y += video_yoffset;
1010 dst_rect.w = width; /* (ignored) */
1011 dst_rect.h = height; /* (ignored) */
1013 #if defined(TARGET_SDL2)
1014 dst_rect2 = dst_rect;
1017 if (initialization_needed)
1019 #if defined(TARGET_SDL2)
1020 unsigned int flags = 0;
1022 unsigned int flags = SDL_SRCALPHA;
1024 /* use same surface type as screen surface */
1025 if ((surface_screen->flags & SDL_HWSURFACE))
1026 flags |= SDL_HWSURFACE;
1028 flags |= SDL_SWSURFACE;
1031 /* create surface for temporary copy of screen buffer (source) */
1032 if ((surface_source =
1033 SDL_CreateRGBSurface(flags,
1036 surface_screen->format->BitsPerPixel,
1037 surface_screen->format->Rmask,
1038 surface_screen->format->Gmask,
1039 surface_screen->format->Bmask,
1040 surface_screen->format->Amask)) == NULL)
1041 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1043 /* create surface for cross-fading screen buffer (target) */
1044 if ((surface_target =
1045 SDL_CreateRGBSurface(flags,
1048 surface_screen->format->BitsPerPixel,
1049 surface_screen->format->Rmask,
1050 surface_screen->format->Gmask,
1051 surface_screen->format->Bmask,
1052 surface_screen->format->Amask)) == NULL)
1053 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1055 /* create black surface for fading from/to black */
1056 if ((surface_black =
1057 SDL_CreateRGBSurface(flags,
1060 surface_screen->format->BitsPerPixel,
1061 surface_screen->format->Rmask,
1062 surface_screen->format->Gmask,
1063 surface_screen->format->Bmask,
1064 surface_screen->format->Amask)) == NULL)
1065 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1067 /* completely fill the surface with black color pixels */
1068 SDL_FillRect(surface_black, NULL,
1069 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1071 initialization_needed = FALSE;
1074 /* copy source and target surfaces to temporary surfaces for fading */
1075 if (fade_mode & FADE_TYPE_TRANSFORM)
1077 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1078 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1080 else if (fade_mode & FADE_TYPE_FADE_IN)
1082 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1083 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1085 else /* FADE_TYPE_FADE_OUT */
1087 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1088 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1091 time_current = SDL_GetTicks();
1093 if (fade_mode == FADE_MODE_MELT)
1095 boolean done = FALSE;
1096 int melt_pixels = 2;
1097 int melt_columns = width / melt_pixels;
1098 int ypos[melt_columns];
1099 int max_steps = height / 8 + 32;
1104 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1105 #if defined(TARGET_SDL2)
1106 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1108 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1111 ypos[0] = -GetSimpleRandom(16);
1113 for (i = 1 ; i < melt_columns; i++)
1115 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1117 ypos[i] = ypos[i - 1] + r;
1130 time_last = time_current;
1131 time_current = SDL_GetTicks();
1132 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1133 steps_final = MIN(MAX(0, steps), max_steps);
1137 done = (steps_done >= steps_final);
1139 for (i = 0 ; i < melt_columns; i++)
1147 else if (ypos[i] < height)
1152 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1154 if (ypos[i] + dy >= height)
1155 dy = height - ypos[i];
1157 /* copy part of (appearing) target surface to upper area */
1158 src_rect.x = src_x + i * melt_pixels;
1159 // src_rect.y = src_y + ypos[i];
1161 src_rect.w = melt_pixels;
1163 src_rect.h = ypos[i] + dy;
1165 dst_rect.x = dst_x + i * melt_pixels;
1166 // dst_rect.y = dst_y + ypos[i];
1169 if (steps_done >= steps_final)
1170 SDL_BlitSurface(surface_target, &src_rect,
1171 surface_screen, &dst_rect);
1175 /* copy part of (disappearing) source surface to lower area */
1176 src_rect.x = src_x + i * melt_pixels;
1178 src_rect.w = melt_pixels;
1179 src_rect.h = height - ypos[i];
1181 dst_rect.x = dst_x + i * melt_pixels;
1182 dst_rect.y = dst_y + ypos[i];
1184 if (steps_done >= steps_final)
1185 SDL_BlitSurface(surface_source, &src_rect,
1186 surface_screen, &dst_rect);
1192 src_rect.x = src_x + i * melt_pixels;
1194 src_rect.w = melt_pixels;
1195 src_rect.h = height;
1197 dst_rect.x = dst_x + i * melt_pixels;
1200 if (steps_done >= steps_final)
1201 SDL_BlitSurface(surface_target, &src_rect,
1202 surface_screen, &dst_rect);
1206 if (steps_done >= steps_final)
1208 if (draw_border_function != NULL)
1209 draw_border_function();
1211 #if defined(TARGET_SDL2)
1212 // SDL_UpdateWindowSurface(sdl_window);
1213 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
1214 UpdateScreen(&dst_rect2);
1216 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1226 for (alpha = 0.0; alpha < 255.0;)
1228 time_last = time_current;
1229 time_current = SDL_GetTicks();
1230 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1231 alpha_final = MIN(MAX(0, alpha), 255);
1233 /* draw existing (source) image to screen buffer */
1234 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1236 /* draw new (target) image to screen buffer using alpha blending */
1237 #if defined(TARGET_SDL2)
1238 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1239 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1241 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1243 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1245 if (draw_border_function != NULL)
1246 draw_border_function();
1249 /* only update the region of the screen that is affected from fading */
1250 #if defined(TARGET_SDL2)
1251 // SDL_UpdateWindowSurface(sdl_window);
1252 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1253 UpdateScreen(&dst_rect);
1255 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1258 SDL_Flip(surface_screen);
1266 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1267 int to_x, int to_y, Uint32 color)
1269 SDL_Surface *surface = dst_bitmap->surface;
1273 swap_numbers(&from_x, &to_x);
1276 swap_numbers(&from_y, &to_y);
1280 rect.w = (to_x - from_x + 1);
1281 rect.h = (to_y - from_y + 1);
1283 if (dst_bitmap == backbuffer || dst_bitmap == window)
1285 rect.x += video_xoffset;
1286 rect.y += video_yoffset;
1289 SDL_FillRect(surface, &rect, color);
1292 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1293 int to_x, int to_y, Uint32 color)
1295 if (dst_bitmap == backbuffer || dst_bitmap == window)
1297 from_x += video_xoffset;
1298 from_y += video_yoffset;
1299 to_x += video_xoffset;
1300 to_y += video_yoffset;
1303 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1307 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1308 int num_points, Uint32 color)
1313 for (i = 0; i < num_points - 1; i++)
1315 for (x = 0; x < line_width; x++)
1317 for (y = 0; y < line_width; y++)
1319 int dx = x - line_width / 2;
1320 int dy = y - line_width / 2;
1322 if ((x == 0 && y == 0) ||
1323 (x == 0 && y == line_width - 1) ||
1324 (x == line_width - 1 && y == 0) ||
1325 (x == line_width - 1 && y == line_width - 1))
1328 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1329 points[i+1].x + dx, points[i+1].y + dy, color);
1336 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1338 SDL_Surface *surface = src_bitmap->surface;
1340 if (src_bitmap == backbuffer || src_bitmap == window)
1346 switch (surface->format->BytesPerPixel)
1348 case 1: /* assuming 8-bpp */
1350 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1354 case 2: /* probably 15-bpp or 16-bpp */
1356 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1360 case 3: /* slow 24-bpp mode; usually not used */
1362 /* does this work? */
1363 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1367 shift = surface->format->Rshift;
1368 color |= *(pix + shift / 8) >> shift;
1369 shift = surface->format->Gshift;
1370 color |= *(pix + shift / 8) >> shift;
1371 shift = surface->format->Bshift;
1372 color |= *(pix + shift / 8) >> shift;
1378 case 4: /* probably 32-bpp */
1380 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1389 /* ========================================================================= */
1390 /* The following functions were taken from the SGE library */
1391 /* (SDL Graphics Extension Library) by Anders Lindström */
1392 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1393 /* ========================================================================= */
1395 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1397 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1399 switch (surface->format->BytesPerPixel)
1403 /* Assuming 8-bpp */
1404 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1410 /* Probably 15-bpp or 16-bpp */
1411 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1417 /* Slow 24-bpp mode, usually not used */
1421 /* Gack - slow, but endian correct */
1422 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1423 shift = surface->format->Rshift;
1424 *(pix+shift/8) = color>>shift;
1425 shift = surface->format->Gshift;
1426 *(pix+shift/8) = color>>shift;
1427 shift = surface->format->Bshift;
1428 *(pix+shift/8) = color>>shift;
1434 /* Probably 32-bpp */
1435 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1442 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1443 Uint8 R, Uint8 G, Uint8 B)
1445 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1448 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1450 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1453 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1455 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1458 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1463 /* Gack - slow, but endian correct */
1464 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1465 shift = surface->format->Rshift;
1466 *(pix+shift/8) = color>>shift;
1467 shift = surface->format->Gshift;
1468 *(pix+shift/8) = color>>shift;
1469 shift = surface->format->Bshift;
1470 *(pix+shift/8) = color>>shift;
1473 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1475 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1478 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1480 switch (dest->format->BytesPerPixel)
1483 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1487 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1491 _PutPixel24(dest,x,y,color);
1495 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1500 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1502 if (SDL_MUSTLOCK(surface))
1504 if (SDL_LockSurface(surface) < 0)
1510 _PutPixel(surface, x, y, color);
1512 if (SDL_MUSTLOCK(surface))
1514 SDL_UnlockSurface(surface);
1518 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1519 Uint8 r, Uint8 g, Uint8 b)
1521 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1524 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1526 if (y >= 0 && y <= dest->h - 1)
1528 switch (dest->format->BytesPerPixel)
1531 return y*dest->pitch;
1535 return y*dest->pitch/2;
1539 return y*dest->pitch;
1543 return y*dest->pitch/4;
1551 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1553 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1555 switch (surface->format->BytesPerPixel)
1559 /* Assuming 8-bpp */
1560 *((Uint8 *)surface->pixels + ypitch + x) = color;
1566 /* Probably 15-bpp or 16-bpp */
1567 *((Uint16 *)surface->pixels + ypitch + x) = color;
1573 /* Slow 24-bpp mode, usually not used */
1577 /* Gack - slow, but endian correct */
1578 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1579 shift = surface->format->Rshift;
1580 *(pix+shift/8) = color>>shift;
1581 shift = surface->format->Gshift;
1582 *(pix+shift/8) = color>>shift;
1583 shift = surface->format->Bshift;
1584 *(pix+shift/8) = color>>shift;
1590 /* Probably 32-bpp */
1591 *((Uint32 *)surface->pixels + ypitch + x) = color;
1598 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1603 if (SDL_MUSTLOCK(Surface))
1605 if (SDL_LockSurface(Surface) < 0)
1618 /* Do the clipping */
1619 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1623 if (x2 > Surface->w - 1)
1624 x2 = Surface->w - 1;
1631 SDL_FillRect(Surface, &l, Color);
1633 if (SDL_MUSTLOCK(Surface))
1635 SDL_UnlockSurface(Surface);
1639 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1640 Uint8 R, Uint8 G, Uint8 B)
1642 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1645 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1656 /* Do the clipping */
1657 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1661 if (x2 > Surface->w - 1)
1662 x2 = Surface->w - 1;
1669 SDL_FillRect(Surface, &l, Color);
1672 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1677 if (SDL_MUSTLOCK(Surface))
1679 if (SDL_LockSurface(Surface) < 0)
1692 /* Do the clipping */
1693 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1697 if (y2 > Surface->h - 1)
1698 y2 = Surface->h - 1;
1705 SDL_FillRect(Surface, &l, Color);
1707 if (SDL_MUSTLOCK(Surface))
1709 SDL_UnlockSurface(Surface);
1713 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1714 Uint8 R, Uint8 G, Uint8 B)
1716 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1719 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1730 /* Do the clipping */
1731 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1735 if (y2 > Surface->h - 1)
1736 y2 = Surface->h - 1;
1743 SDL_FillRect(Surface, &l, Color);
1746 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1747 Sint16 x2, Sint16 y2, Uint32 Color,
1748 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1751 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1756 sdx = (dx < 0) ? -1 : 1;
1757 sdy = (dy < 0) ? -1 : 1;
1769 for (x = 0; x < dx; x++)
1771 Callback(Surface, px, py, Color);
1785 for (y = 0; y < dy; y++)
1787 Callback(Surface, px, py, Color);
1801 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1802 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1803 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1806 sge_DoLine(Surface, X1, Y1, X2, Y2,
1807 SDL_MapRGB(Surface->format, R, G, B), Callback);
1810 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1813 if (SDL_MUSTLOCK(Surface))
1815 if (SDL_LockSurface(Surface) < 0)
1820 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1822 /* unlock the display */
1823 if (SDL_MUSTLOCK(Surface))
1825 SDL_UnlockSurface(Surface);
1829 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1830 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1832 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1835 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1837 if (dst_bitmap == backbuffer || dst_bitmap == window)
1843 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1848 -----------------------------------------------------------------------------
1849 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1850 -----------------------------------------------------------------------------
1853 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1854 int width, int height, Uint32 color)
1858 for (y = src_y; y < src_y + height; y++)
1860 for (x = src_x; x < src_x + width; x++)
1862 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1864 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1869 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1870 int src_x, int src_y, int width, int height,
1871 int dst_x, int dst_y)
1875 for (y = 0; y < height; y++)
1877 for (x = 0; x < width; x++)
1879 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1881 if (pixel != BLACK_PIXEL)
1882 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1888 /* ========================================================================= */
1889 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1890 /* (Rotozoomer) by Andreas Schiffler */
1891 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1892 /* ========================================================================= */
1895 -----------------------------------------------------------------------------
1898 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1899 -----------------------------------------------------------------------------
1910 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1913 tColorRGBA *sp, *csp, *dp;
1920 sp = csp = (tColorRGBA *) src->pixels;
1921 dp = (tColorRGBA *) dst->pixels;
1923 sgap = src->pitch - src->w * 4;
1925 dgap = dst->pitch - dst->w * 4;
1927 for (y = 0; y < dst->h; y++)
1931 for (x = 0; x < dst->w; x++)
1933 tColorRGBA *sp0 = sp;
1934 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1935 tColorRGBA *sp00 = &sp0[0];
1936 tColorRGBA *sp01 = &sp0[1];
1937 tColorRGBA *sp10 = &sp1[0];
1938 tColorRGBA *sp11 = &sp1[1];
1941 /* create new color pixel from all four source color pixels */
1942 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1943 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1944 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1945 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1950 /* advance source pointers */
1953 /* advance destination pointer */
1957 /* advance source pointer */
1958 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1960 /* advance destination pointers */
1961 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1967 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1969 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1970 tColorRGBA *sp, *csp, *dp;
1976 /* use specialized zoom function when scaling down to exactly half size */
1977 if (src->w == 2 * dst->w &&
1978 src->h == 2 * dst->h)
1979 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1981 /* variable setup */
1982 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1983 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1985 /* allocate memory for row increments */
1986 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1987 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1989 /* precalculate row increments */
1992 for (x = 0; x <= dst->w; x++)
2002 for (y = 0; y <= dst->h; y++)
2011 sp = csp = (tColorRGBA *) src->pixels;
2012 dp = (tColorRGBA *) dst->pixels;
2014 sgap = src->pitch - src->w * 4;
2016 dgap = dst->pitch - dst->w * 4;
2019 for (y = 0; y < dst->h; y++)
2024 for (x = 0; x < dst->w; x++)
2029 /* advance source pointers */
2031 sp += (*csax >> 16);
2033 /* advance destination pointer */
2037 /* advance source pointer */
2039 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
2041 /* advance destination pointers */
2042 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2052 -----------------------------------------------------------------------------
2055 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2056 -----------------------------------------------------------------------------
2059 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2061 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2062 Uint8 *sp, *dp, *csp;
2065 /* variable setup */
2066 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2067 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2069 /* allocate memory for row increments */
2070 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2071 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2073 /* precalculate row increments */
2076 for (x = 0; x < dst->w; x++)
2079 *csax = (csx >> 16);
2086 for (y = 0; y < dst->h; y++)
2089 *csay = (csy >> 16);
2096 for (x = 0; x < dst->w; x++)
2104 for (y = 0; y < dst->h; y++)
2111 sp = csp = (Uint8 *) src->pixels;
2112 dp = (Uint8 *) dst->pixels;
2113 dgap = dst->pitch - dst->w;
2117 for (y = 0; y < dst->h; y++)
2121 for (x = 0; x < dst->w; x++)
2126 /* advance source pointers */
2130 /* advance destination pointer */
2134 /* advance source pointer (for row) */
2135 csp += ((*csay) * src->pitch);
2138 /* advance destination pointers */
2149 -----------------------------------------------------------------------------
2152 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2153 'zoomx' and 'zoomy' are scaling factors for width and height.
2154 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2155 into a 32bit RGBA format on the fly.
2156 -----------------------------------------------------------------------------
2159 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2161 SDL_Surface *zoom_src = NULL;
2162 SDL_Surface *zoom_dst = NULL;
2163 boolean is_converted = FALSE;
2170 /* determine if source surface is 32 bit or 8 bit */
2171 is_32bit = (src->format->BitsPerPixel == 32);
2173 if (is_32bit || src->format->BitsPerPixel == 8)
2175 /* use source surface 'as is' */
2180 /* new source surface is 32 bit with a defined RGB ordering */
2181 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
2182 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2183 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2185 is_converted = TRUE;
2188 /* allocate surface to completely contain the zoomed surface */
2191 /* target surface is 32 bit with source RGBA/ABGR ordering */
2192 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
2193 zoom_src->format->Rmask,
2194 zoom_src->format->Gmask,
2195 zoom_src->format->Bmask, 0);
2199 /* target surface is 8 bit */
2200 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
2204 /* lock source surface */
2205 SDL_LockSurface(zoom_src);
2207 /* check which kind of surface we have */
2210 /* call the 32 bit transformation routine to do the zooming */
2211 zoomSurfaceRGBA(zoom_src, zoom_dst);
2216 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2217 zoom_dst->format->palette->colors[i] =
2218 zoom_src->format->palette->colors[i];
2219 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2221 /* call the 8 bit transformation routine to do the zooming */
2222 zoomSurfaceY(zoom_src, zoom_dst);
2225 /* unlock source surface */
2226 SDL_UnlockSurface(zoom_src);
2228 /* free temporary surface */
2230 SDL_FreeSurface(zoom_src);
2232 /* return destination surface */
2236 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
2238 SDL_Surface *sdl_surface_tmp;
2239 int dst_width = dst_bitmap->width;
2240 int dst_height = dst_bitmap->height;
2242 /* throw away old destination surface */
2243 SDL_FreeSurface(dst_bitmap->surface);
2245 /* create zoomed temporary surface from source surface */
2246 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2248 /* create native format destination surface from zoomed temporary surface */
2249 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
2251 /* free temporary surface */
2252 SDL_FreeSurface(sdl_surface_tmp);
2256 /* ========================================================================= */
2257 /* load image to bitmap */
2258 /* ========================================================================= */
2260 Bitmap *SDLLoadImage(char *filename)
2262 Bitmap *new_bitmap = CreateBitmapStruct();
2263 SDL_Surface *sdl_image_tmp;
2265 print_timestamp_init("SDLLoadImage");
2267 print_timestamp_time(getBaseNamePtr(filename));
2269 /* load image to temporary surface */
2270 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2272 SetError("IMG_Load(): %s", SDL_GetError());
2277 print_timestamp_time("IMG_Load");
2279 UPDATE_BUSY_STATE();
2281 /* create native non-transparent surface for current image */
2282 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2284 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2289 print_timestamp_time("SDL_DisplayFormat (opaque)");
2291 UPDATE_BUSY_STATE();
2293 /* create native transparent surface for current image */
2294 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2295 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2296 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2298 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2303 print_timestamp_time("SDL_DisplayFormat (masked)");
2305 UPDATE_BUSY_STATE();
2307 /* free temporary surface */
2308 SDL_FreeSurface(sdl_image_tmp);
2310 new_bitmap->width = new_bitmap->surface->w;
2311 new_bitmap->height = new_bitmap->surface->h;
2313 print_timestamp_done("SDLLoadImage");
2319 /* ------------------------------------------------------------------------- */
2320 /* custom cursor fuctions */
2321 /* ------------------------------------------------------------------------- */
2323 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2325 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2326 cursor_info->width, cursor_info->height,
2327 cursor_info->hot_x, cursor_info->hot_y);
2330 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2332 static struct MouseCursorInfo *last_cursor_info = NULL;
2333 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2334 static SDL_Cursor *cursor_default = NULL;
2335 static SDL_Cursor *cursor_current = NULL;
2337 /* if invoked for the first time, store the SDL default cursor */
2338 if (cursor_default == NULL)
2339 cursor_default = SDL_GetCursor();
2341 /* only create new cursor if cursor info (custom only) has changed */
2342 if (cursor_info != NULL && cursor_info != last_cursor_info)
2344 cursor_current = create_cursor(cursor_info);
2345 last_cursor_info = cursor_info;
2348 /* only set new cursor if cursor info (custom or NULL) has changed */
2349 if (cursor_info != last_cursor_info2)
2350 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2352 last_cursor_info2 = cursor_info;
2356 /* ========================================================================= */
2357 /* audio functions */
2358 /* ========================================================================= */
2360 void SDLOpenAudio(void)
2362 #if !defined(TARGET_SDL2)
2363 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2364 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2367 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2369 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2373 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2374 AUDIO_NUM_CHANNELS_STEREO,
2375 setup.system.audio_fragment_size) < 0)
2377 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2381 audio.sound_available = TRUE;
2382 audio.music_available = TRUE;
2383 audio.loops_available = TRUE;
2384 audio.sound_enabled = TRUE;
2386 /* set number of available mixer channels */
2387 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2388 audio.music_channel = MUSIC_CHANNEL;
2389 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2391 Mixer_InitChannels();
2394 void SDLCloseAudio(void)
2397 Mix_HaltChannel(-1);
2400 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2404 /* ========================================================================= */
2405 /* event functions */
2406 /* ========================================================================= */
2408 void SDLNextEvent(Event *event)
2410 SDL_WaitEvent(event);
2412 if (event->type == EVENT_BUTTONPRESS ||
2413 event->type == EVENT_BUTTONRELEASE)
2415 if (((ButtonEvent *)event)->x > video_xoffset)
2416 ((ButtonEvent *)event)->x -= video_xoffset;
2418 ((ButtonEvent *)event)->x = 0;
2419 if (((ButtonEvent *)event)->y > video_yoffset)
2420 ((ButtonEvent *)event)->y -= video_yoffset;
2422 ((ButtonEvent *)event)->y = 0;
2424 else if (event->type == EVENT_MOTIONNOTIFY)
2426 if (((MotionEvent *)event)->x > video_xoffset)
2427 ((MotionEvent *)event)->x -= video_xoffset;
2429 ((MotionEvent *)event)->x = 0;
2430 if (((MotionEvent *)event)->y > video_yoffset)
2431 ((MotionEvent *)event)->y -= video_yoffset;
2433 ((MotionEvent *)event)->y = 0;
2437 void SDLHandleWindowManagerEvent(Event *event)
2439 #if defined(PLATFORM_WIN32)
2440 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2441 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2443 if (syswmmsg->msg == WM_DROPFILES)
2445 HDROP hdrop = (HDROP)syswmmsg->wParam;
2448 printf("::: SDL_SYSWMEVENT:\n");
2450 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2452 for (i = 0; i < num_files; i++)
2454 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2455 char buffer[buffer_len + 1];
2457 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2459 printf("::: - '%s'\n", buffer);
2462 DragFinish((HDROP)syswmmsg->wParam);
2468 /* ========================================================================= */
2469 /* joystick functions */
2470 /* ========================================================================= */
2472 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2473 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2474 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2476 static boolean SDLOpenJoystick(int nr)
2478 if (nr < 0 || nr > MAX_PLAYERS)
2481 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2484 static void SDLCloseJoystick(int nr)
2486 if (nr < 0 || nr > MAX_PLAYERS)
2489 SDL_JoystickClose(sdl_joystick[nr]);
2491 sdl_joystick[nr] = NULL;
2494 static boolean SDLCheckJoystickOpened(int nr)
2496 if (nr < 0 || nr > MAX_PLAYERS)
2499 #if defined(TARGET_SDL2)
2500 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2502 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2506 void HandleJoystickEvent(Event *event)
2510 case SDL_JOYAXISMOTION:
2511 if (event->jaxis.axis < 2)
2512 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2515 case SDL_JOYBUTTONDOWN:
2516 if (event->jbutton.button < 2)
2517 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2520 case SDL_JOYBUTTONUP:
2521 if (event->jbutton.button < 2)
2522 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2530 void SDLInitJoysticks()
2532 static boolean sdl_joystick_subsystem_initialized = FALSE;
2533 boolean print_warning = !sdl_joystick_subsystem_initialized;
2536 if (!sdl_joystick_subsystem_initialized)
2538 sdl_joystick_subsystem_initialized = TRUE;
2540 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2542 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2547 for (i = 0; i < MAX_PLAYERS; i++)
2549 /* get configured joystick for this player */
2550 char *device_name = setup.input[i].joy.device_name;
2551 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2553 if (joystick_nr >= SDL_NumJoysticks())
2555 if (setup.input[i].use_joystick && print_warning)
2556 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2561 /* misuse joystick file descriptor variable to store joystick number */
2562 joystick.fd[i] = joystick_nr;
2564 if (joystick_nr == -1)
2567 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2568 if (SDLCheckJoystickOpened(joystick_nr))
2569 SDLCloseJoystick(joystick_nr);
2571 if (!setup.input[i].use_joystick)
2574 if (!SDLOpenJoystick(joystick_nr))
2577 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2582 joystick.status = JOYSTICK_ACTIVATED;
2586 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2588 if (nr < 0 || nr >= MAX_PLAYERS)
2592 *x = sdl_js_axis[nr][0];
2594 *y = sdl_js_axis[nr][1];
2597 *b1 = sdl_js_button[nr][0];
2599 *b2 = sdl_js_button[nr][1];
2604 #endif /* TARGET_SDL */