1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
18 #define ENABLE_UNUSED_CODE 0 /* currently unused functions */
21 /* ========================================================================= */
23 /* ========================================================================= */
25 /* SDL internal variables */
26 #if defined(TARGET_SDL2)
27 static SDL_Window *sdl_window = NULL;
28 static SDL_Renderer *sdl_renderer = NULL;
29 static SDL_Texture *sdl_texture = NULL;
31 #define USE_RENDERER TRUE
34 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
35 static int fullscreen_width;
36 static int fullscreen_height;
37 static int fullscreen_xoffset;
38 static int fullscreen_yoffset;
39 static int video_xoffset;
40 static int video_yoffset;
41 static boolean limit_screen_updates = FALSE;
44 /* functions from SGE library */
45 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
47 void SDLLimitScreenUpdates(boolean enable)
49 limit_screen_updates = enable;
52 static void UpdateScreen(SDL_Rect *rect)
54 static unsigned int update_screen_delay = 0;
55 unsigned int update_screen_delay_value = 20; /* (milliseconds) */
57 if (limit_screen_updates &&
58 !DelayReached(&update_screen_delay, update_screen_delay_value))
61 LimitScreenUpdates(FALSE);
65 static int LastFrameCounter = 0;
66 boolean changed = (FrameCounter != LastFrameCounter);
68 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
69 (changed ? "-" : "SAME FRAME UPDATED"));
71 LastFrameCounter = FrameCounter;
80 #if defined(TARGET_SDL2)
82 SDL_Surface *screen = backbuffer->surface;
86 int bytes_x = screen->pitch / video.width;
87 int bytes_y = screen->pitch;
89 if (video.fullscreen_enabled)
90 bytes_x = screen->pitch / fullscreen_width;
92 SDL_UpdateTexture(sdl_texture, rect,
93 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
98 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
100 SDL_RenderClear(sdl_renderer);
101 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
102 SDL_RenderPresent(sdl_renderer);
105 SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
107 SDL_UpdateWindowSurface(sdl_window);
112 SDL_UpdateRects(backbuffer->surface, 1, rect);
114 SDL_UpdateRect(backbuffer->surface, 0, 0, 0, 0);
118 static void setFullscreenParameters(char *fullscreen_mode_string)
120 #if defined(TARGET_SDL2)
121 fullscreen_width = video.width;
122 fullscreen_height = video.height;
123 fullscreen_xoffset = 0;
124 fullscreen_yoffset = 0;
128 struct ScreenModeInfo *fullscreen_mode;
131 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
133 if (fullscreen_mode == NULL)
136 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
138 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
139 fullscreen_mode->height == video.fullscreen_modes[i].height)
141 fullscreen_width = fullscreen_mode->width;
142 fullscreen_height = fullscreen_mode->height;
144 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
145 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
153 static void SDLSetWindowIcon(char *basename)
155 /* (setting the window icon on Mac OS X would replace the high-quality
156 dock icon with the currently smaller (and uglier) icon from file) */
158 #if !defined(PLATFORM_MACOSX)
159 char *filename = getCustomImageFilename(basename);
160 SDL_Surface *surface;
162 if (filename == NULL)
164 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
169 if ((surface = IMG_Load(filename)) == NULL)
171 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
176 /* set transparent color */
177 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
178 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
180 #if defined(TARGET_SDL2)
181 SDL_SetWindowIcon(sdl_window, surface);
183 SDL_WM_SetIcon(surface, NULL);
188 #if defined(TARGET_SDL2)
190 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
191 SDL_PixelFormat *format2)
193 return (format1->format == format2->format &&
194 format1->BitsPerPixel == format2->BitsPerPixel &&
195 format1->BytesPerPixel == format2->BytesPerPixel &&
196 format1->Rmask == format2->Rmask &&
197 format1->Gmask == format2->Gmask &&
198 format1->Bmask == format2->Bmask &&
199 format1->Amask == format2->Amask);
202 boolean SDLSetNativeSurface(SDL_Surface **surface)
204 SDL_Surface *new_surface;
206 if (surface == NULL ||
208 backbuffer == NULL ||
209 backbuffer->surface == NULL)
212 // if pixel format already optimized for destination surface, do nothing
213 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
216 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
218 if (new_surface == NULL)
219 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
221 SDL_FreeSurface(*surface);
223 *surface = new_surface;
228 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
230 SDL_Surface *new_surface;
235 if (backbuffer && backbuffer->surface)
236 new_surface = SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
238 new_surface = SDL_ConvertSurface(surface, surface->format, 0);
240 if (new_surface == NULL)
241 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
248 boolean SDLSetNativeSurface(SDL_Surface **surface)
250 SDL_Surface *new_surface;
252 if (surface == NULL ||
257 new_surface = SDL_DisplayFormat(*surface);
259 if (new_surface == NULL)
260 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
262 SDL_FreeSurface(*surface);
264 *surface = new_surface;
269 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
271 SDL_Surface *new_surface;
273 if (video.initialized)
274 new_surface = SDL_DisplayFormat(surface);
276 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
278 if (new_surface == NULL)
279 Error(ERR_EXIT, "%s() failed: %s",
280 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
288 void SDLInitVideoDisplay(void)
290 #if !defined(TARGET_SDL2)
291 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
292 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
294 SDL_putenv("SDL_VIDEO_CENTERED=1");
297 /* initialize SDL video */
298 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
299 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
301 /* set default SDL depth */
302 #if !defined(TARGET_SDL2)
303 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
305 video.default_depth = 32; // (how to determine video depth in SDL2?)
309 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
312 #if !defined(TARGET_SDL2)
313 static int screen_xy[][2] =
321 SDL_Rect **modes = NULL;
322 boolean hardware_fullscreen_available = TRUE;
325 /* default: normal game window size */
326 fullscreen_width = video.width;
327 fullscreen_height = video.height;
328 fullscreen_xoffset = 0;
329 fullscreen_yoffset = 0;
331 #if !defined(TARGET_SDL2)
332 /* determine required standard fullscreen mode for game screen size */
333 for (i = 0; screen_xy[i][0] != -1; i++)
335 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
337 fullscreen_width = screen_xy[i][0];
338 fullscreen_height = screen_xy[i][1];
344 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
345 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
348 checked_free(video.fullscreen_modes);
350 video.fullscreen_modes = NULL;
351 video.fullscreen_mode_current = NULL;
353 video.window_scaling_percent = setup.window_scaling_percent;
354 video.window_scaling_quality = setup.window_scaling_quality;
356 #if defined(TARGET_SDL2)
357 int num_displays = SDL_GetNumVideoDisplays();
359 if (num_displays > 0)
361 // currently only display modes of first display supported
362 int num_modes = SDL_GetNumDisplayModes(0);
366 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
368 for (i = 0; i < num_modes; i++)
370 SDL_DisplayMode mode;
372 if (SDL_GetDisplayMode(0, i, &mode) < 0)
375 modes[i] = checked_calloc(sizeof(SDL_Rect));
377 modes[i]->w = mode.w;
378 modes[i]->h = mode.h;
383 /* get available hardware supported fullscreen modes */
384 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
389 /* no hardware screen modes available => no fullscreen mode support */
390 // video.fullscreen_available = FALSE;
391 hardware_fullscreen_available = FALSE;
393 else if (modes == (SDL_Rect **)-1)
395 /* fullscreen resolution is not restricted -- all resolutions available */
396 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
398 /* use native video buffer size for fullscreen mode */
399 video.fullscreen_modes[0].width = video.width;
400 video.fullscreen_modes[0].height = video.height;
402 video.fullscreen_modes[1].width = -1;
403 video.fullscreen_modes[1].height = -1;
407 /* in this case, a certain number of screen modes is available */
410 for (i = 0; modes[i] != NULL; i++)
412 boolean found_mode = FALSE;
414 /* screen mode is smaller than video buffer size -- skip it */
415 if (modes[i]->w < video.width || modes[i]->h < video.height)
418 if (video.fullscreen_modes != NULL)
419 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
420 if (modes[i]->w == video.fullscreen_modes[j].width &&
421 modes[i]->h == video.fullscreen_modes[j].height)
424 if (found_mode) /* screen mode already stored -- skip it */
427 /* new mode found; add it to list of available fullscreen modes */
431 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
433 sizeof(struct ScreenModeInfo));
435 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
436 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
438 video.fullscreen_modes[num_modes].width = -1;
439 video.fullscreen_modes[num_modes].height = -1;
444 /* no appropriate screen modes available => no fullscreen mode support */
445 // video.fullscreen_available = FALSE;
446 hardware_fullscreen_available = FALSE;
450 video.fullscreen_available = hardware_fullscreen_available;
452 #if USE_DESKTOP_FULLSCREEN
453 // in SDL 2.0, there is always support for desktop fullscreen mode
454 // (in SDL 1.2, there is only support for "real" fullscreen mode)
455 video.fullscreen_available = TRUE;
458 #if defined(TARGET_SDL2)
461 for (i = 0; modes[i] != NULL; i++)
462 checked_free(modes[i]);
468 /* open SDL video output device (window or fullscreen mode) */
469 if (!SDLSetVideoMode(backbuffer, fullscreen))
470 Error(ERR_EXIT, "setting video mode failed");
472 /* !!! SDL2 can only set the window icon if the window already exists !!! */
473 /* set window icon */
474 SDLSetWindowIcon(program.icon_filename);
476 /* set window and icon title */
477 #if defined(TARGET_SDL2)
478 SDL_SetWindowTitle(sdl_window, program.window_title);
480 SDL_WM_SetCaption(program.window_title, program.window_title);
483 /* SDL cannot directly draw to the visible video framebuffer like X11,
484 but always uses a backbuffer, which is then blitted to the visible
485 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
486 visible video framebuffer with 'SDL_Flip', if the hardware supports
487 this). Therefore do not use an additional backbuffer for drawing, but
488 use a symbolic buffer (distinguishable from the SDL backbuffer) called
489 'window', which indicates that the SDL backbuffer should be updated to
490 the visible video framebuffer when attempting to blit to it.
492 For convenience, it seems to be a good idea to create this symbolic
493 buffer 'window' at the same size as the SDL backbuffer. Although it
494 should never be drawn to directly, it would do no harm nevertheless. */
496 /* create additional (symbolic) buffer for double-buffering */
497 ReCreateBitmap(window, video.width, video.height, video.depth);
500 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
503 SDL_Surface *new_surface = NULL;
505 #if defined(TARGET_SDL2)
506 static boolean fullscreen_enabled = FALSE;
507 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
508 #if USE_DESKTOP_FULLSCREEN
509 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
511 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
515 int surface_flags_window = SURFACE_FLAGS;
516 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
519 int width = (fullscreen ? fullscreen_width : video.width);
520 int height = (fullscreen ? fullscreen_height : video.height);
521 int surface_flags = (fullscreen ? surface_flags_fullscreen :
522 surface_flags_window);
524 // default window size is unscaled
525 video.window_width = video.width;
526 video.window_height = video.height;
528 #if defined(TARGET_SDL2)
530 // store if initial screen mode on game start is fullscreen mode
531 if (sdl_window == NULL)
532 video.fullscreen_initial = fullscreen;
535 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
536 #if !USE_DESKTOP_FULLSCREEN
537 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
540 video.window_width = window_scaling_factor * width;
541 video.window_height = window_scaling_factor * height;
543 if ((*backbuffer)->surface)
545 SDL_FreeSurface((*backbuffer)->surface);
546 (*backbuffer)->surface = NULL;
551 SDL_DestroyTexture(sdl_texture);
555 if (!(fullscreen && fullscreen_enabled))
559 SDL_DestroyRenderer(sdl_renderer);
565 SDL_DestroyWindow(sdl_window);
570 if (sdl_window == NULL)
571 sdl_window = SDL_CreateWindow(program.window_title,
572 SDL_WINDOWPOS_CENTERED,
573 SDL_WINDOWPOS_CENTERED,
574 #if USE_DESKTOP_FULLSCREEN
578 (int)(screen_scaling_factor * width),
579 (int)(screen_scaling_factor * height),
583 if (sdl_window != NULL)
586 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
587 *without* enabling 2D/3D acceleration and/or guest additions installed,
588 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
589 it will try to use accelerated graphics and apparently fails miserably) */
590 if (sdl_renderer == NULL)
591 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
593 if (sdl_renderer == NULL)
594 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
597 if (sdl_renderer != NULL)
599 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
600 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
601 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
603 sdl_texture = SDL_CreateTexture(sdl_renderer,
604 SDL_PIXELFORMAT_ARGB8888,
605 SDL_TEXTUREACCESS_STREAMING,
608 if (sdl_texture != NULL)
610 // use SDL default values for RGB masks and no alpha channel
611 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
613 if (new_surface == NULL)
614 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
619 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
624 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
629 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
635 SDL_DestroyWindow(sdl_window);
637 sdl_window = SDL_CreateWindow(program.window_title,
638 SDL_WINDOWPOS_CENTERED,
639 SDL_WINDOWPOS_CENTERED,
643 if (sdl_window != NULL)
644 new_surface = SDL_GetWindowSurface(sdl_window);
648 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
651 #if defined(TARGET_SDL2)
652 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
653 if (new_surface != NULL)
654 fullscreen_enabled = fullscreen;
660 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
662 boolean success = TRUE;
663 SDL_Surface *new_surface = NULL;
667 if (*backbuffer == NULL)
668 *backbuffer = CreateBitmapStruct();
670 /* (real bitmap might be larger in fullscreen mode with video offsets) */
671 (*backbuffer)->width = video.width;
672 (*backbuffer)->height = video.height;
674 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
676 setFullscreenParameters(setup.fullscreen_mode);
678 video_xoffset = fullscreen_xoffset;
679 video_yoffset = fullscreen_yoffset;
681 /* switch display to fullscreen mode, if available */
682 new_surface = SDLCreateScreen(backbuffer, TRUE);
684 if (new_surface == NULL)
686 /* switching display to fullscreen mode failed */
687 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
689 /* do not try it again */
690 video.fullscreen_available = FALSE;
696 (*backbuffer)->surface = new_surface;
698 video.fullscreen_enabled = TRUE;
699 video.fullscreen_mode_current = setup.fullscreen_mode;
705 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
710 /* switch display to window mode */
711 new_surface = SDLCreateScreen(backbuffer, FALSE);
713 if (new_surface == NULL)
715 /* switching display to window mode failed -- should not happen */
716 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
722 (*backbuffer)->surface = new_surface;
724 video.fullscreen_enabled = FALSE;
725 video.window_scaling_percent = setup.window_scaling_percent;
726 video.window_scaling_quality = setup.window_scaling_quality;
732 #if defined(TARGET_SDL2)
733 SDLRedrawWindow(); // map window
737 #if defined(PLATFORM_WIN32)
738 // experimental drag and drop code
740 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
743 SDL_SysWMinfo wminfo;
745 boolean wminfo_success = FALSE;
747 SDL_VERSION(&wminfo.version);
748 #if defined(TARGET_SDL2)
750 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
752 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
757 #if defined(TARGET_SDL2)
758 hwnd = wminfo.info.win.window;
760 hwnd = wminfo.window;
763 DragAcceptFiles(hwnd, TRUE);
772 void SDLSetWindowTitle()
774 #if defined(TARGET_SDL2)
775 SDL_SetWindowTitle(sdl_window, program.window_title);
777 SDL_WM_SetCaption(program.window_title, program.window_title);
781 #if defined(TARGET_SDL2)
782 void SDLSetWindowScaling(int window_scaling_percent)
784 if (sdl_window == NULL)
787 float window_scaling_factor = (float)window_scaling_percent / 100;
788 int new_window_width = (int)(window_scaling_factor * video.width);
789 int new_window_height = (int)(window_scaling_factor * video.height);
791 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
793 video.window_scaling_percent = window_scaling_percent;
794 video.window_width = new_window_width;
795 video.window_height = new_window_height;
800 void SDLSetWindowScalingQuality(char *window_scaling_quality)
802 if (sdl_texture == NULL)
805 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
807 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
808 SDL_PIXELFORMAT_ARGB8888,
809 SDL_TEXTUREACCESS_STREAMING,
810 video.width, video.height);
812 if (new_texture != NULL)
814 SDL_DestroyTexture(sdl_texture);
816 sdl_texture = new_texture;
821 video.window_scaling_quality = window_scaling_quality;
824 void SDLSetWindowFullscreen(boolean fullscreen)
826 if (sdl_window == NULL)
829 #if USE_DESKTOP_FULLSCREEN
830 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
832 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
835 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
836 video.fullscreen_enabled = fullscreen;
838 // if game started in fullscreen mode, window will also get fullscreen size
839 if (!fullscreen && video.fullscreen_initial)
841 SDLSetWindowScaling(setup.window_scaling_percent);
842 SDL_SetWindowPosition(sdl_window,
843 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
845 video.fullscreen_initial = FALSE;
849 void SDLRedrawWindow()
855 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
858 SDL_Surface *surface =
859 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
862 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
864 SDLSetNativeSurface(&surface);
866 bitmap->surface = surface;
869 void SDLFreeBitmapPointers(Bitmap *bitmap)
872 SDL_FreeSurface(bitmap->surface);
873 if (bitmap->surface_masked)
874 SDL_FreeSurface(bitmap->surface_masked);
875 bitmap->surface = NULL;
876 bitmap->surface_masked = NULL;
879 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
880 int src_x, int src_y, int width, int height,
881 int dst_x, int dst_y, int mask_mode)
883 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
884 SDL_Rect src_rect, dst_rect;
886 if (src_bitmap == backbuffer)
888 src_x += video_xoffset;
889 src_y += video_yoffset;
897 if (dst_bitmap == backbuffer || dst_bitmap == window)
899 dst_x += video_xoffset;
900 dst_y += video_yoffset;
908 // if (src_bitmap != backbuffer || dst_bitmap != window)
909 if (!(src_bitmap == backbuffer && dst_bitmap == window))
910 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
911 src_bitmap->surface_masked : src_bitmap->surface),
912 &src_rect, real_dst_bitmap->surface, &dst_rect);
914 #if defined(TARGET_SDL2)
915 if (dst_bitmap == window)
917 // SDL_UpdateWindowSurface(sdl_window);
918 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
919 UpdateScreen(&dst_rect);
922 if (dst_bitmap == window)
924 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
925 UpdateScreen(&dst_rect);
930 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
933 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
936 if (dst_bitmap == backbuffer || dst_bitmap == window)
947 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
949 #if defined(TARGET_SDL2)
950 if (dst_bitmap == window)
952 // SDL_UpdateWindowSurface(sdl_window);
953 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
957 if (dst_bitmap == window)
959 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
965 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
966 int fade_mode, int fade_delay, int post_delay,
967 void (*draw_border_function)(void))
969 static boolean initialization_needed = TRUE;
970 static SDL_Surface *surface_source = NULL;
971 static SDL_Surface *surface_target = NULL;
972 static SDL_Surface *surface_black = NULL;
973 SDL_Surface *surface_screen = backbuffer->surface;
974 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
975 SDL_Rect src_rect, dst_rect;
977 int src_x = x, src_y = y;
978 int dst_x = x, dst_y = y;
979 unsigned int time_last, time_current;
981 /* check if screen size has changed */
982 if (surface_source != NULL && (video.width != surface_source->w ||
983 video.height != surface_source->h))
985 SDL_FreeSurface(surface_source);
986 SDL_FreeSurface(surface_target);
987 SDL_FreeSurface(surface_black);
989 initialization_needed = TRUE;
997 dst_x += video_xoffset;
998 dst_y += video_yoffset;
1002 dst_rect.w = width; /* (ignored) */
1003 dst_rect.h = height; /* (ignored) */
1005 dst_rect2 = dst_rect;
1007 if (initialization_needed)
1009 #if defined(TARGET_SDL2)
1010 unsigned int flags = 0;
1012 unsigned int flags = SDL_SRCALPHA;
1014 /* use same surface type as screen surface */
1015 if ((surface_screen->flags & SDL_HWSURFACE))
1016 flags |= SDL_HWSURFACE;
1018 flags |= SDL_SWSURFACE;
1021 /* create surface for temporary copy of screen buffer (source) */
1022 if ((surface_source =
1023 SDL_CreateRGBSurface(flags,
1026 surface_screen->format->BitsPerPixel,
1027 surface_screen->format->Rmask,
1028 surface_screen->format->Gmask,
1029 surface_screen->format->Bmask,
1030 surface_screen->format->Amask)) == NULL)
1031 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1033 /* create surface for cross-fading screen buffer (target) */
1034 if ((surface_target =
1035 SDL_CreateRGBSurface(flags,
1038 surface_screen->format->BitsPerPixel,
1039 surface_screen->format->Rmask,
1040 surface_screen->format->Gmask,
1041 surface_screen->format->Bmask,
1042 surface_screen->format->Amask)) == NULL)
1043 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1045 /* create black surface for fading from/to black */
1046 if ((surface_black =
1047 SDL_CreateRGBSurface(flags,
1050 surface_screen->format->BitsPerPixel,
1051 surface_screen->format->Rmask,
1052 surface_screen->format->Gmask,
1053 surface_screen->format->Bmask,
1054 surface_screen->format->Amask)) == NULL)
1055 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1057 /* completely fill the surface with black color pixels */
1058 SDL_FillRect(surface_black, NULL,
1059 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1061 initialization_needed = FALSE;
1064 /* copy source and target surfaces to temporary surfaces for fading */
1065 if (fade_mode & FADE_TYPE_TRANSFORM)
1067 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1068 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1070 else if (fade_mode & FADE_TYPE_FADE_IN)
1072 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1073 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1075 else /* FADE_TYPE_FADE_OUT */
1077 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1078 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1081 time_current = SDL_GetTicks();
1083 if (fade_mode == FADE_MODE_MELT)
1085 boolean done = FALSE;
1086 int melt_pixels = 2;
1087 int melt_columns = width / melt_pixels;
1088 int ypos[melt_columns];
1089 int max_steps = height / 8 + 32;
1094 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1095 #if defined(TARGET_SDL2)
1096 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1098 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1101 ypos[0] = -GetSimpleRandom(16);
1103 for (i = 1 ; i < melt_columns; i++)
1105 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1107 ypos[i] = ypos[i - 1] + r;
1120 time_last = time_current;
1121 time_current = SDL_GetTicks();
1122 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1123 steps_final = MIN(MAX(0, steps), max_steps);
1127 done = (steps_done >= steps_final);
1129 for (i = 0 ; i < melt_columns; i++)
1137 else if (ypos[i] < height)
1142 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1144 if (ypos[i] + dy >= height)
1145 dy = height - ypos[i];
1147 /* copy part of (appearing) target surface to upper area */
1148 src_rect.x = src_x + i * melt_pixels;
1149 // src_rect.y = src_y + ypos[i];
1151 src_rect.w = melt_pixels;
1153 src_rect.h = ypos[i] + dy;
1155 dst_rect.x = dst_x + i * melt_pixels;
1156 // dst_rect.y = dst_y + ypos[i];
1159 if (steps_done >= steps_final)
1160 SDL_BlitSurface(surface_target, &src_rect,
1161 surface_screen, &dst_rect);
1165 /* copy part of (disappearing) source surface to lower area */
1166 src_rect.x = src_x + i * melt_pixels;
1168 src_rect.w = melt_pixels;
1169 src_rect.h = height - ypos[i];
1171 dst_rect.x = dst_x + i * melt_pixels;
1172 dst_rect.y = dst_y + ypos[i];
1174 if (steps_done >= steps_final)
1175 SDL_BlitSurface(surface_source, &src_rect,
1176 surface_screen, &dst_rect);
1182 src_rect.x = src_x + i * melt_pixels;
1184 src_rect.w = melt_pixels;
1185 src_rect.h = height;
1187 dst_rect.x = dst_x + i * melt_pixels;
1190 if (steps_done >= steps_final)
1191 SDL_BlitSurface(surface_target, &src_rect,
1192 surface_screen, &dst_rect);
1196 if (steps_done >= steps_final)
1198 if (draw_border_function != NULL)
1199 draw_border_function();
1201 #if defined(TARGET_SDL2)
1202 // SDL_UpdateWindowSurface(sdl_window);
1203 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
1204 UpdateScreen(&dst_rect2);
1206 // SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1207 UpdateScreen(&dst_rect2);
1217 for (alpha = 0.0; alpha < 255.0;)
1219 time_last = time_current;
1220 time_current = SDL_GetTicks();
1221 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1222 alpha_final = MIN(MAX(0, alpha), 255);
1224 /* draw existing (source) image to screen buffer */
1225 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1227 /* draw new (target) image to screen buffer using alpha blending */
1228 #if defined(TARGET_SDL2)
1229 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1230 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1232 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1234 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1236 if (draw_border_function != NULL)
1237 draw_border_function();
1239 /* only update the region of the screen that is affected from fading */
1240 UpdateScreen(&dst_rect);
1247 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1248 int to_x, int to_y, Uint32 color)
1250 SDL_Surface *surface = dst_bitmap->surface;
1254 swap_numbers(&from_x, &to_x);
1257 swap_numbers(&from_y, &to_y);
1261 rect.w = (to_x - from_x + 1);
1262 rect.h = (to_y - from_y + 1);
1264 if (dst_bitmap == backbuffer || dst_bitmap == window)
1266 rect.x += video_xoffset;
1267 rect.y += video_yoffset;
1270 SDL_FillRect(surface, &rect, color);
1273 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1274 int to_x, int to_y, Uint32 color)
1276 if (dst_bitmap == backbuffer || dst_bitmap == window)
1278 from_x += video_xoffset;
1279 from_y += video_yoffset;
1280 to_x += video_xoffset;
1281 to_y += video_yoffset;
1284 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1287 #if ENABLE_UNUSED_CODE
1288 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1289 int num_points, Uint32 color)
1294 for (i = 0; i < num_points - 1; i++)
1296 for (x = 0; x < line_width; x++)
1298 for (y = 0; y < line_width; y++)
1300 int dx = x - line_width / 2;
1301 int dy = y - line_width / 2;
1303 if ((x == 0 && y == 0) ||
1304 (x == 0 && y == line_width - 1) ||
1305 (x == line_width - 1 && y == 0) ||
1306 (x == line_width - 1 && y == line_width - 1))
1309 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1310 points[i+1].x + dx, points[i+1].y + dy, color);
1317 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1319 SDL_Surface *surface = src_bitmap->surface;
1321 if (src_bitmap == backbuffer || src_bitmap == window)
1327 switch (surface->format->BytesPerPixel)
1329 case 1: /* assuming 8-bpp */
1331 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1335 case 2: /* probably 15-bpp or 16-bpp */
1337 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1341 case 3: /* slow 24-bpp mode; usually not used */
1343 /* does this work? */
1344 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1348 shift = surface->format->Rshift;
1349 color |= *(pix + shift / 8) >> shift;
1350 shift = surface->format->Gshift;
1351 color |= *(pix + shift / 8) >> shift;
1352 shift = surface->format->Bshift;
1353 color |= *(pix + shift / 8) >> shift;
1359 case 4: /* probably 32-bpp */
1361 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1370 /* ========================================================================= */
1371 /* The following functions were taken from the SGE library */
1372 /* (SDL Graphics Extension Library) by Anders Lindström */
1373 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1374 /* ========================================================================= */
1376 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1378 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1380 switch (surface->format->BytesPerPixel)
1384 /* Assuming 8-bpp */
1385 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1391 /* Probably 15-bpp or 16-bpp */
1392 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1398 /* Slow 24-bpp mode, usually not used */
1402 /* Gack - slow, but endian correct */
1403 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1404 shift = surface->format->Rshift;
1405 *(pix+shift/8) = color>>shift;
1406 shift = surface->format->Gshift;
1407 *(pix+shift/8) = color>>shift;
1408 shift = surface->format->Bshift;
1409 *(pix+shift/8) = color>>shift;
1415 /* Probably 32-bpp */
1416 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1423 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1424 Uint8 R, Uint8 G, Uint8 B)
1426 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1429 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1431 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1434 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1436 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1439 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1444 /* Gack - slow, but endian correct */
1445 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1446 shift = surface->format->Rshift;
1447 *(pix+shift/8) = color>>shift;
1448 shift = surface->format->Gshift;
1449 *(pix+shift/8) = color>>shift;
1450 shift = surface->format->Bshift;
1451 *(pix+shift/8) = color>>shift;
1454 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1456 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1459 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1461 switch (dest->format->BytesPerPixel)
1464 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1468 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1472 _PutPixel24(dest,x,y,color);
1476 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1481 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1483 if (SDL_MUSTLOCK(surface))
1485 if (SDL_LockSurface(surface) < 0)
1491 _PutPixel(surface, x, y, color);
1493 if (SDL_MUSTLOCK(surface))
1495 SDL_UnlockSurface(surface);
1499 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1500 Uint8 r, Uint8 g, Uint8 b)
1502 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1505 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1507 if (y >= 0 && y <= dest->h - 1)
1509 switch (dest->format->BytesPerPixel)
1512 return y*dest->pitch;
1516 return y*dest->pitch/2;
1520 return y*dest->pitch;
1524 return y*dest->pitch/4;
1532 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1534 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1536 switch (surface->format->BytesPerPixel)
1540 /* Assuming 8-bpp */
1541 *((Uint8 *)surface->pixels + ypitch + x) = color;
1547 /* Probably 15-bpp or 16-bpp */
1548 *((Uint16 *)surface->pixels + ypitch + x) = color;
1554 /* Slow 24-bpp mode, usually not used */
1558 /* Gack - slow, but endian correct */
1559 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1560 shift = surface->format->Rshift;
1561 *(pix+shift/8) = color>>shift;
1562 shift = surface->format->Gshift;
1563 *(pix+shift/8) = color>>shift;
1564 shift = surface->format->Bshift;
1565 *(pix+shift/8) = color>>shift;
1571 /* Probably 32-bpp */
1572 *((Uint32 *)surface->pixels + ypitch + x) = color;
1579 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1584 if (SDL_MUSTLOCK(Surface))
1586 if (SDL_LockSurface(Surface) < 0)
1599 /* Do the clipping */
1600 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1604 if (x2 > Surface->w - 1)
1605 x2 = Surface->w - 1;
1612 SDL_FillRect(Surface, &l, Color);
1614 if (SDL_MUSTLOCK(Surface))
1616 SDL_UnlockSurface(Surface);
1620 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1621 Uint8 R, Uint8 G, Uint8 B)
1623 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1626 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1637 /* Do the clipping */
1638 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1642 if (x2 > Surface->w - 1)
1643 x2 = Surface->w - 1;
1650 SDL_FillRect(Surface, &l, Color);
1653 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1658 if (SDL_MUSTLOCK(Surface))
1660 if (SDL_LockSurface(Surface) < 0)
1673 /* Do the clipping */
1674 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1678 if (y2 > Surface->h - 1)
1679 y2 = Surface->h - 1;
1686 SDL_FillRect(Surface, &l, Color);
1688 if (SDL_MUSTLOCK(Surface))
1690 SDL_UnlockSurface(Surface);
1694 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1695 Uint8 R, Uint8 G, Uint8 B)
1697 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1700 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1711 /* Do the clipping */
1712 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1716 if (y2 > Surface->h - 1)
1717 y2 = Surface->h - 1;
1724 SDL_FillRect(Surface, &l, Color);
1727 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1728 Sint16 x2, Sint16 y2, Uint32 Color,
1729 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1732 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1737 sdx = (dx < 0) ? -1 : 1;
1738 sdy = (dy < 0) ? -1 : 1;
1750 for (x = 0; x < dx; x++)
1752 Callback(Surface, px, py, Color);
1766 for (y = 0; y < dy; y++)
1768 Callback(Surface, px, py, Color);
1782 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1783 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1784 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1787 sge_DoLine(Surface, X1, Y1, X2, Y2,
1788 SDL_MapRGB(Surface->format, R, G, B), Callback);
1791 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1794 if (SDL_MUSTLOCK(Surface))
1796 if (SDL_LockSurface(Surface) < 0)
1801 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1803 /* unlock the display */
1804 if (SDL_MUSTLOCK(Surface))
1806 SDL_UnlockSurface(Surface);
1810 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1811 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1813 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1816 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1818 if (dst_bitmap == backbuffer || dst_bitmap == window)
1824 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1829 -----------------------------------------------------------------------------
1830 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1831 -----------------------------------------------------------------------------
1834 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1835 int width, int height, Uint32 color)
1839 for (y = src_y; y < src_y + height; y++)
1841 for (x = src_x; x < src_x + width; x++)
1843 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1845 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1850 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1851 int src_x, int src_y, int width, int height,
1852 int dst_x, int dst_y)
1856 for (y = 0; y < height; y++)
1858 for (x = 0; x < width; x++)
1860 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1862 if (pixel != BLACK_PIXEL)
1863 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1869 /* ========================================================================= */
1870 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1871 /* (Rotozoomer) by Andreas Schiffler */
1872 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1873 /* ========================================================================= */
1876 -----------------------------------------------------------------------------
1879 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1880 -----------------------------------------------------------------------------
1891 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1894 tColorRGBA *sp, *csp, *dp;
1898 sp = csp = (tColorRGBA *) src->pixels;
1899 dp = (tColorRGBA *) dst->pixels;
1900 dgap = dst->pitch - dst->w * 4;
1902 for (y = 0; y < dst->h; y++)
1906 for (x = 0; x < dst->w; x++)
1908 tColorRGBA *sp0 = sp;
1909 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1910 tColorRGBA *sp00 = &sp0[0];
1911 tColorRGBA *sp01 = &sp0[1];
1912 tColorRGBA *sp10 = &sp1[0];
1913 tColorRGBA *sp11 = &sp1[1];
1916 /* create new color pixel from all four source color pixels */
1917 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1918 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1919 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1920 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1925 /* advance source pointers */
1928 /* advance destination pointer */
1932 /* advance source pointer */
1933 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1935 /* advance destination pointers */
1936 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1942 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1944 int x, y, *sax, *say, *csax, *csay;
1946 tColorRGBA *sp, *csp, *csp0, *dp;
1949 /* use specialized zoom function when scaling down to exactly half size */
1950 if (src->w == 2 * dst->w &&
1951 src->h == 2 * dst->h)
1952 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1954 /* variable setup */
1955 sx = (float) src->w / (float) dst->w;
1956 sy = (float) src->h / (float) dst->h;
1958 /* allocate memory for row increments */
1959 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1960 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1962 /* precalculate row increments */
1963 for (x = 0; x <= dst->w; x++)
1964 *csax++ = (int)(sx * x);
1966 for (y = 0; y <= dst->h; y++)
1967 *csay++ = (int)(sy * y);
1970 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1971 dp = (tColorRGBA *) dst->pixels;
1972 dgap = dst->pitch - dst->w * 4;
1975 for (y = 0; y < dst->h; y++)
1980 for (x = 0; x < dst->w; x++)
1985 /* advance source pointers */
1989 /* advance destination pointer */
1993 /* advance source pointer */
1995 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1997 /* advance destination pointers */
1998 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2008 -----------------------------------------------------------------------------
2011 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2012 -----------------------------------------------------------------------------
2015 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2017 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2018 Uint8 *sp, *dp, *csp;
2021 /* variable setup */
2022 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2023 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2025 /* allocate memory for row increments */
2026 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2027 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2029 /* precalculate row increments */
2032 for (x = 0; x < dst->w; x++)
2035 *csax = (csx >> 16);
2042 for (y = 0; y < dst->h; y++)
2045 *csay = (csy >> 16);
2052 for (x = 0; x < dst->w; x++)
2060 for (y = 0; y < dst->h; y++)
2067 sp = csp = (Uint8 *) src->pixels;
2068 dp = (Uint8 *) dst->pixels;
2069 dgap = dst->pitch - dst->w;
2073 for (y = 0; y < dst->h; y++)
2077 for (x = 0; x < dst->w; x++)
2082 /* advance source pointers */
2086 /* advance destination pointer */
2090 /* advance source pointer (for row) */
2091 csp += ((*csay) * src->pitch);
2094 /* advance destination pointers */
2105 -----------------------------------------------------------------------------
2108 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2109 'zoomx' and 'zoomy' are scaling factors for width and height.
2110 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2111 into a 32bit RGBA format on the fly.
2112 -----------------------------------------------------------------------------
2115 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2117 SDL_Surface *zoom_src = NULL;
2118 SDL_Surface *zoom_dst = NULL;
2119 boolean is_converted = FALSE;
2126 /* determine if source surface is 32 bit or 8 bit */
2127 is_32bit = (src->format->BitsPerPixel == 32);
2129 if (is_32bit || src->format->BitsPerPixel == 8)
2131 /* use source surface 'as is' */
2136 /* new source surface is 32 bit with a defined RGB ordering */
2137 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2138 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2139 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2141 is_converted = TRUE;
2144 /* allocate surface to completely contain the zoomed surface */
2147 /* target surface is 32 bit with source RGBA/ABGR ordering */
2148 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2149 zoom_src->format->Rmask,
2150 zoom_src->format->Gmask,
2151 zoom_src->format->Bmask, 0);
2155 /* target surface is 8 bit */
2156 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2160 /* lock source surface */
2161 SDL_LockSurface(zoom_src);
2163 /* check which kind of surface we have */
2166 /* call the 32 bit transformation routine to do the zooming */
2167 zoomSurfaceRGBA(zoom_src, zoom_dst);
2172 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2173 zoom_dst->format->palette->colors[i] =
2174 zoom_src->format->palette->colors[i];
2175 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2177 /* call the 8 bit transformation routine to do the zooming */
2178 zoomSurfaceY(zoom_src, zoom_dst);
2181 /* unlock source surface */
2182 SDL_UnlockSurface(zoom_src);
2184 /* free temporary surface */
2186 SDL_FreeSurface(zoom_src);
2188 /* return destination surface */
2192 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2194 Bitmap *dst_bitmap = CreateBitmapStruct();
2195 SDL_Surface **dst_surface = &dst_bitmap->surface;
2197 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2198 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2200 dst_bitmap->width = dst_width;
2201 dst_bitmap->height = dst_height;
2203 /* create zoomed temporary surface from source surface */
2204 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2206 /* create native format destination surface from zoomed temporary surface */
2207 SDLSetNativeSurface(dst_surface);
2213 /* ========================================================================= */
2214 /* load image to bitmap */
2215 /* ========================================================================= */
2217 Bitmap *SDLLoadImage(char *filename)
2219 Bitmap *new_bitmap = CreateBitmapStruct();
2220 SDL_Surface *sdl_image_tmp;
2222 print_timestamp_init("SDLLoadImage");
2224 print_timestamp_time(getBaseNamePtr(filename));
2226 /* load image to temporary surface */
2227 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2229 SetError("IMG_Load(): %s", SDL_GetError());
2234 print_timestamp_time("IMG_Load");
2236 UPDATE_BUSY_STATE();
2238 /* create native non-transparent surface for current image */
2239 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2241 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2246 print_timestamp_time("SDL_DisplayFormat (opaque)");
2248 UPDATE_BUSY_STATE();
2250 /* create native transparent surface for current image */
2251 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2252 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2254 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2256 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2261 print_timestamp_time("SDL_DisplayFormat (masked)");
2263 UPDATE_BUSY_STATE();
2265 /* free temporary surface */
2266 SDL_FreeSurface(sdl_image_tmp);
2268 new_bitmap->width = new_bitmap->surface->w;
2269 new_bitmap->height = new_bitmap->surface->h;
2271 print_timestamp_done("SDLLoadImage");
2277 /* ------------------------------------------------------------------------- */
2278 /* custom cursor fuctions */
2279 /* ------------------------------------------------------------------------- */
2281 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2283 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2284 cursor_info->width, cursor_info->height,
2285 cursor_info->hot_x, cursor_info->hot_y);
2288 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2290 static struct MouseCursorInfo *last_cursor_info = NULL;
2291 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2292 static SDL_Cursor *cursor_default = NULL;
2293 static SDL_Cursor *cursor_current = NULL;
2295 /* if invoked for the first time, store the SDL default cursor */
2296 if (cursor_default == NULL)
2297 cursor_default = SDL_GetCursor();
2299 /* only create new cursor if cursor info (custom only) has changed */
2300 if (cursor_info != NULL && cursor_info != last_cursor_info)
2302 cursor_current = create_cursor(cursor_info);
2303 last_cursor_info = cursor_info;
2306 /* only set new cursor if cursor info (custom or NULL) has changed */
2307 if (cursor_info != last_cursor_info2)
2308 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2310 last_cursor_info2 = cursor_info;
2314 /* ========================================================================= */
2315 /* audio functions */
2316 /* ========================================================================= */
2318 void SDLOpenAudio(void)
2320 #if !defined(TARGET_SDL2)
2321 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2322 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2325 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2327 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2331 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2332 AUDIO_NUM_CHANNELS_STEREO,
2333 setup.system.audio_fragment_size) < 0)
2335 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2339 audio.sound_available = TRUE;
2340 audio.music_available = TRUE;
2341 audio.loops_available = TRUE;
2342 audio.sound_enabled = TRUE;
2344 /* set number of available mixer channels */
2345 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2346 audio.music_channel = MUSIC_CHANNEL;
2347 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2349 Mixer_InitChannels();
2352 void SDLCloseAudio(void)
2355 Mix_HaltChannel(-1);
2358 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2362 /* ========================================================================= */
2363 /* event functions */
2364 /* ========================================================================= */
2366 void SDLNextEvent(Event *event)
2368 SDL_WaitEvent(event);
2370 if (event->type == EVENT_BUTTONPRESS ||
2371 event->type == EVENT_BUTTONRELEASE)
2373 if (((ButtonEvent *)event)->x > video_xoffset)
2374 ((ButtonEvent *)event)->x -= video_xoffset;
2376 ((ButtonEvent *)event)->x = 0;
2377 if (((ButtonEvent *)event)->y > video_yoffset)
2378 ((ButtonEvent *)event)->y -= video_yoffset;
2380 ((ButtonEvent *)event)->y = 0;
2382 else if (event->type == EVENT_MOTIONNOTIFY)
2384 if (((MotionEvent *)event)->x > video_xoffset)
2385 ((MotionEvent *)event)->x -= video_xoffset;
2387 ((MotionEvent *)event)->x = 0;
2388 if (((MotionEvent *)event)->y > video_yoffset)
2389 ((MotionEvent *)event)->y -= video_yoffset;
2391 ((MotionEvent *)event)->y = 0;
2395 void SDLHandleWindowManagerEvent(Event *event)
2398 #if defined(PLATFORM_WIN32)
2399 // experimental drag and drop code
2401 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2402 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2404 #if defined(TARGET_SDL2)
2405 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2407 if (syswmmsg->msg == WM_DROPFILES)
2410 #if defined(TARGET_SDL2)
2411 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2413 HDROP hdrop = (HDROP)syswmmsg->wParam;
2417 printf("::: SDL_SYSWMEVENT:\n");
2419 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2421 for (i = 0; i < num_files; i++)
2423 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2424 char buffer[buffer_len + 1];
2426 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2428 printf("::: - '%s'\n", buffer);
2431 #if defined(TARGET_SDL2)
2432 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2434 DragFinish((HDROP)syswmmsg->wParam);
2442 /* ========================================================================= */
2443 /* joystick functions */
2444 /* ========================================================================= */
2446 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2447 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2448 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2450 static boolean SDLOpenJoystick(int nr)
2452 if (nr < 0 || nr > MAX_PLAYERS)
2455 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2458 static void SDLCloseJoystick(int nr)
2460 if (nr < 0 || nr > MAX_PLAYERS)
2463 SDL_JoystickClose(sdl_joystick[nr]);
2465 sdl_joystick[nr] = NULL;
2468 static boolean SDLCheckJoystickOpened(int nr)
2470 if (nr < 0 || nr > MAX_PLAYERS)
2473 #if defined(TARGET_SDL2)
2474 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2476 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2480 void HandleJoystickEvent(Event *event)
2484 case SDL_JOYAXISMOTION:
2485 if (event->jaxis.axis < 2)
2486 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2489 case SDL_JOYBUTTONDOWN:
2490 if (event->jbutton.button < 2)
2491 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2494 case SDL_JOYBUTTONUP:
2495 if (event->jbutton.button < 2)
2496 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2504 void SDLInitJoysticks()
2506 static boolean sdl_joystick_subsystem_initialized = FALSE;
2507 boolean print_warning = !sdl_joystick_subsystem_initialized;
2510 if (!sdl_joystick_subsystem_initialized)
2512 sdl_joystick_subsystem_initialized = TRUE;
2514 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2516 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2521 for (i = 0; i < MAX_PLAYERS; i++)
2523 /* get configured joystick for this player */
2524 char *device_name = setup.input[i].joy.device_name;
2525 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2527 if (joystick_nr >= SDL_NumJoysticks())
2529 if (setup.input[i].use_joystick && print_warning)
2530 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2535 /* misuse joystick file descriptor variable to store joystick number */
2536 joystick.fd[i] = joystick_nr;
2538 if (joystick_nr == -1)
2541 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2542 if (SDLCheckJoystickOpened(joystick_nr))
2543 SDLCloseJoystick(joystick_nr);
2545 if (!setup.input[i].use_joystick)
2548 if (!SDLOpenJoystick(joystick_nr))
2551 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2556 joystick.status = JOYSTICK_ACTIVATED;
2560 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2562 if (nr < 0 || nr >= MAX_PLAYERS)
2566 *x = sdl_js_axis[nr][0];
2568 *y = sdl_js_axis[nr][1];
2571 *b1 = sdl_js_button[nr][0];
2573 *b2 = sdl_js_button[nr][1];