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.sdl_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
719 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
721 #if defined(PLATFORM_WIN32)
723 SDL_SysWMinfo wminfo;
725 boolean wminfo_success = FALSE;
727 SDL_VERSION(&wminfo.version);
728 #if defined(TARGET_SDL2)
730 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
732 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
737 #if defined(TARGET_SDL2)
738 hwnd = wminfo.info.win.window;
740 hwnd = wminfo.window;
743 DragAcceptFiles(hwnd, TRUE);
751 void SDLSetWindowTitle()
753 #if defined(TARGET_SDL2)
754 SDL_SetWindowTitle(sdl_window, program.window_title);
756 SDL_WM_SetCaption(program.window_title, program.window_title);
760 #if defined(TARGET_SDL2)
761 void SDLSetWindowScaling(int window_scaling_percent)
763 if (sdl_window == NULL)
766 float window_scaling_factor = (float)window_scaling_percent / 100;
767 int new_window_width = (int)(window_scaling_factor * video.width);
768 int new_window_height = (int)(window_scaling_factor * video.height);
770 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
772 video.window_scaling_percent = window_scaling_percent;
773 video.window_width = new_window_width;
774 video.window_height = new_window_height;
779 void SDLSetWindowScalingQuality(char *window_scaling_quality)
781 if (sdl_texture == NULL)
784 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
786 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
787 SDL_PIXELFORMAT_ARGB8888,
788 SDL_TEXTUREACCESS_STREAMING,
789 video.width, video.height);
791 if (new_texture != NULL)
793 SDL_DestroyTexture(sdl_texture);
795 sdl_texture = new_texture;
800 video.window_scaling_quality = window_scaling_quality;
803 void SDLSetWindowFullscreen(boolean fullscreen)
805 if (sdl_window == NULL)
808 #if USE_DESKTOP_FULLSCREEN
809 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
811 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
814 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
815 video.fullscreen_enabled = fullscreen;
817 // if game started in fullscreen mode, window will also get fullscreen size
818 if (!fullscreen && video.fullscreen_initial)
820 SDLSetWindowScaling(setup.window_scaling_percent);
821 SDL_SetWindowPosition(sdl_window,
822 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
824 video.fullscreen_initial = FALSE;
828 void SDLRedrawWindow()
834 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
837 SDL_Surface *surface =
838 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
841 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
843 SDLSetNativeSurface(&surface);
845 bitmap->surface = surface;
848 void SDLFreeBitmapPointers(Bitmap *bitmap)
851 SDL_FreeSurface(bitmap->surface);
852 if (bitmap->surface_masked)
853 SDL_FreeSurface(bitmap->surface_masked);
854 bitmap->surface = NULL;
855 bitmap->surface_masked = NULL;
858 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
859 int src_x, int src_y, int width, int height,
860 int dst_x, int dst_y, int mask_mode)
862 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
863 SDL_Rect src_rect, dst_rect;
865 if (src_bitmap == backbuffer)
867 src_x += video_xoffset;
868 src_y += video_yoffset;
876 if (dst_bitmap == backbuffer || dst_bitmap == window)
878 dst_x += video_xoffset;
879 dst_y += video_yoffset;
887 // if (src_bitmap != backbuffer || dst_bitmap != window)
888 if (!(src_bitmap == backbuffer && dst_bitmap == window))
889 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
890 src_bitmap->surface_masked : src_bitmap->surface),
891 &src_rect, real_dst_bitmap->surface, &dst_rect);
893 #if defined(TARGET_SDL2)
894 if (dst_bitmap == window)
896 // SDL_UpdateWindowSurface(sdl_window);
897 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
898 UpdateScreen(&dst_rect);
901 if (dst_bitmap == window)
903 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
904 UpdateScreen(&dst_rect);
909 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
912 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
915 if (dst_bitmap == backbuffer || dst_bitmap == window)
926 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
928 #if defined(TARGET_SDL2)
929 if (dst_bitmap == window)
931 // SDL_UpdateWindowSurface(sdl_window);
932 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
936 if (dst_bitmap == window)
938 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
944 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
945 int fade_mode, int fade_delay, int post_delay,
946 void (*draw_border_function)(void))
948 static boolean initialization_needed = TRUE;
949 static SDL_Surface *surface_source = NULL;
950 static SDL_Surface *surface_target = NULL;
951 static SDL_Surface *surface_black = NULL;
952 SDL_Surface *surface_screen = backbuffer->surface;
953 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
954 SDL_Rect src_rect, dst_rect;
956 int src_x = x, src_y = y;
957 int dst_x = x, dst_y = y;
958 unsigned int time_last, time_current;
960 /* check if screen size has changed */
961 if (surface_source != NULL && (video.width != surface_source->w ||
962 video.height != surface_source->h))
964 SDL_FreeSurface(surface_source);
965 SDL_FreeSurface(surface_target);
966 SDL_FreeSurface(surface_black);
968 initialization_needed = TRUE;
976 dst_x += video_xoffset;
977 dst_y += video_yoffset;
981 dst_rect.w = width; /* (ignored) */
982 dst_rect.h = height; /* (ignored) */
984 dst_rect2 = dst_rect;
986 if (initialization_needed)
988 #if defined(TARGET_SDL2)
989 unsigned int flags = 0;
991 unsigned int flags = SDL_SRCALPHA;
993 /* use same surface type as screen surface */
994 if ((surface_screen->flags & SDL_HWSURFACE))
995 flags |= SDL_HWSURFACE;
997 flags |= SDL_SWSURFACE;
1000 /* create surface for temporary copy of screen buffer (source) */
1001 if ((surface_source =
1002 SDL_CreateRGBSurface(flags,
1005 surface_screen->format->BitsPerPixel,
1006 surface_screen->format->Rmask,
1007 surface_screen->format->Gmask,
1008 surface_screen->format->Bmask,
1009 surface_screen->format->Amask)) == NULL)
1010 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1012 /* create surface for cross-fading screen buffer (target) */
1013 if ((surface_target =
1014 SDL_CreateRGBSurface(flags,
1017 surface_screen->format->BitsPerPixel,
1018 surface_screen->format->Rmask,
1019 surface_screen->format->Gmask,
1020 surface_screen->format->Bmask,
1021 surface_screen->format->Amask)) == NULL)
1022 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1024 /* create black surface for fading from/to black */
1025 if ((surface_black =
1026 SDL_CreateRGBSurface(flags,
1029 surface_screen->format->BitsPerPixel,
1030 surface_screen->format->Rmask,
1031 surface_screen->format->Gmask,
1032 surface_screen->format->Bmask,
1033 surface_screen->format->Amask)) == NULL)
1034 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1036 /* completely fill the surface with black color pixels */
1037 SDL_FillRect(surface_black, NULL,
1038 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1040 initialization_needed = FALSE;
1043 /* copy source and target surfaces to temporary surfaces for fading */
1044 if (fade_mode & FADE_TYPE_TRANSFORM)
1046 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1047 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1049 else if (fade_mode & FADE_TYPE_FADE_IN)
1051 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1052 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1054 else /* FADE_TYPE_FADE_OUT */
1056 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1057 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1060 time_current = SDL_GetTicks();
1062 if (fade_mode == FADE_MODE_MELT)
1064 boolean done = FALSE;
1065 int melt_pixels = 2;
1066 int melt_columns = width / melt_pixels;
1067 int ypos[melt_columns];
1068 int max_steps = height / 8 + 32;
1073 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1074 #if defined(TARGET_SDL2)
1075 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1077 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1080 ypos[0] = -GetSimpleRandom(16);
1082 for (i = 1 ; i < melt_columns; i++)
1084 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1086 ypos[i] = ypos[i - 1] + r;
1099 time_last = time_current;
1100 time_current = SDL_GetTicks();
1101 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1102 steps_final = MIN(MAX(0, steps), max_steps);
1106 done = (steps_done >= steps_final);
1108 for (i = 0 ; i < melt_columns; i++)
1116 else if (ypos[i] < height)
1121 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1123 if (ypos[i] + dy >= height)
1124 dy = height - ypos[i];
1126 /* copy part of (appearing) target surface to upper area */
1127 src_rect.x = src_x + i * melt_pixels;
1128 // src_rect.y = src_y + ypos[i];
1130 src_rect.w = melt_pixels;
1132 src_rect.h = ypos[i] + dy;
1134 dst_rect.x = dst_x + i * melt_pixels;
1135 // dst_rect.y = dst_y + ypos[i];
1138 if (steps_done >= steps_final)
1139 SDL_BlitSurface(surface_target, &src_rect,
1140 surface_screen, &dst_rect);
1144 /* copy part of (disappearing) source surface to lower area */
1145 src_rect.x = src_x + i * melt_pixels;
1147 src_rect.w = melt_pixels;
1148 src_rect.h = height - ypos[i];
1150 dst_rect.x = dst_x + i * melt_pixels;
1151 dst_rect.y = dst_y + ypos[i];
1153 if (steps_done >= steps_final)
1154 SDL_BlitSurface(surface_source, &src_rect,
1155 surface_screen, &dst_rect);
1161 src_rect.x = src_x + i * melt_pixels;
1163 src_rect.w = melt_pixels;
1164 src_rect.h = height;
1166 dst_rect.x = dst_x + i * melt_pixels;
1169 if (steps_done >= steps_final)
1170 SDL_BlitSurface(surface_target, &src_rect,
1171 surface_screen, &dst_rect);
1175 if (steps_done >= steps_final)
1177 if (draw_border_function != NULL)
1178 draw_border_function();
1180 #if defined(TARGET_SDL2)
1181 // SDL_UpdateWindowSurface(sdl_window);
1182 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
1183 UpdateScreen(&dst_rect2);
1185 // SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1186 UpdateScreen(&dst_rect2);
1196 for (alpha = 0.0; alpha < 255.0;)
1198 time_last = time_current;
1199 time_current = SDL_GetTicks();
1200 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1201 alpha_final = MIN(MAX(0, alpha), 255);
1203 /* draw existing (source) image to screen buffer */
1204 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1206 /* draw new (target) image to screen buffer using alpha blending */
1207 #if defined(TARGET_SDL2)
1208 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1209 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1211 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1213 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1215 if (draw_border_function != NULL)
1216 draw_border_function();
1218 /* only update the region of the screen that is affected from fading */
1219 UpdateScreen(&dst_rect);
1226 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1227 int to_x, int to_y, Uint32 color)
1229 SDL_Surface *surface = dst_bitmap->surface;
1233 swap_numbers(&from_x, &to_x);
1236 swap_numbers(&from_y, &to_y);
1240 rect.w = (to_x - from_x + 1);
1241 rect.h = (to_y - from_y + 1);
1243 if (dst_bitmap == backbuffer || dst_bitmap == window)
1245 rect.x += video_xoffset;
1246 rect.y += video_yoffset;
1249 SDL_FillRect(surface, &rect, color);
1252 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1253 int to_x, int to_y, Uint32 color)
1255 if (dst_bitmap == backbuffer || dst_bitmap == window)
1257 from_x += video_xoffset;
1258 from_y += video_yoffset;
1259 to_x += video_xoffset;
1260 to_y += video_yoffset;
1263 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1266 #if ENABLE_UNUSED_CODE
1267 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1268 int num_points, Uint32 color)
1273 for (i = 0; i < num_points - 1; i++)
1275 for (x = 0; x < line_width; x++)
1277 for (y = 0; y < line_width; y++)
1279 int dx = x - line_width / 2;
1280 int dy = y - line_width / 2;
1282 if ((x == 0 && y == 0) ||
1283 (x == 0 && y == line_width - 1) ||
1284 (x == line_width - 1 && y == 0) ||
1285 (x == line_width - 1 && y == line_width - 1))
1288 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1289 points[i+1].x + dx, points[i+1].y + dy, color);
1296 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1298 SDL_Surface *surface = src_bitmap->surface;
1300 if (src_bitmap == backbuffer || src_bitmap == window)
1306 switch (surface->format->BytesPerPixel)
1308 case 1: /* assuming 8-bpp */
1310 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1314 case 2: /* probably 15-bpp or 16-bpp */
1316 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1320 case 3: /* slow 24-bpp mode; usually not used */
1322 /* does this work? */
1323 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1327 shift = surface->format->Rshift;
1328 color |= *(pix + shift / 8) >> shift;
1329 shift = surface->format->Gshift;
1330 color |= *(pix + shift / 8) >> shift;
1331 shift = surface->format->Bshift;
1332 color |= *(pix + shift / 8) >> shift;
1338 case 4: /* probably 32-bpp */
1340 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1349 /* ========================================================================= */
1350 /* The following functions were taken from the SGE library */
1351 /* (SDL Graphics Extension Library) by Anders Lindström */
1352 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1353 /* ========================================================================= */
1355 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1357 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1359 switch (surface->format->BytesPerPixel)
1363 /* Assuming 8-bpp */
1364 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1370 /* Probably 15-bpp or 16-bpp */
1371 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1377 /* Slow 24-bpp mode, usually not used */
1381 /* Gack - slow, but endian correct */
1382 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1383 shift = surface->format->Rshift;
1384 *(pix+shift/8) = color>>shift;
1385 shift = surface->format->Gshift;
1386 *(pix+shift/8) = color>>shift;
1387 shift = surface->format->Bshift;
1388 *(pix+shift/8) = color>>shift;
1394 /* Probably 32-bpp */
1395 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1402 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1403 Uint8 R, Uint8 G, Uint8 B)
1405 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1408 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1410 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1413 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1415 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1418 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1423 /* Gack - slow, but endian correct */
1424 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1425 shift = surface->format->Rshift;
1426 *(pix+shift/8) = color>>shift;
1427 shift = surface->format->Gshift;
1428 *(pix+shift/8) = color>>shift;
1429 shift = surface->format->Bshift;
1430 *(pix+shift/8) = color>>shift;
1433 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1435 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1438 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1440 switch (dest->format->BytesPerPixel)
1443 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1447 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1451 _PutPixel24(dest,x,y,color);
1455 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1460 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1462 if (SDL_MUSTLOCK(surface))
1464 if (SDL_LockSurface(surface) < 0)
1470 _PutPixel(surface, x, y, color);
1472 if (SDL_MUSTLOCK(surface))
1474 SDL_UnlockSurface(surface);
1478 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1479 Uint8 r, Uint8 g, Uint8 b)
1481 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1484 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1486 if (y >= 0 && y <= dest->h - 1)
1488 switch (dest->format->BytesPerPixel)
1491 return y*dest->pitch;
1495 return y*dest->pitch/2;
1499 return y*dest->pitch;
1503 return y*dest->pitch/4;
1511 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1513 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1515 switch (surface->format->BytesPerPixel)
1519 /* Assuming 8-bpp */
1520 *((Uint8 *)surface->pixels + ypitch + x) = color;
1526 /* Probably 15-bpp or 16-bpp */
1527 *((Uint16 *)surface->pixels + ypitch + x) = color;
1533 /* Slow 24-bpp mode, usually not used */
1537 /* Gack - slow, but endian correct */
1538 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1539 shift = surface->format->Rshift;
1540 *(pix+shift/8) = color>>shift;
1541 shift = surface->format->Gshift;
1542 *(pix+shift/8) = color>>shift;
1543 shift = surface->format->Bshift;
1544 *(pix+shift/8) = color>>shift;
1550 /* Probably 32-bpp */
1551 *((Uint32 *)surface->pixels + ypitch + x) = color;
1558 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1563 if (SDL_MUSTLOCK(Surface))
1565 if (SDL_LockSurface(Surface) < 0)
1578 /* Do the clipping */
1579 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1583 if (x2 > Surface->w - 1)
1584 x2 = Surface->w - 1;
1591 SDL_FillRect(Surface, &l, Color);
1593 if (SDL_MUSTLOCK(Surface))
1595 SDL_UnlockSurface(Surface);
1599 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1600 Uint8 R, Uint8 G, Uint8 B)
1602 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1605 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1616 /* Do the clipping */
1617 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1621 if (x2 > Surface->w - 1)
1622 x2 = Surface->w - 1;
1629 SDL_FillRect(Surface, &l, Color);
1632 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1637 if (SDL_MUSTLOCK(Surface))
1639 if (SDL_LockSurface(Surface) < 0)
1652 /* Do the clipping */
1653 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1657 if (y2 > Surface->h - 1)
1658 y2 = Surface->h - 1;
1665 SDL_FillRect(Surface, &l, Color);
1667 if (SDL_MUSTLOCK(Surface))
1669 SDL_UnlockSurface(Surface);
1673 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1674 Uint8 R, Uint8 G, Uint8 B)
1676 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1679 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1690 /* Do the clipping */
1691 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1695 if (y2 > Surface->h - 1)
1696 y2 = Surface->h - 1;
1703 SDL_FillRect(Surface, &l, Color);
1706 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1707 Sint16 x2, Sint16 y2, Uint32 Color,
1708 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1711 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1716 sdx = (dx < 0) ? -1 : 1;
1717 sdy = (dy < 0) ? -1 : 1;
1729 for (x = 0; x < dx; x++)
1731 Callback(Surface, px, py, Color);
1745 for (y = 0; y < dy; y++)
1747 Callback(Surface, px, py, Color);
1761 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1762 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1763 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1766 sge_DoLine(Surface, X1, Y1, X2, Y2,
1767 SDL_MapRGB(Surface->format, R, G, B), Callback);
1770 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1773 if (SDL_MUSTLOCK(Surface))
1775 if (SDL_LockSurface(Surface) < 0)
1780 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1782 /* unlock the display */
1783 if (SDL_MUSTLOCK(Surface))
1785 SDL_UnlockSurface(Surface);
1789 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1790 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1792 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1795 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1797 if (dst_bitmap == backbuffer || dst_bitmap == window)
1803 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1808 -----------------------------------------------------------------------------
1809 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1810 -----------------------------------------------------------------------------
1813 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1814 int width, int height, Uint32 color)
1818 for (y = src_y; y < src_y + height; y++)
1820 for (x = src_x; x < src_x + width; x++)
1822 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1824 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1829 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1830 int src_x, int src_y, int width, int height,
1831 int dst_x, int dst_y)
1835 for (y = 0; y < height; y++)
1837 for (x = 0; x < width; x++)
1839 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1841 if (pixel != BLACK_PIXEL)
1842 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1848 /* ========================================================================= */
1849 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1850 /* (Rotozoomer) by Andreas Schiffler */
1851 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1852 /* ========================================================================= */
1855 -----------------------------------------------------------------------------
1858 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1859 -----------------------------------------------------------------------------
1870 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1873 tColorRGBA *sp, *csp, *dp;
1877 sp = csp = (tColorRGBA *) src->pixels;
1878 dp = (tColorRGBA *) dst->pixels;
1879 dgap = dst->pitch - dst->w * 4;
1881 for (y = 0; y < dst->h; y++)
1885 for (x = 0; x < dst->w; x++)
1887 tColorRGBA *sp0 = sp;
1888 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1889 tColorRGBA *sp00 = &sp0[0];
1890 tColorRGBA *sp01 = &sp0[1];
1891 tColorRGBA *sp10 = &sp1[0];
1892 tColorRGBA *sp11 = &sp1[1];
1895 /* create new color pixel from all four source color pixels */
1896 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1897 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1898 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1899 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1904 /* advance source pointers */
1907 /* advance destination pointer */
1911 /* advance source pointer */
1912 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1914 /* advance destination pointers */
1915 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1921 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1923 int x, y, *sax, *say, *csax, *csay;
1925 tColorRGBA *sp, *csp, *csp0, *dp;
1928 /* use specialized zoom function when scaling down to exactly half size */
1929 if (src->w == 2 * dst->w &&
1930 src->h == 2 * dst->h)
1931 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1933 /* variable setup */
1934 sx = (float) src->w / (float) dst->w;
1935 sy = (float) src->h / (float) dst->h;
1937 /* allocate memory for row increments */
1938 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1939 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1941 /* precalculate row increments */
1942 for (x = 0; x <= dst->w; x++)
1943 *csax++ = (int)(sx * x);
1945 for (y = 0; y <= dst->h; y++)
1946 *csay++ = (int)(sy * y);
1949 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1950 dp = (tColorRGBA *) dst->pixels;
1951 dgap = dst->pitch - dst->w * 4;
1954 for (y = 0; y < dst->h; y++)
1959 for (x = 0; x < dst->w; x++)
1964 /* advance source pointers */
1968 /* advance destination pointer */
1972 /* advance source pointer */
1974 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1976 /* advance destination pointers */
1977 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1987 -----------------------------------------------------------------------------
1990 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1991 -----------------------------------------------------------------------------
1994 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1996 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1997 Uint8 *sp, *dp, *csp;
2000 /* variable setup */
2001 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2002 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2004 /* allocate memory for row increments */
2005 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2006 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2008 /* precalculate row increments */
2011 for (x = 0; x < dst->w; x++)
2014 *csax = (csx >> 16);
2021 for (y = 0; y < dst->h; y++)
2024 *csay = (csy >> 16);
2031 for (x = 0; x < dst->w; x++)
2039 for (y = 0; y < dst->h; y++)
2046 sp = csp = (Uint8 *) src->pixels;
2047 dp = (Uint8 *) dst->pixels;
2048 dgap = dst->pitch - dst->w;
2052 for (y = 0; y < dst->h; y++)
2056 for (x = 0; x < dst->w; x++)
2061 /* advance source pointers */
2065 /* advance destination pointer */
2069 /* advance source pointer (for row) */
2070 csp += ((*csay) * src->pitch);
2073 /* advance destination pointers */
2084 -----------------------------------------------------------------------------
2087 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2088 'zoomx' and 'zoomy' are scaling factors for width and height.
2089 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2090 into a 32bit RGBA format on the fly.
2091 -----------------------------------------------------------------------------
2094 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2096 SDL_Surface *zoom_src = NULL;
2097 SDL_Surface *zoom_dst = NULL;
2098 boolean is_converted = FALSE;
2105 /* determine if source surface is 32 bit or 8 bit */
2106 is_32bit = (src->format->BitsPerPixel == 32);
2108 if (is_32bit || src->format->BitsPerPixel == 8)
2110 /* use source surface 'as is' */
2115 /* new source surface is 32 bit with a defined RGB ordering */
2116 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2117 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2118 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2120 is_converted = TRUE;
2123 /* allocate surface to completely contain the zoomed surface */
2126 /* target surface is 32 bit with source RGBA/ABGR ordering */
2127 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2128 zoom_src->format->Rmask,
2129 zoom_src->format->Gmask,
2130 zoom_src->format->Bmask, 0);
2134 /* target surface is 8 bit */
2135 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2139 /* lock source surface */
2140 SDL_LockSurface(zoom_src);
2142 /* check which kind of surface we have */
2145 /* call the 32 bit transformation routine to do the zooming */
2146 zoomSurfaceRGBA(zoom_src, zoom_dst);
2151 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2152 zoom_dst->format->palette->colors[i] =
2153 zoom_src->format->palette->colors[i];
2154 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2156 /* call the 8 bit transformation routine to do the zooming */
2157 zoomSurfaceY(zoom_src, zoom_dst);
2160 /* unlock source surface */
2161 SDL_UnlockSurface(zoom_src);
2163 /* free temporary surface */
2165 SDL_FreeSurface(zoom_src);
2167 /* return destination surface */
2171 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2173 Bitmap *dst_bitmap = CreateBitmapStruct();
2174 SDL_Surface **dst_surface = &dst_bitmap->surface;
2176 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2177 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2179 dst_bitmap->width = dst_width;
2180 dst_bitmap->height = dst_height;
2182 /* create zoomed temporary surface from source surface */
2183 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2185 /* create native format destination surface from zoomed temporary surface */
2186 SDLSetNativeSurface(dst_surface);
2192 /* ========================================================================= */
2193 /* load image to bitmap */
2194 /* ========================================================================= */
2196 Bitmap *SDLLoadImage(char *filename)
2198 Bitmap *new_bitmap = CreateBitmapStruct();
2199 SDL_Surface *sdl_image_tmp;
2201 print_timestamp_init("SDLLoadImage");
2203 print_timestamp_time(getBaseNamePtr(filename));
2205 /* load image to temporary surface */
2206 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2208 SetError("IMG_Load(): %s", SDL_GetError());
2213 print_timestamp_time("IMG_Load");
2215 UPDATE_BUSY_STATE();
2217 /* create native non-transparent surface for current image */
2218 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2220 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2225 print_timestamp_time("SDL_DisplayFormat (opaque)");
2227 UPDATE_BUSY_STATE();
2229 /* create native transparent surface for current image */
2230 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2231 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2233 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2235 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2240 print_timestamp_time("SDL_DisplayFormat (masked)");
2242 UPDATE_BUSY_STATE();
2244 /* free temporary surface */
2245 SDL_FreeSurface(sdl_image_tmp);
2247 new_bitmap->width = new_bitmap->surface->w;
2248 new_bitmap->height = new_bitmap->surface->h;
2250 print_timestamp_done("SDLLoadImage");
2256 /* ------------------------------------------------------------------------- */
2257 /* custom cursor fuctions */
2258 /* ------------------------------------------------------------------------- */
2260 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2262 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2263 cursor_info->width, cursor_info->height,
2264 cursor_info->hot_x, cursor_info->hot_y);
2267 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2269 static struct MouseCursorInfo *last_cursor_info = NULL;
2270 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2271 static SDL_Cursor *cursor_default = NULL;
2272 static SDL_Cursor *cursor_current = NULL;
2274 /* if invoked for the first time, store the SDL default cursor */
2275 if (cursor_default == NULL)
2276 cursor_default = SDL_GetCursor();
2278 /* only create new cursor if cursor info (custom only) has changed */
2279 if (cursor_info != NULL && cursor_info != last_cursor_info)
2281 cursor_current = create_cursor(cursor_info);
2282 last_cursor_info = cursor_info;
2285 /* only set new cursor if cursor info (custom or NULL) has changed */
2286 if (cursor_info != last_cursor_info2)
2287 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2289 last_cursor_info2 = cursor_info;
2293 /* ========================================================================= */
2294 /* audio functions */
2295 /* ========================================================================= */
2297 void SDLOpenAudio(void)
2299 #if !defined(TARGET_SDL2)
2300 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2301 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2304 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2306 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2310 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2311 AUDIO_NUM_CHANNELS_STEREO,
2312 setup.system.audio_fragment_size) < 0)
2314 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2318 audio.sound_available = TRUE;
2319 audio.music_available = TRUE;
2320 audio.loops_available = TRUE;
2321 audio.sound_enabled = TRUE;
2323 /* set number of available mixer channels */
2324 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2325 audio.music_channel = MUSIC_CHANNEL;
2326 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2328 Mixer_InitChannels();
2331 void SDLCloseAudio(void)
2334 Mix_HaltChannel(-1);
2337 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2341 /* ========================================================================= */
2342 /* event functions */
2343 /* ========================================================================= */
2345 void SDLNextEvent(Event *event)
2347 SDL_WaitEvent(event);
2349 if (event->type == EVENT_BUTTONPRESS ||
2350 event->type == EVENT_BUTTONRELEASE)
2352 if (((ButtonEvent *)event)->x > video_xoffset)
2353 ((ButtonEvent *)event)->x -= video_xoffset;
2355 ((ButtonEvent *)event)->x = 0;
2356 if (((ButtonEvent *)event)->y > video_yoffset)
2357 ((ButtonEvent *)event)->y -= video_yoffset;
2359 ((ButtonEvent *)event)->y = 0;
2361 else if (event->type == EVENT_MOTIONNOTIFY)
2363 if (((MotionEvent *)event)->x > video_xoffset)
2364 ((MotionEvent *)event)->x -= video_xoffset;
2366 ((MotionEvent *)event)->x = 0;
2367 if (((MotionEvent *)event)->y > video_yoffset)
2368 ((MotionEvent *)event)->y -= video_yoffset;
2370 ((MotionEvent *)event)->y = 0;
2374 void SDLHandleWindowManagerEvent(Event *event)
2376 #if defined(PLATFORM_WIN32)
2377 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2378 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2380 #if defined(TARGET_SDL2)
2381 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2383 if (syswmmsg->msg == WM_DROPFILES)
2386 #if defined(TARGET_SDL2)
2387 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2389 HDROP hdrop = (HDROP)syswmmsg->wParam;
2393 printf("::: SDL_SYSWMEVENT:\n");
2395 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2397 for (i = 0; i < num_files; i++)
2399 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2400 char buffer[buffer_len + 1];
2402 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2404 printf("::: - '%s'\n", buffer);
2407 #if defined(TARGET_SDL2)
2408 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2410 DragFinish((HDROP)syswmmsg->wParam);
2417 /* ========================================================================= */
2418 /* joystick functions */
2419 /* ========================================================================= */
2421 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2422 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2423 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2425 static boolean SDLOpenJoystick(int nr)
2427 if (nr < 0 || nr > MAX_PLAYERS)
2430 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2433 static void SDLCloseJoystick(int nr)
2435 if (nr < 0 || nr > MAX_PLAYERS)
2438 SDL_JoystickClose(sdl_joystick[nr]);
2440 sdl_joystick[nr] = NULL;
2443 static boolean SDLCheckJoystickOpened(int nr)
2445 if (nr < 0 || nr > MAX_PLAYERS)
2448 #if defined(TARGET_SDL2)
2449 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2451 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2455 void HandleJoystickEvent(Event *event)
2459 case SDL_JOYAXISMOTION:
2460 if (event->jaxis.axis < 2)
2461 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2464 case SDL_JOYBUTTONDOWN:
2465 if (event->jbutton.button < 2)
2466 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2469 case SDL_JOYBUTTONUP:
2470 if (event->jbutton.button < 2)
2471 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2479 void SDLInitJoysticks()
2481 static boolean sdl_joystick_subsystem_initialized = FALSE;
2482 boolean print_warning = !sdl_joystick_subsystem_initialized;
2485 if (!sdl_joystick_subsystem_initialized)
2487 sdl_joystick_subsystem_initialized = TRUE;
2489 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2491 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2496 for (i = 0; i < MAX_PLAYERS; i++)
2498 /* get configured joystick for this player */
2499 char *device_name = setup.input[i].joy.device_name;
2500 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2502 if (joystick_nr >= SDL_NumJoysticks())
2504 if (setup.input[i].use_joystick && print_warning)
2505 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2510 /* misuse joystick file descriptor variable to store joystick number */
2511 joystick.fd[i] = joystick_nr;
2513 if (joystick_nr == -1)
2516 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2517 if (SDLCheckJoystickOpened(joystick_nr))
2518 SDLCloseJoystick(joystick_nr);
2520 if (!setup.input[i].use_joystick)
2523 if (!SDLOpenJoystick(joystick_nr))
2526 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2531 joystick.status = JOYSTICK_ACTIVATED;
2535 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2537 if (nr < 0 || nr >= MAX_PLAYERS)
2541 *x = sdl_js_axis[nr][0];
2543 *y = sdl_js_axis[nr][1];
2546 *b1 = sdl_js_button[nr][0];
2548 *b2 = sdl_js_button[nr][1];