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;
30 static boolean fullscreen_enabled = FALSE;
32 #define USE_RENDERER TRUE
35 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
36 static int fullscreen_width;
37 static int fullscreen_height;
38 static int fullscreen_xoffset;
39 static int fullscreen_yoffset;
40 static int video_xoffset;
41 static int video_yoffset;
42 static boolean limit_screen_updates = FALSE;
45 /* functions from SGE library */
46 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
48 void SDLLimitScreenUpdates(boolean enable)
50 limit_screen_updates = enable;
53 static void UpdateScreen(SDL_Rect *rect)
55 static unsigned int update_screen_delay = 0;
56 unsigned int update_screen_delay_value = 20; /* (milliseconds) */
58 if (limit_screen_updates &&
59 !DelayReached(&update_screen_delay, update_screen_delay_value))
62 LimitScreenUpdates(FALSE);
66 static int LastFrameCounter = 0;
67 boolean changed = (FrameCounter != LastFrameCounter);
69 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
70 (changed ? "-" : "SAME FRAME UPDATED"));
72 LastFrameCounter = FrameCounter;
81 #if defined(TARGET_SDL2)
83 SDL_Surface *screen = backbuffer->surface;
87 int bytes_x = screen->pitch / video.width;
88 int bytes_y = screen->pitch;
90 if (video.fullscreen_enabled)
91 bytes_x = screen->pitch / fullscreen_width;
93 SDL_UpdateTexture(sdl_texture, rect,
94 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
99 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
101 SDL_RenderClear(sdl_renderer);
102 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
103 SDL_RenderPresent(sdl_renderer);
106 SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
108 SDL_UpdateWindowSurface(sdl_window);
113 SDL_UpdateRects(backbuffer->surface, 1, rect);
115 SDL_UpdateRect(backbuffer->surface, 0, 0, 0, 0);
119 static void setFullscreenParameters(char *fullscreen_mode_string)
121 #if defined(TARGET_SDL2)
122 fullscreen_width = video.width;
123 fullscreen_height = video.height;
124 fullscreen_xoffset = 0;
125 fullscreen_yoffset = 0;
129 struct ScreenModeInfo *fullscreen_mode;
132 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
134 if (fullscreen_mode == NULL)
137 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
139 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
140 fullscreen_mode->height == video.fullscreen_modes[i].height)
142 fullscreen_width = fullscreen_mode->width;
143 fullscreen_height = fullscreen_mode->height;
145 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
146 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
154 static void SDLSetWindowIcon(char *basename)
156 /* (setting the window icon on Mac OS X would replace the high-quality
157 dock icon with the currently smaller (and uglier) icon from file) */
159 #if !defined(PLATFORM_MACOSX)
160 char *filename = getCustomImageFilename(basename);
161 SDL_Surface *surface;
163 if (filename == NULL)
165 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
170 if ((surface = IMG_Load(filename)) == NULL)
172 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
177 /* set transparent color */
178 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
179 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
181 #if defined(TARGET_SDL2)
182 SDL_SetWindowIcon(sdl_window, surface);
184 SDL_WM_SetIcon(surface, NULL);
189 #if defined(TARGET_SDL2)
191 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
192 SDL_PixelFormat *format2)
194 return (format1->format == format2->format &&
195 format1->BitsPerPixel == format2->BitsPerPixel &&
196 format1->BytesPerPixel == format2->BytesPerPixel &&
197 format1->Rmask == format2->Rmask &&
198 format1->Gmask == format2->Gmask &&
199 format1->Bmask == format2->Bmask &&
200 format1->Amask == format2->Amask);
203 boolean SDLSetNativeSurface(SDL_Surface **surface)
205 SDL_Surface *new_surface;
207 if (surface == NULL ||
209 backbuffer == NULL ||
210 backbuffer->surface == NULL)
213 // if pixel format already optimized for destination surface, do nothing
214 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
217 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
219 if (new_surface == NULL)
220 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
222 SDL_FreeSurface(*surface);
224 *surface = new_surface;
229 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
231 SDL_Surface *new_surface;
236 if (backbuffer && backbuffer->surface)
237 new_surface = SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
239 new_surface = SDL_ConvertSurface(surface, surface->format, 0);
241 if (new_surface == NULL)
242 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
249 boolean SDLSetNativeSurface(SDL_Surface **surface)
251 SDL_Surface *new_surface;
253 if (surface == NULL ||
258 new_surface = SDL_DisplayFormat(*surface);
260 if (new_surface == NULL)
261 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
263 SDL_FreeSurface(*surface);
265 *surface = new_surface;
270 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
272 SDL_Surface *new_surface;
274 if (video.initialized)
275 new_surface = SDL_DisplayFormat(surface);
277 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
279 if (new_surface == NULL)
280 Error(ERR_EXIT, "%s() failed: %s",
281 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
289 void SDLInitVideoDisplay(void)
291 #if !defined(TARGET_SDL2)
292 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
293 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
295 SDL_putenv("SDL_VIDEO_CENTERED=1");
298 /* initialize SDL video */
299 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
300 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
302 /* set default SDL depth */
303 #if !defined(TARGET_SDL2)
304 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
306 video.default_depth = 32; // (how to determine video depth in SDL2?)
310 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
313 #if !defined(TARGET_SDL2)
314 static int screen_xy[][2] =
322 SDL_Rect **modes = NULL;
323 boolean hardware_fullscreen_available = TRUE;
326 /* default: normal game window size */
327 fullscreen_width = video.width;
328 fullscreen_height = video.height;
329 fullscreen_xoffset = 0;
330 fullscreen_yoffset = 0;
332 #if !defined(TARGET_SDL2)
333 /* determine required standard fullscreen mode for game screen size */
334 for (i = 0; screen_xy[i][0] != -1; i++)
336 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
338 fullscreen_width = screen_xy[i][0];
339 fullscreen_height = screen_xy[i][1];
345 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
346 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
349 checked_free(video.fullscreen_modes);
351 video.fullscreen_modes = NULL;
352 video.fullscreen_mode_current = NULL;
354 video.window_scaling_percent = setup.window_scaling_percent;
355 video.window_scaling_quality = setup.window_scaling_quality;
357 #if defined(TARGET_SDL2)
358 int num_displays = SDL_GetNumVideoDisplays();
360 if (num_displays > 0)
362 // currently only display modes of first display supported
363 int num_modes = SDL_GetNumDisplayModes(0);
367 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
369 for (i = 0; i < num_modes; i++)
371 SDL_DisplayMode mode;
373 if (SDL_GetDisplayMode(0, i, &mode) < 0)
376 modes[i] = checked_calloc(sizeof(SDL_Rect));
378 modes[i]->w = mode.w;
379 modes[i]->h = mode.h;
384 /* get available hardware supported fullscreen modes */
385 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
390 /* no hardware screen modes available => no fullscreen mode support */
391 // video.fullscreen_available = FALSE;
392 hardware_fullscreen_available = FALSE;
394 else if (modes == (SDL_Rect **)-1)
396 /* fullscreen resolution is not restricted -- all resolutions available */
397 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
399 /* use native video buffer size for fullscreen mode */
400 video.fullscreen_modes[0].width = video.width;
401 video.fullscreen_modes[0].height = video.height;
403 video.fullscreen_modes[1].width = -1;
404 video.fullscreen_modes[1].height = -1;
408 /* in this case, a certain number of screen modes is available */
411 for (i = 0; modes[i] != NULL; i++)
413 boolean found_mode = FALSE;
415 /* screen mode is smaller than video buffer size -- skip it */
416 if (modes[i]->w < video.width || modes[i]->h < video.height)
419 if (video.fullscreen_modes != NULL)
420 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
421 if (modes[i]->w == video.fullscreen_modes[j].width &&
422 modes[i]->h == video.fullscreen_modes[j].height)
425 if (found_mode) /* screen mode already stored -- skip it */
428 /* new mode found; add it to list of available fullscreen modes */
432 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
434 sizeof(struct ScreenModeInfo));
436 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
437 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
439 video.fullscreen_modes[num_modes].width = -1;
440 video.fullscreen_modes[num_modes].height = -1;
445 /* no appropriate screen modes available => no fullscreen mode support */
446 // video.fullscreen_available = FALSE;
447 hardware_fullscreen_available = FALSE;
451 video.fullscreen_available = hardware_fullscreen_available;
453 #if USE_DESKTOP_FULLSCREEN
454 // in SDL 2.0, there is always support for desktop fullscreen mode
455 // (in SDL 1.2, there is only support for "real" fullscreen mode)
456 video.fullscreen_available = TRUE;
459 #if defined(TARGET_SDL2)
462 for (i = 0; modes[i] != NULL; i++)
463 checked_free(modes[i]);
469 /* open SDL video output device (window or fullscreen mode) */
470 if (!SDLSetVideoMode(backbuffer, fullscreen))
471 Error(ERR_EXIT, "setting video mode failed");
473 /* !!! SDL2 can only set the window icon if the window already exists !!! */
474 /* set window icon */
475 SDLSetWindowIcon(program.icon_filename);
477 /* set window and icon title */
478 #if defined(TARGET_SDL2)
479 SDL_SetWindowTitle(sdl_window, program.window_title);
481 SDL_WM_SetCaption(program.window_title, program.window_title);
484 /* SDL cannot directly draw to the visible video framebuffer like X11,
485 but always uses a backbuffer, which is then blitted to the visible
486 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
487 visible video framebuffer with 'SDL_Flip', if the hardware supports
488 this). Therefore do not use an additional backbuffer for drawing, but
489 use a symbolic buffer (distinguishable from the SDL backbuffer) called
490 'window', which indicates that the SDL backbuffer should be updated to
491 the visible video framebuffer when attempting to blit to it.
493 For convenience, it seems to be a good idea to create this symbolic
494 buffer 'window' at the same size as the SDL backbuffer. Although it
495 should never be drawn to directly, it would do no harm nevertheless. */
497 /* create additional (symbolic) buffer for double-buffering */
498 ReCreateBitmap(window, video.width, video.height, video.depth);
501 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
504 SDL_Surface *new_surface = NULL;
506 #if defined(TARGET_SDL2)
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 is fullscreen mode when changing screen size
531 video.fullscreen_initial = fullscreen;
534 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
535 #if !USE_DESKTOP_FULLSCREEN
536 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
539 video.window_width = window_scaling_factor * width;
540 video.window_height = window_scaling_factor * height;
542 if ((*backbuffer)->surface)
544 SDL_FreeSurface((*backbuffer)->surface);
545 (*backbuffer)->surface = NULL;
550 SDL_DestroyTexture(sdl_texture);
554 if (!(fullscreen && fullscreen_enabled))
558 SDL_DestroyRenderer(sdl_renderer);
564 SDL_DestroyWindow(sdl_window);
569 if (sdl_window == NULL)
570 sdl_window = SDL_CreateWindow(program.window_title,
571 SDL_WINDOWPOS_CENTERED,
572 SDL_WINDOWPOS_CENTERED,
573 #if USE_DESKTOP_FULLSCREEN
577 (int)(screen_scaling_factor * width),
578 (int)(screen_scaling_factor * height),
582 if (sdl_window != NULL)
585 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
586 *without* enabling 2D/3D acceleration and/or guest additions installed,
587 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
588 it will try to use accelerated graphics and apparently fails miserably) */
589 if (sdl_renderer == NULL)
590 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
592 if (sdl_renderer == NULL)
593 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
596 if (sdl_renderer != NULL)
598 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
599 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
600 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
602 sdl_texture = SDL_CreateTexture(sdl_renderer,
603 SDL_PIXELFORMAT_ARGB8888,
604 SDL_TEXTUREACCESS_STREAMING,
607 if (sdl_texture != NULL)
609 // use SDL default values for RGB masks and no alpha channel
610 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
612 if (new_surface == NULL)
613 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
618 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
623 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
628 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
634 SDL_DestroyWindow(sdl_window);
636 sdl_window = SDL_CreateWindow(program.window_title,
637 SDL_WINDOWPOS_CENTERED,
638 SDL_WINDOWPOS_CENTERED,
642 if (sdl_window != NULL)
643 new_surface = SDL_GetWindowSurface(sdl_window);
647 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
650 #if defined(TARGET_SDL2)
651 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
652 if (new_surface != NULL)
653 fullscreen_enabled = fullscreen;
659 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
661 boolean success = TRUE;
662 SDL_Surface *new_surface = NULL;
666 if (*backbuffer == NULL)
667 *backbuffer = CreateBitmapStruct();
669 /* (real bitmap might be larger in fullscreen mode with video offsets) */
670 (*backbuffer)->width = video.width;
671 (*backbuffer)->height = video.height;
673 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
675 setFullscreenParameters(setup.fullscreen_mode);
677 video_xoffset = fullscreen_xoffset;
678 video_yoffset = fullscreen_yoffset;
680 /* switch display to fullscreen mode, if available */
681 new_surface = SDLCreateScreen(backbuffer, TRUE);
683 if (new_surface == NULL)
685 /* switching display to fullscreen mode failed */
686 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
688 /* do not try it again */
689 video.fullscreen_available = FALSE;
695 (*backbuffer)->surface = new_surface;
697 video.fullscreen_enabled = TRUE;
698 video.fullscreen_mode_current = setup.fullscreen_mode;
704 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
709 /* switch display to window mode */
710 new_surface = SDLCreateScreen(backbuffer, FALSE);
712 if (new_surface == NULL)
714 /* switching display to window mode failed -- should not happen */
715 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
721 (*backbuffer)->surface = new_surface;
723 video.fullscreen_enabled = FALSE;
724 video.window_scaling_percent = setup.window_scaling_percent;
725 video.window_scaling_quality = setup.window_scaling_quality;
731 #if defined(TARGET_SDL2)
732 SDLRedrawWindow(); // map window
736 #if defined(PLATFORM_WIN32)
737 // experimental drag and drop code
739 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
742 SDL_SysWMinfo wminfo;
744 boolean wminfo_success = FALSE;
746 SDL_VERSION(&wminfo.version);
747 #if defined(TARGET_SDL2)
749 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
751 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
756 #if defined(TARGET_SDL2)
757 hwnd = wminfo.info.win.window;
759 hwnd = wminfo.window;
762 DragAcceptFiles(hwnd, TRUE);
771 void SDLSetWindowTitle()
773 #if defined(TARGET_SDL2)
774 SDL_SetWindowTitle(sdl_window, program.window_title);
776 SDL_WM_SetCaption(program.window_title, program.window_title);
780 #if defined(TARGET_SDL2)
781 void SDLSetWindowScaling(int window_scaling_percent)
783 if (sdl_window == NULL)
786 float window_scaling_factor = (float)window_scaling_percent / 100;
787 int new_window_width = (int)(window_scaling_factor * video.width);
788 int new_window_height = (int)(window_scaling_factor * video.height);
790 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
792 video.window_scaling_percent = window_scaling_percent;
793 video.window_width = new_window_width;
794 video.window_height = new_window_height;
799 void SDLSetWindowScalingQuality(char *window_scaling_quality)
801 if (sdl_texture == NULL)
804 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
806 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
807 SDL_PIXELFORMAT_ARGB8888,
808 SDL_TEXTUREACCESS_STREAMING,
809 video.width, video.height);
811 if (new_texture != NULL)
813 SDL_DestroyTexture(sdl_texture);
815 sdl_texture = new_texture;
820 video.window_scaling_quality = window_scaling_quality;
823 void SDLSetWindowFullscreen(boolean fullscreen)
825 if (sdl_window == NULL)
828 #if USE_DESKTOP_FULLSCREEN
829 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
831 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
834 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
835 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
837 // if screen size was changed in fullscreen mode, correct desktop window size
838 if (!fullscreen && video.fullscreen_initial)
840 SDLSetWindowScaling(setup.window_scaling_percent);
841 SDL_SetWindowPosition(sdl_window,
842 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
844 video.fullscreen_initial = FALSE;
848 void SDLRedrawWindow()
854 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
857 SDL_Surface *surface =
858 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
861 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
863 SDLSetNativeSurface(&surface);
865 bitmap->surface = surface;
868 void SDLFreeBitmapPointers(Bitmap *bitmap)
871 SDL_FreeSurface(bitmap->surface);
872 if (bitmap->surface_masked)
873 SDL_FreeSurface(bitmap->surface_masked);
874 bitmap->surface = NULL;
875 bitmap->surface_masked = NULL;
878 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
879 int src_x, int src_y, int width, int height,
880 int dst_x, int dst_y, int mask_mode)
882 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
883 SDL_Rect src_rect, dst_rect;
885 if (src_bitmap == backbuffer)
887 src_x += video_xoffset;
888 src_y += video_yoffset;
896 if (dst_bitmap == backbuffer || dst_bitmap == window)
898 dst_x += video_xoffset;
899 dst_y += video_yoffset;
907 // if (src_bitmap != backbuffer || dst_bitmap != window)
908 if (!(src_bitmap == backbuffer && dst_bitmap == window))
909 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
910 src_bitmap->surface_masked : src_bitmap->surface),
911 &src_rect, real_dst_bitmap->surface, &dst_rect);
913 #if defined(TARGET_SDL2)
914 if (dst_bitmap == window)
916 // SDL_UpdateWindowSurface(sdl_window);
917 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
918 UpdateScreen(&dst_rect);
921 if (dst_bitmap == window)
923 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
924 UpdateScreen(&dst_rect);
929 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
932 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
935 if (dst_bitmap == backbuffer || dst_bitmap == window)
946 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
948 #if defined(TARGET_SDL2)
949 if (dst_bitmap == window)
951 // SDL_UpdateWindowSurface(sdl_window);
952 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
956 if (dst_bitmap == window)
958 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
964 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
965 int fade_mode, int fade_delay, int post_delay,
966 void (*draw_border_function)(void))
968 static boolean initialization_needed = TRUE;
969 static SDL_Surface *surface_source = NULL;
970 static SDL_Surface *surface_target = NULL;
971 static SDL_Surface *surface_black = NULL;
972 SDL_Surface *surface_screen = backbuffer->surface;
973 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
974 SDL_Rect src_rect, dst_rect;
976 int src_x = x, src_y = y;
977 int dst_x = x, dst_y = y;
978 unsigned int time_last, time_current;
980 /* check if screen size has changed */
981 if (surface_source != NULL && (video.width != surface_source->w ||
982 video.height != surface_source->h))
984 SDL_FreeSurface(surface_source);
985 SDL_FreeSurface(surface_target);
986 SDL_FreeSurface(surface_black);
988 initialization_needed = TRUE;
996 dst_x += video_xoffset;
997 dst_y += video_yoffset;
1001 dst_rect.w = width; /* (ignored) */
1002 dst_rect.h = height; /* (ignored) */
1004 dst_rect2 = dst_rect;
1006 if (initialization_needed)
1008 #if defined(TARGET_SDL2)
1009 unsigned int flags = 0;
1011 unsigned int flags = SDL_SRCALPHA;
1013 /* use same surface type as screen surface */
1014 if ((surface_screen->flags & SDL_HWSURFACE))
1015 flags |= SDL_HWSURFACE;
1017 flags |= SDL_SWSURFACE;
1020 /* create surface for temporary copy of screen buffer (source) */
1021 if ((surface_source =
1022 SDL_CreateRGBSurface(flags,
1025 surface_screen->format->BitsPerPixel,
1026 surface_screen->format->Rmask,
1027 surface_screen->format->Gmask,
1028 surface_screen->format->Bmask,
1029 surface_screen->format->Amask)) == NULL)
1030 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1032 /* create surface for cross-fading screen buffer (target) */
1033 if ((surface_target =
1034 SDL_CreateRGBSurface(flags,
1037 surface_screen->format->BitsPerPixel,
1038 surface_screen->format->Rmask,
1039 surface_screen->format->Gmask,
1040 surface_screen->format->Bmask,
1041 surface_screen->format->Amask)) == NULL)
1042 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1044 /* create black surface for fading from/to black */
1045 if ((surface_black =
1046 SDL_CreateRGBSurface(flags,
1049 surface_screen->format->BitsPerPixel,
1050 surface_screen->format->Rmask,
1051 surface_screen->format->Gmask,
1052 surface_screen->format->Bmask,
1053 surface_screen->format->Amask)) == NULL)
1054 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1056 /* completely fill the surface with black color pixels */
1057 SDL_FillRect(surface_black, NULL,
1058 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1060 initialization_needed = FALSE;
1063 /* copy source and target surfaces to temporary surfaces for fading */
1064 if (fade_mode & FADE_TYPE_TRANSFORM)
1066 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1067 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1069 else if (fade_mode & FADE_TYPE_FADE_IN)
1071 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1072 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1074 else /* FADE_TYPE_FADE_OUT */
1076 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1077 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1080 time_current = SDL_GetTicks();
1082 if (fade_mode == FADE_MODE_MELT)
1084 boolean done = FALSE;
1085 int melt_pixels = 2;
1086 int melt_columns = width / melt_pixels;
1087 int ypos[melt_columns];
1088 int max_steps = height / 8 + 32;
1093 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1094 #if defined(TARGET_SDL2)
1095 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1097 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1100 ypos[0] = -GetSimpleRandom(16);
1102 for (i = 1 ; i < melt_columns; i++)
1104 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1106 ypos[i] = ypos[i - 1] + r;
1119 time_last = time_current;
1120 time_current = SDL_GetTicks();
1121 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1122 steps_final = MIN(MAX(0, steps), max_steps);
1126 done = (steps_done >= steps_final);
1128 for (i = 0 ; i < melt_columns; i++)
1136 else if (ypos[i] < height)
1141 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1143 if (ypos[i] + dy >= height)
1144 dy = height - ypos[i];
1146 /* copy part of (appearing) target surface to upper area */
1147 src_rect.x = src_x + i * melt_pixels;
1148 // src_rect.y = src_y + ypos[i];
1150 src_rect.w = melt_pixels;
1152 src_rect.h = ypos[i] + dy;
1154 dst_rect.x = dst_x + i * melt_pixels;
1155 // dst_rect.y = dst_y + ypos[i];
1158 if (steps_done >= steps_final)
1159 SDL_BlitSurface(surface_target, &src_rect,
1160 surface_screen, &dst_rect);
1164 /* copy part of (disappearing) source surface to lower area */
1165 src_rect.x = src_x + i * melt_pixels;
1167 src_rect.w = melt_pixels;
1168 src_rect.h = height - ypos[i];
1170 dst_rect.x = dst_x + i * melt_pixels;
1171 dst_rect.y = dst_y + ypos[i];
1173 if (steps_done >= steps_final)
1174 SDL_BlitSurface(surface_source, &src_rect,
1175 surface_screen, &dst_rect);
1181 src_rect.x = src_x + i * melt_pixels;
1183 src_rect.w = melt_pixels;
1184 src_rect.h = height;
1186 dst_rect.x = dst_x + i * melt_pixels;
1189 if (steps_done >= steps_final)
1190 SDL_BlitSurface(surface_target, &src_rect,
1191 surface_screen, &dst_rect);
1195 if (steps_done >= steps_final)
1197 if (draw_border_function != NULL)
1198 draw_border_function();
1200 UpdateScreen(&dst_rect2);
1204 else if (fade_mode == FADE_MODE_CURTAIN)
1208 int xx_size = width / 2;
1210 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1211 #if defined(TARGET_SDL2)
1212 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1214 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1217 for (xx = 0; xx < xx_size;)
1219 time_last = time_current;
1220 time_current = SDL_GetTicks();
1221 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1222 xx_final = MIN(MAX(0, xx), xx_size);
1227 src_rect.h = height;
1232 /* draw new (target) image to screen buffer */
1233 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1235 if (xx_final < xx_size)
1237 src_rect.w = xx_size - xx_final;
1238 src_rect.h = height;
1240 /* draw old (source) image to screen buffer (left side) */
1242 src_rect.x = src_x + xx_final;
1245 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1247 /* draw old (source) image to screen buffer (right side) */
1249 src_rect.x = src_x + xx_size;
1250 dst_rect.x = dst_x + xx_size + xx_final;
1252 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1255 if (draw_border_function != NULL)
1256 draw_border_function();
1258 /* only update the region of the screen that is affected from fading */
1259 UpdateScreen(&dst_rect2);
1262 else /* fading in, fading out or cross-fading */
1267 for (alpha = 0.0; alpha < 255.0;)
1269 time_last = time_current;
1270 time_current = SDL_GetTicks();
1271 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1272 alpha_final = MIN(MAX(0, alpha), 255);
1274 /* draw existing (source) image to screen buffer */
1275 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1277 /* draw new (target) image to screen buffer using alpha blending */
1278 #if defined(TARGET_SDL2)
1279 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1280 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1282 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1284 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1286 if (draw_border_function != NULL)
1287 draw_border_function();
1289 /* only update the region of the screen that is affected from fading */
1290 UpdateScreen(&dst_rect);
1297 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1298 int to_x, int to_y, Uint32 color)
1300 SDL_Surface *surface = dst_bitmap->surface;
1304 swap_numbers(&from_x, &to_x);
1307 swap_numbers(&from_y, &to_y);
1311 rect.w = (to_x - from_x + 1);
1312 rect.h = (to_y - from_y + 1);
1314 if (dst_bitmap == backbuffer || dst_bitmap == window)
1316 rect.x += video_xoffset;
1317 rect.y += video_yoffset;
1320 SDL_FillRect(surface, &rect, color);
1323 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1324 int to_x, int to_y, Uint32 color)
1326 if (dst_bitmap == backbuffer || dst_bitmap == window)
1328 from_x += video_xoffset;
1329 from_y += video_yoffset;
1330 to_x += video_xoffset;
1331 to_y += video_yoffset;
1334 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1337 #if ENABLE_UNUSED_CODE
1338 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1339 int num_points, Uint32 color)
1344 for (i = 0; i < num_points - 1; i++)
1346 for (x = 0; x < line_width; x++)
1348 for (y = 0; y < line_width; y++)
1350 int dx = x - line_width / 2;
1351 int dy = y - line_width / 2;
1353 if ((x == 0 && y == 0) ||
1354 (x == 0 && y == line_width - 1) ||
1355 (x == line_width - 1 && y == 0) ||
1356 (x == line_width - 1 && y == line_width - 1))
1359 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1360 points[i+1].x + dx, points[i+1].y + dy, color);
1367 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1369 SDL_Surface *surface = src_bitmap->surface;
1371 if (src_bitmap == backbuffer || src_bitmap == window)
1377 switch (surface->format->BytesPerPixel)
1379 case 1: /* assuming 8-bpp */
1381 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1385 case 2: /* probably 15-bpp or 16-bpp */
1387 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1391 case 3: /* slow 24-bpp mode; usually not used */
1393 /* does this work? */
1394 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1398 shift = surface->format->Rshift;
1399 color |= *(pix + shift / 8) >> shift;
1400 shift = surface->format->Gshift;
1401 color |= *(pix + shift / 8) >> shift;
1402 shift = surface->format->Bshift;
1403 color |= *(pix + shift / 8) >> shift;
1409 case 4: /* probably 32-bpp */
1411 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1420 /* ========================================================================= */
1421 /* The following functions were taken from the SGE library */
1422 /* (SDL Graphics Extension Library) by Anders Lindström */
1423 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1424 /* ========================================================================= */
1426 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1428 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1430 switch (surface->format->BytesPerPixel)
1434 /* Assuming 8-bpp */
1435 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1441 /* Probably 15-bpp or 16-bpp */
1442 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1448 /* Slow 24-bpp mode, usually not used */
1452 /* Gack - slow, but endian correct */
1453 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1454 shift = surface->format->Rshift;
1455 *(pix+shift/8) = color>>shift;
1456 shift = surface->format->Gshift;
1457 *(pix+shift/8) = color>>shift;
1458 shift = surface->format->Bshift;
1459 *(pix+shift/8) = color>>shift;
1465 /* Probably 32-bpp */
1466 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1473 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1474 Uint8 R, Uint8 G, Uint8 B)
1476 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1479 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1481 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1484 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1486 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1489 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1494 /* Gack - slow, but endian correct */
1495 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1496 shift = surface->format->Rshift;
1497 *(pix+shift/8) = color>>shift;
1498 shift = surface->format->Gshift;
1499 *(pix+shift/8) = color>>shift;
1500 shift = surface->format->Bshift;
1501 *(pix+shift/8) = color>>shift;
1504 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1506 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1509 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1511 switch (dest->format->BytesPerPixel)
1514 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1518 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1522 _PutPixel24(dest,x,y,color);
1526 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1531 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1533 if (SDL_MUSTLOCK(surface))
1535 if (SDL_LockSurface(surface) < 0)
1541 _PutPixel(surface, x, y, color);
1543 if (SDL_MUSTLOCK(surface))
1545 SDL_UnlockSurface(surface);
1549 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1550 Uint8 r, Uint8 g, Uint8 b)
1552 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1555 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1557 if (y >= 0 && y <= dest->h - 1)
1559 switch (dest->format->BytesPerPixel)
1562 return y*dest->pitch;
1566 return y*dest->pitch/2;
1570 return y*dest->pitch;
1574 return y*dest->pitch/4;
1582 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1584 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1586 switch (surface->format->BytesPerPixel)
1590 /* Assuming 8-bpp */
1591 *((Uint8 *)surface->pixels + ypitch + x) = color;
1597 /* Probably 15-bpp or 16-bpp */
1598 *((Uint16 *)surface->pixels + ypitch + x) = color;
1604 /* Slow 24-bpp mode, usually not used */
1608 /* Gack - slow, but endian correct */
1609 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1610 shift = surface->format->Rshift;
1611 *(pix+shift/8) = color>>shift;
1612 shift = surface->format->Gshift;
1613 *(pix+shift/8) = color>>shift;
1614 shift = surface->format->Bshift;
1615 *(pix+shift/8) = color>>shift;
1621 /* Probably 32-bpp */
1622 *((Uint32 *)surface->pixels + ypitch + x) = color;
1629 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1634 if (SDL_MUSTLOCK(Surface))
1636 if (SDL_LockSurface(Surface) < 0)
1649 /* Do the clipping */
1650 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1654 if (x2 > Surface->w - 1)
1655 x2 = Surface->w - 1;
1662 SDL_FillRect(Surface, &l, Color);
1664 if (SDL_MUSTLOCK(Surface))
1666 SDL_UnlockSurface(Surface);
1670 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1671 Uint8 R, Uint8 G, Uint8 B)
1673 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1676 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1687 /* Do the clipping */
1688 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1692 if (x2 > Surface->w - 1)
1693 x2 = Surface->w - 1;
1700 SDL_FillRect(Surface, &l, Color);
1703 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1708 if (SDL_MUSTLOCK(Surface))
1710 if (SDL_LockSurface(Surface) < 0)
1723 /* Do the clipping */
1724 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1728 if (y2 > Surface->h - 1)
1729 y2 = Surface->h - 1;
1736 SDL_FillRect(Surface, &l, Color);
1738 if (SDL_MUSTLOCK(Surface))
1740 SDL_UnlockSurface(Surface);
1744 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1745 Uint8 R, Uint8 G, Uint8 B)
1747 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1750 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1761 /* Do the clipping */
1762 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1766 if (y2 > Surface->h - 1)
1767 y2 = Surface->h - 1;
1774 SDL_FillRect(Surface, &l, Color);
1777 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1778 Sint16 x2, Sint16 y2, Uint32 Color,
1779 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1782 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1787 sdx = (dx < 0) ? -1 : 1;
1788 sdy = (dy < 0) ? -1 : 1;
1800 for (x = 0; x < dx; x++)
1802 Callback(Surface, px, py, Color);
1816 for (y = 0; y < dy; y++)
1818 Callback(Surface, px, py, Color);
1832 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1833 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1834 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1837 sge_DoLine(Surface, X1, Y1, X2, Y2,
1838 SDL_MapRGB(Surface->format, R, G, B), Callback);
1841 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1844 if (SDL_MUSTLOCK(Surface))
1846 if (SDL_LockSurface(Surface) < 0)
1851 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1853 /* unlock the display */
1854 if (SDL_MUSTLOCK(Surface))
1856 SDL_UnlockSurface(Surface);
1860 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1861 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1863 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1866 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1868 if (dst_bitmap == backbuffer || dst_bitmap == window)
1874 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1879 -----------------------------------------------------------------------------
1880 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1881 -----------------------------------------------------------------------------
1884 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1885 int width, int height, Uint32 color)
1889 for (y = src_y; y < src_y + height; y++)
1891 for (x = src_x; x < src_x + width; x++)
1893 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1895 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1900 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1901 int src_x, int src_y, int width, int height,
1902 int dst_x, int dst_y)
1906 for (y = 0; y < height; y++)
1908 for (x = 0; x < width; x++)
1910 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1912 if (pixel != BLACK_PIXEL)
1913 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1919 /* ========================================================================= */
1920 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1921 /* (Rotozoomer) by Andreas Schiffler */
1922 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1923 /* ========================================================================= */
1926 -----------------------------------------------------------------------------
1929 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1930 -----------------------------------------------------------------------------
1941 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1944 tColorRGBA *sp, *csp, *dp;
1948 sp = csp = (tColorRGBA *) src->pixels;
1949 dp = (tColorRGBA *) dst->pixels;
1950 dgap = dst->pitch - dst->w * 4;
1952 for (y = 0; y < dst->h; y++)
1956 for (x = 0; x < dst->w; x++)
1958 tColorRGBA *sp0 = sp;
1959 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1960 tColorRGBA *sp00 = &sp0[0];
1961 tColorRGBA *sp01 = &sp0[1];
1962 tColorRGBA *sp10 = &sp1[0];
1963 tColorRGBA *sp11 = &sp1[1];
1966 /* create new color pixel from all four source color pixels */
1967 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1968 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1969 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1970 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1975 /* advance source pointers */
1978 /* advance destination pointer */
1982 /* advance source pointer */
1983 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1985 /* advance destination pointers */
1986 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1992 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1994 int x, y, *sax, *say, *csax, *csay;
1996 tColorRGBA *sp, *csp, *csp0, *dp;
1999 /* use specialized zoom function when scaling down to exactly half size */
2000 if (src->w == 2 * dst->w &&
2001 src->h == 2 * dst->h)
2002 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2004 /* variable setup */
2005 sx = (float) src->w / (float) dst->w;
2006 sy = (float) src->h / (float) dst->h;
2008 /* allocate memory for row increments */
2009 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2010 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2012 /* precalculate row increments */
2013 for (x = 0; x <= dst->w; x++)
2014 *csax++ = (int)(sx * x);
2016 for (y = 0; y <= dst->h; y++)
2017 *csay++ = (int)(sy * y);
2020 sp = csp = csp0 = (tColorRGBA *) src->pixels;
2021 dp = (tColorRGBA *) dst->pixels;
2022 dgap = dst->pitch - dst->w * 4;
2025 for (y = 0; y < dst->h; y++)
2030 for (x = 0; x < dst->w; x++)
2035 /* advance source pointers */
2039 /* advance destination pointer */
2043 /* advance source pointer */
2045 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
2047 /* advance destination pointers */
2048 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2058 -----------------------------------------------------------------------------
2061 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2062 -----------------------------------------------------------------------------
2065 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2067 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2068 Uint8 *sp, *dp, *csp;
2071 /* variable setup */
2072 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2073 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2075 /* allocate memory for row increments */
2076 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2077 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2079 /* precalculate row increments */
2082 for (x = 0; x < dst->w; x++)
2085 *csax = (csx >> 16);
2092 for (y = 0; y < dst->h; y++)
2095 *csay = (csy >> 16);
2102 for (x = 0; x < dst->w; x++)
2110 for (y = 0; y < dst->h; y++)
2117 sp = csp = (Uint8 *) src->pixels;
2118 dp = (Uint8 *) dst->pixels;
2119 dgap = dst->pitch - dst->w;
2123 for (y = 0; y < dst->h; y++)
2127 for (x = 0; x < dst->w; x++)
2132 /* advance source pointers */
2136 /* advance destination pointer */
2140 /* advance source pointer (for row) */
2141 csp += ((*csay) * src->pitch);
2144 /* advance destination pointers */
2155 -----------------------------------------------------------------------------
2158 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2159 'zoomx' and 'zoomy' are scaling factors for width and height.
2160 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2161 into a 32bit RGBA format on the fly.
2162 -----------------------------------------------------------------------------
2165 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2167 SDL_Surface *zoom_src = NULL;
2168 SDL_Surface *zoom_dst = NULL;
2169 boolean is_converted = FALSE;
2176 /* determine if source surface is 32 bit or 8 bit */
2177 is_32bit = (src->format->BitsPerPixel == 32);
2179 if (is_32bit || src->format->BitsPerPixel == 8)
2181 /* use source surface 'as is' */
2186 /* new source surface is 32 bit with a defined RGB ordering */
2187 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2188 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2189 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2191 is_converted = TRUE;
2194 /* allocate surface to completely contain the zoomed surface */
2197 /* target surface is 32 bit with source RGBA/ABGR ordering */
2198 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2199 zoom_src->format->Rmask,
2200 zoom_src->format->Gmask,
2201 zoom_src->format->Bmask, 0);
2205 /* target surface is 8 bit */
2206 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2210 /* lock source surface */
2211 SDL_LockSurface(zoom_src);
2213 /* check which kind of surface we have */
2216 /* call the 32 bit transformation routine to do the zooming */
2217 zoomSurfaceRGBA(zoom_src, zoom_dst);
2222 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2223 zoom_dst->format->palette->colors[i] =
2224 zoom_src->format->palette->colors[i];
2225 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2227 /* call the 8 bit transformation routine to do the zooming */
2228 zoomSurfaceY(zoom_src, zoom_dst);
2231 /* unlock source surface */
2232 SDL_UnlockSurface(zoom_src);
2234 /* free temporary surface */
2236 SDL_FreeSurface(zoom_src);
2238 /* return destination surface */
2242 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2244 Bitmap *dst_bitmap = CreateBitmapStruct();
2245 SDL_Surface **dst_surface = &dst_bitmap->surface;
2247 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2248 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2250 dst_bitmap->width = dst_width;
2251 dst_bitmap->height = dst_height;
2253 /* create zoomed temporary surface from source surface */
2254 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2256 /* create native format destination surface from zoomed temporary surface */
2257 SDLSetNativeSurface(dst_surface);
2263 /* ========================================================================= */
2264 /* load image to bitmap */
2265 /* ========================================================================= */
2267 Bitmap *SDLLoadImage(char *filename)
2269 Bitmap *new_bitmap = CreateBitmapStruct();
2270 SDL_Surface *sdl_image_tmp;
2272 print_timestamp_init("SDLLoadImage");
2274 print_timestamp_time(getBaseNamePtr(filename));
2276 /* load image to temporary surface */
2277 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2279 SetError("IMG_Load(): %s", SDL_GetError());
2284 print_timestamp_time("IMG_Load");
2286 UPDATE_BUSY_STATE();
2288 /* create native non-transparent surface for current image */
2289 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2291 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2296 print_timestamp_time("SDL_DisplayFormat (opaque)");
2298 UPDATE_BUSY_STATE();
2300 /* create native transparent surface for current image */
2301 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2302 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2304 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2306 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2311 print_timestamp_time("SDL_DisplayFormat (masked)");
2313 UPDATE_BUSY_STATE();
2315 /* free temporary surface */
2316 SDL_FreeSurface(sdl_image_tmp);
2318 new_bitmap->width = new_bitmap->surface->w;
2319 new_bitmap->height = new_bitmap->surface->h;
2321 print_timestamp_done("SDLLoadImage");
2327 /* ------------------------------------------------------------------------- */
2328 /* custom cursor fuctions */
2329 /* ------------------------------------------------------------------------- */
2331 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2333 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2334 cursor_info->width, cursor_info->height,
2335 cursor_info->hot_x, cursor_info->hot_y);
2338 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2340 static struct MouseCursorInfo *last_cursor_info = NULL;
2341 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2342 static SDL_Cursor *cursor_default = NULL;
2343 static SDL_Cursor *cursor_current = NULL;
2345 /* if invoked for the first time, store the SDL default cursor */
2346 if (cursor_default == NULL)
2347 cursor_default = SDL_GetCursor();
2349 /* only create new cursor if cursor info (custom only) has changed */
2350 if (cursor_info != NULL && cursor_info != last_cursor_info)
2352 cursor_current = create_cursor(cursor_info);
2353 last_cursor_info = cursor_info;
2356 /* only set new cursor if cursor info (custom or NULL) has changed */
2357 if (cursor_info != last_cursor_info2)
2358 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2360 last_cursor_info2 = cursor_info;
2364 /* ========================================================================= */
2365 /* audio functions */
2366 /* ========================================================================= */
2368 void SDLOpenAudio(void)
2370 #if !defined(TARGET_SDL2)
2371 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2372 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2375 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2377 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2381 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2382 AUDIO_NUM_CHANNELS_STEREO,
2383 setup.system.audio_fragment_size) < 0)
2385 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2389 audio.sound_available = TRUE;
2390 audio.music_available = TRUE;
2391 audio.loops_available = TRUE;
2392 audio.sound_enabled = TRUE;
2394 /* set number of available mixer channels */
2395 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2396 audio.music_channel = MUSIC_CHANNEL;
2397 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2399 Mixer_InitChannels();
2402 void SDLCloseAudio(void)
2405 Mix_HaltChannel(-1);
2408 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2412 /* ========================================================================= */
2413 /* event functions */
2414 /* ========================================================================= */
2416 void SDLNextEvent(Event *event)
2418 SDL_WaitEvent(event);
2420 if (event->type == EVENT_BUTTONPRESS ||
2421 event->type == EVENT_BUTTONRELEASE)
2423 if (((ButtonEvent *)event)->x > video_xoffset)
2424 ((ButtonEvent *)event)->x -= video_xoffset;
2426 ((ButtonEvent *)event)->x = 0;
2427 if (((ButtonEvent *)event)->y > video_yoffset)
2428 ((ButtonEvent *)event)->y -= video_yoffset;
2430 ((ButtonEvent *)event)->y = 0;
2432 else if (event->type == EVENT_MOTIONNOTIFY)
2434 if (((MotionEvent *)event)->x > video_xoffset)
2435 ((MotionEvent *)event)->x -= video_xoffset;
2437 ((MotionEvent *)event)->x = 0;
2438 if (((MotionEvent *)event)->y > video_yoffset)
2439 ((MotionEvent *)event)->y -= video_yoffset;
2441 ((MotionEvent *)event)->y = 0;
2445 void SDLHandleWindowManagerEvent(Event *event)
2448 #if defined(PLATFORM_WIN32)
2449 // experimental drag and drop code
2451 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2452 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2454 #if defined(TARGET_SDL2)
2455 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2457 if (syswmmsg->msg == WM_DROPFILES)
2460 #if defined(TARGET_SDL2)
2461 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2463 HDROP hdrop = (HDROP)syswmmsg->wParam;
2467 printf("::: SDL_SYSWMEVENT:\n");
2469 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2471 for (i = 0; i < num_files; i++)
2473 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2474 char buffer[buffer_len + 1];
2476 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2478 printf("::: - '%s'\n", buffer);
2481 #if defined(TARGET_SDL2)
2482 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2484 DragFinish((HDROP)syswmmsg->wParam);
2492 /* ========================================================================= */
2493 /* joystick functions */
2494 /* ========================================================================= */
2496 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2497 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2498 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2500 static boolean SDLOpenJoystick(int nr)
2502 if (nr < 0 || nr > MAX_PLAYERS)
2505 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2508 static void SDLCloseJoystick(int nr)
2510 if (nr < 0 || nr > MAX_PLAYERS)
2513 SDL_JoystickClose(sdl_joystick[nr]);
2515 sdl_joystick[nr] = NULL;
2518 static boolean SDLCheckJoystickOpened(int nr)
2520 if (nr < 0 || nr > MAX_PLAYERS)
2523 #if defined(TARGET_SDL2)
2524 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2526 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2530 void HandleJoystickEvent(Event *event)
2534 case SDL_JOYAXISMOTION:
2535 if (event->jaxis.axis < 2)
2536 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2539 case SDL_JOYBUTTONDOWN:
2540 if (event->jbutton.button < 2)
2541 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2544 case SDL_JOYBUTTONUP:
2545 if (event->jbutton.button < 2)
2546 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2554 void SDLInitJoysticks()
2556 static boolean sdl_joystick_subsystem_initialized = FALSE;
2557 boolean print_warning = !sdl_joystick_subsystem_initialized;
2560 if (!sdl_joystick_subsystem_initialized)
2562 sdl_joystick_subsystem_initialized = TRUE;
2564 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2566 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2571 for (i = 0; i < MAX_PLAYERS; i++)
2573 /* get configured joystick for this player */
2574 char *device_name = setup.input[i].joy.device_name;
2575 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2577 if (joystick_nr >= SDL_NumJoysticks())
2579 if (setup.input[i].use_joystick && print_warning)
2580 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2585 /* misuse joystick file descriptor variable to store joystick number */
2586 joystick.fd[i] = joystick_nr;
2588 if (joystick_nr == -1)
2591 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2592 if (SDLCheckJoystickOpened(joystick_nr))
2593 SDLCloseJoystick(joystick_nr);
2595 if (!setup.input[i].use_joystick)
2598 if (!SDLOpenJoystick(joystick_nr))
2601 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2606 joystick.status = JOYSTICK_ACTIVATED;
2610 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2612 if (nr < 0 || nr >= MAX_PLAYERS)
2616 *x = sdl_js_axis[nr][0];
2618 *y = sdl_js_axis[nr][1];
2621 *b1 = sdl_js_button[nr][0];
2623 *b2 = sdl_js_button[nr][1];