1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
18 #define ENABLE_UNUSED_CODE 0 /* currently unused functions */
21 /* ========================================================================= */
23 /* ========================================================================= */
25 /* SDL internal variables */
26 #if defined(TARGET_SDL2)
27 static SDL_Window *sdl_window = NULL;
28 static SDL_Renderer *sdl_renderer = NULL;
29 static SDL_Texture *sdl_texture = NULL;
31 #define USE_RENDERER TRUE
34 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
35 static int fullscreen_width;
36 static int fullscreen_height;
37 static int fullscreen_xoffset;
38 static int fullscreen_yoffset;
39 static int video_xoffset;
40 static int video_yoffset;
41 static boolean limit_screen_updates = FALSE;
44 /* functions from SGE library */
45 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
47 void SDLLimitScreenUpdates(boolean enable)
49 limit_screen_updates = enable;
52 static void UpdateScreen(SDL_Rect *rect)
54 static unsigned int update_screen_delay = 0;
55 unsigned int update_screen_delay_value = 20; /* (milliseconds) */
57 if (limit_screen_updates &&
58 !DelayReached(&update_screen_delay, update_screen_delay_value))
61 LimitScreenUpdates(FALSE);
63 #if defined(TARGET_SDL2)
65 SDL_Surface *screen = backbuffer->surface;
69 int bytes_x = screen->pitch / video.width;
70 int bytes_y = screen->pitch;
72 if (video.fullscreen_enabled)
73 bytes_x = screen->pitch / fullscreen_width;
75 SDL_UpdateTexture(sdl_texture, rect,
76 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
81 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
83 SDL_RenderClear(sdl_renderer);
84 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
85 SDL_RenderPresent(sdl_renderer);
88 SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
90 SDL_UpdateWindowSurface(sdl_window);
95 SDL_UpdateRects(backbuffer->surface, 1, rect);
97 SDL_UpdateRect(backbuffer->surface, 0, 0, 0, 0);
101 static void setFullscreenParameters(char *fullscreen_mode_string)
103 #if defined(TARGET_SDL2)
104 fullscreen_width = video.width;
105 fullscreen_height = video.height;
106 fullscreen_xoffset = 0;
107 fullscreen_yoffset = 0;
111 struct ScreenModeInfo *fullscreen_mode;
114 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
116 if (fullscreen_mode == NULL)
119 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
121 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
122 fullscreen_mode->height == video.fullscreen_modes[i].height)
124 fullscreen_width = fullscreen_mode->width;
125 fullscreen_height = fullscreen_mode->height;
127 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
128 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
136 static void SDLSetWindowIcon(char *basename)
138 /* (setting the window icon on Mac OS X would replace the high-quality
139 dock icon with the currently smaller (and uglier) icon from file) */
141 #if !defined(PLATFORM_MACOSX)
142 char *filename = getCustomImageFilename(basename);
143 SDL_Surface *surface;
145 if (filename == NULL)
147 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
152 if ((surface = IMG_Load(filename)) == NULL)
154 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
159 /* set transparent color */
160 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
161 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
163 #if defined(TARGET_SDL2)
164 SDL_SetWindowIcon(sdl_window, surface);
166 SDL_WM_SetIcon(surface, NULL);
171 #if defined(TARGET_SDL2)
173 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
174 SDL_PixelFormat *format2)
176 return (format1->format == format2->format &&
177 format1->BitsPerPixel == format2->BitsPerPixel &&
178 format1->BytesPerPixel == format2->BytesPerPixel &&
179 format1->Rmask == format2->Rmask &&
180 format1->Gmask == format2->Gmask &&
181 format1->Bmask == format2->Bmask &&
182 format1->Amask == format2->Amask);
185 boolean SDLSetNativeSurface(SDL_Surface **surface)
187 SDL_Surface *new_surface;
189 if (surface == NULL ||
191 backbuffer == NULL ||
192 backbuffer->surface == NULL)
195 // if pixel format already optimized for destination surface, do nothing
196 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
199 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
201 SDL_FreeSurface(*surface);
203 *surface = new_surface;
208 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
213 if (backbuffer == NULL ||
214 backbuffer->surface == NULL)
215 return SDL_ConvertSurface(surface, surface->format, 0);
217 return SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
220 SDL_Surface *SDL_DisplayFormat(SDL_Surface *surface)
222 if (surface == NULL ||
223 backbuffer == NULL ||
224 backbuffer->surface == NULL)
227 return SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
232 boolean SDLSetNativeSurface(SDL_Surface **surface)
234 SDL_Surface *new_surface;
239 new_surface = SDL_DisplayFormat(*surface);
241 if (new_surface == NULL)
242 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
244 SDL_FreeSurface(*surface);
246 *surface = new_surface;
251 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
253 SDL_Surface *new_surface = SDL_DisplayFormat(surface);
255 if (new_surface == NULL)
256 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
263 void SDLInitVideoDisplay(void)
265 #if !defined(TARGET_SDL2)
266 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
267 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
269 SDL_putenv("SDL_VIDEO_CENTERED=1");
272 /* initialize SDL video */
273 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
274 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
276 /* set default SDL depth */
277 #if !defined(TARGET_SDL2)
278 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
280 video.default_depth = 32; // (how to determine video depth in SDL2?)
284 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
287 #if !defined(TARGET_SDL2)
288 static int screen_xy[][2] =
296 SDL_Rect **modes = NULL;
297 boolean hardware_fullscreen_available = TRUE;
300 /* default: normal game window size */
301 fullscreen_width = video.width;
302 fullscreen_height = video.height;
303 fullscreen_xoffset = 0;
304 fullscreen_yoffset = 0;
306 #if !defined(TARGET_SDL2)
307 /* determine required standard fullscreen mode for game screen size */
308 for (i = 0; screen_xy[i][0] != -1; i++)
310 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
312 fullscreen_width = screen_xy[i][0];
313 fullscreen_height = screen_xy[i][1];
319 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
320 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
323 checked_free(video.fullscreen_modes);
325 video.fullscreen_modes = NULL;
326 video.fullscreen_mode_current = NULL;
328 video.window_scaling_percent = setup.window_scaling_percent;
329 video.window_scaling_quality = setup.window_scaling_quality;
331 #if defined(TARGET_SDL2)
332 int num_displays = SDL_GetNumVideoDisplays();
334 if (num_displays > 0)
336 // currently only display modes of first display supported
337 int num_modes = SDL_GetNumDisplayModes(0);
341 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
343 for (i = 0; i < num_modes; i++)
345 SDL_DisplayMode mode;
347 if (SDL_GetDisplayMode(0, i, &mode) < 0)
350 modes[i] = checked_calloc(sizeof(SDL_Rect));
352 modes[i]->w = mode.w;
353 modes[i]->h = mode.h;
358 /* get available hardware supported fullscreen modes */
359 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
364 /* no hardware screen modes available => no fullscreen mode support */
365 // video.fullscreen_available = FALSE;
366 hardware_fullscreen_available = FALSE;
368 else if (modes == (SDL_Rect **)-1)
370 /* fullscreen resolution is not restricted -- all resolutions available */
371 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
373 /* use native video buffer size for fullscreen mode */
374 video.fullscreen_modes[0].width = video.width;
375 video.fullscreen_modes[0].height = video.height;
377 video.fullscreen_modes[1].width = -1;
378 video.fullscreen_modes[1].height = -1;
382 /* in this case, a certain number of screen modes is available */
385 for (i = 0; modes[i] != NULL; i++)
387 boolean found_mode = FALSE;
389 /* screen mode is smaller than video buffer size -- skip it */
390 if (modes[i]->w < video.width || modes[i]->h < video.height)
393 if (video.fullscreen_modes != NULL)
394 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
395 if (modes[i]->w == video.fullscreen_modes[j].width &&
396 modes[i]->h == video.fullscreen_modes[j].height)
399 if (found_mode) /* screen mode already stored -- skip it */
402 /* new mode found; add it to list of available fullscreen modes */
406 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
408 sizeof(struct ScreenModeInfo));
410 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
411 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
413 video.fullscreen_modes[num_modes].width = -1;
414 video.fullscreen_modes[num_modes].height = -1;
419 /* no appropriate screen modes available => no fullscreen mode support */
420 // video.fullscreen_available = FALSE;
421 hardware_fullscreen_available = FALSE;
425 video.fullscreen_available = hardware_fullscreen_available;
427 #if USE_DESKTOP_FULLSCREEN
428 // in SDL 2.0, there is always support for desktop fullscreen mode
429 // (in SDL 1.2, there is only support for "real" fullscreen mode)
430 video.fullscreen_available = TRUE;
433 #if defined(TARGET_SDL2)
436 for (i = 0; modes[i] != NULL; i++)
437 checked_free(modes[i]);
443 /* open SDL video output device (window or fullscreen mode) */
444 if (!SDLSetVideoMode(backbuffer, fullscreen))
445 Error(ERR_EXIT, "setting video mode failed");
447 /* !!! SDL2 can only set the window icon if the window already exists !!! */
448 /* set window icon */
449 SDLSetWindowIcon(program.sdl_icon_filename);
451 /* set window and icon title */
452 #if defined(TARGET_SDL2)
453 SDL_SetWindowTitle(sdl_window, program.window_title);
455 SDL_WM_SetCaption(program.window_title, program.window_title);
458 /* SDL cannot directly draw to the visible video framebuffer like X11,
459 but always uses a backbuffer, which is then blitted to the visible
460 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
461 visible video framebuffer with 'SDL_Flip', if the hardware supports
462 this). Therefore do not use an additional backbuffer for drawing, but
463 use a symbolic buffer (distinguishable from the SDL backbuffer) called
464 'window', which indicates that the SDL backbuffer should be updated to
465 the visible video framebuffer when attempting to blit to it.
467 For convenience, it seems to be a good idea to create this symbolic
468 buffer 'window' at the same size as the SDL backbuffer. Although it
469 should never be drawn to directly, it would do no harm nevertheless. */
471 /* create additional (symbolic) buffer for double-buffering */
472 ReCreateBitmap(window, video.width, video.height, video.depth);
475 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
478 SDL_Surface *new_surface = NULL;
480 #if defined(TARGET_SDL2)
481 static boolean fullscreen_enabled = FALSE;
482 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
483 #if USE_DESKTOP_FULLSCREEN
484 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
486 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
490 int surface_flags_window = SURFACE_FLAGS;
491 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
494 int width = (fullscreen ? fullscreen_width : video.width);
495 int height = (fullscreen ? fullscreen_height : video.height);
496 int surface_flags = (fullscreen ? surface_flags_fullscreen :
497 surface_flags_window);
499 // default window size is unscaled
500 video.window_width = video.width;
501 video.window_height = video.height;
503 #if defined(TARGET_SDL2)
505 // store if initial screen mode on game start is fullscreen mode
506 if (sdl_window == NULL)
507 video.fullscreen_initial = fullscreen;
510 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
511 #if !USE_DESKTOP_FULLSCREEN
512 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
515 video.window_width = window_scaling_factor * width;
516 video.window_height = window_scaling_factor * height;
518 if ((*backbuffer)->surface)
520 SDL_FreeSurface((*backbuffer)->surface);
521 (*backbuffer)->surface = NULL;
526 SDL_DestroyTexture(sdl_texture);
530 if (!(fullscreen && fullscreen_enabled))
534 SDL_DestroyRenderer(sdl_renderer);
540 SDL_DestroyWindow(sdl_window);
545 if (sdl_window == NULL)
546 sdl_window = SDL_CreateWindow(program.window_title,
547 SDL_WINDOWPOS_CENTERED,
548 SDL_WINDOWPOS_CENTERED,
549 #if USE_DESKTOP_FULLSCREEN
553 (int)(screen_scaling_factor * width),
554 (int)(screen_scaling_factor * height),
558 if (sdl_window != NULL)
561 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
562 *without* enabling 2D/3D acceleration and/or guest additions installed,
563 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
564 it will try to use accelerated graphics and apparently fails miserably) */
565 if (sdl_renderer == NULL)
566 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
568 if (sdl_renderer == NULL)
569 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
572 if (sdl_renderer != NULL)
574 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
575 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
576 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
578 sdl_texture = SDL_CreateTexture(sdl_renderer,
579 SDL_PIXELFORMAT_ARGB8888,
580 SDL_TEXTUREACCESS_STREAMING,
583 if (sdl_texture != NULL)
585 // use SDL default values for RGB masks and no alpha channel
586 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
588 if (new_surface == NULL)
589 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
594 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
599 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
604 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
610 SDL_DestroyWindow(sdl_window);
612 sdl_window = SDL_CreateWindow(program.window_title,
613 SDL_WINDOWPOS_CENTERED,
614 SDL_WINDOWPOS_CENTERED,
618 if (sdl_window != NULL)
619 new_surface = SDL_GetWindowSurface(sdl_window);
623 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
626 #if defined(TARGET_SDL2)
627 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
628 if (new_surface != NULL)
629 fullscreen_enabled = fullscreen;
635 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
637 boolean success = TRUE;
638 SDL_Surface *new_surface = NULL;
642 if (*backbuffer == NULL)
643 *backbuffer = CreateBitmapStruct();
645 /* (real bitmap might be larger in fullscreen mode with video offsets) */
646 (*backbuffer)->width = video.width;
647 (*backbuffer)->height = video.height;
649 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
651 setFullscreenParameters(setup.fullscreen_mode);
653 video_xoffset = fullscreen_xoffset;
654 video_yoffset = fullscreen_yoffset;
656 /* switch display to fullscreen mode, if available */
657 new_surface = SDLCreateScreen(backbuffer, TRUE);
659 if (new_surface == NULL)
661 /* switching display to fullscreen mode failed */
662 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
664 /* do not try it again */
665 video.fullscreen_available = FALSE;
671 (*backbuffer)->surface = new_surface;
673 video.fullscreen_enabled = TRUE;
674 video.fullscreen_mode_current = setup.fullscreen_mode;
680 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
685 /* switch display to window mode */
686 new_surface = SDLCreateScreen(backbuffer, FALSE);
688 if (new_surface == NULL)
690 /* switching display to window mode failed -- should not happen */
691 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
697 (*backbuffer)->surface = new_surface;
699 video.fullscreen_enabled = FALSE;
700 video.window_scaling_percent = setup.window_scaling_percent;
701 video.window_scaling_quality = setup.window_scaling_quality;
707 #if defined(TARGET_SDL2)
708 SDLRedrawWindow(); // map window
711 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
713 #if defined(PLATFORM_WIN32)
715 SDL_SysWMinfo wminfo;
717 boolean wminfo_success = FALSE;
719 SDL_VERSION(&wminfo.version);
720 #if defined(TARGET_SDL2)
722 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
724 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
729 #if defined(TARGET_SDL2)
730 hwnd = wminfo.info.win.window;
732 hwnd = wminfo.window;
735 DragAcceptFiles(hwnd, TRUE);
743 void SDLSetWindowTitle()
745 #if defined(TARGET_SDL2)
746 SDL_SetWindowTitle(sdl_window, program.window_title);
748 SDL_WM_SetCaption(program.window_title, program.window_title);
752 #if defined(TARGET_SDL2)
753 void SDLSetWindowScaling(int window_scaling_percent)
755 if (sdl_window == NULL)
758 float window_scaling_factor = (float)window_scaling_percent / 100;
759 int new_window_width = (int)(window_scaling_factor * video.width);
760 int new_window_height = (int)(window_scaling_factor * video.height);
762 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
764 video.window_scaling_percent = window_scaling_percent;
765 video.window_width = new_window_width;
766 video.window_height = new_window_height;
771 void SDLSetWindowScalingQuality(char *window_scaling_quality)
773 if (sdl_texture == NULL)
776 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
778 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
779 SDL_PIXELFORMAT_ARGB8888,
780 SDL_TEXTUREACCESS_STREAMING,
781 video.width, video.height);
783 if (new_texture != NULL)
785 SDL_DestroyTexture(sdl_texture);
787 sdl_texture = new_texture;
792 video.window_scaling_quality = window_scaling_quality;
795 void SDLSetWindowFullscreen(boolean fullscreen)
797 if (sdl_window == NULL)
800 #if USE_DESKTOP_FULLSCREEN
801 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
803 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
806 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
807 video.fullscreen_enabled = fullscreen;
809 // if game started in fullscreen mode, window will also get fullscreen size
810 if (!fullscreen && video.fullscreen_initial)
812 SDLSetWindowScaling(setup.window_scaling_percent);
813 SDL_SetWindowPosition(sdl_window,
814 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
816 video.fullscreen_initial = FALSE;
820 void SDLRedrawWindow()
826 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
829 SDL_Surface *surface =
830 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
833 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
835 SDLSetNativeSurface(&surface);
837 bitmap->surface = surface;
840 void SDLFreeBitmapPointers(Bitmap *bitmap)
843 SDL_FreeSurface(bitmap->surface);
844 if (bitmap->surface_masked)
845 SDL_FreeSurface(bitmap->surface_masked);
846 bitmap->surface = NULL;
847 bitmap->surface_masked = NULL;
850 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
851 int src_x, int src_y, int width, int height,
852 int dst_x, int dst_y, int mask_mode)
854 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
855 SDL_Rect src_rect, dst_rect;
857 if (src_bitmap == backbuffer)
859 src_x += video_xoffset;
860 src_y += video_yoffset;
868 if (dst_bitmap == backbuffer || dst_bitmap == window)
870 dst_x += video_xoffset;
871 dst_y += video_yoffset;
879 // if (src_bitmap != backbuffer || dst_bitmap != window)
880 if (!(src_bitmap == backbuffer && dst_bitmap == window))
881 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
882 src_bitmap->surface_masked : src_bitmap->surface),
883 &src_rect, real_dst_bitmap->surface, &dst_rect);
885 #if defined(TARGET_SDL2)
886 if (dst_bitmap == window)
888 // SDL_UpdateWindowSurface(sdl_window);
889 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
890 UpdateScreen(&dst_rect);
893 if (dst_bitmap == window)
895 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
896 UpdateScreen(&dst_rect);
901 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
904 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
907 if (dst_bitmap == backbuffer || dst_bitmap == window)
918 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
920 #if defined(TARGET_SDL2)
921 if (dst_bitmap == window)
923 // SDL_UpdateWindowSurface(sdl_window);
924 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
928 if (dst_bitmap == window)
930 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
936 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
937 int fade_mode, int fade_delay, int post_delay,
938 void (*draw_border_function)(void))
940 static boolean initialization_needed = TRUE;
941 static SDL_Surface *surface_source = NULL;
942 static SDL_Surface *surface_target = NULL;
943 static SDL_Surface *surface_black = NULL;
944 SDL_Surface *surface_screen = backbuffer->surface;
945 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
946 SDL_Rect src_rect, dst_rect;
948 int src_x = x, src_y = y;
949 int dst_x = x, dst_y = y;
950 unsigned int time_last, time_current;
952 /* check if screen size has changed */
953 if (surface_source != NULL && (video.width != surface_source->w ||
954 video.height != surface_source->h))
956 SDL_FreeSurface(surface_source);
957 SDL_FreeSurface(surface_target);
958 SDL_FreeSurface(surface_black);
960 initialization_needed = TRUE;
968 dst_x += video_xoffset;
969 dst_y += video_yoffset;
973 dst_rect.w = width; /* (ignored) */
974 dst_rect.h = height; /* (ignored) */
976 dst_rect2 = dst_rect;
978 if (initialization_needed)
980 #if defined(TARGET_SDL2)
981 unsigned int flags = 0;
983 unsigned int flags = SDL_SRCALPHA;
985 /* use same surface type as screen surface */
986 if ((surface_screen->flags & SDL_HWSURFACE))
987 flags |= SDL_HWSURFACE;
989 flags |= SDL_SWSURFACE;
992 /* create surface for temporary copy of screen buffer (source) */
993 if ((surface_source =
994 SDL_CreateRGBSurface(flags,
997 surface_screen->format->BitsPerPixel,
998 surface_screen->format->Rmask,
999 surface_screen->format->Gmask,
1000 surface_screen->format->Bmask,
1001 surface_screen->format->Amask)) == NULL)
1002 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1004 /* create surface for cross-fading screen buffer (target) */
1005 if ((surface_target =
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 black surface for fading from/to black */
1017 if ((surface_black =
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 /* completely fill the surface with black color pixels */
1029 SDL_FillRect(surface_black, NULL,
1030 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1032 initialization_needed = FALSE;
1035 /* copy source and target surfaces to temporary surfaces for fading */
1036 if (fade_mode & FADE_TYPE_TRANSFORM)
1038 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1039 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1041 else if (fade_mode & FADE_TYPE_FADE_IN)
1043 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1044 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1046 else /* FADE_TYPE_FADE_OUT */
1048 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1049 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1052 time_current = SDL_GetTicks();
1054 if (fade_mode == FADE_MODE_MELT)
1056 boolean done = FALSE;
1057 int melt_pixels = 2;
1058 int melt_columns = width / melt_pixels;
1059 int ypos[melt_columns];
1060 int max_steps = height / 8 + 32;
1065 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1066 #if defined(TARGET_SDL2)
1067 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1069 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1072 ypos[0] = -GetSimpleRandom(16);
1074 for (i = 1 ; i < melt_columns; i++)
1076 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1078 ypos[i] = ypos[i - 1] + r;
1091 time_last = time_current;
1092 time_current = SDL_GetTicks();
1093 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1094 steps_final = MIN(MAX(0, steps), max_steps);
1098 done = (steps_done >= steps_final);
1100 for (i = 0 ; i < melt_columns; i++)
1108 else if (ypos[i] < height)
1113 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1115 if (ypos[i] + dy >= height)
1116 dy = height - ypos[i];
1118 /* copy part of (appearing) target surface to upper area */
1119 src_rect.x = src_x + i * melt_pixels;
1120 // src_rect.y = src_y + ypos[i];
1122 src_rect.w = melt_pixels;
1124 src_rect.h = ypos[i] + dy;
1126 dst_rect.x = dst_x + i * melt_pixels;
1127 // dst_rect.y = dst_y + ypos[i];
1130 if (steps_done >= steps_final)
1131 SDL_BlitSurface(surface_target, &src_rect,
1132 surface_screen, &dst_rect);
1136 /* copy part of (disappearing) source surface to lower area */
1137 src_rect.x = src_x + i * melt_pixels;
1139 src_rect.w = melt_pixels;
1140 src_rect.h = height - ypos[i];
1142 dst_rect.x = dst_x + i * melt_pixels;
1143 dst_rect.y = dst_y + ypos[i];
1145 if (steps_done >= steps_final)
1146 SDL_BlitSurface(surface_source, &src_rect,
1147 surface_screen, &dst_rect);
1153 src_rect.x = src_x + i * melt_pixels;
1155 src_rect.w = melt_pixels;
1156 src_rect.h = height;
1158 dst_rect.x = dst_x + i * melt_pixels;
1161 if (steps_done >= steps_final)
1162 SDL_BlitSurface(surface_target, &src_rect,
1163 surface_screen, &dst_rect);
1167 if (steps_done >= steps_final)
1169 if (draw_border_function != NULL)
1170 draw_border_function();
1172 #if defined(TARGET_SDL2)
1173 // SDL_UpdateWindowSurface(sdl_window);
1174 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
1175 UpdateScreen(&dst_rect2);
1177 // SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1178 UpdateScreen(&dst_rect2);
1188 for (alpha = 0.0; alpha < 255.0;)
1190 time_last = time_current;
1191 time_current = SDL_GetTicks();
1192 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1193 alpha_final = MIN(MAX(0, alpha), 255);
1195 /* draw existing (source) image to screen buffer */
1196 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1198 /* draw new (target) image to screen buffer using alpha blending */
1199 #if defined(TARGET_SDL2)
1200 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1201 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1203 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1205 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1207 if (draw_border_function != NULL)
1208 draw_border_function();
1210 /* only update the region of the screen that is affected from fading */
1211 UpdateScreen(&dst_rect);
1218 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1219 int to_x, int to_y, Uint32 color)
1221 SDL_Surface *surface = dst_bitmap->surface;
1225 swap_numbers(&from_x, &to_x);
1228 swap_numbers(&from_y, &to_y);
1232 rect.w = (to_x - from_x + 1);
1233 rect.h = (to_y - from_y + 1);
1235 if (dst_bitmap == backbuffer || dst_bitmap == window)
1237 rect.x += video_xoffset;
1238 rect.y += video_yoffset;
1241 SDL_FillRect(surface, &rect, color);
1244 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1245 int to_x, int to_y, Uint32 color)
1247 if (dst_bitmap == backbuffer || dst_bitmap == window)
1249 from_x += video_xoffset;
1250 from_y += video_yoffset;
1251 to_x += video_xoffset;
1252 to_y += video_yoffset;
1255 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1258 #if ENABLE_UNUSED_CODE
1259 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1260 int num_points, Uint32 color)
1265 for (i = 0; i < num_points - 1; i++)
1267 for (x = 0; x < line_width; x++)
1269 for (y = 0; y < line_width; y++)
1271 int dx = x - line_width / 2;
1272 int dy = y - line_width / 2;
1274 if ((x == 0 && y == 0) ||
1275 (x == 0 && y == line_width - 1) ||
1276 (x == line_width - 1 && y == 0) ||
1277 (x == line_width - 1 && y == line_width - 1))
1280 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1281 points[i+1].x + dx, points[i+1].y + dy, color);
1288 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1290 SDL_Surface *surface = src_bitmap->surface;
1292 if (src_bitmap == backbuffer || src_bitmap == window)
1298 switch (surface->format->BytesPerPixel)
1300 case 1: /* assuming 8-bpp */
1302 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1306 case 2: /* probably 15-bpp or 16-bpp */
1308 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1312 case 3: /* slow 24-bpp mode; usually not used */
1314 /* does this work? */
1315 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1319 shift = surface->format->Rshift;
1320 color |= *(pix + shift / 8) >> shift;
1321 shift = surface->format->Gshift;
1322 color |= *(pix + shift / 8) >> shift;
1323 shift = surface->format->Bshift;
1324 color |= *(pix + shift / 8) >> shift;
1330 case 4: /* probably 32-bpp */
1332 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1341 /* ========================================================================= */
1342 /* The following functions were taken from the SGE library */
1343 /* (SDL Graphics Extension Library) by Anders Lindström */
1344 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1345 /* ========================================================================= */
1347 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1349 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1351 switch (surface->format->BytesPerPixel)
1355 /* Assuming 8-bpp */
1356 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1362 /* Probably 15-bpp or 16-bpp */
1363 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1369 /* Slow 24-bpp mode, usually not used */
1373 /* Gack - slow, but endian correct */
1374 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1375 shift = surface->format->Rshift;
1376 *(pix+shift/8) = color>>shift;
1377 shift = surface->format->Gshift;
1378 *(pix+shift/8) = color>>shift;
1379 shift = surface->format->Bshift;
1380 *(pix+shift/8) = color>>shift;
1386 /* Probably 32-bpp */
1387 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1394 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1395 Uint8 R, Uint8 G, Uint8 B)
1397 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1400 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1402 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1405 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1407 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1410 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1415 /* Gack - slow, but endian correct */
1416 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1417 shift = surface->format->Rshift;
1418 *(pix+shift/8) = color>>shift;
1419 shift = surface->format->Gshift;
1420 *(pix+shift/8) = color>>shift;
1421 shift = surface->format->Bshift;
1422 *(pix+shift/8) = color>>shift;
1425 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1427 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1430 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1432 switch (dest->format->BytesPerPixel)
1435 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1439 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1443 _PutPixel24(dest,x,y,color);
1447 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1452 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1454 if (SDL_MUSTLOCK(surface))
1456 if (SDL_LockSurface(surface) < 0)
1462 _PutPixel(surface, x, y, color);
1464 if (SDL_MUSTLOCK(surface))
1466 SDL_UnlockSurface(surface);
1470 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1471 Uint8 r, Uint8 g, Uint8 b)
1473 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1476 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1478 if (y >= 0 && y <= dest->h - 1)
1480 switch (dest->format->BytesPerPixel)
1483 return y*dest->pitch;
1487 return y*dest->pitch/2;
1491 return y*dest->pitch;
1495 return y*dest->pitch/4;
1503 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1505 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1507 switch (surface->format->BytesPerPixel)
1511 /* Assuming 8-bpp */
1512 *((Uint8 *)surface->pixels + ypitch + x) = color;
1518 /* Probably 15-bpp or 16-bpp */
1519 *((Uint16 *)surface->pixels + ypitch + x) = color;
1525 /* Slow 24-bpp mode, usually not used */
1529 /* Gack - slow, but endian correct */
1530 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1531 shift = surface->format->Rshift;
1532 *(pix+shift/8) = color>>shift;
1533 shift = surface->format->Gshift;
1534 *(pix+shift/8) = color>>shift;
1535 shift = surface->format->Bshift;
1536 *(pix+shift/8) = color>>shift;
1542 /* Probably 32-bpp */
1543 *((Uint32 *)surface->pixels + ypitch + x) = color;
1550 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1555 if (SDL_MUSTLOCK(Surface))
1557 if (SDL_LockSurface(Surface) < 0)
1570 /* Do the clipping */
1571 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1575 if (x2 > Surface->w - 1)
1576 x2 = Surface->w - 1;
1583 SDL_FillRect(Surface, &l, Color);
1585 if (SDL_MUSTLOCK(Surface))
1587 SDL_UnlockSurface(Surface);
1591 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1592 Uint8 R, Uint8 G, Uint8 B)
1594 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1597 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1608 /* Do the clipping */
1609 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1613 if (x2 > Surface->w - 1)
1614 x2 = Surface->w - 1;
1621 SDL_FillRect(Surface, &l, Color);
1624 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1629 if (SDL_MUSTLOCK(Surface))
1631 if (SDL_LockSurface(Surface) < 0)
1644 /* Do the clipping */
1645 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1649 if (y2 > Surface->h - 1)
1650 y2 = Surface->h - 1;
1657 SDL_FillRect(Surface, &l, Color);
1659 if (SDL_MUSTLOCK(Surface))
1661 SDL_UnlockSurface(Surface);
1665 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1666 Uint8 R, Uint8 G, Uint8 B)
1668 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1671 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1682 /* Do the clipping */
1683 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1687 if (y2 > Surface->h - 1)
1688 y2 = Surface->h - 1;
1695 SDL_FillRect(Surface, &l, Color);
1698 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1699 Sint16 x2, Sint16 y2, Uint32 Color,
1700 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1703 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1708 sdx = (dx < 0) ? -1 : 1;
1709 sdy = (dy < 0) ? -1 : 1;
1721 for (x = 0; x < dx; x++)
1723 Callback(Surface, px, py, Color);
1737 for (y = 0; y < dy; y++)
1739 Callback(Surface, px, py, Color);
1753 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1754 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1755 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1758 sge_DoLine(Surface, X1, Y1, X2, Y2,
1759 SDL_MapRGB(Surface->format, R, G, B), Callback);
1762 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1765 if (SDL_MUSTLOCK(Surface))
1767 if (SDL_LockSurface(Surface) < 0)
1772 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1774 /* unlock the display */
1775 if (SDL_MUSTLOCK(Surface))
1777 SDL_UnlockSurface(Surface);
1781 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1782 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1784 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1787 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1789 if (dst_bitmap == backbuffer || dst_bitmap == window)
1795 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1800 -----------------------------------------------------------------------------
1801 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1802 -----------------------------------------------------------------------------
1805 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1806 int width, int height, Uint32 color)
1810 for (y = src_y; y < src_y + height; y++)
1812 for (x = src_x; x < src_x + width; x++)
1814 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1816 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1821 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1822 int src_x, int src_y, int width, int height,
1823 int dst_x, int dst_y)
1827 for (y = 0; y < height; y++)
1829 for (x = 0; x < width; x++)
1831 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1833 if (pixel != BLACK_PIXEL)
1834 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1840 /* ========================================================================= */
1841 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1842 /* (Rotozoomer) by Andreas Schiffler */
1843 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1844 /* ========================================================================= */
1847 -----------------------------------------------------------------------------
1850 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1851 -----------------------------------------------------------------------------
1862 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1865 tColorRGBA *sp, *csp, *dp;
1869 sp = csp = (tColorRGBA *) src->pixels;
1870 dp = (tColorRGBA *) dst->pixels;
1871 dgap = dst->pitch - dst->w * 4;
1873 for (y = 0; y < dst->h; y++)
1877 for (x = 0; x < dst->w; x++)
1879 tColorRGBA *sp0 = sp;
1880 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1881 tColorRGBA *sp00 = &sp0[0];
1882 tColorRGBA *sp01 = &sp0[1];
1883 tColorRGBA *sp10 = &sp1[0];
1884 tColorRGBA *sp11 = &sp1[1];
1887 /* create new color pixel from all four source color pixels */
1888 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1889 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1890 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1891 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1896 /* advance source pointers */
1899 /* advance destination pointer */
1903 /* advance source pointer */
1904 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1906 /* advance destination pointers */
1907 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1913 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1915 int x, y, *sax, *say, *csax, *csay;
1917 tColorRGBA *sp, *csp, *csp0, *dp;
1920 /* use specialized zoom function when scaling down to exactly half size */
1921 if (src->w == 2 * dst->w &&
1922 src->h == 2 * dst->h)
1923 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1925 /* variable setup */
1926 sx = (float) src->w / (float) dst->w;
1927 sy = (float) src->h / (float) dst->h;
1929 /* allocate memory for row increments */
1930 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1931 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1933 /* precalculate row increments */
1934 for (x = 0; x <= dst->w; x++)
1935 *csax++ = (int)(sx * x);
1937 for (y = 0; y <= dst->h; y++)
1938 *csay++ = (int)(sy * y);
1941 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1942 dp = (tColorRGBA *) dst->pixels;
1943 dgap = dst->pitch - dst->w * 4;
1946 for (y = 0; y < dst->h; y++)
1951 for (x = 0; x < dst->w; x++)
1956 /* advance source pointers */
1960 /* advance destination pointer */
1964 /* advance source pointer */
1966 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1968 /* advance destination pointers */
1969 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1979 -----------------------------------------------------------------------------
1982 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1983 -----------------------------------------------------------------------------
1986 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1988 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1989 Uint8 *sp, *dp, *csp;
1992 /* variable setup */
1993 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1994 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1996 /* allocate memory for row increments */
1997 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1998 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2000 /* precalculate row increments */
2003 for (x = 0; x < dst->w; x++)
2006 *csax = (csx >> 16);
2013 for (y = 0; y < dst->h; y++)
2016 *csay = (csy >> 16);
2023 for (x = 0; x < dst->w; x++)
2031 for (y = 0; y < dst->h; y++)
2038 sp = csp = (Uint8 *) src->pixels;
2039 dp = (Uint8 *) dst->pixels;
2040 dgap = dst->pitch - dst->w;
2044 for (y = 0; y < dst->h; y++)
2048 for (x = 0; x < dst->w; x++)
2053 /* advance source pointers */
2057 /* advance destination pointer */
2061 /* advance source pointer (for row) */
2062 csp += ((*csay) * src->pitch);
2065 /* advance destination pointers */
2076 -----------------------------------------------------------------------------
2079 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2080 'zoomx' and 'zoomy' are scaling factors for width and height.
2081 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2082 into a 32bit RGBA format on the fly.
2083 -----------------------------------------------------------------------------
2086 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2088 SDL_Surface *zoom_src = NULL;
2089 SDL_Surface *zoom_dst = NULL;
2090 boolean is_converted = FALSE;
2097 /* determine if source surface is 32 bit or 8 bit */
2098 is_32bit = (src->format->BitsPerPixel == 32);
2100 if (is_32bit || src->format->BitsPerPixel == 8)
2102 /* use source surface 'as is' */
2107 /* new source surface is 32 bit with a defined RGB ordering */
2108 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2109 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2110 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2112 is_converted = TRUE;
2115 /* allocate surface to completely contain the zoomed surface */
2118 /* target surface is 32 bit with source RGBA/ABGR ordering */
2119 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2120 zoom_src->format->Rmask,
2121 zoom_src->format->Gmask,
2122 zoom_src->format->Bmask, 0);
2126 /* target surface is 8 bit */
2127 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2131 /* lock source surface */
2132 SDL_LockSurface(zoom_src);
2134 /* check which kind of surface we have */
2137 /* call the 32 bit transformation routine to do the zooming */
2138 zoomSurfaceRGBA(zoom_src, zoom_dst);
2143 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2144 zoom_dst->format->palette->colors[i] =
2145 zoom_src->format->palette->colors[i];
2146 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2148 /* call the 8 bit transformation routine to do the zooming */
2149 zoomSurfaceY(zoom_src, zoom_dst);
2152 /* unlock source surface */
2153 SDL_UnlockSurface(zoom_src);
2155 /* free temporary surface */
2157 SDL_FreeSurface(zoom_src);
2159 /* return destination surface */
2163 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2165 Bitmap *dst_bitmap = CreateBitmapStruct();
2166 SDL_Surface **dst_surface = &dst_bitmap->surface;
2168 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2169 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2171 dst_bitmap->width = dst_width;
2172 dst_bitmap->height = dst_height;
2174 /* create zoomed temporary surface from source surface */
2175 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2177 /* create native format destination surface from zoomed temporary surface */
2178 SDLSetNativeSurface(dst_surface);
2184 /* ========================================================================= */
2185 /* load image to bitmap */
2186 /* ========================================================================= */
2188 Bitmap *SDLLoadImage(char *filename)
2190 Bitmap *new_bitmap = CreateBitmapStruct();
2191 SDL_Surface *sdl_image_tmp;
2193 print_timestamp_init("SDLLoadImage");
2195 print_timestamp_time(getBaseNamePtr(filename));
2197 /* load image to temporary surface */
2198 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2200 SetError("IMG_Load(): %s", SDL_GetError());
2205 print_timestamp_time("IMG_Load");
2207 UPDATE_BUSY_STATE();
2209 /* create native non-transparent surface for current image */
2210 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2212 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2217 print_timestamp_time("SDL_DisplayFormat (opaque)");
2219 UPDATE_BUSY_STATE();
2221 /* create native transparent surface for current image */
2222 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2223 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2225 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2227 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2232 print_timestamp_time("SDL_DisplayFormat (masked)");
2234 UPDATE_BUSY_STATE();
2236 /* free temporary surface */
2237 SDL_FreeSurface(sdl_image_tmp);
2239 new_bitmap->width = new_bitmap->surface->w;
2240 new_bitmap->height = new_bitmap->surface->h;
2242 print_timestamp_done("SDLLoadImage");
2248 /* ------------------------------------------------------------------------- */
2249 /* custom cursor fuctions */
2250 /* ------------------------------------------------------------------------- */
2252 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2254 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2255 cursor_info->width, cursor_info->height,
2256 cursor_info->hot_x, cursor_info->hot_y);
2259 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2261 static struct MouseCursorInfo *last_cursor_info = NULL;
2262 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2263 static SDL_Cursor *cursor_default = NULL;
2264 static SDL_Cursor *cursor_current = NULL;
2266 /* if invoked for the first time, store the SDL default cursor */
2267 if (cursor_default == NULL)
2268 cursor_default = SDL_GetCursor();
2270 /* only create new cursor if cursor info (custom only) has changed */
2271 if (cursor_info != NULL && cursor_info != last_cursor_info)
2273 cursor_current = create_cursor(cursor_info);
2274 last_cursor_info = cursor_info;
2277 /* only set new cursor if cursor info (custom or NULL) has changed */
2278 if (cursor_info != last_cursor_info2)
2279 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2281 last_cursor_info2 = cursor_info;
2285 /* ========================================================================= */
2286 /* audio functions */
2287 /* ========================================================================= */
2289 void SDLOpenAudio(void)
2291 #if !defined(TARGET_SDL2)
2292 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2293 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2296 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2298 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2302 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2303 AUDIO_NUM_CHANNELS_STEREO,
2304 setup.system.audio_fragment_size) < 0)
2306 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2310 audio.sound_available = TRUE;
2311 audio.music_available = TRUE;
2312 audio.loops_available = TRUE;
2313 audio.sound_enabled = TRUE;
2315 /* set number of available mixer channels */
2316 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2317 audio.music_channel = MUSIC_CHANNEL;
2318 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2320 Mixer_InitChannels();
2323 void SDLCloseAudio(void)
2326 Mix_HaltChannel(-1);
2329 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2333 /* ========================================================================= */
2334 /* event functions */
2335 /* ========================================================================= */
2337 void SDLNextEvent(Event *event)
2339 SDL_WaitEvent(event);
2341 if (event->type == EVENT_BUTTONPRESS ||
2342 event->type == EVENT_BUTTONRELEASE)
2344 if (((ButtonEvent *)event)->x > video_xoffset)
2345 ((ButtonEvent *)event)->x -= video_xoffset;
2347 ((ButtonEvent *)event)->x = 0;
2348 if (((ButtonEvent *)event)->y > video_yoffset)
2349 ((ButtonEvent *)event)->y -= video_yoffset;
2351 ((ButtonEvent *)event)->y = 0;
2353 else if (event->type == EVENT_MOTIONNOTIFY)
2355 if (((MotionEvent *)event)->x > video_xoffset)
2356 ((MotionEvent *)event)->x -= video_xoffset;
2358 ((MotionEvent *)event)->x = 0;
2359 if (((MotionEvent *)event)->y > video_yoffset)
2360 ((MotionEvent *)event)->y -= video_yoffset;
2362 ((MotionEvent *)event)->y = 0;
2366 void SDLHandleWindowManagerEvent(Event *event)
2368 #if defined(PLATFORM_WIN32)
2369 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2370 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2372 #if defined(TARGET_SDL2)
2373 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2375 if (syswmmsg->msg == WM_DROPFILES)
2378 #if defined(TARGET_SDL2)
2379 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2381 HDROP hdrop = (HDROP)syswmmsg->wParam;
2385 printf("::: SDL_SYSWMEVENT:\n");
2387 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2389 for (i = 0; i < num_files; i++)
2391 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2392 char buffer[buffer_len + 1];
2394 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2396 printf("::: - '%s'\n", buffer);
2399 #if defined(TARGET_SDL2)
2400 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2402 DragFinish((HDROP)syswmmsg->wParam);
2409 /* ========================================================================= */
2410 /* joystick functions */
2411 /* ========================================================================= */
2413 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2414 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2415 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2417 static boolean SDLOpenJoystick(int nr)
2419 if (nr < 0 || nr > MAX_PLAYERS)
2422 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2425 static void SDLCloseJoystick(int nr)
2427 if (nr < 0 || nr > MAX_PLAYERS)
2430 SDL_JoystickClose(sdl_joystick[nr]);
2432 sdl_joystick[nr] = NULL;
2435 static boolean SDLCheckJoystickOpened(int nr)
2437 if (nr < 0 || nr > MAX_PLAYERS)
2440 #if defined(TARGET_SDL2)
2441 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2443 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2447 void HandleJoystickEvent(Event *event)
2451 case SDL_JOYAXISMOTION:
2452 if (event->jaxis.axis < 2)
2453 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2456 case SDL_JOYBUTTONDOWN:
2457 if (event->jbutton.button < 2)
2458 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2461 case SDL_JOYBUTTONUP:
2462 if (event->jbutton.button < 2)
2463 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2471 void SDLInitJoysticks()
2473 static boolean sdl_joystick_subsystem_initialized = FALSE;
2474 boolean print_warning = !sdl_joystick_subsystem_initialized;
2477 if (!sdl_joystick_subsystem_initialized)
2479 sdl_joystick_subsystem_initialized = TRUE;
2481 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2483 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2488 for (i = 0; i < MAX_PLAYERS; i++)
2490 /* get configured joystick for this player */
2491 char *device_name = setup.input[i].joy.device_name;
2492 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2494 if (joystick_nr >= SDL_NumJoysticks())
2496 if (setup.input[i].use_joystick && print_warning)
2497 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2502 /* misuse joystick file descriptor variable to store joystick number */
2503 joystick.fd[i] = joystick_nr;
2505 if (joystick_nr == -1)
2508 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2509 if (SDLCheckJoystickOpened(joystick_nr))
2510 SDLCloseJoystick(joystick_nr);
2512 if (!setup.input[i].use_joystick)
2515 if (!SDLOpenJoystick(joystick_nr))
2518 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2523 joystick.status = JOYSTICK_ACTIVATED;
2527 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2529 if (nr < 0 || nr >= MAX_PLAYERS)
2533 *x = sdl_js_axis[nr][0];
2535 *y = sdl_js_axis[nr][1];
2538 *b1 = sdl_js_button[nr][0];
2540 *b2 = sdl_js_button[nr][1];