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);
63 #if defined(TARGET_SDL2)
65 SDL_Surface *screen = backbuffer->surface;
69 int bytes_x = screen->pitch / video.width;
70 int bytes_y = screen->pitch;
72 if (video.fullscreen_enabled)
73 bytes_x = screen->pitch / fullscreen_width;
75 SDL_UpdateTexture(sdl_texture, rect,
76 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
81 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
83 SDL_RenderClear(sdl_renderer);
84 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
85 SDL_RenderPresent(sdl_renderer);
88 SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
90 SDL_UpdateWindowSurface(sdl_window);
95 SDL_UpdateRects(backbuffer->surface, 1, rect);
97 SDL_UpdateRect(backbuffer->surface, 0, 0, 0, 0);
101 static void setFullscreenParameters(char *fullscreen_mode_string)
103 #if defined(TARGET_SDL2)
104 fullscreen_width = video.width;
105 fullscreen_height = video.height;
106 fullscreen_xoffset = 0;
107 fullscreen_yoffset = 0;
111 struct ScreenModeInfo *fullscreen_mode;
114 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
116 if (fullscreen_mode == NULL)
119 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
121 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
122 fullscreen_mode->height == video.fullscreen_modes[i].height)
124 fullscreen_width = fullscreen_mode->width;
125 fullscreen_height = fullscreen_mode->height;
127 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
128 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
136 static void SDLSetWindowIcon(char *basename)
138 /* (setting the window icon on Mac OS X would replace the high-quality
139 dock icon with the currently smaller (and uglier) icon from file) */
141 #if !defined(PLATFORM_MACOSX)
142 char *filename = getCustomImageFilename(basename);
143 SDL_Surface *surface;
145 if (filename == NULL)
147 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
152 if ((surface = IMG_Load(filename)) == NULL)
154 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
159 /* set transparent color */
160 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
161 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
163 #if defined(TARGET_SDL2)
164 SDL_SetWindowIcon(sdl_window, surface);
166 SDL_WM_SetIcon(surface, NULL);
171 #if defined(TARGET_SDL2)
173 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
174 SDL_PixelFormat *format2)
176 return (format1->format == format2->format &&
177 format1->BitsPerPixel == format2->BitsPerPixel &&
178 format1->BytesPerPixel == format2->BytesPerPixel &&
179 format1->Rmask == format2->Rmask &&
180 format1->Gmask == format2->Gmask &&
181 format1->Bmask == format2->Bmask &&
182 format1->Amask == format2->Amask);
185 boolean SDLSetNativeSurface(SDL_Surface **surface)
187 SDL_Surface *new_surface;
189 if (surface == NULL ||
191 backbuffer == NULL ||
192 backbuffer->surface == NULL)
195 // if pixel format already optimized for destination surface, do nothing
196 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
199 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
201 SDL_FreeSurface(*surface);
203 *surface = new_surface;
208 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
210 if (surface == NULL ||
211 backbuffer == NULL ||
212 backbuffer->surface == NULL)
215 return SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
218 SDL_Surface *SDL_DisplayFormat(SDL_Surface *surface)
220 if (surface == NULL ||
221 backbuffer == NULL ||
222 backbuffer->surface == NULL)
225 return SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
230 boolean SDLSetNativeSurface(SDL_Surface **surface)
232 SDL_Surface *new_surface;
237 new_surface = SDL_DisplayFormat(*surface);
239 if (new_surface == NULL)
240 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
242 SDL_FreeSurface(*surface);
244 *surface = new_surface;
249 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
251 SDL_Surface *new_surface = SDL_DisplayFormat(surface);
253 if (new_surface == NULL)
254 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
261 void SDLInitVideoDisplay(void)
263 #if !defined(TARGET_SDL2)
264 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
265 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
267 SDL_putenv("SDL_VIDEO_CENTERED=1");
270 /* initialize SDL video */
271 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
272 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
274 /* set default SDL depth */
275 #if !defined(TARGET_SDL2)
276 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
278 video.default_depth = 32; // (how to determine video depth in SDL2?)
282 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
285 #if !defined(TARGET_SDL2)
286 static int screen_xy[][2] =
294 SDL_Rect **modes = NULL;
295 boolean hardware_fullscreen_available = TRUE;
298 /* default: normal game window size */
299 fullscreen_width = video.width;
300 fullscreen_height = video.height;
301 fullscreen_xoffset = 0;
302 fullscreen_yoffset = 0;
304 #if !defined(TARGET_SDL2)
305 /* determine required standard fullscreen mode for game screen size */
306 for (i = 0; screen_xy[i][0] != -1; i++)
308 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
310 fullscreen_width = screen_xy[i][0];
311 fullscreen_height = screen_xy[i][1];
317 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
318 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
321 checked_free(video.fullscreen_modes);
323 video.fullscreen_modes = NULL;
324 video.fullscreen_mode_current = NULL;
326 video.window_scaling_percent = setup.window_scaling_percent;
327 video.window_scaling_quality = setup.window_scaling_quality;
329 #if defined(TARGET_SDL2)
330 int num_displays = SDL_GetNumVideoDisplays();
332 if (num_displays > 0)
334 // currently only display modes of first display supported
335 int num_modes = SDL_GetNumDisplayModes(0);
339 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
341 for (i = 0; i < num_modes; i++)
343 SDL_DisplayMode mode;
345 if (SDL_GetDisplayMode(0, i, &mode) < 0)
348 modes[i] = checked_calloc(sizeof(SDL_Rect));
350 modes[i]->w = mode.w;
351 modes[i]->h = mode.h;
356 /* get available hardware supported fullscreen modes */
357 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
362 /* no hardware screen modes available => no fullscreen mode support */
363 // video.fullscreen_available = FALSE;
364 hardware_fullscreen_available = FALSE;
366 else if (modes == (SDL_Rect **)-1)
368 /* fullscreen resolution is not restricted -- all resolutions available */
369 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
371 /* use native video buffer size for fullscreen mode */
372 video.fullscreen_modes[0].width = video.width;
373 video.fullscreen_modes[0].height = video.height;
375 video.fullscreen_modes[1].width = -1;
376 video.fullscreen_modes[1].height = -1;
380 /* in this case, a certain number of screen modes is available */
383 for (i = 0; modes[i] != NULL; i++)
385 boolean found_mode = FALSE;
387 /* screen mode is smaller than video buffer size -- skip it */
388 if (modes[i]->w < video.width || modes[i]->h < video.height)
391 if (video.fullscreen_modes != NULL)
392 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
393 if (modes[i]->w == video.fullscreen_modes[j].width &&
394 modes[i]->h == video.fullscreen_modes[j].height)
397 if (found_mode) /* screen mode already stored -- skip it */
400 /* new mode found; add it to list of available fullscreen modes */
404 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
406 sizeof(struct ScreenModeInfo));
408 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
409 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
411 video.fullscreen_modes[num_modes].width = -1;
412 video.fullscreen_modes[num_modes].height = -1;
417 /* no appropriate screen modes available => no fullscreen mode support */
418 // video.fullscreen_available = FALSE;
419 hardware_fullscreen_available = FALSE;
423 video.fullscreen_available = hardware_fullscreen_available;
425 #if USE_DESKTOP_FULLSCREEN
426 // in SDL 2.0, there is always support for desktop fullscreen mode
427 // (in SDL 1.2, there is only support for "real" fullscreen mode)
428 video.fullscreen_available = TRUE;
431 #if defined(TARGET_SDL2)
434 for (i = 0; modes[i] != NULL; i++)
435 checked_free(modes[i]);
441 /* open SDL video output device (window or fullscreen mode) */
442 if (!SDLSetVideoMode(backbuffer, fullscreen))
443 Error(ERR_EXIT, "setting video mode failed");
445 /* !!! SDL2 can only set the window icon if the window already exists !!! */
446 /* set window icon */
447 SDLSetWindowIcon(program.sdl_icon_filename);
449 /* set window and icon title */
450 #if defined(TARGET_SDL2)
451 SDL_SetWindowTitle(sdl_window, program.window_title);
453 SDL_WM_SetCaption(program.window_title, program.window_title);
456 /* SDL cannot directly draw to the visible video framebuffer like X11,
457 but always uses a backbuffer, which is then blitted to the visible
458 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
459 visible video framebuffer with 'SDL_Flip', if the hardware supports
460 this). Therefore do not use an additional backbuffer for drawing, but
461 use a symbolic buffer (distinguishable from the SDL backbuffer) called
462 'window', which indicates that the SDL backbuffer should be updated to
463 the visible video framebuffer when attempting to blit to it.
465 For convenience, it seems to be a good idea to create this symbolic
466 buffer 'window' at the same size as the SDL backbuffer. Although it
467 should never be drawn to directly, it would do no harm nevertheless. */
469 /* create additional (symbolic) buffer for double-buffering */
470 ReCreateBitmap(window, video.width, video.height, video.depth);
473 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
476 SDL_Surface *new_surface = NULL;
478 #if defined(TARGET_SDL2)
479 static boolean fullscreen_enabled = FALSE;
480 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
481 #if USE_DESKTOP_FULLSCREEN
482 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
484 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
488 int surface_flags_window = SURFACE_FLAGS;
489 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
492 int width = (fullscreen ? fullscreen_width : video.width);
493 int height = (fullscreen ? fullscreen_height : video.height);
494 int surface_flags = (fullscreen ? surface_flags_fullscreen :
495 surface_flags_window);
497 // default window size is unscaled
498 video.window_width = video.width;
499 video.window_height = video.height;
501 #if defined(TARGET_SDL2)
503 // store if initial screen mode on game start is fullscreen mode
504 if (sdl_window == NULL)
505 video.fullscreen_initial = fullscreen;
508 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
509 #if !USE_DESKTOP_FULLSCREEN
510 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
513 video.window_width = window_scaling_factor * width;
514 video.window_height = window_scaling_factor * height;
516 if ((*backbuffer)->surface)
518 SDL_FreeSurface((*backbuffer)->surface);
519 (*backbuffer)->surface = NULL;
524 SDL_DestroyTexture(sdl_texture);
528 if (!(fullscreen && fullscreen_enabled))
532 SDL_DestroyRenderer(sdl_renderer);
538 SDL_DestroyWindow(sdl_window);
543 if (sdl_window == NULL)
544 sdl_window = SDL_CreateWindow(program.window_title,
545 SDL_WINDOWPOS_CENTERED,
546 SDL_WINDOWPOS_CENTERED,
547 #if USE_DESKTOP_FULLSCREEN
551 (int)(screen_scaling_factor * width),
552 (int)(screen_scaling_factor * height),
556 if (sdl_window != NULL)
559 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
560 *without* enabling 2D/3D acceleration and/or guest additions installed,
561 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
562 it will try to use accelerated graphics and apparently fails miserably) */
563 if (sdl_renderer == NULL)
564 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
566 if (sdl_renderer == NULL)
567 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
570 if (sdl_renderer != NULL)
572 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
573 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
574 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
576 sdl_texture = SDL_CreateTexture(sdl_renderer,
577 SDL_PIXELFORMAT_ARGB8888,
578 SDL_TEXTUREACCESS_STREAMING,
581 if (sdl_texture != NULL)
583 // use SDL default values for RGB masks and no alpha channel
584 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
586 if (new_surface == NULL)
587 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
592 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
597 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
602 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
608 SDL_DestroyWindow(sdl_window);
610 sdl_window = SDL_CreateWindow(program.window_title,
611 SDL_WINDOWPOS_CENTERED,
612 SDL_WINDOWPOS_CENTERED,
616 if (sdl_window != NULL)
617 new_surface = SDL_GetWindowSurface(sdl_window);
621 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
624 #if defined(TARGET_SDL2)
625 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
626 if (new_surface != NULL)
627 fullscreen_enabled = fullscreen;
633 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
635 boolean success = TRUE;
636 SDL_Surface *new_surface = NULL;
640 if (*backbuffer == NULL)
641 *backbuffer = CreateBitmapStruct();
643 /* (real bitmap might be larger in fullscreen mode with video offsets) */
644 (*backbuffer)->width = video.width;
645 (*backbuffer)->height = video.height;
647 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
649 setFullscreenParameters(setup.fullscreen_mode);
651 video_xoffset = fullscreen_xoffset;
652 video_yoffset = fullscreen_yoffset;
654 /* switch display to fullscreen mode, if available */
655 new_surface = SDLCreateScreen(backbuffer, TRUE);
657 if (new_surface == NULL)
659 /* switching display to fullscreen mode failed */
660 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
662 /* do not try it again */
663 video.fullscreen_available = FALSE;
669 (*backbuffer)->surface = new_surface;
671 video.fullscreen_enabled = TRUE;
672 video.fullscreen_mode_current = setup.fullscreen_mode;
678 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
683 /* switch display to window mode */
684 new_surface = SDLCreateScreen(backbuffer, FALSE);
686 if (new_surface == NULL)
688 /* switching display to window mode failed -- should not happen */
689 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
695 (*backbuffer)->surface = new_surface;
697 video.fullscreen_enabled = FALSE;
698 video.window_scaling_percent = setup.window_scaling_percent;
699 video.window_scaling_quality = setup.window_scaling_quality;
705 #if defined(TARGET_SDL2)
706 SDLRedrawWindow(); // map window
709 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
711 #if defined(PLATFORM_WIN32)
713 SDL_SysWMinfo wminfo;
715 boolean wminfo_success = FALSE;
717 SDL_VERSION(&wminfo.version);
718 #if defined(TARGET_SDL2)
720 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
722 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
727 #if defined(TARGET_SDL2)
728 hwnd = wminfo.info.win.window;
730 hwnd = wminfo.window;
733 DragAcceptFiles(hwnd, TRUE);
741 void SDLSetWindowTitle()
743 #if defined(TARGET_SDL2)
744 SDL_SetWindowTitle(sdl_window, program.window_title);
746 SDL_WM_SetCaption(program.window_title, program.window_title);
750 #if defined(TARGET_SDL2)
751 void SDLSetWindowScaling(int window_scaling_percent)
753 if (sdl_window == NULL)
756 float window_scaling_factor = (float)window_scaling_percent / 100;
757 int new_window_width = (int)(window_scaling_factor * video.width);
758 int new_window_height = (int)(window_scaling_factor * video.height);
760 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
762 video.window_scaling_percent = window_scaling_percent;
763 video.window_width = new_window_width;
764 video.window_height = new_window_height;
769 void SDLSetWindowScalingQuality(char *window_scaling_quality)
771 if (sdl_texture == NULL)
774 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
776 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
777 SDL_PIXELFORMAT_ARGB8888,
778 SDL_TEXTUREACCESS_STREAMING,
779 video.width, video.height);
781 if (new_texture != NULL)
783 SDL_DestroyTexture(sdl_texture);
785 sdl_texture = new_texture;
790 video.window_scaling_quality = window_scaling_quality;
793 void SDLSetWindowFullscreen(boolean fullscreen)
795 if (sdl_window == NULL)
798 #if USE_DESKTOP_FULLSCREEN
799 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
801 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
804 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
805 video.fullscreen_enabled = fullscreen;
807 // if game started in fullscreen mode, window will also get fullscreen size
808 if (!fullscreen && video.fullscreen_initial)
810 SDLSetWindowScaling(setup.window_scaling_percent);
811 SDL_SetWindowPosition(sdl_window,
812 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
814 video.fullscreen_initial = FALSE;
818 void SDLRedrawWindow()
824 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
827 SDL_Surface *surface =
828 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
831 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
833 SDLSetNativeSurface(&surface);
835 bitmap->surface = surface;
838 void SDLFreeBitmapPointers(Bitmap *bitmap)
841 SDL_FreeSurface(bitmap->surface);
842 if (bitmap->surface_masked)
843 SDL_FreeSurface(bitmap->surface_masked);
844 bitmap->surface = NULL;
845 bitmap->surface_masked = NULL;
848 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
849 int src_x, int src_y, int width, int height,
850 int dst_x, int dst_y, int mask_mode)
852 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
853 SDL_Rect src_rect, dst_rect;
855 if (src_bitmap == backbuffer)
857 src_x += video_xoffset;
858 src_y += video_yoffset;
866 if (dst_bitmap == backbuffer || dst_bitmap == window)
868 dst_x += video_xoffset;
869 dst_y += video_yoffset;
877 // if (src_bitmap != backbuffer || dst_bitmap != window)
878 if (!(src_bitmap == backbuffer && dst_bitmap == window))
879 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
880 src_bitmap->surface_masked : src_bitmap->surface),
881 &src_rect, real_dst_bitmap->surface, &dst_rect);
883 #if defined(TARGET_SDL2)
884 if (dst_bitmap == window)
886 // SDL_UpdateWindowSurface(sdl_window);
887 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
888 UpdateScreen(&dst_rect);
891 if (dst_bitmap == window)
893 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
894 UpdateScreen(&dst_rect);
899 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
902 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
905 if (dst_bitmap == backbuffer || dst_bitmap == window)
916 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
918 #if defined(TARGET_SDL2)
919 if (dst_bitmap == window)
921 // SDL_UpdateWindowSurface(sdl_window);
922 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
926 if (dst_bitmap == window)
928 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
934 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
935 int fade_mode, int fade_delay, int post_delay,
936 void (*draw_border_function)(void))
938 static boolean initialization_needed = TRUE;
939 static SDL_Surface *surface_source = NULL;
940 static SDL_Surface *surface_target = NULL;
941 static SDL_Surface *surface_black = NULL;
942 SDL_Surface *surface_screen = backbuffer->surface;
943 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
944 SDL_Rect src_rect, dst_rect;
946 int src_x = x, src_y = y;
947 int dst_x = x, dst_y = y;
948 unsigned int time_last, time_current;
950 /* check if screen size has changed */
951 if (surface_source != NULL && (video.width != surface_source->w ||
952 video.height != surface_source->h))
954 SDL_FreeSurface(surface_source);
955 SDL_FreeSurface(surface_target);
956 SDL_FreeSurface(surface_black);
958 initialization_needed = TRUE;
966 dst_x += video_xoffset;
967 dst_y += video_yoffset;
971 dst_rect.w = width; /* (ignored) */
972 dst_rect.h = height; /* (ignored) */
974 dst_rect2 = dst_rect;
976 if (initialization_needed)
978 #if defined(TARGET_SDL2)
979 unsigned int flags = 0;
981 unsigned int flags = SDL_SRCALPHA;
983 /* use same surface type as screen surface */
984 if ((surface_screen->flags & SDL_HWSURFACE))
985 flags |= SDL_HWSURFACE;
987 flags |= SDL_SWSURFACE;
990 /* create surface for temporary copy of screen buffer (source) */
991 if ((surface_source =
992 SDL_CreateRGBSurface(flags,
995 surface_screen->format->BitsPerPixel,
996 surface_screen->format->Rmask,
997 surface_screen->format->Gmask,
998 surface_screen->format->Bmask,
999 surface_screen->format->Amask)) == NULL)
1000 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1002 /* create surface for cross-fading screen buffer (target) */
1003 if ((surface_target =
1004 SDL_CreateRGBSurface(flags,
1007 surface_screen->format->BitsPerPixel,
1008 surface_screen->format->Rmask,
1009 surface_screen->format->Gmask,
1010 surface_screen->format->Bmask,
1011 surface_screen->format->Amask)) == NULL)
1012 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1014 /* create black surface for fading from/to black */
1015 if ((surface_black =
1016 SDL_CreateRGBSurface(flags,
1019 surface_screen->format->BitsPerPixel,
1020 surface_screen->format->Rmask,
1021 surface_screen->format->Gmask,
1022 surface_screen->format->Bmask,
1023 surface_screen->format->Amask)) == NULL)
1024 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1026 /* completely fill the surface with black color pixels */
1027 SDL_FillRect(surface_black, NULL,
1028 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1030 initialization_needed = FALSE;
1033 /* copy source and target surfaces to temporary surfaces for fading */
1034 if (fade_mode & FADE_TYPE_TRANSFORM)
1036 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1037 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1039 else if (fade_mode & FADE_TYPE_FADE_IN)
1041 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1042 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1044 else /* FADE_TYPE_FADE_OUT */
1046 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1047 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1050 time_current = SDL_GetTicks();
1052 if (fade_mode == FADE_MODE_MELT)
1054 boolean done = FALSE;
1055 int melt_pixels = 2;
1056 int melt_columns = width / melt_pixels;
1057 int ypos[melt_columns];
1058 int max_steps = height / 8 + 32;
1063 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1064 #if defined(TARGET_SDL2)
1065 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1067 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1070 ypos[0] = -GetSimpleRandom(16);
1072 for (i = 1 ; i < melt_columns; i++)
1074 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1076 ypos[i] = ypos[i - 1] + r;
1089 time_last = time_current;
1090 time_current = SDL_GetTicks();
1091 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1092 steps_final = MIN(MAX(0, steps), max_steps);
1096 done = (steps_done >= steps_final);
1098 for (i = 0 ; i < melt_columns; i++)
1106 else if (ypos[i] < height)
1111 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1113 if (ypos[i] + dy >= height)
1114 dy = height - ypos[i];
1116 /* copy part of (appearing) target surface to upper area */
1117 src_rect.x = src_x + i * melt_pixels;
1118 // src_rect.y = src_y + ypos[i];
1120 src_rect.w = melt_pixels;
1122 src_rect.h = ypos[i] + dy;
1124 dst_rect.x = dst_x + i * melt_pixels;
1125 // dst_rect.y = dst_y + ypos[i];
1128 if (steps_done >= steps_final)
1129 SDL_BlitSurface(surface_target, &src_rect,
1130 surface_screen, &dst_rect);
1134 /* copy part of (disappearing) source surface to lower area */
1135 src_rect.x = src_x + i * melt_pixels;
1137 src_rect.w = melt_pixels;
1138 src_rect.h = height - ypos[i];
1140 dst_rect.x = dst_x + i * melt_pixels;
1141 dst_rect.y = dst_y + ypos[i];
1143 if (steps_done >= steps_final)
1144 SDL_BlitSurface(surface_source, &src_rect,
1145 surface_screen, &dst_rect);
1151 src_rect.x = src_x + i * melt_pixels;
1153 src_rect.w = melt_pixels;
1154 src_rect.h = height;
1156 dst_rect.x = dst_x + i * melt_pixels;
1159 if (steps_done >= steps_final)
1160 SDL_BlitSurface(surface_target, &src_rect,
1161 surface_screen, &dst_rect);
1165 if (steps_done >= steps_final)
1167 if (draw_border_function != NULL)
1168 draw_border_function();
1170 #if defined(TARGET_SDL2)
1171 // SDL_UpdateWindowSurface(sdl_window);
1172 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
1173 UpdateScreen(&dst_rect2);
1175 // SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1176 UpdateScreen(&dst_rect2);
1186 for (alpha = 0.0; alpha < 255.0;)
1188 time_last = time_current;
1189 time_current = SDL_GetTicks();
1190 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1191 alpha_final = MIN(MAX(0, alpha), 255);
1193 /* draw existing (source) image to screen buffer */
1194 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1196 /* draw new (target) image to screen buffer using alpha blending */
1197 #if defined(TARGET_SDL2)
1198 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1199 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1201 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1203 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1205 if (draw_border_function != NULL)
1206 draw_border_function();
1208 /* only update the region of the screen that is affected from fading */
1209 UpdateScreen(&dst_rect);
1216 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1217 int to_x, int to_y, Uint32 color)
1219 SDL_Surface *surface = dst_bitmap->surface;
1223 swap_numbers(&from_x, &to_x);
1226 swap_numbers(&from_y, &to_y);
1230 rect.w = (to_x - from_x + 1);
1231 rect.h = (to_y - from_y + 1);
1233 if (dst_bitmap == backbuffer || dst_bitmap == window)
1235 rect.x += video_xoffset;
1236 rect.y += video_yoffset;
1239 SDL_FillRect(surface, &rect, color);
1242 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1243 int to_x, int to_y, Uint32 color)
1245 if (dst_bitmap == backbuffer || dst_bitmap == window)
1247 from_x += video_xoffset;
1248 from_y += video_yoffset;
1249 to_x += video_xoffset;
1250 to_y += video_yoffset;
1253 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1256 #if ENABLE_UNUSED_CODE
1257 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1258 int num_points, Uint32 color)
1263 for (i = 0; i < num_points - 1; i++)
1265 for (x = 0; x < line_width; x++)
1267 for (y = 0; y < line_width; y++)
1269 int dx = x - line_width / 2;
1270 int dy = y - line_width / 2;
1272 if ((x == 0 && y == 0) ||
1273 (x == 0 && y == line_width - 1) ||
1274 (x == line_width - 1 && y == 0) ||
1275 (x == line_width - 1 && y == line_width - 1))
1278 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1279 points[i+1].x + dx, points[i+1].y + dy, color);
1286 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1288 SDL_Surface *surface = src_bitmap->surface;
1290 if (src_bitmap == backbuffer || src_bitmap == window)
1296 switch (surface->format->BytesPerPixel)
1298 case 1: /* assuming 8-bpp */
1300 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1304 case 2: /* probably 15-bpp or 16-bpp */
1306 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1310 case 3: /* slow 24-bpp mode; usually not used */
1312 /* does this work? */
1313 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1317 shift = surface->format->Rshift;
1318 color |= *(pix + shift / 8) >> shift;
1319 shift = surface->format->Gshift;
1320 color |= *(pix + shift / 8) >> shift;
1321 shift = surface->format->Bshift;
1322 color |= *(pix + shift / 8) >> shift;
1328 case 4: /* probably 32-bpp */
1330 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1339 /* ========================================================================= */
1340 /* The following functions were taken from the SGE library */
1341 /* (SDL Graphics Extension Library) by Anders Lindström */
1342 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1343 /* ========================================================================= */
1345 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1347 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1349 switch (surface->format->BytesPerPixel)
1353 /* Assuming 8-bpp */
1354 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1360 /* Probably 15-bpp or 16-bpp */
1361 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1367 /* Slow 24-bpp mode, usually not used */
1371 /* Gack - slow, but endian correct */
1372 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1373 shift = surface->format->Rshift;
1374 *(pix+shift/8) = color>>shift;
1375 shift = surface->format->Gshift;
1376 *(pix+shift/8) = color>>shift;
1377 shift = surface->format->Bshift;
1378 *(pix+shift/8) = color>>shift;
1384 /* Probably 32-bpp */
1385 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1392 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1393 Uint8 R, Uint8 G, Uint8 B)
1395 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1398 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1400 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1403 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1405 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1408 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1413 /* Gack - slow, but endian correct */
1414 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1415 shift = surface->format->Rshift;
1416 *(pix+shift/8) = color>>shift;
1417 shift = surface->format->Gshift;
1418 *(pix+shift/8) = color>>shift;
1419 shift = surface->format->Bshift;
1420 *(pix+shift/8) = color>>shift;
1423 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1425 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1428 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1430 switch (dest->format->BytesPerPixel)
1433 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1437 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1441 _PutPixel24(dest,x,y,color);
1445 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1450 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1452 if (SDL_MUSTLOCK(surface))
1454 if (SDL_LockSurface(surface) < 0)
1460 _PutPixel(surface, x, y, color);
1462 if (SDL_MUSTLOCK(surface))
1464 SDL_UnlockSurface(surface);
1468 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1469 Uint8 r, Uint8 g, Uint8 b)
1471 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1474 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1476 if (y >= 0 && y <= dest->h - 1)
1478 switch (dest->format->BytesPerPixel)
1481 return y*dest->pitch;
1485 return y*dest->pitch/2;
1489 return y*dest->pitch;
1493 return y*dest->pitch/4;
1501 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1503 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1505 switch (surface->format->BytesPerPixel)
1509 /* Assuming 8-bpp */
1510 *((Uint8 *)surface->pixels + ypitch + x) = color;
1516 /* Probably 15-bpp or 16-bpp */
1517 *((Uint16 *)surface->pixels + ypitch + x) = color;
1523 /* Slow 24-bpp mode, usually not used */
1527 /* Gack - slow, but endian correct */
1528 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1529 shift = surface->format->Rshift;
1530 *(pix+shift/8) = color>>shift;
1531 shift = surface->format->Gshift;
1532 *(pix+shift/8) = color>>shift;
1533 shift = surface->format->Bshift;
1534 *(pix+shift/8) = color>>shift;
1540 /* Probably 32-bpp */
1541 *((Uint32 *)surface->pixels + ypitch + x) = color;
1548 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1553 if (SDL_MUSTLOCK(Surface))
1555 if (SDL_LockSurface(Surface) < 0)
1568 /* Do the clipping */
1569 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1573 if (x2 > Surface->w - 1)
1574 x2 = Surface->w - 1;
1581 SDL_FillRect(Surface, &l, Color);
1583 if (SDL_MUSTLOCK(Surface))
1585 SDL_UnlockSurface(Surface);
1589 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1590 Uint8 R, Uint8 G, Uint8 B)
1592 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1595 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1606 /* Do the clipping */
1607 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1611 if (x2 > Surface->w - 1)
1612 x2 = Surface->w - 1;
1619 SDL_FillRect(Surface, &l, Color);
1622 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1627 if (SDL_MUSTLOCK(Surface))
1629 if (SDL_LockSurface(Surface) < 0)
1642 /* Do the clipping */
1643 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1647 if (y2 > Surface->h - 1)
1648 y2 = Surface->h - 1;
1655 SDL_FillRect(Surface, &l, Color);
1657 if (SDL_MUSTLOCK(Surface))
1659 SDL_UnlockSurface(Surface);
1663 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1664 Uint8 R, Uint8 G, Uint8 B)
1666 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1669 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1680 /* Do the clipping */
1681 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1685 if (y2 > Surface->h - 1)
1686 y2 = Surface->h - 1;
1693 SDL_FillRect(Surface, &l, Color);
1696 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1697 Sint16 x2, Sint16 y2, Uint32 Color,
1698 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1701 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1706 sdx = (dx < 0) ? -1 : 1;
1707 sdy = (dy < 0) ? -1 : 1;
1719 for (x = 0; x < dx; x++)
1721 Callback(Surface, px, py, Color);
1735 for (y = 0; y < dy; y++)
1737 Callback(Surface, px, py, Color);
1751 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1752 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1753 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1756 sge_DoLine(Surface, X1, Y1, X2, Y2,
1757 SDL_MapRGB(Surface->format, R, G, B), Callback);
1760 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1763 if (SDL_MUSTLOCK(Surface))
1765 if (SDL_LockSurface(Surface) < 0)
1770 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1772 /* unlock the display */
1773 if (SDL_MUSTLOCK(Surface))
1775 SDL_UnlockSurface(Surface);
1779 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1780 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1782 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1785 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1787 if (dst_bitmap == backbuffer || dst_bitmap == window)
1793 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1798 -----------------------------------------------------------------------------
1799 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1800 -----------------------------------------------------------------------------
1803 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1804 int width, int height, Uint32 color)
1808 for (y = src_y; y < src_y + height; y++)
1810 for (x = src_x; x < src_x + width; x++)
1812 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1814 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1819 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1820 int src_x, int src_y, int width, int height,
1821 int dst_x, int dst_y)
1825 for (y = 0; y < height; y++)
1827 for (x = 0; x < width; x++)
1829 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1831 if (pixel != BLACK_PIXEL)
1832 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1838 /* ========================================================================= */
1839 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1840 /* (Rotozoomer) by Andreas Schiffler */
1841 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1842 /* ========================================================================= */
1845 -----------------------------------------------------------------------------
1848 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1849 -----------------------------------------------------------------------------
1860 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1863 tColorRGBA *sp, *csp, *dp;
1867 sp = csp = (tColorRGBA *) src->pixels;
1868 dp = (tColorRGBA *) dst->pixels;
1869 dgap = dst->pitch - dst->w * 4;
1871 for (y = 0; y < dst->h; y++)
1875 for (x = 0; x < dst->w; x++)
1877 tColorRGBA *sp0 = sp;
1878 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1879 tColorRGBA *sp00 = &sp0[0];
1880 tColorRGBA *sp01 = &sp0[1];
1881 tColorRGBA *sp10 = &sp1[0];
1882 tColorRGBA *sp11 = &sp1[1];
1885 /* create new color pixel from all four source color pixels */
1886 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1887 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1888 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1889 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1894 /* advance source pointers */
1897 /* advance destination pointer */
1901 /* advance source pointer */
1902 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1904 /* advance destination pointers */
1905 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1911 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1913 int x, y, *sax, *say, *csax, *csay;
1915 tColorRGBA *sp, *csp, *csp0, *dp;
1918 /* use specialized zoom function when scaling down to exactly half size */
1919 if (src->w == 2 * dst->w &&
1920 src->h == 2 * dst->h)
1921 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1923 /* variable setup */
1924 sx = (float) src->w / (float) dst->w;
1925 sy = (float) src->h / (float) dst->h;
1927 /* allocate memory for row increments */
1928 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1929 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1931 /* precalculate row increments */
1932 for (x = 0; x <= dst->w; x++)
1933 *csax++ = (int)(sx * x);
1935 for (y = 0; y <= dst->h; y++)
1936 *csay++ = (int)(sy * y);
1939 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1940 dp = (tColorRGBA *) dst->pixels;
1941 dgap = dst->pitch - dst->w * 4;
1944 for (y = 0; y < dst->h; y++)
1949 for (x = 0; x < dst->w; x++)
1954 /* advance source pointers */
1958 /* advance destination pointer */
1962 /* advance source pointer */
1964 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1966 /* advance destination pointers */
1967 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1977 -----------------------------------------------------------------------------
1980 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1981 -----------------------------------------------------------------------------
1984 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1986 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1987 Uint8 *sp, *dp, *csp;
1990 /* variable setup */
1991 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1992 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1994 /* allocate memory for row increments */
1995 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1996 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1998 /* precalculate row increments */
2001 for (x = 0; x < dst->w; x++)
2004 *csax = (csx >> 16);
2011 for (y = 0; y < dst->h; y++)
2014 *csay = (csy >> 16);
2021 for (x = 0; x < dst->w; x++)
2029 for (y = 0; y < dst->h; y++)
2036 sp = csp = (Uint8 *) src->pixels;
2037 dp = (Uint8 *) dst->pixels;
2038 dgap = dst->pitch - dst->w;
2042 for (y = 0; y < dst->h; y++)
2046 for (x = 0; x < dst->w; x++)
2051 /* advance source pointers */
2055 /* advance destination pointer */
2059 /* advance source pointer (for row) */
2060 csp += ((*csay) * src->pitch);
2063 /* advance destination pointers */
2074 -----------------------------------------------------------------------------
2077 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2078 'zoomx' and 'zoomy' are scaling factors for width and height.
2079 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2080 into a 32bit RGBA format on the fly.
2081 -----------------------------------------------------------------------------
2084 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2086 SDL_Surface *zoom_src = NULL;
2087 SDL_Surface *zoom_dst = NULL;
2088 boolean is_converted = FALSE;
2095 /* determine if source surface is 32 bit or 8 bit */
2096 is_32bit = (src->format->BitsPerPixel == 32);
2098 if (is_32bit || src->format->BitsPerPixel == 8)
2100 /* use source surface 'as is' */
2105 /* new source surface is 32 bit with a defined RGB ordering */
2106 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2107 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2108 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2110 is_converted = TRUE;
2113 /* allocate surface to completely contain the zoomed surface */
2116 /* target surface is 32 bit with source RGBA/ABGR ordering */
2117 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2118 zoom_src->format->Rmask,
2119 zoom_src->format->Gmask,
2120 zoom_src->format->Bmask, 0);
2124 /* target surface is 8 bit */
2125 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2129 /* lock source surface */
2130 SDL_LockSurface(zoom_src);
2132 /* check which kind of surface we have */
2135 /* call the 32 bit transformation routine to do the zooming */
2136 zoomSurfaceRGBA(zoom_src, zoom_dst);
2141 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2142 zoom_dst->format->palette->colors[i] =
2143 zoom_src->format->palette->colors[i];
2144 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2146 /* call the 8 bit transformation routine to do the zooming */
2147 zoomSurfaceY(zoom_src, zoom_dst);
2150 /* unlock source surface */
2151 SDL_UnlockSurface(zoom_src);
2153 /* free temporary surface */
2155 SDL_FreeSurface(zoom_src);
2157 /* return destination surface */
2161 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2163 Bitmap *dst_bitmap = CreateBitmapStruct();
2164 SDL_Surface **dst_surface = &dst_bitmap->surface;
2166 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2167 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2169 dst_bitmap->width = dst_width;
2170 dst_bitmap->height = dst_height;
2172 /* create zoomed temporary surface from source surface */
2173 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2175 /* create native format destination surface from zoomed temporary surface */
2176 SDLSetNativeSurface(dst_surface);
2182 /* ========================================================================= */
2183 /* load image to bitmap */
2184 /* ========================================================================= */
2186 Bitmap *SDLLoadImage(char *filename)
2188 Bitmap *new_bitmap = CreateBitmapStruct();
2189 SDL_Surface *sdl_image_tmp;
2191 print_timestamp_init("SDLLoadImage");
2193 print_timestamp_time(getBaseNamePtr(filename));
2195 /* load image to temporary surface */
2196 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2198 SetError("IMG_Load(): %s", SDL_GetError());
2203 print_timestamp_time("IMG_Load");
2205 UPDATE_BUSY_STATE();
2207 /* create native non-transparent surface for current image */
2208 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2210 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2215 print_timestamp_time("SDL_DisplayFormat (opaque)");
2217 UPDATE_BUSY_STATE();
2219 /* create native transparent surface for current image */
2220 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2221 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2223 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2225 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2230 print_timestamp_time("SDL_DisplayFormat (masked)");
2232 UPDATE_BUSY_STATE();
2234 /* free temporary surface */
2235 SDL_FreeSurface(sdl_image_tmp);
2237 new_bitmap->width = new_bitmap->surface->w;
2238 new_bitmap->height = new_bitmap->surface->h;
2240 print_timestamp_done("SDLLoadImage");
2246 /* ------------------------------------------------------------------------- */
2247 /* custom cursor fuctions */
2248 /* ------------------------------------------------------------------------- */
2250 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2252 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2253 cursor_info->width, cursor_info->height,
2254 cursor_info->hot_x, cursor_info->hot_y);
2257 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2259 static struct MouseCursorInfo *last_cursor_info = NULL;
2260 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2261 static SDL_Cursor *cursor_default = NULL;
2262 static SDL_Cursor *cursor_current = NULL;
2264 /* if invoked for the first time, store the SDL default cursor */
2265 if (cursor_default == NULL)
2266 cursor_default = SDL_GetCursor();
2268 /* only create new cursor if cursor info (custom only) has changed */
2269 if (cursor_info != NULL && cursor_info != last_cursor_info)
2271 cursor_current = create_cursor(cursor_info);
2272 last_cursor_info = cursor_info;
2275 /* only set new cursor if cursor info (custom or NULL) has changed */
2276 if (cursor_info != last_cursor_info2)
2277 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2279 last_cursor_info2 = cursor_info;
2283 /* ========================================================================= */
2284 /* audio functions */
2285 /* ========================================================================= */
2287 void SDLOpenAudio(void)
2289 #if !defined(TARGET_SDL2)
2290 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2291 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2294 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2296 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2300 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2301 AUDIO_NUM_CHANNELS_STEREO,
2302 setup.system.audio_fragment_size) < 0)
2304 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2308 audio.sound_available = TRUE;
2309 audio.music_available = TRUE;
2310 audio.loops_available = TRUE;
2311 audio.sound_enabled = TRUE;
2313 /* set number of available mixer channels */
2314 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2315 audio.music_channel = MUSIC_CHANNEL;
2316 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2318 Mixer_InitChannels();
2321 void SDLCloseAudio(void)
2324 Mix_HaltChannel(-1);
2327 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2331 /* ========================================================================= */
2332 /* event functions */
2333 /* ========================================================================= */
2335 void SDLNextEvent(Event *event)
2337 SDL_WaitEvent(event);
2339 if (event->type == EVENT_BUTTONPRESS ||
2340 event->type == EVENT_BUTTONRELEASE)
2342 if (((ButtonEvent *)event)->x > video_xoffset)
2343 ((ButtonEvent *)event)->x -= video_xoffset;
2345 ((ButtonEvent *)event)->x = 0;
2346 if (((ButtonEvent *)event)->y > video_yoffset)
2347 ((ButtonEvent *)event)->y -= video_yoffset;
2349 ((ButtonEvent *)event)->y = 0;
2351 else if (event->type == EVENT_MOTIONNOTIFY)
2353 if (((MotionEvent *)event)->x > video_xoffset)
2354 ((MotionEvent *)event)->x -= video_xoffset;
2356 ((MotionEvent *)event)->x = 0;
2357 if (((MotionEvent *)event)->y > video_yoffset)
2358 ((MotionEvent *)event)->y -= video_yoffset;
2360 ((MotionEvent *)event)->y = 0;
2364 void SDLHandleWindowManagerEvent(Event *event)
2366 #if defined(PLATFORM_WIN32)
2367 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2368 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2370 #if defined(TARGET_SDL2)
2371 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2373 if (syswmmsg->msg == WM_DROPFILES)
2376 #if defined(TARGET_SDL2)
2377 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2379 HDROP hdrop = (HDROP)syswmmsg->wParam;
2383 printf("::: SDL_SYSWMEVENT:\n");
2385 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2387 for (i = 0; i < num_files; i++)
2389 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2390 char buffer[buffer_len + 1];
2392 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2394 printf("::: - '%s'\n", buffer);
2397 #if defined(TARGET_SDL2)
2398 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2400 DragFinish((HDROP)syswmmsg->wParam);
2407 /* ========================================================================= */
2408 /* joystick functions */
2409 /* ========================================================================= */
2411 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2412 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2413 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2415 static boolean SDLOpenJoystick(int nr)
2417 if (nr < 0 || nr > MAX_PLAYERS)
2420 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2423 static void SDLCloseJoystick(int nr)
2425 if (nr < 0 || nr > MAX_PLAYERS)
2428 SDL_JoystickClose(sdl_joystick[nr]);
2430 sdl_joystick[nr] = NULL;
2433 static boolean SDLCheckJoystickOpened(int nr)
2435 if (nr < 0 || nr > MAX_PLAYERS)
2438 #if defined(TARGET_SDL2)
2439 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2441 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2445 void HandleJoystickEvent(Event *event)
2449 case SDL_JOYAXISMOTION:
2450 if (event->jaxis.axis < 2)
2451 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2454 case SDL_JOYBUTTONDOWN:
2455 if (event->jbutton.button < 2)
2456 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2459 case SDL_JOYBUTTONUP:
2460 if (event->jbutton.button < 2)
2461 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2469 void SDLInitJoysticks()
2471 static boolean sdl_joystick_subsystem_initialized = FALSE;
2472 boolean print_warning = !sdl_joystick_subsystem_initialized;
2475 if (!sdl_joystick_subsystem_initialized)
2477 sdl_joystick_subsystem_initialized = TRUE;
2479 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2481 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2486 for (i = 0; i < MAX_PLAYERS; i++)
2488 /* get configured joystick for this player */
2489 char *device_name = setup.input[i].joy.device_name;
2490 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2492 if (joystick_nr >= SDL_NumJoysticks())
2494 if (setup.input[i].use_joystick && print_warning)
2495 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2500 /* misuse joystick file descriptor variable to store joystick number */
2501 joystick.fd[i] = joystick_nr;
2503 if (joystick_nr == -1)
2506 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2507 if (SDLCheckJoystickOpened(joystick_nr))
2508 SDLCloseJoystick(joystick_nr);
2510 if (!setup.input[i].use_joystick)
2513 if (!SDLOpenJoystick(joystick_nr))
2516 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2521 joystick.status = JOYSTICK_ACTIVATED;
2525 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2527 if (nr < 0 || nr >= MAX_PLAYERS)
2531 *x = sdl_js_axis[nr][0];
2533 *y = sdl_js_axis[nr][1];
2536 *b1 = sdl_js_button[nr][0];
2538 *b2 = sdl_js_button[nr][1];