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;
43 static boolean limit_screen_updates = FALSE;
46 /* functions from SGE library */
47 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
49 void SDLLimitScreenUpdates(boolean enable)
51 limit_screen_updates = enable;
54 static void UpdateScreen(SDL_Rect *rect)
56 static unsigned int update_screen_delay = 0;
57 unsigned int update_screen_delay_value = 20; /* (milliseconds) */
60 if (limit_screen_updates &&
61 !DelayReached(&update_screen_delay, update_screen_delay_value))
64 LimitScreenUpdates(FALSE);
67 #if defined(TARGET_SDL2)
69 SDL_Surface *screen = backbuffer->surface;
74 int bytes_x = screen->pitch / video.width;
75 int bytes_y = screen->pitch;
77 if (video.fullscreen_enabled)
78 bytes_x = screen->pitch / fullscreen_width;
80 SDL_UpdateTexture(sdl_texture, rect,
81 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
86 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
89 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
91 SDL_RenderClear(sdl_renderer);
92 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
93 SDL_RenderPresent(sdl_renderer);
96 SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
98 SDL_UpdateWindowSurface(sdl_window);
103 SDL_UpdateRects(backbuffer->surface, 1, rect);
105 SDL_UpdateRect(backbuffer->surface, 0, 0, 0, 0);
109 static void setFullscreenParameters(char *fullscreen_mode_string)
111 #if defined(TARGET_SDL2)
112 fullscreen_width = video.width;
113 fullscreen_height = video.height;
114 fullscreen_xoffset = 0;
115 fullscreen_yoffset = 0;
119 struct ScreenModeInfo *fullscreen_mode;
122 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
124 if (fullscreen_mode == NULL)
127 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
129 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
130 fullscreen_mode->height == video.fullscreen_modes[i].height)
132 fullscreen_width = fullscreen_mode->width;
133 fullscreen_height = fullscreen_mode->height;
135 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
136 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
144 static void SDLSetWindowIcon(char *basename)
146 /* (setting the window icon on Mac OS X would replace the high-quality
147 dock icon with the currently smaller (and uglier) icon from file) */
149 #if !defined(PLATFORM_MACOSX)
150 char *filename = getCustomImageFilename(basename);
151 SDL_Surface *surface;
153 if (filename == NULL)
155 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
160 if ((surface = IMG_Load(filename)) == NULL)
162 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
167 /* set transparent color */
168 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
169 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
171 #if defined(TARGET_SDL2)
172 SDL_SetWindowIcon(sdl_window, surface);
174 SDL_WM_SetIcon(surface, NULL);
179 #if defined(TARGET_SDL2)
180 SDL_Surface *SDL_DisplayFormat(SDL_Surface *surface)
182 if (backbuffer == NULL ||
183 backbuffer->surface == NULL)
186 return SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
190 void SDLInitVideoDisplay(void)
192 #if !defined(TARGET_SDL2)
193 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
194 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
196 SDL_putenv("SDL_VIDEO_CENTERED=1");
199 /* initialize SDL video */
200 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
201 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
203 /* set default SDL depth */
204 #if !defined(TARGET_SDL2)
205 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
207 video.default_depth = 32; // (how to determine video depth in SDL2?)
211 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
214 #if !defined(TARGET_SDL2)
215 static int screen_xy[][2] =
223 SDL_Rect **modes = NULL;
224 boolean hardware_fullscreen_available = TRUE;
227 /* default: normal game window size */
228 fullscreen_width = video.width;
229 fullscreen_height = video.height;
230 fullscreen_xoffset = 0;
231 fullscreen_yoffset = 0;
233 #if !defined(TARGET_SDL2)
234 /* determine required standard fullscreen mode for game screen size */
235 for (i = 0; screen_xy[i][0] != -1; i++)
237 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
239 fullscreen_width = screen_xy[i][0];
240 fullscreen_height = screen_xy[i][1];
246 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
247 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
251 checked_free(video.fullscreen_modes);
253 video.fullscreen_modes = NULL;
254 video.fullscreen_mode_current = NULL;
257 video.window_scaling_percent = setup.window_scaling_percent;
259 #if defined(TARGET_SDL2)
260 int num_displays = SDL_GetNumVideoDisplays();
262 if (num_displays > 0)
264 // currently only display modes of first display supported
265 int num_modes = SDL_GetNumDisplayModes(0);
269 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
271 for (i = 0; i < num_modes; i++)
273 SDL_DisplayMode mode;
275 if (SDL_GetDisplayMode(0, i, &mode) < 0)
278 modes[i] = checked_calloc(sizeof(SDL_Rect));
280 modes[i]->w = mode.w;
281 modes[i]->h = mode.h;
286 /* get available hardware supported fullscreen modes */
287 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
292 /* no hardware screen modes available => no fullscreen mode support */
293 // video.fullscreen_available = FALSE;
294 hardware_fullscreen_available = FALSE;
296 else if (modes == (SDL_Rect **)-1)
298 /* fullscreen resolution is not restricted -- all resolutions available */
299 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
301 /* use native video buffer size for fullscreen mode */
302 video.fullscreen_modes[0].width = video.width;
303 video.fullscreen_modes[0].height = video.height;
305 video.fullscreen_modes[1].width = -1;
306 video.fullscreen_modes[1].height = -1;
310 /* in this case, a certain number of screen modes is available */
313 for (i = 0; modes[i] != NULL; i++)
315 boolean found_mode = FALSE;
317 /* screen mode is smaller than video buffer size -- skip it */
318 if (modes[i]->w < video.width || modes[i]->h < video.height)
321 if (video.fullscreen_modes != NULL)
322 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
323 if (modes[i]->w == video.fullscreen_modes[j].width &&
324 modes[i]->h == video.fullscreen_modes[j].height)
327 if (found_mode) /* screen mode already stored -- skip it */
330 /* new mode found; add it to list of available fullscreen modes */
334 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
336 sizeof(struct ScreenModeInfo));
338 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
339 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
341 video.fullscreen_modes[num_modes].width = -1;
342 video.fullscreen_modes[num_modes].height = -1;
347 /* no appropriate screen modes available => no fullscreen mode support */
348 // video.fullscreen_available = FALSE;
349 hardware_fullscreen_available = FALSE;
353 video.fullscreen_available = hardware_fullscreen_available;
355 #if USE_DESKTOP_FULLSCREEN
356 // in SDL 2.0, there is always support for desktop fullscreen mode
357 // (in SDL 1.2, there is only support for "real" fullscreen mode)
358 video.fullscreen_available = TRUE;
361 #if defined(TARGET_SDL2)
364 for (i = 0; modes[i] != NULL; i++)
365 checked_free(modes[i]);
372 /* set window icon */
373 SDLSetWindowIcon(program.sdl_icon_filename);
376 /* open SDL video output device (window or fullscreen mode) */
377 if (!SDLSetVideoMode(backbuffer, fullscreen))
378 Error(ERR_EXIT, "setting video mode failed");
381 /* !!! SDL2 can only set the window icon if the window already exists !!! */
382 /* set window icon */
383 SDLSetWindowIcon(program.sdl_icon_filename);
386 /* set window and icon title */
387 #if defined(TARGET_SDL2)
388 SDL_SetWindowTitle(sdl_window, program.window_title);
390 SDL_WM_SetCaption(program.window_title, program.window_title);
393 /* SDL cannot directly draw to the visible video framebuffer like X11,
394 but always uses a backbuffer, which is then blitted to the visible
395 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
396 visible video framebuffer with 'SDL_Flip', if the hardware supports
397 this). Therefore do not use an additional backbuffer for drawing, but
398 use a symbolic buffer (distinguishable from the SDL backbuffer) called
399 'window', which indicates that the SDL backbuffer should be updated to
400 the visible video framebuffer when attempting to blit to it.
402 For convenience, it seems to be a good idea to create this symbolic
403 buffer 'window' at the same size as the SDL backbuffer. Although it
404 should never be drawn to directly, it would do no harm nevertheless. */
406 /* create additional (symbolic) buffer for double-buffering */
408 ReCreateBitmap(window, video.width, video.height, video.depth);
410 *window = CreateBitmap(video.width, video.height, video.depth);
414 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
417 SDL_Surface *new_surface = NULL;
419 #if defined(TARGET_SDL2)
420 static boolean fullscreen_enabled = FALSE;
421 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
422 #if USE_DESKTOP_FULLSCREEN
423 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
425 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
429 int surface_flags_window = SURFACE_FLAGS;
430 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
433 int width = (fullscreen ? fullscreen_width : video.width);
434 int height = (fullscreen ? fullscreen_height : video.height);
435 int surface_flags = (fullscreen ? surface_flags_fullscreen :
436 surface_flags_window);
438 // default window size is unscaled
439 video.window_width = video.width;
440 video.window_height = video.height;
442 #if defined(TARGET_SDL2)
444 // store if initial screen mode on game start is fullscreen mode
445 if (sdl_window == NULL)
448 printf("::: GAME STARTS WITH FULLSCREEN %d\n", fullscreen);
451 video.fullscreen_initial = fullscreen;
455 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
456 #if !USE_DESKTOP_FULLSCREEN
457 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
460 video.window_width = window_scaling_factor * width;
461 video.window_height = window_scaling_factor * height;
464 printf("::: use window scaling factor %f\n", screen_scaling_factor);
467 if ((*backbuffer)->surface)
469 SDL_FreeSurface((*backbuffer)->surface);
470 (*backbuffer)->surface = NULL;
475 SDL_DestroyTexture(sdl_texture);
479 if (!(fullscreen && fullscreen_enabled))
483 SDL_DestroyRenderer(sdl_renderer);
489 SDL_DestroyWindow(sdl_window);
495 Error(ERR_INFO, "::: checking 'sdl_window' ...");
497 if (sdl_window == NULL)
498 Error(ERR_INFO, "::: calling SDL_CreateWindow() [%d, %d, %d] ...",
499 setup.fullscreen, fullscreen, fullscreen_enabled);
502 if (sdl_window == NULL)
503 sdl_window = SDL_CreateWindow(program.window_title,
504 SDL_WINDOWPOS_CENTERED,
505 SDL_WINDOWPOS_CENTERED,
506 #if USE_DESKTOP_FULLSCREEN
510 (int)(screen_scaling_factor * width),
511 (int)(screen_scaling_factor * height),
515 if (sdl_window != NULL)
517 if (sdl_renderer == NULL)
518 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
520 if (sdl_renderer != NULL)
522 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
523 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
525 sdl_texture = SDL_CreateTexture(sdl_renderer,
526 SDL_PIXELFORMAT_ARGB8888,
527 SDL_TEXTUREACCESS_STREAMING,
530 if (sdl_texture != NULL)
533 // (do not use alpha channel)
534 new_surface = SDL_CreateRGBSurface(0, width, height, 32,
540 // (this uses an alpha channel, which we don't want here)
541 new_surface = SDL_CreateRGBSurface(0, width, height, 32,
548 if (new_surface == NULL)
549 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
554 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
559 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
564 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
570 SDL_DestroyWindow(sdl_window);
572 sdl_window = SDL_CreateWindow(program.window_title,
573 SDL_WINDOWPOS_CENTERED,
574 SDL_WINDOWPOS_CENTERED,
578 if (sdl_window != NULL)
579 new_surface = SDL_GetWindowSurface(sdl_window);
583 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
586 #if defined(TARGET_SDL2)
587 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
588 if (new_surface != NULL)
589 fullscreen_enabled = fullscreen;
595 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
597 boolean success = TRUE;
600 #if defined(TARGET_SDL2)
601 // int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
602 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
603 int surface_flags_window = SURFACE_FLAGS;
605 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
606 int surface_flags_window = SURFACE_FLAGS;
609 SDL_Surface *new_surface = NULL;
611 if (*backbuffer == NULL)
612 *backbuffer = CreateBitmapStruct();
614 /* (real bitmap might be larger in fullscreen mode with video offsets) */
615 (*backbuffer)->width = video.width;
616 (*backbuffer)->height = video.height;
618 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
620 setFullscreenParameters(setup.fullscreen_mode);
622 video_xoffset = fullscreen_xoffset;
623 video_yoffset = fullscreen_yoffset;
625 /* switch display to fullscreen mode, if available */
627 new_surface = SDLCreateScreen(backbuffer, TRUE);
630 #if defined(TARGET_SDL2)
631 sdl_window = SDL_CreateWindow(program.window_title,
632 SDL_WINDOWPOS_CENTERED,
633 SDL_WINDOWPOS_CENTERED,
634 fullscreen_width, fullscreen_height,
635 surface_flags_fullscreen);
636 if (sdl_window != NULL)
638 new_surface = SDL_GetWindowSurface(sdl_window);
640 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
641 // UpdateScreen(NULL); // immediately map window
644 new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
645 video.depth, surface_flags_fullscreen);
649 if (new_surface == NULL)
651 /* switching display to fullscreen mode failed */
652 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
654 /* do not try it again */
655 video.fullscreen_available = FALSE;
661 (*backbuffer)->surface = new_surface;
663 video.fullscreen_enabled = TRUE;
664 video.fullscreen_mode_current = setup.fullscreen_mode;
670 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
675 /* switch display to window mode */
677 new_surface = SDLCreateScreen(backbuffer, FALSE);
680 #if defined(TARGET_SDL2)
683 float screen_scaling_factor = 1.2;
684 int test_fullscreen = 0;
685 int surface_flags = (test_fullscreen ? surface_flags_fullscreen :
686 surface_flags_window);
688 if ((*backbuffer)->surface)
689 SDL_FreeSurface((*backbuffer)->surface);
692 SDL_DestroyTexture(sdl_texture);
695 SDL_DestroyRenderer(sdl_renderer);
698 SDL_DestroyWindow(sdl_window);
700 sdl_window = SDL_CreateWindow(program.window_title,
701 SDL_WINDOWPOS_CENTERED,
702 SDL_WINDOWPOS_CENTERED,
703 (int)(screen_scaling_factor * video.width),
704 (int)(screen_scaling_factor * video.height),
707 if (sdl_window != NULL)
709 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
711 if (sdl_renderer != NULL)
713 SDL_RenderSetLogicalSize(sdl_renderer, video.width, video.height);
714 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
716 sdl_texture = SDL_CreateTexture(sdl_renderer,
717 SDL_PIXELFORMAT_ARGB8888,
718 SDL_TEXTUREACCESS_STREAMING,
719 video.width, video.height);
721 if (sdl_texture != NULL)
724 // (do not use alpha channel)
725 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
731 // (this uses an alpha channel, which we don't want here)
732 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
739 if (new_surface == NULL)
740 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
745 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
750 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
755 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
761 SDL_DestroyWindow(sdl_window);
763 sdl_window = SDL_CreateWindow(program.window_title,
764 SDL_WINDOWPOS_CENTERED,
765 SDL_WINDOWPOS_CENTERED,
766 video.width, video.height,
767 surface_flags_window);
769 if (sdl_window != NULL)
771 new_surface = SDL_GetWindowSurface(sdl_window);
773 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
774 // UpdateScreen(NULL); // immediately map window
779 new_surface = SDL_SetVideoMode(video.width, video.height,
780 video.depth, surface_flags_window);
784 if (new_surface == NULL)
786 /* switching display to window mode failed -- should not happen */
787 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
793 (*backbuffer)->surface = new_surface;
795 video.fullscreen_enabled = FALSE;
796 video.window_scaling_percent = setup.window_scaling_percent;
802 #if defined(TARGET_SDL2)
803 SDLRedrawWindow(); // map window
804 // UpdateScreen(NULL); // map window
808 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
810 #if defined(PLATFORM_WIN32)
812 SDL_SysWMinfo wminfo;
815 SDL_VERSION(&wminfo.version);
816 SDL_GetWMInfo(&wminfo);
818 hwnd = wminfo.window;
820 DragAcceptFiles(hwnd, TRUE);
828 #if defined(TARGET_SDL2)
829 void SDLSetWindowScaling(int window_scaling_percent)
831 if (sdl_window == NULL)
834 float window_scaling_factor = (float)window_scaling_percent / 100;
835 int new_window_width = (int)(window_scaling_factor * video.width);
836 int new_window_height = (int)(window_scaling_factor * video.height);
839 Error(ERR_DEBUG, "::: SDLSetWindowScaling(%d) ...", window_scaling_percent);
842 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
844 video.window_scaling_percent = window_scaling_percent;
845 video.window_width = new_window_width;
846 video.window_height = new_window_height;
849 void SDLSetWindowFullscreen(boolean fullscreen)
851 if (sdl_window == NULL)
854 #if USE_DESKTOP_FULLSCREEN
855 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
857 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
861 Error(ERR_DEBUG, "::: SDL_SetWindowFullscreen(%d) ...", fullscreen);
864 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
865 video.fullscreen_enabled = fullscreen;
868 printf("::: SDLSetWindowFullscreen: %d, %d\n",
869 fullscreen, video.fullscreen_initial);
873 // if game started in fullscreen mode, window will also get fullscreen size
874 if (!fullscreen && video.fullscreen_initial)
876 SDLSetWindowScaling(setup.window_scaling_percent);
877 SDL_SetWindowPosition(sdl_window,
878 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
880 video.fullscreen_initial = FALSE;
885 void SDLRedrawWindow()
891 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
894 SDL_Surface *surface_tmp, *surface_native;
896 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
899 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
901 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
902 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
904 SDL_FreeSurface(surface_tmp);
906 new_bitmap->surface = surface_native;
909 void SDLFreeBitmapPointers(Bitmap *bitmap)
912 SDL_FreeSurface(bitmap->surface);
913 if (bitmap->surface_masked)
914 SDL_FreeSurface(bitmap->surface_masked);
915 bitmap->surface = NULL;
916 bitmap->surface_masked = NULL;
919 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
920 int src_x, int src_y, int width, int height,
921 int dst_x, int dst_y, int mask_mode)
923 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
924 SDL_Rect src_rect, dst_rect;
926 if (src_bitmap == backbuffer)
928 src_x += video_xoffset;
929 src_y += video_yoffset;
937 if (dst_bitmap == backbuffer || dst_bitmap == window)
939 dst_x += video_xoffset;
940 dst_y += video_yoffset;
948 // if (src_bitmap != backbuffer || dst_bitmap != window)
949 if (!(src_bitmap == backbuffer && dst_bitmap == window))
950 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
951 src_bitmap->surface_masked : src_bitmap->surface),
952 &src_rect, real_dst_bitmap->surface, &dst_rect);
954 #if defined(TARGET_SDL2)
955 if (dst_bitmap == window)
957 // SDL_UpdateWindowSurface(sdl_window);
958 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
959 UpdateScreen(&dst_rect);
962 if (dst_bitmap == window)
964 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
965 UpdateScreen(&dst_rect);
970 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
973 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
976 if (dst_bitmap == backbuffer || dst_bitmap == window)
987 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
989 #if defined(TARGET_SDL2)
990 if (dst_bitmap == window)
992 // SDL_UpdateWindowSurface(sdl_window);
993 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
997 if (dst_bitmap == window)
999 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
1000 UpdateScreen(&rect);
1005 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
1006 int fade_mode, int fade_delay, int post_delay,
1007 void (*draw_border_function)(void))
1009 static boolean initialization_needed = TRUE;
1010 static SDL_Surface *surface_source = NULL;
1011 static SDL_Surface *surface_target = NULL;
1012 static SDL_Surface *surface_black = NULL;
1013 SDL_Surface *surface_screen = backbuffer->surface;
1014 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
1015 SDL_Rect src_rect, dst_rect;
1017 int src_x = x, src_y = y;
1018 int dst_x = x, dst_y = y;
1019 unsigned int time_last, time_current;
1021 /* check if screen size has changed */
1022 if (surface_source != NULL && (video.width != surface_source->w ||
1023 video.height != surface_source->h))
1025 SDL_FreeSurface(surface_source);
1026 SDL_FreeSurface(surface_target);
1027 SDL_FreeSurface(surface_black);
1029 initialization_needed = TRUE;
1035 src_rect.h = height;
1037 dst_x += video_xoffset;
1038 dst_y += video_yoffset;
1042 dst_rect.w = width; /* (ignored) */
1043 dst_rect.h = height; /* (ignored) */
1045 dst_rect2 = dst_rect;
1047 if (initialization_needed)
1049 #if defined(TARGET_SDL2)
1050 unsigned int flags = 0;
1052 unsigned int flags = SDL_SRCALPHA;
1054 /* use same surface type as screen surface */
1055 if ((surface_screen->flags & SDL_HWSURFACE))
1056 flags |= SDL_HWSURFACE;
1058 flags |= SDL_SWSURFACE;
1061 /* create surface for temporary copy of screen buffer (source) */
1062 if ((surface_source =
1063 SDL_CreateRGBSurface(flags,
1066 surface_screen->format->BitsPerPixel,
1067 surface_screen->format->Rmask,
1068 surface_screen->format->Gmask,
1069 surface_screen->format->Bmask,
1070 surface_screen->format->Amask)) == NULL)
1071 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1073 /* create surface for cross-fading screen buffer (target) */
1074 if ((surface_target =
1075 SDL_CreateRGBSurface(flags,
1078 surface_screen->format->BitsPerPixel,
1079 surface_screen->format->Rmask,
1080 surface_screen->format->Gmask,
1081 surface_screen->format->Bmask,
1082 surface_screen->format->Amask)) == NULL)
1083 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1085 /* create black surface for fading from/to black */
1086 if ((surface_black =
1087 SDL_CreateRGBSurface(flags,
1090 surface_screen->format->BitsPerPixel,
1091 surface_screen->format->Rmask,
1092 surface_screen->format->Gmask,
1093 surface_screen->format->Bmask,
1094 surface_screen->format->Amask)) == NULL)
1095 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1097 /* completely fill the surface with black color pixels */
1098 SDL_FillRect(surface_black, NULL,
1099 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1101 initialization_needed = FALSE;
1104 /* copy source and target surfaces to temporary surfaces for fading */
1105 if (fade_mode & FADE_TYPE_TRANSFORM)
1107 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1108 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1110 else if (fade_mode & FADE_TYPE_FADE_IN)
1112 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1113 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1115 else /* FADE_TYPE_FADE_OUT */
1117 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1118 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1121 time_current = SDL_GetTicks();
1123 if (fade_mode == FADE_MODE_MELT)
1125 boolean done = FALSE;
1126 int melt_pixels = 2;
1127 int melt_columns = width / melt_pixels;
1128 int ypos[melt_columns];
1129 int max_steps = height / 8 + 32;
1134 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1135 #if defined(TARGET_SDL2)
1136 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1138 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1141 ypos[0] = -GetSimpleRandom(16);
1143 for (i = 1 ; i < melt_columns; i++)
1145 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1147 ypos[i] = ypos[i - 1] + r;
1160 time_last = time_current;
1161 time_current = SDL_GetTicks();
1162 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1163 steps_final = MIN(MAX(0, steps), max_steps);
1167 done = (steps_done >= steps_final);
1169 for (i = 0 ; i < melt_columns; i++)
1177 else if (ypos[i] < height)
1182 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1184 if (ypos[i] + dy >= height)
1185 dy = height - ypos[i];
1187 /* copy part of (appearing) target surface to upper area */
1188 src_rect.x = src_x + i * melt_pixels;
1189 // src_rect.y = src_y + ypos[i];
1191 src_rect.w = melt_pixels;
1193 src_rect.h = ypos[i] + dy;
1195 dst_rect.x = dst_x + i * melt_pixels;
1196 // dst_rect.y = dst_y + ypos[i];
1199 if (steps_done >= steps_final)
1200 SDL_BlitSurface(surface_target, &src_rect,
1201 surface_screen, &dst_rect);
1205 /* copy part of (disappearing) source surface to lower area */
1206 src_rect.x = src_x + i * melt_pixels;
1208 src_rect.w = melt_pixels;
1209 src_rect.h = height - ypos[i];
1211 dst_rect.x = dst_x + i * melt_pixels;
1212 dst_rect.y = dst_y + ypos[i];
1214 if (steps_done >= steps_final)
1215 SDL_BlitSurface(surface_source, &src_rect,
1216 surface_screen, &dst_rect);
1222 src_rect.x = src_x + i * melt_pixels;
1224 src_rect.w = melt_pixels;
1225 src_rect.h = height;
1227 dst_rect.x = dst_x + i * melt_pixels;
1230 if (steps_done >= steps_final)
1231 SDL_BlitSurface(surface_target, &src_rect,
1232 surface_screen, &dst_rect);
1236 if (steps_done >= steps_final)
1238 if (draw_border_function != NULL)
1239 draw_border_function();
1241 #if defined(TARGET_SDL2)
1242 // SDL_UpdateWindowSurface(sdl_window);
1243 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
1244 UpdateScreen(&dst_rect2);
1246 // SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1247 UpdateScreen(&dst_rect2);
1257 for (alpha = 0.0; alpha < 255.0;)
1259 time_last = time_current;
1260 time_current = SDL_GetTicks();
1261 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1262 alpha_final = MIN(MAX(0, alpha), 255);
1264 /* draw existing (source) image to screen buffer */
1265 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1267 /* draw new (target) image to screen buffer using alpha blending */
1268 #if defined(TARGET_SDL2)
1269 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1270 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1272 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1274 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1276 if (draw_border_function != NULL)
1277 draw_border_function();
1280 /* only update the region of the screen that is affected from fading */
1281 #if defined(TARGET_SDL2)
1282 // SDL_UpdateWindowSurface(sdl_window);
1283 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1284 UpdateScreen(&dst_rect);
1286 // SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1287 UpdateScreen(&dst_rect);
1290 SDL_Flip(surface_screen);
1298 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1299 int to_x, int to_y, Uint32 color)
1301 SDL_Surface *surface = dst_bitmap->surface;
1305 swap_numbers(&from_x, &to_x);
1308 swap_numbers(&from_y, &to_y);
1312 rect.w = (to_x - from_x + 1);
1313 rect.h = (to_y - from_y + 1);
1315 if (dst_bitmap == backbuffer || dst_bitmap == window)
1317 rect.x += video_xoffset;
1318 rect.y += video_yoffset;
1321 SDL_FillRect(surface, &rect, color);
1324 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1325 int to_x, int to_y, Uint32 color)
1327 if (dst_bitmap == backbuffer || dst_bitmap == window)
1329 from_x += video_xoffset;
1330 from_y += video_yoffset;
1331 to_x += video_xoffset;
1332 to_y += video_yoffset;
1335 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1339 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1340 int num_points, Uint32 color)
1345 for (i = 0; i < num_points - 1; i++)
1347 for (x = 0; x < line_width; x++)
1349 for (y = 0; y < line_width; y++)
1351 int dx = x - line_width / 2;
1352 int dy = y - line_width / 2;
1354 if ((x == 0 && y == 0) ||
1355 (x == 0 && y == line_width - 1) ||
1356 (x == line_width - 1 && y == 0) ||
1357 (x == line_width - 1 && y == line_width - 1))
1360 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1361 points[i+1].x + dx, points[i+1].y + dy, color);
1368 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1370 SDL_Surface *surface = src_bitmap->surface;
1372 if (src_bitmap == backbuffer || src_bitmap == window)
1378 switch (surface->format->BytesPerPixel)
1380 case 1: /* assuming 8-bpp */
1382 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1386 case 2: /* probably 15-bpp or 16-bpp */
1388 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1392 case 3: /* slow 24-bpp mode; usually not used */
1394 /* does this work? */
1395 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1399 shift = surface->format->Rshift;
1400 color |= *(pix + shift / 8) >> shift;
1401 shift = surface->format->Gshift;
1402 color |= *(pix + shift / 8) >> shift;
1403 shift = surface->format->Bshift;
1404 color |= *(pix + shift / 8) >> shift;
1410 case 4: /* probably 32-bpp */
1412 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1421 /* ========================================================================= */
1422 /* The following functions were taken from the SGE library */
1423 /* (SDL Graphics Extension Library) by Anders Lindström */
1424 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1425 /* ========================================================================= */
1427 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1429 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1431 switch (surface->format->BytesPerPixel)
1435 /* Assuming 8-bpp */
1436 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1442 /* Probably 15-bpp or 16-bpp */
1443 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1449 /* Slow 24-bpp mode, usually not used */
1453 /* Gack - slow, but endian correct */
1454 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1455 shift = surface->format->Rshift;
1456 *(pix+shift/8) = color>>shift;
1457 shift = surface->format->Gshift;
1458 *(pix+shift/8) = color>>shift;
1459 shift = surface->format->Bshift;
1460 *(pix+shift/8) = color>>shift;
1466 /* Probably 32-bpp */
1467 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1474 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1475 Uint8 R, Uint8 G, Uint8 B)
1477 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1480 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1482 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1485 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1487 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1490 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1495 /* Gack - slow, but endian correct */
1496 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1497 shift = surface->format->Rshift;
1498 *(pix+shift/8) = color>>shift;
1499 shift = surface->format->Gshift;
1500 *(pix+shift/8) = color>>shift;
1501 shift = surface->format->Bshift;
1502 *(pix+shift/8) = color>>shift;
1505 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1507 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1510 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1512 switch (dest->format->BytesPerPixel)
1515 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1519 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1523 _PutPixel24(dest,x,y,color);
1527 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1532 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1534 if (SDL_MUSTLOCK(surface))
1536 if (SDL_LockSurface(surface) < 0)
1542 _PutPixel(surface, x, y, color);
1544 if (SDL_MUSTLOCK(surface))
1546 SDL_UnlockSurface(surface);
1550 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1551 Uint8 r, Uint8 g, Uint8 b)
1553 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1556 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1558 if (y >= 0 && y <= dest->h - 1)
1560 switch (dest->format->BytesPerPixel)
1563 return y*dest->pitch;
1567 return y*dest->pitch/2;
1571 return y*dest->pitch;
1575 return y*dest->pitch/4;
1583 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1585 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1587 switch (surface->format->BytesPerPixel)
1591 /* Assuming 8-bpp */
1592 *((Uint8 *)surface->pixels + ypitch + x) = color;
1598 /* Probably 15-bpp or 16-bpp */
1599 *((Uint16 *)surface->pixels + ypitch + x) = color;
1605 /* Slow 24-bpp mode, usually not used */
1609 /* Gack - slow, but endian correct */
1610 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1611 shift = surface->format->Rshift;
1612 *(pix+shift/8) = color>>shift;
1613 shift = surface->format->Gshift;
1614 *(pix+shift/8) = color>>shift;
1615 shift = surface->format->Bshift;
1616 *(pix+shift/8) = color>>shift;
1622 /* Probably 32-bpp */
1623 *((Uint32 *)surface->pixels + ypitch + x) = color;
1630 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1635 if (SDL_MUSTLOCK(Surface))
1637 if (SDL_LockSurface(Surface) < 0)
1650 /* Do the clipping */
1651 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1655 if (x2 > Surface->w - 1)
1656 x2 = Surface->w - 1;
1663 SDL_FillRect(Surface, &l, Color);
1665 if (SDL_MUSTLOCK(Surface))
1667 SDL_UnlockSurface(Surface);
1671 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1672 Uint8 R, Uint8 G, Uint8 B)
1674 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1677 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1688 /* Do the clipping */
1689 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1693 if (x2 > Surface->w - 1)
1694 x2 = Surface->w - 1;
1701 SDL_FillRect(Surface, &l, Color);
1704 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1709 if (SDL_MUSTLOCK(Surface))
1711 if (SDL_LockSurface(Surface) < 0)
1724 /* Do the clipping */
1725 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1729 if (y2 > Surface->h - 1)
1730 y2 = Surface->h - 1;
1737 SDL_FillRect(Surface, &l, Color);
1739 if (SDL_MUSTLOCK(Surface))
1741 SDL_UnlockSurface(Surface);
1745 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1746 Uint8 R, Uint8 G, Uint8 B)
1748 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1751 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1762 /* Do the clipping */
1763 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1767 if (y2 > Surface->h - 1)
1768 y2 = Surface->h - 1;
1775 SDL_FillRect(Surface, &l, Color);
1778 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1779 Sint16 x2, Sint16 y2, Uint32 Color,
1780 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1783 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1788 sdx = (dx < 0) ? -1 : 1;
1789 sdy = (dy < 0) ? -1 : 1;
1801 for (x = 0; x < dx; x++)
1803 Callback(Surface, px, py, Color);
1817 for (y = 0; y < dy; y++)
1819 Callback(Surface, px, py, Color);
1833 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1834 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1835 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1838 sge_DoLine(Surface, X1, Y1, X2, Y2,
1839 SDL_MapRGB(Surface->format, R, G, B), Callback);
1842 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1845 if (SDL_MUSTLOCK(Surface))
1847 if (SDL_LockSurface(Surface) < 0)
1852 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1854 /* unlock the display */
1855 if (SDL_MUSTLOCK(Surface))
1857 SDL_UnlockSurface(Surface);
1861 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1862 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1864 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1867 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1869 if (dst_bitmap == backbuffer || dst_bitmap == window)
1875 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1880 -----------------------------------------------------------------------------
1881 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1882 -----------------------------------------------------------------------------
1885 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1886 int width, int height, Uint32 color)
1890 for (y = src_y; y < src_y + height; y++)
1892 for (x = src_x; x < src_x + width; x++)
1894 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1896 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1901 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1902 int src_x, int src_y, int width, int height,
1903 int dst_x, int dst_y)
1907 for (y = 0; y < height; y++)
1909 for (x = 0; x < width; x++)
1911 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1913 if (pixel != BLACK_PIXEL)
1914 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1920 /* ========================================================================= */
1921 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1922 /* (Rotozoomer) by Andreas Schiffler */
1923 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1924 /* ========================================================================= */
1927 -----------------------------------------------------------------------------
1930 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1931 -----------------------------------------------------------------------------
1942 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1945 tColorRGBA *sp, *csp, *dp;
1952 sp = csp = (tColorRGBA *) src->pixels;
1953 dp = (tColorRGBA *) dst->pixels;
1955 sgap = src->pitch - src->w * 4;
1957 dgap = dst->pitch - dst->w * 4;
1959 for (y = 0; y < dst->h; y++)
1963 for (x = 0; x < dst->w; x++)
1965 tColorRGBA *sp0 = sp;
1966 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1967 tColorRGBA *sp00 = &sp0[0];
1968 tColorRGBA *sp01 = &sp0[1];
1969 tColorRGBA *sp10 = &sp1[0];
1970 tColorRGBA *sp11 = &sp1[1];
1973 /* create new color pixel from all four source color pixels */
1974 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1975 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1976 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1977 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1982 /* advance source pointers */
1985 /* advance destination pointer */
1989 /* advance source pointer */
1990 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1992 /* advance destination pointers */
1993 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1999 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2001 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2002 tColorRGBA *sp, *csp, *dp;
2008 /* use specialized zoom function when scaling down to exactly half size */
2009 if (src->w == 2 * dst->w &&
2010 src->h == 2 * dst->h)
2011 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2013 /* variable setup */
2014 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
2015 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
2017 /* allocate memory for row increments */
2018 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2019 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2021 /* precalculate row increments */
2024 for (x = 0; x <= dst->w; x++)
2034 for (y = 0; y <= dst->h; y++)
2043 sp = csp = (tColorRGBA *) src->pixels;
2044 dp = (tColorRGBA *) dst->pixels;
2046 sgap = src->pitch - src->w * 4;
2048 dgap = dst->pitch - dst->w * 4;
2051 for (y = 0; y < dst->h; y++)
2056 for (x = 0; x < dst->w; x++)
2061 /* advance source pointers */
2063 sp += (*csax >> 16);
2065 /* advance destination pointer */
2069 /* advance source pointer */
2071 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
2073 /* advance destination pointers */
2074 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2084 -----------------------------------------------------------------------------
2087 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2088 -----------------------------------------------------------------------------
2091 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2093 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2094 Uint8 *sp, *dp, *csp;
2097 /* variable setup */
2098 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2099 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2101 /* allocate memory for row increments */
2102 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2103 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2105 /* precalculate row increments */
2108 for (x = 0; x < dst->w; x++)
2111 *csax = (csx >> 16);
2118 for (y = 0; y < dst->h; y++)
2121 *csay = (csy >> 16);
2128 for (x = 0; x < dst->w; x++)
2136 for (y = 0; y < dst->h; y++)
2143 sp = csp = (Uint8 *) src->pixels;
2144 dp = (Uint8 *) dst->pixels;
2145 dgap = dst->pitch - dst->w;
2149 for (y = 0; y < dst->h; y++)
2153 for (x = 0; x < dst->w; x++)
2158 /* advance source pointers */
2162 /* advance destination pointer */
2166 /* advance source pointer (for row) */
2167 csp += ((*csay) * src->pitch);
2170 /* advance destination pointers */
2181 -----------------------------------------------------------------------------
2184 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2185 'zoomx' and 'zoomy' are scaling factors for width and height.
2186 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2187 into a 32bit RGBA format on the fly.
2188 -----------------------------------------------------------------------------
2191 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2193 SDL_Surface *zoom_src = NULL;
2194 SDL_Surface *zoom_dst = NULL;
2195 boolean is_converted = FALSE;
2202 /* determine if source surface is 32 bit or 8 bit */
2203 is_32bit = (src->format->BitsPerPixel == 32);
2205 if (is_32bit || src->format->BitsPerPixel == 8)
2207 /* use source surface 'as is' */
2212 /* new source surface is 32 bit with a defined RGB ordering */
2213 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
2214 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2215 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2217 is_converted = TRUE;
2220 /* allocate surface to completely contain the zoomed surface */
2223 /* target surface is 32 bit with source RGBA/ABGR ordering */
2224 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
2225 zoom_src->format->Rmask,
2226 zoom_src->format->Gmask,
2227 zoom_src->format->Bmask, 0);
2231 /* target surface is 8 bit */
2232 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
2236 /* lock source surface */
2237 SDL_LockSurface(zoom_src);
2239 /* check which kind of surface we have */
2242 /* call the 32 bit transformation routine to do the zooming */
2243 zoomSurfaceRGBA(zoom_src, zoom_dst);
2248 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2249 zoom_dst->format->palette->colors[i] =
2250 zoom_src->format->palette->colors[i];
2251 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2253 /* call the 8 bit transformation routine to do the zooming */
2254 zoomSurfaceY(zoom_src, zoom_dst);
2257 /* unlock source surface */
2258 SDL_UnlockSurface(zoom_src);
2260 /* free temporary surface */
2262 SDL_FreeSurface(zoom_src);
2264 /* return destination surface */
2268 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
2270 SDL_Surface *sdl_surface_tmp;
2271 int dst_width = dst_bitmap->width;
2272 int dst_height = dst_bitmap->height;
2274 /* throw away old destination surface */
2275 SDL_FreeSurface(dst_bitmap->surface);
2277 /* create zoomed temporary surface from source surface */
2278 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2280 /* create native format destination surface from zoomed temporary surface */
2281 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
2283 /* free temporary surface */
2284 SDL_FreeSurface(sdl_surface_tmp);
2288 /* ========================================================================= */
2289 /* load image to bitmap */
2290 /* ========================================================================= */
2292 Bitmap *SDLLoadImage(char *filename)
2294 Bitmap *new_bitmap = CreateBitmapStruct();
2295 SDL_Surface *sdl_image_tmp;
2297 print_timestamp_init("SDLLoadImage");
2299 print_timestamp_time(getBaseNamePtr(filename));
2301 /* load image to temporary surface */
2302 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2304 SetError("IMG_Load(): %s", SDL_GetError());
2309 print_timestamp_time("IMG_Load");
2311 UPDATE_BUSY_STATE();
2313 /* create native non-transparent surface for current image */
2314 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2316 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2321 print_timestamp_time("SDL_DisplayFormat (opaque)");
2323 UPDATE_BUSY_STATE();
2325 /* create native transparent surface for current image */
2326 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2327 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2328 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2330 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2335 print_timestamp_time("SDL_DisplayFormat (masked)");
2337 UPDATE_BUSY_STATE();
2339 /* free temporary surface */
2340 SDL_FreeSurface(sdl_image_tmp);
2342 new_bitmap->width = new_bitmap->surface->w;
2343 new_bitmap->height = new_bitmap->surface->h;
2345 print_timestamp_done("SDLLoadImage");
2351 /* ------------------------------------------------------------------------- */
2352 /* custom cursor fuctions */
2353 /* ------------------------------------------------------------------------- */
2355 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2357 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2358 cursor_info->width, cursor_info->height,
2359 cursor_info->hot_x, cursor_info->hot_y);
2362 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2364 static struct MouseCursorInfo *last_cursor_info = NULL;
2365 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2366 static SDL_Cursor *cursor_default = NULL;
2367 static SDL_Cursor *cursor_current = NULL;
2369 /* if invoked for the first time, store the SDL default cursor */
2370 if (cursor_default == NULL)
2371 cursor_default = SDL_GetCursor();
2373 /* only create new cursor if cursor info (custom only) has changed */
2374 if (cursor_info != NULL && cursor_info != last_cursor_info)
2376 cursor_current = create_cursor(cursor_info);
2377 last_cursor_info = cursor_info;
2380 /* only set new cursor if cursor info (custom or NULL) has changed */
2381 if (cursor_info != last_cursor_info2)
2382 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2384 last_cursor_info2 = cursor_info;
2388 /* ========================================================================= */
2389 /* audio functions */
2390 /* ========================================================================= */
2392 void SDLOpenAudio(void)
2394 #if !defined(TARGET_SDL2)
2395 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2396 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2399 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2401 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2405 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2406 AUDIO_NUM_CHANNELS_STEREO,
2407 setup.system.audio_fragment_size) < 0)
2409 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2413 audio.sound_available = TRUE;
2414 audio.music_available = TRUE;
2415 audio.loops_available = TRUE;
2416 audio.sound_enabled = TRUE;
2418 /* set number of available mixer channels */
2419 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2420 audio.music_channel = MUSIC_CHANNEL;
2421 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2423 Mixer_InitChannels();
2426 void SDLCloseAudio(void)
2429 Mix_HaltChannel(-1);
2432 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2436 /* ========================================================================= */
2437 /* event functions */
2438 /* ========================================================================= */
2440 void SDLNextEvent(Event *event)
2442 SDL_WaitEvent(event);
2444 if (event->type == EVENT_BUTTONPRESS ||
2445 event->type == EVENT_BUTTONRELEASE)
2447 if (((ButtonEvent *)event)->x > video_xoffset)
2448 ((ButtonEvent *)event)->x -= video_xoffset;
2450 ((ButtonEvent *)event)->x = 0;
2451 if (((ButtonEvent *)event)->y > video_yoffset)
2452 ((ButtonEvent *)event)->y -= video_yoffset;
2454 ((ButtonEvent *)event)->y = 0;
2456 else if (event->type == EVENT_MOTIONNOTIFY)
2458 if (((MotionEvent *)event)->x > video_xoffset)
2459 ((MotionEvent *)event)->x -= video_xoffset;
2461 ((MotionEvent *)event)->x = 0;
2462 if (((MotionEvent *)event)->y > video_yoffset)
2463 ((MotionEvent *)event)->y -= video_yoffset;
2465 ((MotionEvent *)event)->y = 0;
2469 void SDLHandleWindowManagerEvent(Event *event)
2471 #if defined(PLATFORM_WIN32)
2472 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2473 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2475 if (syswmmsg->msg == WM_DROPFILES)
2477 HDROP hdrop = (HDROP)syswmmsg->wParam;
2480 printf("::: SDL_SYSWMEVENT:\n");
2482 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2484 for (i = 0; i < num_files; i++)
2486 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2487 char buffer[buffer_len + 1];
2489 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2491 printf("::: - '%s'\n", buffer);
2494 DragFinish((HDROP)syswmmsg->wParam);
2500 /* ========================================================================= */
2501 /* joystick functions */
2502 /* ========================================================================= */
2504 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2505 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2506 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2508 static boolean SDLOpenJoystick(int nr)
2510 if (nr < 0 || nr > MAX_PLAYERS)
2513 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2516 static void SDLCloseJoystick(int nr)
2518 if (nr < 0 || nr > MAX_PLAYERS)
2521 SDL_JoystickClose(sdl_joystick[nr]);
2523 sdl_joystick[nr] = NULL;
2526 static boolean SDLCheckJoystickOpened(int nr)
2528 if (nr < 0 || nr > MAX_PLAYERS)
2531 #if defined(TARGET_SDL2)
2532 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2534 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2538 void HandleJoystickEvent(Event *event)
2542 case SDL_JOYAXISMOTION:
2543 if (event->jaxis.axis < 2)
2544 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2547 case SDL_JOYBUTTONDOWN:
2548 if (event->jbutton.button < 2)
2549 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2552 case SDL_JOYBUTTONUP:
2553 if (event->jbutton.button < 2)
2554 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2562 void SDLInitJoysticks()
2564 static boolean sdl_joystick_subsystem_initialized = FALSE;
2565 boolean print_warning = !sdl_joystick_subsystem_initialized;
2568 if (!sdl_joystick_subsystem_initialized)
2570 sdl_joystick_subsystem_initialized = TRUE;
2572 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2574 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2579 for (i = 0; i < MAX_PLAYERS; i++)
2581 /* get configured joystick for this player */
2582 char *device_name = setup.input[i].joy.device_name;
2583 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2585 if (joystick_nr >= SDL_NumJoysticks())
2587 if (setup.input[i].use_joystick && print_warning)
2588 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2593 /* misuse joystick file descriptor variable to store joystick number */
2594 joystick.fd[i] = joystick_nr;
2596 if (joystick_nr == -1)
2599 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2600 if (SDLCheckJoystickOpened(joystick_nr))
2601 SDLCloseJoystick(joystick_nr);
2603 if (!setup.input[i].use_joystick)
2606 if (!SDLOpenJoystick(joystick_nr))
2609 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2614 joystick.status = JOYSTICK_ACTIVATED;
2618 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2620 if (nr < 0 || nr >= MAX_PLAYERS)
2624 *x = sdl_js_axis[nr][0];
2626 *y = sdl_js_axis[nr][1];
2629 *b1 = sdl_js_button[nr][0];
2631 *b2 = sdl_js_button[nr][1];
2636 #endif /* TARGET_SDL */