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);
1209 for (alpha = 0.0; alpha < 255.0;)
1211 time_last = time_current;
1212 time_current = SDL_GetTicks();
1213 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1214 alpha_final = MIN(MAX(0, alpha), 255);
1216 /* draw existing (source) image to screen buffer */
1217 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1219 /* draw new (target) image to screen buffer using alpha blending */
1220 #if defined(TARGET_SDL2)
1221 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1222 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1224 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1226 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1228 if (draw_border_function != NULL)
1229 draw_border_function();
1231 /* only update the region of the screen that is affected from fading */
1232 UpdateScreen(&dst_rect);
1239 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1240 int to_x, int to_y, Uint32 color)
1242 SDL_Surface *surface = dst_bitmap->surface;
1246 swap_numbers(&from_x, &to_x);
1249 swap_numbers(&from_y, &to_y);
1253 rect.w = (to_x - from_x + 1);
1254 rect.h = (to_y - from_y + 1);
1256 if (dst_bitmap == backbuffer || dst_bitmap == window)
1258 rect.x += video_xoffset;
1259 rect.y += video_yoffset;
1262 SDL_FillRect(surface, &rect, color);
1265 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1266 int to_x, int to_y, Uint32 color)
1268 if (dst_bitmap == backbuffer || dst_bitmap == window)
1270 from_x += video_xoffset;
1271 from_y += video_yoffset;
1272 to_x += video_xoffset;
1273 to_y += video_yoffset;
1276 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1279 #if ENABLE_UNUSED_CODE
1280 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1281 int num_points, Uint32 color)
1286 for (i = 0; i < num_points - 1; i++)
1288 for (x = 0; x < line_width; x++)
1290 for (y = 0; y < line_width; y++)
1292 int dx = x - line_width / 2;
1293 int dy = y - line_width / 2;
1295 if ((x == 0 && y == 0) ||
1296 (x == 0 && y == line_width - 1) ||
1297 (x == line_width - 1 && y == 0) ||
1298 (x == line_width - 1 && y == line_width - 1))
1301 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1302 points[i+1].x + dx, points[i+1].y + dy, color);
1309 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1311 SDL_Surface *surface = src_bitmap->surface;
1313 if (src_bitmap == backbuffer || src_bitmap == window)
1319 switch (surface->format->BytesPerPixel)
1321 case 1: /* assuming 8-bpp */
1323 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1327 case 2: /* probably 15-bpp or 16-bpp */
1329 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1333 case 3: /* slow 24-bpp mode; usually not used */
1335 /* does this work? */
1336 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1340 shift = surface->format->Rshift;
1341 color |= *(pix + shift / 8) >> shift;
1342 shift = surface->format->Gshift;
1343 color |= *(pix + shift / 8) >> shift;
1344 shift = surface->format->Bshift;
1345 color |= *(pix + shift / 8) >> shift;
1351 case 4: /* probably 32-bpp */
1353 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1362 /* ========================================================================= */
1363 /* The following functions were taken from the SGE library */
1364 /* (SDL Graphics Extension Library) by Anders Lindström */
1365 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1366 /* ========================================================================= */
1368 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1370 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1372 switch (surface->format->BytesPerPixel)
1376 /* Assuming 8-bpp */
1377 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1383 /* Probably 15-bpp or 16-bpp */
1384 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1390 /* Slow 24-bpp mode, usually not used */
1394 /* Gack - slow, but endian correct */
1395 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1396 shift = surface->format->Rshift;
1397 *(pix+shift/8) = color>>shift;
1398 shift = surface->format->Gshift;
1399 *(pix+shift/8) = color>>shift;
1400 shift = surface->format->Bshift;
1401 *(pix+shift/8) = color>>shift;
1407 /* Probably 32-bpp */
1408 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1415 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1416 Uint8 R, Uint8 G, Uint8 B)
1418 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1421 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1423 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1426 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1428 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1431 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1436 /* Gack - slow, but endian correct */
1437 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1438 shift = surface->format->Rshift;
1439 *(pix+shift/8) = color>>shift;
1440 shift = surface->format->Gshift;
1441 *(pix+shift/8) = color>>shift;
1442 shift = surface->format->Bshift;
1443 *(pix+shift/8) = color>>shift;
1446 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1448 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1451 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1453 switch (dest->format->BytesPerPixel)
1456 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1460 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1464 _PutPixel24(dest,x,y,color);
1468 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1473 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1475 if (SDL_MUSTLOCK(surface))
1477 if (SDL_LockSurface(surface) < 0)
1483 _PutPixel(surface, x, y, color);
1485 if (SDL_MUSTLOCK(surface))
1487 SDL_UnlockSurface(surface);
1491 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1492 Uint8 r, Uint8 g, Uint8 b)
1494 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1497 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1499 if (y >= 0 && y <= dest->h - 1)
1501 switch (dest->format->BytesPerPixel)
1504 return y*dest->pitch;
1508 return y*dest->pitch/2;
1512 return y*dest->pitch;
1516 return y*dest->pitch/4;
1524 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1526 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1528 switch (surface->format->BytesPerPixel)
1532 /* Assuming 8-bpp */
1533 *((Uint8 *)surface->pixels + ypitch + x) = color;
1539 /* Probably 15-bpp or 16-bpp */
1540 *((Uint16 *)surface->pixels + ypitch + x) = color;
1546 /* Slow 24-bpp mode, usually not used */
1550 /* Gack - slow, but endian correct */
1551 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1552 shift = surface->format->Rshift;
1553 *(pix+shift/8) = color>>shift;
1554 shift = surface->format->Gshift;
1555 *(pix+shift/8) = color>>shift;
1556 shift = surface->format->Bshift;
1557 *(pix+shift/8) = color>>shift;
1563 /* Probably 32-bpp */
1564 *((Uint32 *)surface->pixels + ypitch + x) = color;
1571 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1576 if (SDL_MUSTLOCK(Surface))
1578 if (SDL_LockSurface(Surface) < 0)
1591 /* Do the clipping */
1592 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1596 if (x2 > Surface->w - 1)
1597 x2 = Surface->w - 1;
1604 SDL_FillRect(Surface, &l, Color);
1606 if (SDL_MUSTLOCK(Surface))
1608 SDL_UnlockSurface(Surface);
1612 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1613 Uint8 R, Uint8 G, Uint8 B)
1615 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1618 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1629 /* Do the clipping */
1630 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1634 if (x2 > Surface->w - 1)
1635 x2 = Surface->w - 1;
1642 SDL_FillRect(Surface, &l, Color);
1645 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1650 if (SDL_MUSTLOCK(Surface))
1652 if (SDL_LockSurface(Surface) < 0)
1665 /* Do the clipping */
1666 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1670 if (y2 > Surface->h - 1)
1671 y2 = Surface->h - 1;
1678 SDL_FillRect(Surface, &l, Color);
1680 if (SDL_MUSTLOCK(Surface))
1682 SDL_UnlockSurface(Surface);
1686 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1687 Uint8 R, Uint8 G, Uint8 B)
1689 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1692 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1703 /* Do the clipping */
1704 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1708 if (y2 > Surface->h - 1)
1709 y2 = Surface->h - 1;
1716 SDL_FillRect(Surface, &l, Color);
1719 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1720 Sint16 x2, Sint16 y2, Uint32 Color,
1721 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1724 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1729 sdx = (dx < 0) ? -1 : 1;
1730 sdy = (dy < 0) ? -1 : 1;
1742 for (x = 0; x < dx; x++)
1744 Callback(Surface, px, py, Color);
1758 for (y = 0; y < dy; y++)
1760 Callback(Surface, px, py, Color);
1774 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1775 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1776 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1779 sge_DoLine(Surface, X1, Y1, X2, Y2,
1780 SDL_MapRGB(Surface->format, R, G, B), Callback);
1783 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1786 if (SDL_MUSTLOCK(Surface))
1788 if (SDL_LockSurface(Surface) < 0)
1793 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1795 /* unlock the display */
1796 if (SDL_MUSTLOCK(Surface))
1798 SDL_UnlockSurface(Surface);
1802 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1803 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1805 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1808 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1810 if (dst_bitmap == backbuffer || dst_bitmap == window)
1816 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1821 -----------------------------------------------------------------------------
1822 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1823 -----------------------------------------------------------------------------
1826 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1827 int width, int height, Uint32 color)
1831 for (y = src_y; y < src_y + height; y++)
1833 for (x = src_x; x < src_x + width; x++)
1835 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1837 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1842 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1843 int src_x, int src_y, int width, int height,
1844 int dst_x, int dst_y)
1848 for (y = 0; y < height; y++)
1850 for (x = 0; x < width; x++)
1852 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1854 if (pixel != BLACK_PIXEL)
1855 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1861 /* ========================================================================= */
1862 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1863 /* (Rotozoomer) by Andreas Schiffler */
1864 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1865 /* ========================================================================= */
1868 -----------------------------------------------------------------------------
1871 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1872 -----------------------------------------------------------------------------
1883 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1886 tColorRGBA *sp, *csp, *dp;
1890 sp = csp = (tColorRGBA *) src->pixels;
1891 dp = (tColorRGBA *) dst->pixels;
1892 dgap = dst->pitch - dst->w * 4;
1894 for (y = 0; y < dst->h; y++)
1898 for (x = 0; x < dst->w; x++)
1900 tColorRGBA *sp0 = sp;
1901 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1902 tColorRGBA *sp00 = &sp0[0];
1903 tColorRGBA *sp01 = &sp0[1];
1904 tColorRGBA *sp10 = &sp1[0];
1905 tColorRGBA *sp11 = &sp1[1];
1908 /* create new color pixel from all four source color pixels */
1909 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1910 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1911 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1912 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1917 /* advance source pointers */
1920 /* advance destination pointer */
1924 /* advance source pointer */
1925 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1927 /* advance destination pointers */
1928 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1934 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1936 int x, y, *sax, *say, *csax, *csay;
1938 tColorRGBA *sp, *csp, *csp0, *dp;
1941 /* use specialized zoom function when scaling down to exactly half size */
1942 if (src->w == 2 * dst->w &&
1943 src->h == 2 * dst->h)
1944 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1946 /* variable setup */
1947 sx = (float) src->w / (float) dst->w;
1948 sy = (float) src->h / (float) dst->h;
1950 /* allocate memory for row increments */
1951 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1952 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1954 /* precalculate row increments */
1955 for (x = 0; x <= dst->w; x++)
1956 *csax++ = (int)(sx * x);
1958 for (y = 0; y <= dst->h; y++)
1959 *csay++ = (int)(sy * y);
1962 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1963 dp = (tColorRGBA *) dst->pixels;
1964 dgap = dst->pitch - dst->w * 4;
1967 for (y = 0; y < dst->h; y++)
1972 for (x = 0; x < dst->w; x++)
1977 /* advance source pointers */
1981 /* advance destination pointer */
1985 /* advance source pointer */
1987 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1989 /* advance destination pointers */
1990 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2000 -----------------------------------------------------------------------------
2003 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2004 -----------------------------------------------------------------------------
2007 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2009 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2010 Uint8 *sp, *dp, *csp;
2013 /* variable setup */
2014 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2015 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2017 /* allocate memory for row increments */
2018 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2019 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2021 /* precalculate row increments */
2024 for (x = 0; x < dst->w; x++)
2027 *csax = (csx >> 16);
2034 for (y = 0; y < dst->h; y++)
2037 *csay = (csy >> 16);
2044 for (x = 0; x < dst->w; x++)
2052 for (y = 0; y < dst->h; y++)
2059 sp = csp = (Uint8 *) src->pixels;
2060 dp = (Uint8 *) dst->pixels;
2061 dgap = dst->pitch - dst->w;
2065 for (y = 0; y < dst->h; y++)
2069 for (x = 0; x < dst->w; x++)
2074 /* advance source pointers */
2078 /* advance destination pointer */
2082 /* advance source pointer (for row) */
2083 csp += ((*csay) * src->pitch);
2086 /* advance destination pointers */
2097 -----------------------------------------------------------------------------
2100 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2101 'zoomx' and 'zoomy' are scaling factors for width and height.
2102 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2103 into a 32bit RGBA format on the fly.
2104 -----------------------------------------------------------------------------
2107 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2109 SDL_Surface *zoom_src = NULL;
2110 SDL_Surface *zoom_dst = NULL;
2111 boolean is_converted = FALSE;
2118 /* determine if source surface is 32 bit or 8 bit */
2119 is_32bit = (src->format->BitsPerPixel == 32);
2121 if (is_32bit || src->format->BitsPerPixel == 8)
2123 /* use source surface 'as is' */
2128 /* new source surface is 32 bit with a defined RGB ordering */
2129 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2130 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2131 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2133 is_converted = TRUE;
2136 /* allocate surface to completely contain the zoomed surface */
2139 /* target surface is 32 bit with source RGBA/ABGR ordering */
2140 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2141 zoom_src->format->Rmask,
2142 zoom_src->format->Gmask,
2143 zoom_src->format->Bmask, 0);
2147 /* target surface is 8 bit */
2148 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2152 /* lock source surface */
2153 SDL_LockSurface(zoom_src);
2155 /* check which kind of surface we have */
2158 /* call the 32 bit transformation routine to do the zooming */
2159 zoomSurfaceRGBA(zoom_src, zoom_dst);
2164 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2165 zoom_dst->format->palette->colors[i] =
2166 zoom_src->format->palette->colors[i];
2167 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2169 /* call the 8 bit transformation routine to do the zooming */
2170 zoomSurfaceY(zoom_src, zoom_dst);
2173 /* unlock source surface */
2174 SDL_UnlockSurface(zoom_src);
2176 /* free temporary surface */
2178 SDL_FreeSurface(zoom_src);
2180 /* return destination surface */
2184 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2186 Bitmap *dst_bitmap = CreateBitmapStruct();
2187 SDL_Surface **dst_surface = &dst_bitmap->surface;
2189 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2190 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2192 dst_bitmap->width = dst_width;
2193 dst_bitmap->height = dst_height;
2195 /* create zoomed temporary surface from source surface */
2196 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2198 /* create native format destination surface from zoomed temporary surface */
2199 SDLSetNativeSurface(dst_surface);
2205 /* ========================================================================= */
2206 /* load image to bitmap */
2207 /* ========================================================================= */
2209 Bitmap *SDLLoadImage(char *filename)
2211 Bitmap *new_bitmap = CreateBitmapStruct();
2212 SDL_Surface *sdl_image_tmp;
2214 print_timestamp_init("SDLLoadImage");
2216 print_timestamp_time(getBaseNamePtr(filename));
2218 /* load image to temporary surface */
2219 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2221 SetError("IMG_Load(): %s", SDL_GetError());
2226 print_timestamp_time("IMG_Load");
2228 UPDATE_BUSY_STATE();
2230 /* create native non-transparent surface for current image */
2231 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2233 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2238 print_timestamp_time("SDL_DisplayFormat (opaque)");
2240 UPDATE_BUSY_STATE();
2242 /* create native transparent surface for current image */
2243 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2244 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2246 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2248 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2253 print_timestamp_time("SDL_DisplayFormat (masked)");
2255 UPDATE_BUSY_STATE();
2257 /* free temporary surface */
2258 SDL_FreeSurface(sdl_image_tmp);
2260 new_bitmap->width = new_bitmap->surface->w;
2261 new_bitmap->height = new_bitmap->surface->h;
2263 print_timestamp_done("SDLLoadImage");
2269 /* ------------------------------------------------------------------------- */
2270 /* custom cursor fuctions */
2271 /* ------------------------------------------------------------------------- */
2273 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2275 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2276 cursor_info->width, cursor_info->height,
2277 cursor_info->hot_x, cursor_info->hot_y);
2280 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2282 static struct MouseCursorInfo *last_cursor_info = NULL;
2283 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2284 static SDL_Cursor *cursor_default = NULL;
2285 static SDL_Cursor *cursor_current = NULL;
2287 /* if invoked for the first time, store the SDL default cursor */
2288 if (cursor_default == NULL)
2289 cursor_default = SDL_GetCursor();
2291 /* only create new cursor if cursor info (custom only) has changed */
2292 if (cursor_info != NULL && cursor_info != last_cursor_info)
2294 cursor_current = create_cursor(cursor_info);
2295 last_cursor_info = cursor_info;
2298 /* only set new cursor if cursor info (custom or NULL) has changed */
2299 if (cursor_info != last_cursor_info2)
2300 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2302 last_cursor_info2 = cursor_info;
2306 /* ========================================================================= */
2307 /* audio functions */
2308 /* ========================================================================= */
2310 void SDLOpenAudio(void)
2312 #if !defined(TARGET_SDL2)
2313 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2314 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2317 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2319 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2323 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2324 AUDIO_NUM_CHANNELS_STEREO,
2325 setup.system.audio_fragment_size) < 0)
2327 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2331 audio.sound_available = TRUE;
2332 audio.music_available = TRUE;
2333 audio.loops_available = TRUE;
2334 audio.sound_enabled = TRUE;
2336 /* set number of available mixer channels */
2337 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2338 audio.music_channel = MUSIC_CHANNEL;
2339 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2341 Mixer_InitChannels();
2344 void SDLCloseAudio(void)
2347 Mix_HaltChannel(-1);
2350 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2354 /* ========================================================================= */
2355 /* event functions */
2356 /* ========================================================================= */
2358 void SDLNextEvent(Event *event)
2360 SDL_WaitEvent(event);
2362 if (event->type == EVENT_BUTTONPRESS ||
2363 event->type == EVENT_BUTTONRELEASE)
2365 if (((ButtonEvent *)event)->x > video_xoffset)
2366 ((ButtonEvent *)event)->x -= video_xoffset;
2368 ((ButtonEvent *)event)->x = 0;
2369 if (((ButtonEvent *)event)->y > video_yoffset)
2370 ((ButtonEvent *)event)->y -= video_yoffset;
2372 ((ButtonEvent *)event)->y = 0;
2374 else if (event->type == EVENT_MOTIONNOTIFY)
2376 if (((MotionEvent *)event)->x > video_xoffset)
2377 ((MotionEvent *)event)->x -= video_xoffset;
2379 ((MotionEvent *)event)->x = 0;
2380 if (((MotionEvent *)event)->y > video_yoffset)
2381 ((MotionEvent *)event)->y -= video_yoffset;
2383 ((MotionEvent *)event)->y = 0;
2387 void SDLHandleWindowManagerEvent(Event *event)
2390 #if defined(PLATFORM_WIN32)
2391 // experimental drag and drop code
2393 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2394 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2396 #if defined(TARGET_SDL2)
2397 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2399 if (syswmmsg->msg == WM_DROPFILES)
2402 #if defined(TARGET_SDL2)
2403 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2405 HDROP hdrop = (HDROP)syswmmsg->wParam;
2409 printf("::: SDL_SYSWMEVENT:\n");
2411 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2413 for (i = 0; i < num_files; i++)
2415 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2416 char buffer[buffer_len + 1];
2418 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2420 printf("::: - '%s'\n", buffer);
2423 #if defined(TARGET_SDL2)
2424 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2426 DragFinish((HDROP)syswmmsg->wParam);
2434 /* ========================================================================= */
2435 /* joystick functions */
2436 /* ========================================================================= */
2438 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2439 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2440 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2442 static boolean SDLOpenJoystick(int nr)
2444 if (nr < 0 || nr > MAX_PLAYERS)
2447 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2450 static void SDLCloseJoystick(int nr)
2452 if (nr < 0 || nr > MAX_PLAYERS)
2455 SDL_JoystickClose(sdl_joystick[nr]);
2457 sdl_joystick[nr] = NULL;
2460 static boolean SDLCheckJoystickOpened(int nr)
2462 if (nr < 0 || nr > MAX_PLAYERS)
2465 #if defined(TARGET_SDL2)
2466 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2468 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2472 void HandleJoystickEvent(Event *event)
2476 case SDL_JOYAXISMOTION:
2477 if (event->jaxis.axis < 2)
2478 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2481 case SDL_JOYBUTTONDOWN:
2482 if (event->jbutton.button < 2)
2483 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2486 case SDL_JOYBUTTONUP:
2487 if (event->jbutton.button < 2)
2488 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2496 void SDLInitJoysticks()
2498 static boolean sdl_joystick_subsystem_initialized = FALSE;
2499 boolean print_warning = !sdl_joystick_subsystem_initialized;
2502 if (!sdl_joystick_subsystem_initialized)
2504 sdl_joystick_subsystem_initialized = TRUE;
2506 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2508 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2513 for (i = 0; i < MAX_PLAYERS; i++)
2515 /* get configured joystick for this player */
2516 char *device_name = setup.input[i].joy.device_name;
2517 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2519 if (joystick_nr >= SDL_NumJoysticks())
2521 if (setup.input[i].use_joystick && print_warning)
2522 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2527 /* misuse joystick file descriptor variable to store joystick number */
2528 joystick.fd[i] = joystick_nr;
2530 if (joystick_nr == -1)
2533 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2534 if (SDLCheckJoystickOpened(joystick_nr))
2535 SDLCloseJoystick(joystick_nr);
2537 if (!setup.input[i].use_joystick)
2540 if (!SDLOpenJoystick(joystick_nr))
2543 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2548 joystick.status = JOYSTICK_ACTIVATED;
2552 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2554 if (nr < 0 || nr >= MAX_PLAYERS)
2558 *x = sdl_js_axis[nr][0];
2560 *y = sdl_js_axis[nr][1];
2563 *b1 = sdl_js_button[nr][0];
2565 *b2 = sdl_js_button[nr][1];