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 UpdateScreen(&dst_rect2);
1210 for (alpha = 0.0; alpha < 255.0;)
1212 time_last = time_current;
1213 time_current = SDL_GetTicks();
1214 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1215 alpha_final = MIN(MAX(0, alpha), 255);
1217 /* draw existing (source) image to screen buffer */
1218 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1220 /* draw new (target) image to screen buffer using alpha blending */
1221 #if defined(TARGET_SDL2)
1222 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1223 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1225 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1227 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1229 if (draw_border_function != NULL)
1230 draw_border_function();
1232 /* only update the region of the screen that is affected from fading */
1233 UpdateScreen(&dst_rect);
1240 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1241 int to_x, int to_y, Uint32 color)
1243 SDL_Surface *surface = dst_bitmap->surface;
1247 swap_numbers(&from_x, &to_x);
1250 swap_numbers(&from_y, &to_y);
1254 rect.w = (to_x - from_x + 1);
1255 rect.h = (to_y - from_y + 1);
1257 if (dst_bitmap == backbuffer || dst_bitmap == window)
1259 rect.x += video_xoffset;
1260 rect.y += video_yoffset;
1263 SDL_FillRect(surface, &rect, color);
1266 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1267 int to_x, int to_y, Uint32 color)
1269 if (dst_bitmap == backbuffer || dst_bitmap == window)
1271 from_x += video_xoffset;
1272 from_y += video_yoffset;
1273 to_x += video_xoffset;
1274 to_y += video_yoffset;
1277 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1280 #if ENABLE_UNUSED_CODE
1281 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1282 int num_points, Uint32 color)
1287 for (i = 0; i < num_points - 1; i++)
1289 for (x = 0; x < line_width; x++)
1291 for (y = 0; y < line_width; y++)
1293 int dx = x - line_width / 2;
1294 int dy = y - line_width / 2;
1296 if ((x == 0 && y == 0) ||
1297 (x == 0 && y == line_width - 1) ||
1298 (x == line_width - 1 && y == 0) ||
1299 (x == line_width - 1 && y == line_width - 1))
1302 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1303 points[i+1].x + dx, points[i+1].y + dy, color);
1310 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1312 SDL_Surface *surface = src_bitmap->surface;
1314 if (src_bitmap == backbuffer || src_bitmap == window)
1320 switch (surface->format->BytesPerPixel)
1322 case 1: /* assuming 8-bpp */
1324 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1328 case 2: /* probably 15-bpp or 16-bpp */
1330 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1334 case 3: /* slow 24-bpp mode; usually not used */
1336 /* does this work? */
1337 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1341 shift = surface->format->Rshift;
1342 color |= *(pix + shift / 8) >> shift;
1343 shift = surface->format->Gshift;
1344 color |= *(pix + shift / 8) >> shift;
1345 shift = surface->format->Bshift;
1346 color |= *(pix + shift / 8) >> shift;
1352 case 4: /* probably 32-bpp */
1354 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1363 /* ========================================================================= */
1364 /* The following functions were taken from the SGE library */
1365 /* (SDL Graphics Extension Library) by Anders Lindström */
1366 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1367 /* ========================================================================= */
1369 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1371 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1373 switch (surface->format->BytesPerPixel)
1377 /* Assuming 8-bpp */
1378 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1384 /* Probably 15-bpp or 16-bpp */
1385 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1391 /* Slow 24-bpp mode, usually not used */
1395 /* Gack - slow, but endian correct */
1396 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1397 shift = surface->format->Rshift;
1398 *(pix+shift/8) = color>>shift;
1399 shift = surface->format->Gshift;
1400 *(pix+shift/8) = color>>shift;
1401 shift = surface->format->Bshift;
1402 *(pix+shift/8) = color>>shift;
1408 /* Probably 32-bpp */
1409 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1416 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1417 Uint8 R, Uint8 G, Uint8 B)
1419 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1422 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1424 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1427 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1429 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1432 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1437 /* Gack - slow, but endian correct */
1438 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1439 shift = surface->format->Rshift;
1440 *(pix+shift/8) = color>>shift;
1441 shift = surface->format->Gshift;
1442 *(pix+shift/8) = color>>shift;
1443 shift = surface->format->Bshift;
1444 *(pix+shift/8) = color>>shift;
1447 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1449 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1452 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1454 switch (dest->format->BytesPerPixel)
1457 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1461 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1465 _PutPixel24(dest,x,y,color);
1469 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1474 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1476 if (SDL_MUSTLOCK(surface))
1478 if (SDL_LockSurface(surface) < 0)
1484 _PutPixel(surface, x, y, color);
1486 if (SDL_MUSTLOCK(surface))
1488 SDL_UnlockSurface(surface);
1492 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1493 Uint8 r, Uint8 g, Uint8 b)
1495 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1498 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1500 if (y >= 0 && y <= dest->h - 1)
1502 switch (dest->format->BytesPerPixel)
1505 return y*dest->pitch;
1509 return y*dest->pitch/2;
1513 return y*dest->pitch;
1517 return y*dest->pitch/4;
1525 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1527 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1529 switch (surface->format->BytesPerPixel)
1533 /* Assuming 8-bpp */
1534 *((Uint8 *)surface->pixels + ypitch + x) = color;
1540 /* Probably 15-bpp or 16-bpp */
1541 *((Uint16 *)surface->pixels + ypitch + x) = color;
1547 /* Slow 24-bpp mode, usually not used */
1551 /* Gack - slow, but endian correct */
1552 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1553 shift = surface->format->Rshift;
1554 *(pix+shift/8) = color>>shift;
1555 shift = surface->format->Gshift;
1556 *(pix+shift/8) = color>>shift;
1557 shift = surface->format->Bshift;
1558 *(pix+shift/8) = color>>shift;
1564 /* Probably 32-bpp */
1565 *((Uint32 *)surface->pixels + ypitch + x) = color;
1572 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1577 if (SDL_MUSTLOCK(Surface))
1579 if (SDL_LockSurface(Surface) < 0)
1592 /* Do the clipping */
1593 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1597 if (x2 > Surface->w - 1)
1598 x2 = Surface->w - 1;
1605 SDL_FillRect(Surface, &l, Color);
1607 if (SDL_MUSTLOCK(Surface))
1609 SDL_UnlockSurface(Surface);
1613 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1614 Uint8 R, Uint8 G, Uint8 B)
1616 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1619 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1630 /* Do the clipping */
1631 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1635 if (x2 > Surface->w - 1)
1636 x2 = Surface->w - 1;
1643 SDL_FillRect(Surface, &l, Color);
1646 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1651 if (SDL_MUSTLOCK(Surface))
1653 if (SDL_LockSurface(Surface) < 0)
1666 /* Do the clipping */
1667 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1671 if (y2 > Surface->h - 1)
1672 y2 = Surface->h - 1;
1679 SDL_FillRect(Surface, &l, Color);
1681 if (SDL_MUSTLOCK(Surface))
1683 SDL_UnlockSurface(Surface);
1687 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1688 Uint8 R, Uint8 G, Uint8 B)
1690 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1693 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1704 /* Do the clipping */
1705 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1709 if (y2 > Surface->h - 1)
1710 y2 = Surface->h - 1;
1717 SDL_FillRect(Surface, &l, Color);
1720 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1721 Sint16 x2, Sint16 y2, Uint32 Color,
1722 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1725 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1730 sdx = (dx < 0) ? -1 : 1;
1731 sdy = (dy < 0) ? -1 : 1;
1743 for (x = 0; x < dx; x++)
1745 Callback(Surface, px, py, Color);
1759 for (y = 0; y < dy; y++)
1761 Callback(Surface, px, py, Color);
1775 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1776 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1777 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1780 sge_DoLine(Surface, X1, Y1, X2, Y2,
1781 SDL_MapRGB(Surface->format, R, G, B), Callback);
1784 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1787 if (SDL_MUSTLOCK(Surface))
1789 if (SDL_LockSurface(Surface) < 0)
1794 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1796 /* unlock the display */
1797 if (SDL_MUSTLOCK(Surface))
1799 SDL_UnlockSurface(Surface);
1803 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1804 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1806 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1809 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1811 if (dst_bitmap == backbuffer || dst_bitmap == window)
1817 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1822 -----------------------------------------------------------------------------
1823 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1824 -----------------------------------------------------------------------------
1827 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1828 int width, int height, Uint32 color)
1832 for (y = src_y; y < src_y + height; y++)
1834 for (x = src_x; x < src_x + width; x++)
1836 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1838 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1843 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1844 int src_x, int src_y, int width, int height,
1845 int dst_x, int dst_y)
1849 for (y = 0; y < height; y++)
1851 for (x = 0; x < width; x++)
1853 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1855 if (pixel != BLACK_PIXEL)
1856 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1862 /* ========================================================================= */
1863 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1864 /* (Rotozoomer) by Andreas Schiffler */
1865 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1866 /* ========================================================================= */
1869 -----------------------------------------------------------------------------
1872 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1873 -----------------------------------------------------------------------------
1884 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1887 tColorRGBA *sp, *csp, *dp;
1891 sp = csp = (tColorRGBA *) src->pixels;
1892 dp = (tColorRGBA *) dst->pixels;
1893 dgap = dst->pitch - dst->w * 4;
1895 for (y = 0; y < dst->h; y++)
1899 for (x = 0; x < dst->w; x++)
1901 tColorRGBA *sp0 = sp;
1902 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1903 tColorRGBA *sp00 = &sp0[0];
1904 tColorRGBA *sp01 = &sp0[1];
1905 tColorRGBA *sp10 = &sp1[0];
1906 tColorRGBA *sp11 = &sp1[1];
1909 /* create new color pixel from all four source color pixels */
1910 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1911 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1912 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1913 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1918 /* advance source pointers */
1921 /* advance destination pointer */
1925 /* advance source pointer */
1926 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1928 /* advance destination pointers */
1929 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1935 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1937 int x, y, *sax, *say, *csax, *csay;
1939 tColorRGBA *sp, *csp, *csp0, *dp;
1942 /* use specialized zoom function when scaling down to exactly half size */
1943 if (src->w == 2 * dst->w &&
1944 src->h == 2 * dst->h)
1945 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1947 /* variable setup */
1948 sx = (float) src->w / (float) dst->w;
1949 sy = (float) src->h / (float) dst->h;
1951 /* allocate memory for row increments */
1952 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1953 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1955 /* precalculate row increments */
1956 for (x = 0; x <= dst->w; x++)
1957 *csax++ = (int)(sx * x);
1959 for (y = 0; y <= dst->h; y++)
1960 *csay++ = (int)(sy * y);
1963 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1964 dp = (tColorRGBA *) dst->pixels;
1965 dgap = dst->pitch - dst->w * 4;
1968 for (y = 0; y < dst->h; y++)
1973 for (x = 0; x < dst->w; x++)
1978 /* advance source pointers */
1982 /* advance destination pointer */
1986 /* advance source pointer */
1988 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1990 /* advance destination pointers */
1991 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2001 -----------------------------------------------------------------------------
2004 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2005 -----------------------------------------------------------------------------
2008 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2010 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2011 Uint8 *sp, *dp, *csp;
2014 /* variable setup */
2015 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2016 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2018 /* allocate memory for row increments */
2019 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2020 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2022 /* precalculate row increments */
2025 for (x = 0; x < dst->w; x++)
2028 *csax = (csx >> 16);
2035 for (y = 0; y < dst->h; y++)
2038 *csay = (csy >> 16);
2045 for (x = 0; x < dst->w; x++)
2053 for (y = 0; y < dst->h; y++)
2060 sp = csp = (Uint8 *) src->pixels;
2061 dp = (Uint8 *) dst->pixels;
2062 dgap = dst->pitch - dst->w;
2066 for (y = 0; y < dst->h; y++)
2070 for (x = 0; x < dst->w; x++)
2075 /* advance source pointers */
2079 /* advance destination pointer */
2083 /* advance source pointer (for row) */
2084 csp += ((*csay) * src->pitch);
2087 /* advance destination pointers */
2098 -----------------------------------------------------------------------------
2101 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2102 'zoomx' and 'zoomy' are scaling factors for width and height.
2103 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2104 into a 32bit RGBA format on the fly.
2105 -----------------------------------------------------------------------------
2108 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2110 SDL_Surface *zoom_src = NULL;
2111 SDL_Surface *zoom_dst = NULL;
2112 boolean is_converted = FALSE;
2119 /* determine if source surface is 32 bit or 8 bit */
2120 is_32bit = (src->format->BitsPerPixel == 32);
2122 if (is_32bit || src->format->BitsPerPixel == 8)
2124 /* use source surface 'as is' */
2129 /* new source surface is 32 bit with a defined RGB ordering */
2130 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2131 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2132 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2134 is_converted = TRUE;
2137 /* allocate surface to completely contain the zoomed surface */
2140 /* target surface is 32 bit with source RGBA/ABGR ordering */
2141 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2142 zoom_src->format->Rmask,
2143 zoom_src->format->Gmask,
2144 zoom_src->format->Bmask, 0);
2148 /* target surface is 8 bit */
2149 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2153 /* lock source surface */
2154 SDL_LockSurface(zoom_src);
2156 /* check which kind of surface we have */
2159 /* call the 32 bit transformation routine to do the zooming */
2160 zoomSurfaceRGBA(zoom_src, zoom_dst);
2165 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2166 zoom_dst->format->palette->colors[i] =
2167 zoom_src->format->palette->colors[i];
2168 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2170 /* call the 8 bit transformation routine to do the zooming */
2171 zoomSurfaceY(zoom_src, zoom_dst);
2174 /* unlock source surface */
2175 SDL_UnlockSurface(zoom_src);
2177 /* free temporary surface */
2179 SDL_FreeSurface(zoom_src);
2181 /* return destination surface */
2185 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2187 Bitmap *dst_bitmap = CreateBitmapStruct();
2188 SDL_Surface **dst_surface = &dst_bitmap->surface;
2190 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2191 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2193 dst_bitmap->width = dst_width;
2194 dst_bitmap->height = dst_height;
2196 /* create zoomed temporary surface from source surface */
2197 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2199 /* create native format destination surface from zoomed temporary surface */
2200 SDLSetNativeSurface(dst_surface);
2206 /* ========================================================================= */
2207 /* load image to bitmap */
2208 /* ========================================================================= */
2210 Bitmap *SDLLoadImage(char *filename)
2212 Bitmap *new_bitmap = CreateBitmapStruct();
2213 SDL_Surface *sdl_image_tmp;
2215 print_timestamp_init("SDLLoadImage");
2217 print_timestamp_time(getBaseNamePtr(filename));
2219 /* load image to temporary surface */
2220 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2222 SetError("IMG_Load(): %s", SDL_GetError());
2227 print_timestamp_time("IMG_Load");
2229 UPDATE_BUSY_STATE();
2231 /* create native non-transparent surface for current image */
2232 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2234 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2239 print_timestamp_time("SDL_DisplayFormat (opaque)");
2241 UPDATE_BUSY_STATE();
2243 /* create native transparent surface for current image */
2244 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2245 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2247 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2249 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2254 print_timestamp_time("SDL_DisplayFormat (masked)");
2256 UPDATE_BUSY_STATE();
2258 /* free temporary surface */
2259 SDL_FreeSurface(sdl_image_tmp);
2261 new_bitmap->width = new_bitmap->surface->w;
2262 new_bitmap->height = new_bitmap->surface->h;
2264 print_timestamp_done("SDLLoadImage");
2270 /* ------------------------------------------------------------------------- */
2271 /* custom cursor fuctions */
2272 /* ------------------------------------------------------------------------- */
2274 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2276 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2277 cursor_info->width, cursor_info->height,
2278 cursor_info->hot_x, cursor_info->hot_y);
2281 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2283 static struct MouseCursorInfo *last_cursor_info = NULL;
2284 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2285 static SDL_Cursor *cursor_default = NULL;
2286 static SDL_Cursor *cursor_current = NULL;
2288 /* if invoked for the first time, store the SDL default cursor */
2289 if (cursor_default == NULL)
2290 cursor_default = SDL_GetCursor();
2292 /* only create new cursor if cursor info (custom only) has changed */
2293 if (cursor_info != NULL && cursor_info != last_cursor_info)
2295 cursor_current = create_cursor(cursor_info);
2296 last_cursor_info = cursor_info;
2299 /* only set new cursor if cursor info (custom or NULL) has changed */
2300 if (cursor_info != last_cursor_info2)
2301 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2303 last_cursor_info2 = cursor_info;
2307 /* ========================================================================= */
2308 /* audio functions */
2309 /* ========================================================================= */
2311 void SDLOpenAudio(void)
2313 #if !defined(TARGET_SDL2)
2314 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2315 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2318 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2320 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2324 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2325 AUDIO_NUM_CHANNELS_STEREO,
2326 setup.system.audio_fragment_size) < 0)
2328 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2332 audio.sound_available = TRUE;
2333 audio.music_available = TRUE;
2334 audio.loops_available = TRUE;
2335 audio.sound_enabled = TRUE;
2337 /* set number of available mixer channels */
2338 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2339 audio.music_channel = MUSIC_CHANNEL;
2340 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2342 Mixer_InitChannels();
2345 void SDLCloseAudio(void)
2348 Mix_HaltChannel(-1);
2351 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2355 /* ========================================================================= */
2356 /* event functions */
2357 /* ========================================================================= */
2359 void SDLNextEvent(Event *event)
2361 SDL_WaitEvent(event);
2363 if (event->type == EVENT_BUTTONPRESS ||
2364 event->type == EVENT_BUTTONRELEASE)
2366 if (((ButtonEvent *)event)->x > video_xoffset)
2367 ((ButtonEvent *)event)->x -= video_xoffset;
2369 ((ButtonEvent *)event)->x = 0;
2370 if (((ButtonEvent *)event)->y > video_yoffset)
2371 ((ButtonEvent *)event)->y -= video_yoffset;
2373 ((ButtonEvent *)event)->y = 0;
2375 else if (event->type == EVENT_MOTIONNOTIFY)
2377 if (((MotionEvent *)event)->x > video_xoffset)
2378 ((MotionEvent *)event)->x -= video_xoffset;
2380 ((MotionEvent *)event)->x = 0;
2381 if (((MotionEvent *)event)->y > video_yoffset)
2382 ((MotionEvent *)event)->y -= video_yoffset;
2384 ((MotionEvent *)event)->y = 0;
2388 void SDLHandleWindowManagerEvent(Event *event)
2391 #if defined(PLATFORM_WIN32)
2392 // experimental drag and drop code
2394 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2395 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2397 #if defined(TARGET_SDL2)
2398 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2400 if (syswmmsg->msg == WM_DROPFILES)
2403 #if defined(TARGET_SDL2)
2404 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2406 HDROP hdrop = (HDROP)syswmmsg->wParam;
2410 printf("::: SDL_SYSWMEVENT:\n");
2412 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2414 for (i = 0; i < num_files; i++)
2416 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2417 char buffer[buffer_len + 1];
2419 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2421 printf("::: - '%s'\n", buffer);
2424 #if defined(TARGET_SDL2)
2425 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2427 DragFinish((HDROP)syswmmsg->wParam);
2435 /* ========================================================================= */
2436 /* joystick functions */
2437 /* ========================================================================= */
2439 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2440 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2441 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2443 static boolean SDLOpenJoystick(int nr)
2445 if (nr < 0 || nr > MAX_PLAYERS)
2448 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2451 static void SDLCloseJoystick(int nr)
2453 if (nr < 0 || nr > MAX_PLAYERS)
2456 SDL_JoystickClose(sdl_joystick[nr]);
2458 sdl_joystick[nr] = NULL;
2461 static boolean SDLCheckJoystickOpened(int nr)
2463 if (nr < 0 || nr > MAX_PLAYERS)
2466 #if defined(TARGET_SDL2)
2467 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2469 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2473 void HandleJoystickEvent(Event *event)
2477 case SDL_JOYAXISMOTION:
2478 if (event->jaxis.axis < 2)
2479 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2482 case SDL_JOYBUTTONDOWN:
2483 if (event->jbutton.button < 2)
2484 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2487 case SDL_JOYBUTTONUP:
2488 if (event->jbutton.button < 2)
2489 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2497 void SDLInitJoysticks()
2499 static boolean sdl_joystick_subsystem_initialized = FALSE;
2500 boolean print_warning = !sdl_joystick_subsystem_initialized;
2503 if (!sdl_joystick_subsystem_initialized)
2505 sdl_joystick_subsystem_initialized = TRUE;
2507 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2509 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2514 for (i = 0; i < MAX_PLAYERS; i++)
2516 /* get configured joystick for this player */
2517 char *device_name = setup.input[i].joy.device_name;
2518 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2520 if (joystick_nr >= SDL_NumJoysticks())
2522 if (setup.input[i].use_joystick && print_warning)
2523 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2528 /* misuse joystick file descriptor variable to store joystick number */
2529 joystick.fd[i] = joystick_nr;
2531 if (joystick_nr == -1)
2534 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2535 if (SDLCheckJoystickOpened(joystick_nr))
2536 SDLCloseJoystick(joystick_nr);
2538 if (!setup.input[i].use_joystick)
2541 if (!SDLOpenJoystick(joystick_nr))
2544 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2549 joystick.status = JOYSTICK_ACTIVATED;
2553 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2555 if (nr < 0 || nr >= MAX_PLAYERS)
2559 *x = sdl_js_axis[nr][0];
2561 *y = sdl_js_axis[nr][1];
2564 *b1 = sdl_js_button[nr][0];
2566 *b2 = sdl_js_button[nr][1];