1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
18 #define ENABLE_UNUSED_CODE 0 /* currently unused functions */
21 /* ========================================================================= */
23 /* ========================================================================= */
25 /* SDL internal variables */
26 #if defined(TARGET_SDL2)
27 static SDL_Window *sdl_window = NULL;
28 static SDL_Renderer *sdl_renderer = NULL;
29 static SDL_Texture *sdl_texture = NULL;
31 #define USE_RENDERER TRUE
34 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
35 static int fullscreen_width;
36 static int fullscreen_height;
37 static int fullscreen_xoffset;
38 static int fullscreen_yoffset;
39 static int video_xoffset;
40 static int video_yoffset;
41 static boolean limit_screen_updates = FALSE;
44 /* functions from SGE library */
45 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
47 void SDLLimitScreenUpdates(boolean enable)
49 limit_screen_updates = enable;
52 static void UpdateScreen(SDL_Rect *rect)
54 static unsigned int update_screen_delay = 0;
55 unsigned int update_screen_delay_value = 20; /* (milliseconds) */
57 if (limit_screen_updates &&
58 !DelayReached(&update_screen_delay, update_screen_delay_value))
61 LimitScreenUpdates(FALSE);
63 #if defined(TARGET_SDL2)
65 SDL_Surface *screen = backbuffer->surface;
69 int bytes_x = screen->pitch / video.width;
70 int bytes_y = screen->pitch;
72 if (video.fullscreen_enabled)
73 bytes_x = screen->pitch / fullscreen_width;
75 SDL_UpdateTexture(sdl_texture, rect,
76 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
81 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
83 SDL_RenderClear(sdl_renderer);
84 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
85 SDL_RenderPresent(sdl_renderer);
88 SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
90 SDL_UpdateWindowSurface(sdl_window);
95 SDL_UpdateRects(backbuffer->surface, 1, rect);
97 SDL_UpdateRect(backbuffer->surface, 0, 0, 0, 0);
101 static void setFullscreenParameters(char *fullscreen_mode_string)
103 #if defined(TARGET_SDL2)
104 fullscreen_width = video.width;
105 fullscreen_height = video.height;
106 fullscreen_xoffset = 0;
107 fullscreen_yoffset = 0;
111 struct ScreenModeInfo *fullscreen_mode;
114 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
116 if (fullscreen_mode == NULL)
119 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
121 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
122 fullscreen_mode->height == video.fullscreen_modes[i].height)
124 fullscreen_width = fullscreen_mode->width;
125 fullscreen_height = fullscreen_mode->height;
127 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
128 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
136 static void SDLSetWindowIcon(char *basename)
138 /* (setting the window icon on Mac OS X would replace the high-quality
139 dock icon with the currently smaller (and uglier) icon from file) */
141 #if !defined(PLATFORM_MACOSX)
142 char *filename = getCustomImageFilename(basename);
143 SDL_Surface *surface;
145 if (filename == NULL)
147 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
152 if ((surface = IMG_Load(filename)) == NULL)
154 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
159 /* set transparent color */
160 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
161 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
163 #if defined(TARGET_SDL2)
164 SDL_SetWindowIcon(sdl_window, surface);
166 SDL_WM_SetIcon(surface, NULL);
171 #if defined(TARGET_SDL2)
173 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
174 SDL_PixelFormat *format2)
176 return (format1->format == format2->format &&
177 format1->BitsPerPixel == format2->BitsPerPixel &&
178 format1->BytesPerPixel == format2->BytesPerPixel &&
179 format1->Rmask == format2->Rmask &&
180 format1->Gmask == format2->Gmask &&
181 format1->Bmask == format2->Bmask &&
182 format1->Amask == format2->Amask);
185 boolean SDLSetNativeSurface(SDL_Surface **surface)
187 SDL_Surface *new_surface;
189 if (surface == NULL ||
191 backbuffer == NULL ||
192 backbuffer->surface == NULL)
195 // if pixel format already optimized for destination surface, do nothing
196 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
199 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
201 if (new_surface == NULL)
202 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
204 SDL_FreeSurface(*surface);
206 *surface = new_surface;
211 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
213 SDL_Surface *new_surface;
218 if (backbuffer && backbuffer->surface)
219 new_surface = SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
221 new_surface = SDL_ConvertSurface(surface, surface->format, 0);
223 if (new_surface == NULL)
224 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
231 boolean SDLSetNativeSurface(SDL_Surface **surface)
233 SDL_Surface *new_surface;
235 if (surface == NULL ||
240 new_surface = SDL_DisplayFormat(*surface);
242 if (new_surface == NULL)
243 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
245 SDL_FreeSurface(*surface);
247 *surface = new_surface;
252 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
254 SDL_Surface *new_surface;
256 if (video.initialized)
257 new_surface = SDL_DisplayFormat(surface);
259 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
261 if (new_surface == NULL)
262 Error(ERR_EXIT, "%s() failed: %s",
263 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
271 void SDLInitVideoDisplay(void)
273 #if !defined(TARGET_SDL2)
274 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
275 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
277 SDL_putenv("SDL_VIDEO_CENTERED=1");
280 /* initialize SDL video */
281 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
282 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
284 /* set default SDL depth */
285 #if !defined(TARGET_SDL2)
286 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
288 video.default_depth = 32; // (how to determine video depth in SDL2?)
292 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
295 #if !defined(TARGET_SDL2)
296 static int screen_xy[][2] =
304 SDL_Rect **modes = NULL;
305 boolean hardware_fullscreen_available = TRUE;
308 /* default: normal game window size */
309 fullscreen_width = video.width;
310 fullscreen_height = video.height;
311 fullscreen_xoffset = 0;
312 fullscreen_yoffset = 0;
314 #if !defined(TARGET_SDL2)
315 /* determine required standard fullscreen mode for game screen size */
316 for (i = 0; screen_xy[i][0] != -1; i++)
318 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
320 fullscreen_width = screen_xy[i][0];
321 fullscreen_height = screen_xy[i][1];
327 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
328 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
331 checked_free(video.fullscreen_modes);
333 video.fullscreen_modes = NULL;
334 video.fullscreen_mode_current = NULL;
336 video.window_scaling_percent = setup.window_scaling_percent;
337 video.window_scaling_quality = setup.window_scaling_quality;
339 #if defined(TARGET_SDL2)
340 int num_displays = SDL_GetNumVideoDisplays();
342 if (num_displays > 0)
344 // currently only display modes of first display supported
345 int num_modes = SDL_GetNumDisplayModes(0);
349 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
351 for (i = 0; i < num_modes; i++)
353 SDL_DisplayMode mode;
355 if (SDL_GetDisplayMode(0, i, &mode) < 0)
358 modes[i] = checked_calloc(sizeof(SDL_Rect));
360 modes[i]->w = mode.w;
361 modes[i]->h = mode.h;
366 /* get available hardware supported fullscreen modes */
367 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
372 /* no hardware screen modes available => no fullscreen mode support */
373 // video.fullscreen_available = FALSE;
374 hardware_fullscreen_available = FALSE;
376 else if (modes == (SDL_Rect **)-1)
378 /* fullscreen resolution is not restricted -- all resolutions available */
379 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
381 /* use native video buffer size for fullscreen mode */
382 video.fullscreen_modes[0].width = video.width;
383 video.fullscreen_modes[0].height = video.height;
385 video.fullscreen_modes[1].width = -1;
386 video.fullscreen_modes[1].height = -1;
390 /* in this case, a certain number of screen modes is available */
393 for (i = 0; modes[i] != NULL; i++)
395 boolean found_mode = FALSE;
397 /* screen mode is smaller than video buffer size -- skip it */
398 if (modes[i]->w < video.width || modes[i]->h < video.height)
401 if (video.fullscreen_modes != NULL)
402 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
403 if (modes[i]->w == video.fullscreen_modes[j].width &&
404 modes[i]->h == video.fullscreen_modes[j].height)
407 if (found_mode) /* screen mode already stored -- skip it */
410 /* new mode found; add it to list of available fullscreen modes */
414 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
416 sizeof(struct ScreenModeInfo));
418 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
419 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
421 video.fullscreen_modes[num_modes].width = -1;
422 video.fullscreen_modes[num_modes].height = -1;
427 /* no appropriate screen modes available => no fullscreen mode support */
428 // video.fullscreen_available = FALSE;
429 hardware_fullscreen_available = FALSE;
433 video.fullscreen_available = hardware_fullscreen_available;
435 #if USE_DESKTOP_FULLSCREEN
436 // in SDL 2.0, there is always support for desktop fullscreen mode
437 // (in SDL 1.2, there is only support for "real" fullscreen mode)
438 video.fullscreen_available = TRUE;
441 #if defined(TARGET_SDL2)
444 for (i = 0; modes[i] != NULL; i++)
445 checked_free(modes[i]);
451 /* open SDL video output device (window or fullscreen mode) */
452 if (!SDLSetVideoMode(backbuffer, fullscreen))
453 Error(ERR_EXIT, "setting video mode failed");
455 /* !!! SDL2 can only set the window icon if the window already exists !!! */
456 /* set window icon */
457 SDLSetWindowIcon(program.icon_filename);
459 /* set window and icon title */
460 #if defined(TARGET_SDL2)
461 SDL_SetWindowTitle(sdl_window, program.window_title);
463 SDL_WM_SetCaption(program.window_title, program.window_title);
466 /* SDL cannot directly draw to the visible video framebuffer like X11,
467 but always uses a backbuffer, which is then blitted to the visible
468 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
469 visible video framebuffer with 'SDL_Flip', if the hardware supports
470 this). Therefore do not use an additional backbuffer for drawing, but
471 use a symbolic buffer (distinguishable from the SDL backbuffer) called
472 'window', which indicates that the SDL backbuffer should be updated to
473 the visible video framebuffer when attempting to blit to it.
475 For convenience, it seems to be a good idea to create this symbolic
476 buffer 'window' at the same size as the SDL backbuffer. Although it
477 should never be drawn to directly, it would do no harm nevertheless. */
479 /* create additional (symbolic) buffer for double-buffering */
480 ReCreateBitmap(window, video.width, video.height, video.depth);
483 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
486 SDL_Surface *new_surface = NULL;
488 #if defined(TARGET_SDL2)
489 static boolean fullscreen_enabled = FALSE;
490 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
491 #if USE_DESKTOP_FULLSCREEN
492 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
494 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
498 int surface_flags_window = SURFACE_FLAGS;
499 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
502 int width = (fullscreen ? fullscreen_width : video.width);
503 int height = (fullscreen ? fullscreen_height : video.height);
504 int surface_flags = (fullscreen ? surface_flags_fullscreen :
505 surface_flags_window);
507 // default window size is unscaled
508 video.window_width = video.width;
509 video.window_height = video.height;
511 #if defined(TARGET_SDL2)
513 // store if initial screen mode on game start is fullscreen mode
514 if (sdl_window == NULL)
515 video.fullscreen_initial = fullscreen;
518 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
519 #if !USE_DESKTOP_FULLSCREEN
520 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
523 video.window_width = window_scaling_factor * width;
524 video.window_height = window_scaling_factor * height;
526 if ((*backbuffer)->surface)
528 SDL_FreeSurface((*backbuffer)->surface);
529 (*backbuffer)->surface = NULL;
534 SDL_DestroyTexture(sdl_texture);
538 if (!(fullscreen && fullscreen_enabled))
542 SDL_DestroyRenderer(sdl_renderer);
548 SDL_DestroyWindow(sdl_window);
553 if (sdl_window == NULL)
554 sdl_window = SDL_CreateWindow(program.window_title,
555 SDL_WINDOWPOS_CENTERED,
556 SDL_WINDOWPOS_CENTERED,
557 #if USE_DESKTOP_FULLSCREEN
561 (int)(screen_scaling_factor * width),
562 (int)(screen_scaling_factor * height),
566 if (sdl_window != NULL)
569 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
570 *without* enabling 2D/3D acceleration and/or guest additions installed,
571 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
572 it will try to use accelerated graphics and apparently fails miserably) */
573 if (sdl_renderer == NULL)
574 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
576 if (sdl_renderer == NULL)
577 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
580 if (sdl_renderer != NULL)
582 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
583 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
584 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
586 sdl_texture = SDL_CreateTexture(sdl_renderer,
587 SDL_PIXELFORMAT_ARGB8888,
588 SDL_TEXTUREACCESS_STREAMING,
591 if (sdl_texture != NULL)
593 // use SDL default values for RGB masks and no alpha channel
594 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
596 if (new_surface == NULL)
597 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
602 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
607 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
612 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
618 SDL_DestroyWindow(sdl_window);
620 sdl_window = SDL_CreateWindow(program.window_title,
621 SDL_WINDOWPOS_CENTERED,
622 SDL_WINDOWPOS_CENTERED,
626 if (sdl_window != NULL)
627 new_surface = SDL_GetWindowSurface(sdl_window);
631 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
634 #if defined(TARGET_SDL2)
635 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
636 if (new_surface != NULL)
637 fullscreen_enabled = fullscreen;
643 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
645 boolean success = TRUE;
646 SDL_Surface *new_surface = NULL;
650 if (*backbuffer == NULL)
651 *backbuffer = CreateBitmapStruct();
653 /* (real bitmap might be larger in fullscreen mode with video offsets) */
654 (*backbuffer)->width = video.width;
655 (*backbuffer)->height = video.height;
657 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
659 setFullscreenParameters(setup.fullscreen_mode);
661 video_xoffset = fullscreen_xoffset;
662 video_yoffset = fullscreen_yoffset;
664 /* switch display to fullscreen mode, if available */
665 new_surface = SDLCreateScreen(backbuffer, TRUE);
667 if (new_surface == NULL)
669 /* switching display to fullscreen mode failed */
670 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
672 /* do not try it again */
673 video.fullscreen_available = FALSE;
679 (*backbuffer)->surface = new_surface;
681 video.fullscreen_enabled = TRUE;
682 video.fullscreen_mode_current = setup.fullscreen_mode;
688 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
693 /* switch display to window mode */
694 new_surface = SDLCreateScreen(backbuffer, FALSE);
696 if (new_surface == NULL)
698 /* switching display to window mode failed -- should not happen */
699 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
705 (*backbuffer)->surface = new_surface;
707 video.fullscreen_enabled = FALSE;
708 video.window_scaling_percent = setup.window_scaling_percent;
709 video.window_scaling_quality = setup.window_scaling_quality;
715 #if defined(TARGET_SDL2)
716 SDLRedrawWindow(); // map window
720 #if defined(PLATFORM_WIN32)
721 // experimental drag and drop code
723 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
726 SDL_SysWMinfo wminfo;
728 boolean wminfo_success = FALSE;
730 SDL_VERSION(&wminfo.version);
731 #if defined(TARGET_SDL2)
733 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
735 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
740 #if defined(TARGET_SDL2)
741 hwnd = wminfo.info.win.window;
743 hwnd = wminfo.window;
746 DragAcceptFiles(hwnd, TRUE);
755 void SDLSetWindowTitle()
757 #if defined(TARGET_SDL2)
758 SDL_SetWindowTitle(sdl_window, program.window_title);
760 SDL_WM_SetCaption(program.window_title, program.window_title);
764 #if defined(TARGET_SDL2)
765 void SDLSetWindowScaling(int window_scaling_percent)
767 if (sdl_window == NULL)
770 float window_scaling_factor = (float)window_scaling_percent / 100;
771 int new_window_width = (int)(window_scaling_factor * video.width);
772 int new_window_height = (int)(window_scaling_factor * video.height);
774 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
776 video.window_scaling_percent = window_scaling_percent;
777 video.window_width = new_window_width;
778 video.window_height = new_window_height;
783 void SDLSetWindowScalingQuality(char *window_scaling_quality)
785 if (sdl_texture == NULL)
788 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
790 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
791 SDL_PIXELFORMAT_ARGB8888,
792 SDL_TEXTUREACCESS_STREAMING,
793 video.width, video.height);
795 if (new_texture != NULL)
797 SDL_DestroyTexture(sdl_texture);
799 sdl_texture = new_texture;
804 video.window_scaling_quality = window_scaling_quality;
807 void SDLSetWindowFullscreen(boolean fullscreen)
809 if (sdl_window == NULL)
812 #if USE_DESKTOP_FULLSCREEN
813 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
815 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
818 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
819 video.fullscreen_enabled = fullscreen;
821 // if game started in fullscreen mode, window will also get fullscreen size
822 if (!fullscreen && video.fullscreen_initial)
824 SDLSetWindowScaling(setup.window_scaling_percent);
825 SDL_SetWindowPosition(sdl_window,
826 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
828 video.fullscreen_initial = FALSE;
832 void SDLRedrawWindow()
838 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
841 SDL_Surface *surface =
842 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
845 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
847 SDLSetNativeSurface(&surface);
849 bitmap->surface = surface;
852 void SDLFreeBitmapPointers(Bitmap *bitmap)
855 SDL_FreeSurface(bitmap->surface);
856 if (bitmap->surface_masked)
857 SDL_FreeSurface(bitmap->surface_masked);
858 bitmap->surface = NULL;
859 bitmap->surface_masked = NULL;
862 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
863 int src_x, int src_y, int width, int height,
864 int dst_x, int dst_y, int mask_mode)
866 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
867 SDL_Rect src_rect, dst_rect;
869 if (src_bitmap == backbuffer)
871 src_x += video_xoffset;
872 src_y += video_yoffset;
880 if (dst_bitmap == backbuffer || dst_bitmap == window)
882 dst_x += video_xoffset;
883 dst_y += video_yoffset;
891 // if (src_bitmap != backbuffer || dst_bitmap != window)
892 if (!(src_bitmap == backbuffer && dst_bitmap == window))
893 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
894 src_bitmap->surface_masked : src_bitmap->surface),
895 &src_rect, real_dst_bitmap->surface, &dst_rect);
897 #if defined(TARGET_SDL2)
898 if (dst_bitmap == window)
900 // SDL_UpdateWindowSurface(sdl_window);
901 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
902 UpdateScreen(&dst_rect);
905 if (dst_bitmap == window)
907 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
908 UpdateScreen(&dst_rect);
913 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
916 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
919 if (dst_bitmap == backbuffer || dst_bitmap == window)
930 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
932 #if defined(TARGET_SDL2)
933 if (dst_bitmap == window)
935 // SDL_UpdateWindowSurface(sdl_window);
936 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
940 if (dst_bitmap == window)
942 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
948 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
949 int fade_mode, int fade_delay, int post_delay,
950 void (*draw_border_function)(void))
952 static boolean initialization_needed = TRUE;
953 static SDL_Surface *surface_source = NULL;
954 static SDL_Surface *surface_target = NULL;
955 static SDL_Surface *surface_black = NULL;
956 SDL_Surface *surface_screen = backbuffer->surface;
957 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
958 SDL_Rect src_rect, dst_rect;
960 int src_x = x, src_y = y;
961 int dst_x = x, dst_y = y;
962 unsigned int time_last, time_current;
964 /* check if screen size has changed */
965 if (surface_source != NULL && (video.width != surface_source->w ||
966 video.height != surface_source->h))
968 SDL_FreeSurface(surface_source);
969 SDL_FreeSurface(surface_target);
970 SDL_FreeSurface(surface_black);
972 initialization_needed = TRUE;
980 dst_x += video_xoffset;
981 dst_y += video_yoffset;
985 dst_rect.w = width; /* (ignored) */
986 dst_rect.h = height; /* (ignored) */
988 dst_rect2 = dst_rect;
990 if (initialization_needed)
992 #if defined(TARGET_SDL2)
993 unsigned int flags = 0;
995 unsigned int flags = SDL_SRCALPHA;
997 /* use same surface type as screen surface */
998 if ((surface_screen->flags & SDL_HWSURFACE))
999 flags |= SDL_HWSURFACE;
1001 flags |= SDL_SWSURFACE;
1004 /* create surface for temporary copy of screen buffer (source) */
1005 if ((surface_source =
1006 SDL_CreateRGBSurface(flags,
1009 surface_screen->format->BitsPerPixel,
1010 surface_screen->format->Rmask,
1011 surface_screen->format->Gmask,
1012 surface_screen->format->Bmask,
1013 surface_screen->format->Amask)) == NULL)
1014 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1016 /* create surface for cross-fading screen buffer (target) */
1017 if ((surface_target =
1018 SDL_CreateRGBSurface(flags,
1021 surface_screen->format->BitsPerPixel,
1022 surface_screen->format->Rmask,
1023 surface_screen->format->Gmask,
1024 surface_screen->format->Bmask,
1025 surface_screen->format->Amask)) == NULL)
1026 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1028 /* create black surface for fading from/to black */
1029 if ((surface_black =
1030 SDL_CreateRGBSurface(flags,
1033 surface_screen->format->BitsPerPixel,
1034 surface_screen->format->Rmask,
1035 surface_screen->format->Gmask,
1036 surface_screen->format->Bmask,
1037 surface_screen->format->Amask)) == NULL)
1038 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1040 /* completely fill the surface with black color pixels */
1041 SDL_FillRect(surface_black, NULL,
1042 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1044 initialization_needed = FALSE;
1047 /* copy source and target surfaces to temporary surfaces for fading */
1048 if (fade_mode & FADE_TYPE_TRANSFORM)
1050 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1051 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1053 else if (fade_mode & FADE_TYPE_FADE_IN)
1055 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1056 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1058 else /* FADE_TYPE_FADE_OUT */
1060 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1061 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1064 time_current = SDL_GetTicks();
1066 if (fade_mode == FADE_MODE_MELT)
1068 boolean done = FALSE;
1069 int melt_pixels = 2;
1070 int melt_columns = width / melt_pixels;
1071 int ypos[melt_columns];
1072 int max_steps = height / 8 + 32;
1077 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1078 #if defined(TARGET_SDL2)
1079 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1081 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1084 ypos[0] = -GetSimpleRandom(16);
1086 for (i = 1 ; i < melt_columns; i++)
1088 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1090 ypos[i] = ypos[i - 1] + r;
1103 time_last = time_current;
1104 time_current = SDL_GetTicks();
1105 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1106 steps_final = MIN(MAX(0, steps), max_steps);
1110 done = (steps_done >= steps_final);
1112 for (i = 0 ; i < melt_columns; i++)
1120 else if (ypos[i] < height)
1125 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1127 if (ypos[i] + dy >= height)
1128 dy = height - ypos[i];
1130 /* copy part of (appearing) target surface to upper area */
1131 src_rect.x = src_x + i * melt_pixels;
1132 // src_rect.y = src_y + ypos[i];
1134 src_rect.w = melt_pixels;
1136 src_rect.h = ypos[i] + dy;
1138 dst_rect.x = dst_x + i * melt_pixels;
1139 // dst_rect.y = dst_y + ypos[i];
1142 if (steps_done >= steps_final)
1143 SDL_BlitSurface(surface_target, &src_rect,
1144 surface_screen, &dst_rect);
1148 /* copy part of (disappearing) source surface to lower area */
1149 src_rect.x = src_x + i * melt_pixels;
1151 src_rect.w = melt_pixels;
1152 src_rect.h = height - ypos[i];
1154 dst_rect.x = dst_x + i * melt_pixels;
1155 dst_rect.y = dst_y + ypos[i];
1157 if (steps_done >= steps_final)
1158 SDL_BlitSurface(surface_source, &src_rect,
1159 surface_screen, &dst_rect);
1165 src_rect.x = src_x + i * melt_pixels;
1167 src_rect.w = melt_pixels;
1168 src_rect.h = height;
1170 dst_rect.x = dst_x + i * melt_pixels;
1173 if (steps_done >= steps_final)
1174 SDL_BlitSurface(surface_target, &src_rect,
1175 surface_screen, &dst_rect);
1179 if (steps_done >= steps_final)
1181 if (draw_border_function != NULL)
1182 draw_border_function();
1184 #if defined(TARGET_SDL2)
1185 // SDL_UpdateWindowSurface(sdl_window);
1186 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
1187 UpdateScreen(&dst_rect2);
1189 // SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1190 UpdateScreen(&dst_rect2);
1200 for (alpha = 0.0; alpha < 255.0;)
1202 time_last = time_current;
1203 time_current = SDL_GetTicks();
1204 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1205 alpha_final = MIN(MAX(0, alpha), 255);
1207 /* draw existing (source) image to screen buffer */
1208 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1210 /* draw new (target) image to screen buffer using alpha blending */
1211 #if defined(TARGET_SDL2)
1212 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1213 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1215 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1217 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1219 if (draw_border_function != NULL)
1220 draw_border_function();
1222 /* only update the region of the screen that is affected from fading */
1223 UpdateScreen(&dst_rect);
1230 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1231 int to_x, int to_y, Uint32 color)
1233 SDL_Surface *surface = dst_bitmap->surface;
1237 swap_numbers(&from_x, &to_x);
1240 swap_numbers(&from_y, &to_y);
1244 rect.w = (to_x - from_x + 1);
1245 rect.h = (to_y - from_y + 1);
1247 if (dst_bitmap == backbuffer || dst_bitmap == window)
1249 rect.x += video_xoffset;
1250 rect.y += video_yoffset;
1253 SDL_FillRect(surface, &rect, color);
1256 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1257 int to_x, int to_y, Uint32 color)
1259 if (dst_bitmap == backbuffer || dst_bitmap == window)
1261 from_x += video_xoffset;
1262 from_y += video_yoffset;
1263 to_x += video_xoffset;
1264 to_y += video_yoffset;
1267 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1270 #if ENABLE_UNUSED_CODE
1271 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1272 int num_points, Uint32 color)
1277 for (i = 0; i < num_points - 1; i++)
1279 for (x = 0; x < line_width; x++)
1281 for (y = 0; y < line_width; y++)
1283 int dx = x - line_width / 2;
1284 int dy = y - line_width / 2;
1286 if ((x == 0 && y == 0) ||
1287 (x == 0 && y == line_width - 1) ||
1288 (x == line_width - 1 && y == 0) ||
1289 (x == line_width - 1 && y == line_width - 1))
1292 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1293 points[i+1].x + dx, points[i+1].y + dy, color);
1300 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1302 SDL_Surface *surface = src_bitmap->surface;
1304 if (src_bitmap == backbuffer || src_bitmap == window)
1310 switch (surface->format->BytesPerPixel)
1312 case 1: /* assuming 8-bpp */
1314 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1318 case 2: /* probably 15-bpp or 16-bpp */
1320 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1324 case 3: /* slow 24-bpp mode; usually not used */
1326 /* does this work? */
1327 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1331 shift = surface->format->Rshift;
1332 color |= *(pix + shift / 8) >> shift;
1333 shift = surface->format->Gshift;
1334 color |= *(pix + shift / 8) >> shift;
1335 shift = surface->format->Bshift;
1336 color |= *(pix + shift / 8) >> shift;
1342 case 4: /* probably 32-bpp */
1344 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1353 /* ========================================================================= */
1354 /* The following functions were taken from the SGE library */
1355 /* (SDL Graphics Extension Library) by Anders Lindström */
1356 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1357 /* ========================================================================= */
1359 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1361 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1363 switch (surface->format->BytesPerPixel)
1367 /* Assuming 8-bpp */
1368 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1374 /* Probably 15-bpp or 16-bpp */
1375 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1381 /* Slow 24-bpp mode, usually not used */
1385 /* Gack - slow, but endian correct */
1386 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1387 shift = surface->format->Rshift;
1388 *(pix+shift/8) = color>>shift;
1389 shift = surface->format->Gshift;
1390 *(pix+shift/8) = color>>shift;
1391 shift = surface->format->Bshift;
1392 *(pix+shift/8) = color>>shift;
1398 /* Probably 32-bpp */
1399 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1406 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1407 Uint8 R, Uint8 G, Uint8 B)
1409 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1412 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1414 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1417 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1419 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1422 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1427 /* Gack - slow, but endian correct */
1428 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1429 shift = surface->format->Rshift;
1430 *(pix+shift/8) = color>>shift;
1431 shift = surface->format->Gshift;
1432 *(pix+shift/8) = color>>shift;
1433 shift = surface->format->Bshift;
1434 *(pix+shift/8) = color>>shift;
1437 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1439 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1442 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1444 switch (dest->format->BytesPerPixel)
1447 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1451 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1455 _PutPixel24(dest,x,y,color);
1459 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1464 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1466 if (SDL_MUSTLOCK(surface))
1468 if (SDL_LockSurface(surface) < 0)
1474 _PutPixel(surface, x, y, color);
1476 if (SDL_MUSTLOCK(surface))
1478 SDL_UnlockSurface(surface);
1482 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1483 Uint8 r, Uint8 g, Uint8 b)
1485 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1488 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1490 if (y >= 0 && y <= dest->h - 1)
1492 switch (dest->format->BytesPerPixel)
1495 return y*dest->pitch;
1499 return y*dest->pitch/2;
1503 return y*dest->pitch;
1507 return y*dest->pitch/4;
1515 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1517 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1519 switch (surface->format->BytesPerPixel)
1523 /* Assuming 8-bpp */
1524 *((Uint8 *)surface->pixels + ypitch + x) = color;
1530 /* Probably 15-bpp or 16-bpp */
1531 *((Uint16 *)surface->pixels + ypitch + x) = color;
1537 /* Slow 24-bpp mode, usually not used */
1541 /* Gack - slow, but endian correct */
1542 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1543 shift = surface->format->Rshift;
1544 *(pix+shift/8) = color>>shift;
1545 shift = surface->format->Gshift;
1546 *(pix+shift/8) = color>>shift;
1547 shift = surface->format->Bshift;
1548 *(pix+shift/8) = color>>shift;
1554 /* Probably 32-bpp */
1555 *((Uint32 *)surface->pixels + ypitch + x) = color;
1562 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1567 if (SDL_MUSTLOCK(Surface))
1569 if (SDL_LockSurface(Surface) < 0)
1582 /* Do the clipping */
1583 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1587 if (x2 > Surface->w - 1)
1588 x2 = Surface->w - 1;
1595 SDL_FillRect(Surface, &l, Color);
1597 if (SDL_MUSTLOCK(Surface))
1599 SDL_UnlockSurface(Surface);
1603 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1604 Uint8 R, Uint8 G, Uint8 B)
1606 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1609 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1620 /* Do the clipping */
1621 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1625 if (x2 > Surface->w - 1)
1626 x2 = Surface->w - 1;
1633 SDL_FillRect(Surface, &l, Color);
1636 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1641 if (SDL_MUSTLOCK(Surface))
1643 if (SDL_LockSurface(Surface) < 0)
1656 /* Do the clipping */
1657 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1661 if (y2 > Surface->h - 1)
1662 y2 = Surface->h - 1;
1669 SDL_FillRect(Surface, &l, Color);
1671 if (SDL_MUSTLOCK(Surface))
1673 SDL_UnlockSurface(Surface);
1677 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1678 Uint8 R, Uint8 G, Uint8 B)
1680 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1683 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1694 /* Do the clipping */
1695 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1699 if (y2 > Surface->h - 1)
1700 y2 = Surface->h - 1;
1707 SDL_FillRect(Surface, &l, Color);
1710 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1711 Sint16 x2, Sint16 y2, Uint32 Color,
1712 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1715 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1720 sdx = (dx < 0) ? -1 : 1;
1721 sdy = (dy < 0) ? -1 : 1;
1733 for (x = 0; x < dx; x++)
1735 Callback(Surface, px, py, Color);
1749 for (y = 0; y < dy; y++)
1751 Callback(Surface, px, py, Color);
1765 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1766 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1767 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1770 sge_DoLine(Surface, X1, Y1, X2, Y2,
1771 SDL_MapRGB(Surface->format, R, G, B), Callback);
1774 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1777 if (SDL_MUSTLOCK(Surface))
1779 if (SDL_LockSurface(Surface) < 0)
1784 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1786 /* unlock the display */
1787 if (SDL_MUSTLOCK(Surface))
1789 SDL_UnlockSurface(Surface);
1793 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1794 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1796 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1799 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1801 if (dst_bitmap == backbuffer || dst_bitmap == window)
1807 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1812 -----------------------------------------------------------------------------
1813 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1814 -----------------------------------------------------------------------------
1817 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1818 int width, int height, Uint32 color)
1822 for (y = src_y; y < src_y + height; y++)
1824 for (x = src_x; x < src_x + width; x++)
1826 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1828 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1833 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1834 int src_x, int src_y, int width, int height,
1835 int dst_x, int dst_y)
1839 for (y = 0; y < height; y++)
1841 for (x = 0; x < width; x++)
1843 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1845 if (pixel != BLACK_PIXEL)
1846 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1852 /* ========================================================================= */
1853 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1854 /* (Rotozoomer) by Andreas Schiffler */
1855 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1856 /* ========================================================================= */
1859 -----------------------------------------------------------------------------
1862 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1863 -----------------------------------------------------------------------------
1874 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1877 tColorRGBA *sp, *csp, *dp;
1881 sp = csp = (tColorRGBA *) src->pixels;
1882 dp = (tColorRGBA *) dst->pixels;
1883 dgap = dst->pitch - dst->w * 4;
1885 for (y = 0; y < dst->h; y++)
1889 for (x = 0; x < dst->w; x++)
1891 tColorRGBA *sp0 = sp;
1892 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1893 tColorRGBA *sp00 = &sp0[0];
1894 tColorRGBA *sp01 = &sp0[1];
1895 tColorRGBA *sp10 = &sp1[0];
1896 tColorRGBA *sp11 = &sp1[1];
1899 /* create new color pixel from all four source color pixels */
1900 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1901 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1902 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1903 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1908 /* advance source pointers */
1911 /* advance destination pointer */
1915 /* advance source pointer */
1916 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1918 /* advance destination pointers */
1919 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1925 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1927 int x, y, *sax, *say, *csax, *csay;
1929 tColorRGBA *sp, *csp, *csp0, *dp;
1932 /* use specialized zoom function when scaling down to exactly half size */
1933 if (src->w == 2 * dst->w &&
1934 src->h == 2 * dst->h)
1935 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1937 /* variable setup */
1938 sx = (float) src->w / (float) dst->w;
1939 sy = (float) src->h / (float) dst->h;
1941 /* allocate memory for row increments */
1942 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1943 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1945 /* precalculate row increments */
1946 for (x = 0; x <= dst->w; x++)
1947 *csax++ = (int)(sx * x);
1949 for (y = 0; y <= dst->h; y++)
1950 *csay++ = (int)(sy * y);
1953 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1954 dp = (tColorRGBA *) dst->pixels;
1955 dgap = dst->pitch - dst->w * 4;
1958 for (y = 0; y < dst->h; y++)
1963 for (x = 0; x < dst->w; x++)
1968 /* advance source pointers */
1972 /* advance destination pointer */
1976 /* advance source pointer */
1978 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1980 /* advance destination pointers */
1981 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1991 -----------------------------------------------------------------------------
1994 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1995 -----------------------------------------------------------------------------
1998 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2000 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2001 Uint8 *sp, *dp, *csp;
2004 /* variable setup */
2005 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2006 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2008 /* allocate memory for row increments */
2009 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2010 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2012 /* precalculate row increments */
2015 for (x = 0; x < dst->w; x++)
2018 *csax = (csx >> 16);
2025 for (y = 0; y < dst->h; y++)
2028 *csay = (csy >> 16);
2035 for (x = 0; x < dst->w; x++)
2043 for (y = 0; y < dst->h; y++)
2050 sp = csp = (Uint8 *) src->pixels;
2051 dp = (Uint8 *) dst->pixels;
2052 dgap = dst->pitch - dst->w;
2056 for (y = 0; y < dst->h; y++)
2060 for (x = 0; x < dst->w; x++)
2065 /* advance source pointers */
2069 /* advance destination pointer */
2073 /* advance source pointer (for row) */
2074 csp += ((*csay) * src->pitch);
2077 /* advance destination pointers */
2088 -----------------------------------------------------------------------------
2091 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2092 'zoomx' and 'zoomy' are scaling factors for width and height.
2093 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2094 into a 32bit RGBA format on the fly.
2095 -----------------------------------------------------------------------------
2098 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2100 SDL_Surface *zoom_src = NULL;
2101 SDL_Surface *zoom_dst = NULL;
2102 boolean is_converted = FALSE;
2109 /* determine if source surface is 32 bit or 8 bit */
2110 is_32bit = (src->format->BitsPerPixel == 32);
2112 if (is_32bit || src->format->BitsPerPixel == 8)
2114 /* use source surface 'as is' */
2119 /* new source surface is 32 bit with a defined RGB ordering */
2120 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2121 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2122 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2124 is_converted = TRUE;
2127 /* allocate surface to completely contain the zoomed surface */
2130 /* target surface is 32 bit with source RGBA/ABGR ordering */
2131 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2132 zoom_src->format->Rmask,
2133 zoom_src->format->Gmask,
2134 zoom_src->format->Bmask, 0);
2138 /* target surface is 8 bit */
2139 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2143 /* lock source surface */
2144 SDL_LockSurface(zoom_src);
2146 /* check which kind of surface we have */
2149 /* call the 32 bit transformation routine to do the zooming */
2150 zoomSurfaceRGBA(zoom_src, zoom_dst);
2155 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2156 zoom_dst->format->palette->colors[i] =
2157 zoom_src->format->palette->colors[i];
2158 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2160 /* call the 8 bit transformation routine to do the zooming */
2161 zoomSurfaceY(zoom_src, zoom_dst);
2164 /* unlock source surface */
2165 SDL_UnlockSurface(zoom_src);
2167 /* free temporary surface */
2169 SDL_FreeSurface(zoom_src);
2171 /* return destination surface */
2175 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2177 Bitmap *dst_bitmap = CreateBitmapStruct();
2178 SDL_Surface **dst_surface = &dst_bitmap->surface;
2180 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2181 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2183 dst_bitmap->width = dst_width;
2184 dst_bitmap->height = dst_height;
2186 /* create zoomed temporary surface from source surface */
2187 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2189 /* create native format destination surface from zoomed temporary surface */
2190 SDLSetNativeSurface(dst_surface);
2196 /* ========================================================================= */
2197 /* load image to bitmap */
2198 /* ========================================================================= */
2200 Bitmap *SDLLoadImage(char *filename)
2202 Bitmap *new_bitmap = CreateBitmapStruct();
2203 SDL_Surface *sdl_image_tmp;
2205 print_timestamp_init("SDLLoadImage");
2207 print_timestamp_time(getBaseNamePtr(filename));
2209 /* load image to temporary surface */
2210 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2212 SetError("IMG_Load(): %s", SDL_GetError());
2217 print_timestamp_time("IMG_Load");
2219 UPDATE_BUSY_STATE();
2221 /* create native non-transparent surface for current image */
2222 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2224 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2229 print_timestamp_time("SDL_DisplayFormat (opaque)");
2231 UPDATE_BUSY_STATE();
2233 /* create native transparent surface for current image */
2234 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2235 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2237 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2239 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2244 print_timestamp_time("SDL_DisplayFormat (masked)");
2246 UPDATE_BUSY_STATE();
2248 /* free temporary surface */
2249 SDL_FreeSurface(sdl_image_tmp);
2251 new_bitmap->width = new_bitmap->surface->w;
2252 new_bitmap->height = new_bitmap->surface->h;
2254 print_timestamp_done("SDLLoadImage");
2260 /* ------------------------------------------------------------------------- */
2261 /* custom cursor fuctions */
2262 /* ------------------------------------------------------------------------- */
2264 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2266 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2267 cursor_info->width, cursor_info->height,
2268 cursor_info->hot_x, cursor_info->hot_y);
2271 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2273 static struct MouseCursorInfo *last_cursor_info = NULL;
2274 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2275 static SDL_Cursor *cursor_default = NULL;
2276 static SDL_Cursor *cursor_current = NULL;
2278 /* if invoked for the first time, store the SDL default cursor */
2279 if (cursor_default == NULL)
2280 cursor_default = SDL_GetCursor();
2282 /* only create new cursor if cursor info (custom only) has changed */
2283 if (cursor_info != NULL && cursor_info != last_cursor_info)
2285 cursor_current = create_cursor(cursor_info);
2286 last_cursor_info = cursor_info;
2289 /* only set new cursor if cursor info (custom or NULL) has changed */
2290 if (cursor_info != last_cursor_info2)
2291 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2293 last_cursor_info2 = cursor_info;
2297 /* ========================================================================= */
2298 /* audio functions */
2299 /* ========================================================================= */
2301 void SDLOpenAudio(void)
2303 #if !defined(TARGET_SDL2)
2304 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2305 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2308 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2310 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2314 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2315 AUDIO_NUM_CHANNELS_STEREO,
2316 setup.system.audio_fragment_size) < 0)
2318 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2322 audio.sound_available = TRUE;
2323 audio.music_available = TRUE;
2324 audio.loops_available = TRUE;
2325 audio.sound_enabled = TRUE;
2327 /* set number of available mixer channels */
2328 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2329 audio.music_channel = MUSIC_CHANNEL;
2330 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2332 Mixer_InitChannels();
2335 void SDLCloseAudio(void)
2338 Mix_HaltChannel(-1);
2341 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2345 /* ========================================================================= */
2346 /* event functions */
2347 /* ========================================================================= */
2349 void SDLNextEvent(Event *event)
2351 SDL_WaitEvent(event);
2353 if (event->type == EVENT_BUTTONPRESS ||
2354 event->type == EVENT_BUTTONRELEASE)
2356 if (((ButtonEvent *)event)->x > video_xoffset)
2357 ((ButtonEvent *)event)->x -= video_xoffset;
2359 ((ButtonEvent *)event)->x = 0;
2360 if (((ButtonEvent *)event)->y > video_yoffset)
2361 ((ButtonEvent *)event)->y -= video_yoffset;
2363 ((ButtonEvent *)event)->y = 0;
2365 else if (event->type == EVENT_MOTIONNOTIFY)
2367 if (((MotionEvent *)event)->x > video_xoffset)
2368 ((MotionEvent *)event)->x -= video_xoffset;
2370 ((MotionEvent *)event)->x = 0;
2371 if (((MotionEvent *)event)->y > video_yoffset)
2372 ((MotionEvent *)event)->y -= video_yoffset;
2374 ((MotionEvent *)event)->y = 0;
2378 void SDLHandleWindowManagerEvent(Event *event)
2381 #if defined(PLATFORM_WIN32)
2382 // experimental drag and drop code
2384 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2385 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2387 #if defined(TARGET_SDL2)
2388 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2390 if (syswmmsg->msg == WM_DROPFILES)
2393 #if defined(TARGET_SDL2)
2394 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2396 HDROP hdrop = (HDROP)syswmmsg->wParam;
2400 printf("::: SDL_SYSWMEVENT:\n");
2402 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2404 for (i = 0; i < num_files; i++)
2406 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2407 char buffer[buffer_len + 1];
2409 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2411 printf("::: - '%s'\n", buffer);
2414 #if defined(TARGET_SDL2)
2415 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2417 DragFinish((HDROP)syswmmsg->wParam);
2425 /* ========================================================================= */
2426 /* joystick functions */
2427 /* ========================================================================= */
2429 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2430 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2431 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2433 static boolean SDLOpenJoystick(int nr)
2435 if (nr < 0 || nr > MAX_PLAYERS)
2438 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2441 static void SDLCloseJoystick(int nr)
2443 if (nr < 0 || nr > MAX_PLAYERS)
2446 SDL_JoystickClose(sdl_joystick[nr]);
2448 sdl_joystick[nr] = NULL;
2451 static boolean SDLCheckJoystickOpened(int nr)
2453 if (nr < 0 || nr > MAX_PLAYERS)
2456 #if defined(TARGET_SDL2)
2457 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2459 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2463 void HandleJoystickEvent(Event *event)
2467 case SDL_JOYAXISMOTION:
2468 if (event->jaxis.axis < 2)
2469 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2472 case SDL_JOYBUTTONDOWN:
2473 if (event->jbutton.button < 2)
2474 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2477 case SDL_JOYBUTTONUP:
2478 if (event->jbutton.button < 2)
2479 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2487 void SDLInitJoysticks()
2489 static boolean sdl_joystick_subsystem_initialized = FALSE;
2490 boolean print_warning = !sdl_joystick_subsystem_initialized;
2493 if (!sdl_joystick_subsystem_initialized)
2495 sdl_joystick_subsystem_initialized = TRUE;
2497 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2499 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2504 for (i = 0; i < MAX_PLAYERS; i++)
2506 /* get configured joystick for this player */
2507 char *device_name = setup.input[i].joy.device_name;
2508 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2510 if (joystick_nr >= SDL_NumJoysticks())
2512 if (setup.input[i].use_joystick && print_warning)
2513 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2518 /* misuse joystick file descriptor variable to store joystick number */
2519 joystick.fd[i] = joystick_nr;
2521 if (joystick_nr == -1)
2524 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2525 if (SDLCheckJoystickOpened(joystick_nr))
2526 SDLCloseJoystick(joystick_nr);
2528 if (!setup.input[i].use_joystick)
2531 if (!SDLOpenJoystick(joystick_nr))
2534 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2539 joystick.status = JOYSTICK_ACTIVATED;
2543 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2545 if (nr < 0 || nr >= MAX_PLAYERS)
2549 *x = sdl_js_axis[nr][0];
2551 *y = sdl_js_axis[nr][1];
2554 *b1 = sdl_js_button[nr][0];
2556 *b2 = sdl_js_button[nr][1];