1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
21 #if defined(TARGET_SDL)
23 /* ========================================================================= */
25 /* ========================================================================= */
27 /* SDL internal variables */
28 #if defined(TARGET_SDL2)
29 static SDL_Window *sdl_window = NULL;
30 static SDL_Renderer *sdl_renderer = NULL;
31 static SDL_Texture *sdl_texture = NULL;
33 #define USE_RENDERER TRUE
36 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
37 static int fullscreen_width;
38 static int fullscreen_height;
39 static int fullscreen_xoffset;
40 static int fullscreen_yoffset;
41 static int video_xoffset;
42 static int video_yoffset;
43 static boolean limit_screen_updates = FALSE;
46 /* functions from SGE library */
47 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
49 void SDLLimitScreenUpdates(boolean enable)
51 limit_screen_updates = enable;
54 static void UpdateScreen(SDL_Rect *rect)
56 static unsigned int update_screen_delay = 0;
57 unsigned int update_screen_delay_value = 20; /* (milliseconds) */
60 if (limit_screen_updates &&
61 !DelayReached(&update_screen_delay, update_screen_delay_value))
64 LimitScreenUpdates(FALSE);
67 #if defined(TARGET_SDL2)
69 SDL_Surface *screen = backbuffer->surface;
74 int bytes_x = screen->pitch / video.width;
75 int bytes_y = screen->pitch;
77 if (video.fullscreen_enabled)
78 bytes_x = screen->pitch / fullscreen_width;
80 SDL_UpdateTexture(sdl_texture, rect,
81 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
86 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
89 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
91 SDL_RenderClear(sdl_renderer);
92 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
93 SDL_RenderPresent(sdl_renderer);
96 SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
98 SDL_UpdateWindowSurface(sdl_window);
103 SDL_UpdateRects(backbuffer->surface, 1, rect);
105 SDL_UpdateRect(backbuffer->surface, 0, 0, 0, 0);
109 static void setFullscreenParameters(char *fullscreen_mode_string)
111 #if defined(TARGET_SDL2)
112 fullscreen_width = video.width;
113 fullscreen_height = video.height;
114 fullscreen_xoffset = 0;
115 fullscreen_yoffset = 0;
119 struct ScreenModeInfo *fullscreen_mode;
122 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
124 if (fullscreen_mode == NULL)
127 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
129 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
130 fullscreen_mode->height == video.fullscreen_modes[i].height)
132 fullscreen_width = fullscreen_mode->width;
133 fullscreen_height = fullscreen_mode->height;
135 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
136 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
144 static void SDLSetWindowIcon(char *basename)
146 /* (setting the window icon on Mac OS X would replace the high-quality
147 dock icon with the currently smaller (and uglier) icon from file) */
149 #if !defined(PLATFORM_MACOSX)
150 char *filename = getCustomImageFilename(basename);
151 SDL_Surface *surface;
153 if (filename == NULL)
155 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
160 if ((surface = IMG_Load(filename)) == NULL)
162 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
167 /* set transparent color */
168 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
169 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
171 #if defined(TARGET_SDL2)
172 SDL_SetWindowIcon(sdl_window, surface);
174 SDL_WM_SetIcon(surface, NULL);
179 #if defined(TARGET_SDL2)
180 SDL_Surface *SDL_DisplayFormat(SDL_Surface *surface)
182 if (backbuffer == NULL ||
183 backbuffer->surface == NULL)
186 return SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
190 void SDLInitVideoDisplay(void)
192 #if !defined(TARGET_SDL2)
193 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
194 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
196 SDL_putenv("SDL_VIDEO_CENTERED=1");
199 /* initialize SDL video */
200 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
201 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
203 /* set default SDL depth */
204 #if !defined(TARGET_SDL2)
205 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
207 video.default_depth = 32; // (how to determine video depth in SDL2?)
211 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
214 #if !defined(TARGET_SDL2)
215 static int screen_xy[][2] =
223 SDL_Rect **modes = NULL;
224 boolean hardware_fullscreen_available = TRUE;
227 /* default: normal game window size */
228 fullscreen_width = video.width;
229 fullscreen_height = video.height;
230 fullscreen_xoffset = 0;
231 fullscreen_yoffset = 0;
233 #if !defined(TARGET_SDL2)
234 /* determine required standard fullscreen mode for game screen size */
235 for (i = 0; screen_xy[i][0] != -1; i++)
237 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
239 fullscreen_width = screen_xy[i][0];
240 fullscreen_height = screen_xy[i][1];
246 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
247 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
251 checked_free(video.fullscreen_modes);
253 video.fullscreen_modes = NULL;
254 video.fullscreen_mode_current = NULL;
257 video.window_scaling_percent = setup.window_scaling_percent;
258 video.window_scaling_quality = setup.window_scaling_quality;
260 #if defined(TARGET_SDL2)
261 int num_displays = SDL_GetNumVideoDisplays();
263 if (num_displays > 0)
265 // currently only display modes of first display supported
266 int num_modes = SDL_GetNumDisplayModes(0);
270 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
272 for (i = 0; i < num_modes; i++)
274 SDL_DisplayMode mode;
276 if (SDL_GetDisplayMode(0, i, &mode) < 0)
279 modes[i] = checked_calloc(sizeof(SDL_Rect));
281 modes[i]->w = mode.w;
282 modes[i]->h = mode.h;
287 /* get available hardware supported fullscreen modes */
288 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
293 /* no hardware screen modes available => no fullscreen mode support */
294 // video.fullscreen_available = FALSE;
295 hardware_fullscreen_available = FALSE;
297 else if (modes == (SDL_Rect **)-1)
299 /* fullscreen resolution is not restricted -- all resolutions available */
300 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
302 /* use native video buffer size for fullscreen mode */
303 video.fullscreen_modes[0].width = video.width;
304 video.fullscreen_modes[0].height = video.height;
306 video.fullscreen_modes[1].width = -1;
307 video.fullscreen_modes[1].height = -1;
311 /* in this case, a certain number of screen modes is available */
314 for (i = 0; modes[i] != NULL; i++)
316 boolean found_mode = FALSE;
318 /* screen mode is smaller than video buffer size -- skip it */
319 if (modes[i]->w < video.width || modes[i]->h < video.height)
322 if (video.fullscreen_modes != NULL)
323 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
324 if (modes[i]->w == video.fullscreen_modes[j].width &&
325 modes[i]->h == video.fullscreen_modes[j].height)
328 if (found_mode) /* screen mode already stored -- skip it */
331 /* new mode found; add it to list of available fullscreen modes */
335 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
337 sizeof(struct ScreenModeInfo));
339 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
340 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
342 video.fullscreen_modes[num_modes].width = -1;
343 video.fullscreen_modes[num_modes].height = -1;
348 /* no appropriate screen modes available => no fullscreen mode support */
349 // video.fullscreen_available = FALSE;
350 hardware_fullscreen_available = FALSE;
354 video.fullscreen_available = hardware_fullscreen_available;
356 #if USE_DESKTOP_FULLSCREEN
357 // in SDL 2.0, there is always support for desktop fullscreen mode
358 // (in SDL 1.2, there is only support for "real" fullscreen mode)
359 video.fullscreen_available = TRUE;
362 #if defined(TARGET_SDL2)
365 for (i = 0; modes[i] != NULL; i++)
366 checked_free(modes[i]);
373 /* set window icon */
374 SDLSetWindowIcon(program.sdl_icon_filename);
377 /* open SDL video output device (window or fullscreen mode) */
378 if (!SDLSetVideoMode(backbuffer, fullscreen))
379 Error(ERR_EXIT, "setting video mode failed");
382 /* !!! SDL2 can only set the window icon if the window already exists !!! */
383 /* set window icon */
384 SDLSetWindowIcon(program.sdl_icon_filename);
387 /* set window and icon title */
388 #if defined(TARGET_SDL2)
389 SDL_SetWindowTitle(sdl_window, program.window_title);
391 SDL_WM_SetCaption(program.window_title, program.window_title);
394 /* SDL cannot directly draw to the visible video framebuffer like X11,
395 but always uses a backbuffer, which is then blitted to the visible
396 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
397 visible video framebuffer with 'SDL_Flip', if the hardware supports
398 this). Therefore do not use an additional backbuffer for drawing, but
399 use a symbolic buffer (distinguishable from the SDL backbuffer) called
400 'window', which indicates that the SDL backbuffer should be updated to
401 the visible video framebuffer when attempting to blit to it.
403 For convenience, it seems to be a good idea to create this symbolic
404 buffer 'window' at the same size as the SDL backbuffer. Although it
405 should never be drawn to directly, it would do no harm nevertheless. */
407 /* create additional (symbolic) buffer for double-buffering */
409 ReCreateBitmap(window, video.width, video.height, video.depth);
411 *window = CreateBitmap(video.width, video.height, video.depth);
415 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
418 SDL_Surface *new_surface = NULL;
420 #if defined(TARGET_SDL2)
421 static boolean fullscreen_enabled = FALSE;
422 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
423 #if USE_DESKTOP_FULLSCREEN
424 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
426 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
430 int surface_flags_window = SURFACE_FLAGS;
431 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
434 int width = (fullscreen ? fullscreen_width : video.width);
435 int height = (fullscreen ? fullscreen_height : video.height);
436 int surface_flags = (fullscreen ? surface_flags_fullscreen :
437 surface_flags_window);
439 // default window size is unscaled
440 video.window_width = video.width;
441 video.window_height = video.height;
443 #if defined(TARGET_SDL2)
445 // store if initial screen mode on game start is fullscreen mode
446 if (sdl_window == NULL)
449 printf("::: GAME STARTS WITH FULLSCREEN %d\n", fullscreen);
452 video.fullscreen_initial = fullscreen;
456 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
457 #if !USE_DESKTOP_FULLSCREEN
458 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
461 video.window_width = window_scaling_factor * width;
462 video.window_height = window_scaling_factor * height;
465 printf("::: use window scaling factor %f\n", screen_scaling_factor);
468 if ((*backbuffer)->surface)
470 SDL_FreeSurface((*backbuffer)->surface);
471 (*backbuffer)->surface = NULL;
476 SDL_DestroyTexture(sdl_texture);
480 if (!(fullscreen && fullscreen_enabled))
484 SDL_DestroyRenderer(sdl_renderer);
490 SDL_DestroyWindow(sdl_window);
496 Error(ERR_INFO, "::: checking 'sdl_window' ...");
498 if (sdl_window == NULL)
499 Error(ERR_INFO, "::: calling SDL_CreateWindow() [%d, %d, %d] ...",
500 setup.fullscreen, fullscreen, fullscreen_enabled);
503 if (sdl_window == NULL)
504 sdl_window = SDL_CreateWindow(program.window_title,
505 SDL_WINDOWPOS_CENTERED,
506 SDL_WINDOWPOS_CENTERED,
507 #if USE_DESKTOP_FULLSCREEN
511 (int)(screen_scaling_factor * width),
512 (int)(screen_scaling_factor * height),
516 if (sdl_window != NULL)
519 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
520 *without* enabling 2D/3D acceleration and/or guest additions installed,
521 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
522 it will try to use accelerated graphics and apparently fails miserably) */
523 if (sdl_renderer == NULL)
524 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
526 if (sdl_renderer == NULL)
527 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
530 if (sdl_renderer != NULL)
532 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
533 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
534 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
536 sdl_texture = SDL_CreateTexture(sdl_renderer,
537 SDL_PIXELFORMAT_ARGB8888,
538 SDL_TEXTUREACCESS_STREAMING,
541 if (sdl_texture != NULL)
544 // (do not use alpha channel)
545 new_surface = SDL_CreateRGBSurface(0, width, height, 32,
551 // (this uses an alpha channel, which we don't want here)
552 new_surface = SDL_CreateRGBSurface(0, width, height, 32,
559 if (new_surface == NULL)
560 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
565 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
570 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
575 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
581 SDL_DestroyWindow(sdl_window);
583 sdl_window = SDL_CreateWindow(program.window_title,
584 SDL_WINDOWPOS_CENTERED,
585 SDL_WINDOWPOS_CENTERED,
589 if (sdl_window != NULL)
590 new_surface = SDL_GetWindowSurface(sdl_window);
594 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
597 #if defined(TARGET_SDL2)
598 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
599 if (new_surface != NULL)
600 fullscreen_enabled = fullscreen;
606 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
608 boolean success = TRUE;
611 #if defined(TARGET_SDL2)
612 // int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
613 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
614 int surface_flags_window = SURFACE_FLAGS;
616 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
617 int surface_flags_window = SURFACE_FLAGS;
620 SDL_Surface *new_surface = NULL;
624 if (*backbuffer == NULL)
625 *backbuffer = CreateBitmapStruct();
627 /* (real bitmap might be larger in fullscreen mode with video offsets) */
628 (*backbuffer)->width = video.width;
629 (*backbuffer)->height = video.height;
631 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
633 setFullscreenParameters(setup.fullscreen_mode);
635 video_xoffset = fullscreen_xoffset;
636 video_yoffset = fullscreen_yoffset;
638 /* switch display to fullscreen mode, if available */
640 new_surface = SDLCreateScreen(backbuffer, TRUE);
643 #if defined(TARGET_SDL2)
644 sdl_window = SDL_CreateWindow(program.window_title,
645 SDL_WINDOWPOS_CENTERED,
646 SDL_WINDOWPOS_CENTERED,
647 fullscreen_width, fullscreen_height,
648 surface_flags_fullscreen);
649 if (sdl_window != NULL)
651 new_surface = SDL_GetWindowSurface(sdl_window);
653 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
654 // UpdateScreen(NULL); // immediately map window
657 new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
658 video.depth, surface_flags_fullscreen);
662 if (new_surface == NULL)
664 /* switching display to fullscreen mode failed */
665 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
667 /* do not try it again */
668 video.fullscreen_available = FALSE;
674 (*backbuffer)->surface = new_surface;
676 video.fullscreen_enabled = TRUE;
677 video.fullscreen_mode_current = setup.fullscreen_mode;
683 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
688 /* switch display to window mode */
690 new_surface = SDLCreateScreen(backbuffer, FALSE);
693 #if defined(TARGET_SDL2)
696 float screen_scaling_factor = 1.2;
697 int test_fullscreen = 0;
698 int surface_flags = (test_fullscreen ? surface_flags_fullscreen :
699 surface_flags_window);
701 if ((*backbuffer)->surface)
702 SDL_FreeSurface((*backbuffer)->surface);
705 SDL_DestroyTexture(sdl_texture);
708 SDL_DestroyRenderer(sdl_renderer);
711 SDL_DestroyWindow(sdl_window);
713 sdl_window = SDL_CreateWindow(program.window_title,
714 SDL_WINDOWPOS_CENTERED,
715 SDL_WINDOWPOS_CENTERED,
716 (int)(screen_scaling_factor * video.width),
717 (int)(screen_scaling_factor * video.height),
720 if (sdl_window != NULL)
722 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
724 if (sdl_renderer != NULL)
726 SDL_RenderSetLogicalSize(sdl_renderer, video.width, video.height);
727 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
729 sdl_texture = SDL_CreateTexture(sdl_renderer,
730 SDL_PIXELFORMAT_ARGB8888,
731 SDL_TEXTUREACCESS_STREAMING,
732 video.width, video.height);
734 if (sdl_texture != NULL)
737 // (do not use alpha channel)
738 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
744 // (this uses an alpha channel, which we don't want here)
745 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
752 if (new_surface == NULL)
753 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
758 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
763 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
768 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
774 SDL_DestroyWindow(sdl_window);
776 sdl_window = SDL_CreateWindow(program.window_title,
777 SDL_WINDOWPOS_CENTERED,
778 SDL_WINDOWPOS_CENTERED,
779 video.width, video.height,
780 surface_flags_window);
782 if (sdl_window != NULL)
784 new_surface = SDL_GetWindowSurface(sdl_window);
786 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
787 // UpdateScreen(NULL); // immediately map window
792 new_surface = SDL_SetVideoMode(video.width, video.height,
793 video.depth, surface_flags_window);
797 if (new_surface == NULL)
799 /* switching display to window mode failed -- should not happen */
800 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
806 (*backbuffer)->surface = new_surface;
808 video.fullscreen_enabled = FALSE;
809 video.window_scaling_percent = setup.window_scaling_percent;
810 video.window_scaling_quality = setup.window_scaling_quality;
816 #if defined(TARGET_SDL2)
817 SDLRedrawWindow(); // map window
818 // UpdateScreen(NULL); // map window
822 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
824 #if defined(PLATFORM_WIN32)
826 SDL_SysWMinfo wminfo;
828 boolean wminfo_success = FALSE;
830 SDL_VERSION(&wminfo.version);
831 #if defined(TARGET_SDL2)
833 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
835 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
840 #if defined(TARGET_SDL2)
841 hwnd = wminfo.info.win.window;
843 hwnd = wminfo.window;
846 DragAcceptFiles(hwnd, TRUE);
855 void SDLSetWindowTitle()
857 #if defined(TARGET_SDL2)
858 SDL_SetWindowTitle(sdl_window, program.window_title);
860 SDL_WM_SetCaption(program.window_title, program.window_title);
864 #if defined(TARGET_SDL2)
865 void SDLSetWindowScaling(int window_scaling_percent)
867 if (sdl_window == NULL)
870 float window_scaling_factor = (float)window_scaling_percent / 100;
871 int new_window_width = (int)(window_scaling_factor * video.width);
872 int new_window_height = (int)(window_scaling_factor * video.height);
875 Error(ERR_DEBUG, "::: SDLSetWindowScaling(%d) ...", window_scaling_percent);
878 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
880 video.window_scaling_percent = window_scaling_percent;
881 video.window_width = new_window_width;
882 video.window_height = new_window_height;
887 void SDLSetWindowScalingQuality(char *window_scaling_quality)
889 if (sdl_texture == NULL)
892 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
894 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
895 SDL_PIXELFORMAT_ARGB8888,
896 SDL_TEXTUREACCESS_STREAMING,
897 video.width, video.height);
899 if (new_texture != NULL)
901 SDL_DestroyTexture(sdl_texture);
903 sdl_texture = new_texture;
908 video.window_scaling_quality = window_scaling_quality;
911 void SDLSetWindowFullscreen(boolean fullscreen)
913 if (sdl_window == NULL)
916 #if USE_DESKTOP_FULLSCREEN
917 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
919 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
923 Error(ERR_DEBUG, "::: SDL_SetWindowFullscreen(%d) ...", fullscreen);
926 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
927 video.fullscreen_enabled = fullscreen;
930 printf("::: SDLSetWindowFullscreen: %d, %d\n",
931 fullscreen, video.fullscreen_initial);
935 // if game started in fullscreen mode, window will also get fullscreen size
936 if (!fullscreen && video.fullscreen_initial)
938 SDLSetWindowScaling(setup.window_scaling_percent);
939 SDL_SetWindowPosition(sdl_window,
940 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
942 video.fullscreen_initial = FALSE;
947 void SDLRedrawWindow()
953 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
956 SDL_Surface *surface_tmp, *surface_native;
958 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
961 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
963 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
964 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
966 SDL_FreeSurface(surface_tmp);
968 new_bitmap->surface = surface_native;
971 void SDLFreeBitmapPointers(Bitmap *bitmap)
974 SDL_FreeSurface(bitmap->surface);
975 if (bitmap->surface_masked)
976 SDL_FreeSurface(bitmap->surface_masked);
977 bitmap->surface = NULL;
978 bitmap->surface_masked = NULL;
981 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
982 int src_x, int src_y, int width, int height,
983 int dst_x, int dst_y, int mask_mode)
985 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
986 SDL_Rect src_rect, dst_rect;
988 if (src_bitmap == backbuffer)
990 src_x += video_xoffset;
991 src_y += video_yoffset;
999 if (dst_bitmap == backbuffer || dst_bitmap == window)
1001 dst_x += video_xoffset;
1002 dst_y += video_yoffset;
1008 dst_rect.h = height;
1010 // if (src_bitmap != backbuffer || dst_bitmap != window)
1011 if (!(src_bitmap == backbuffer && dst_bitmap == window))
1012 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
1013 src_bitmap->surface_masked : src_bitmap->surface),
1014 &src_rect, real_dst_bitmap->surface, &dst_rect);
1016 #if defined(TARGET_SDL2)
1017 if (dst_bitmap == window)
1019 // SDL_UpdateWindowSurface(sdl_window);
1020 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1021 UpdateScreen(&dst_rect);
1024 if (dst_bitmap == window)
1026 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
1027 UpdateScreen(&dst_rect);
1032 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
1035 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1038 if (dst_bitmap == backbuffer || dst_bitmap == window)
1049 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
1051 #if defined(TARGET_SDL2)
1052 if (dst_bitmap == window)
1054 // SDL_UpdateWindowSurface(sdl_window);
1055 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
1056 UpdateScreen(&rect);
1059 if (dst_bitmap == window)
1061 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
1062 UpdateScreen(&rect);
1067 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
1068 int fade_mode, int fade_delay, int post_delay,
1069 void (*draw_border_function)(void))
1071 static boolean initialization_needed = TRUE;
1072 static SDL_Surface *surface_source = NULL;
1073 static SDL_Surface *surface_target = NULL;
1074 static SDL_Surface *surface_black = NULL;
1075 SDL_Surface *surface_screen = backbuffer->surface;
1076 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
1077 SDL_Rect src_rect, dst_rect;
1079 int src_x = x, src_y = y;
1080 int dst_x = x, dst_y = y;
1081 unsigned int time_last, time_current;
1083 /* check if screen size has changed */
1084 if (surface_source != NULL && (video.width != surface_source->w ||
1085 video.height != surface_source->h))
1087 SDL_FreeSurface(surface_source);
1088 SDL_FreeSurface(surface_target);
1089 SDL_FreeSurface(surface_black);
1091 initialization_needed = TRUE;
1097 src_rect.h = height;
1099 dst_x += video_xoffset;
1100 dst_y += video_yoffset;
1104 dst_rect.w = width; /* (ignored) */
1105 dst_rect.h = height; /* (ignored) */
1107 dst_rect2 = dst_rect;
1109 if (initialization_needed)
1111 #if defined(TARGET_SDL2)
1112 unsigned int flags = 0;
1114 unsigned int flags = SDL_SRCALPHA;
1116 /* use same surface type as screen surface */
1117 if ((surface_screen->flags & SDL_HWSURFACE))
1118 flags |= SDL_HWSURFACE;
1120 flags |= SDL_SWSURFACE;
1123 /* create surface for temporary copy of screen buffer (source) */
1124 if ((surface_source =
1125 SDL_CreateRGBSurface(flags,
1128 surface_screen->format->BitsPerPixel,
1129 surface_screen->format->Rmask,
1130 surface_screen->format->Gmask,
1131 surface_screen->format->Bmask,
1132 surface_screen->format->Amask)) == NULL)
1133 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1135 /* create surface for cross-fading screen buffer (target) */
1136 if ((surface_target =
1137 SDL_CreateRGBSurface(flags,
1140 surface_screen->format->BitsPerPixel,
1141 surface_screen->format->Rmask,
1142 surface_screen->format->Gmask,
1143 surface_screen->format->Bmask,
1144 surface_screen->format->Amask)) == NULL)
1145 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1147 /* create black surface for fading from/to black */
1148 if ((surface_black =
1149 SDL_CreateRGBSurface(flags,
1152 surface_screen->format->BitsPerPixel,
1153 surface_screen->format->Rmask,
1154 surface_screen->format->Gmask,
1155 surface_screen->format->Bmask,
1156 surface_screen->format->Amask)) == NULL)
1157 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1159 /* completely fill the surface with black color pixels */
1160 SDL_FillRect(surface_black, NULL,
1161 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1163 initialization_needed = FALSE;
1166 /* copy source and target surfaces to temporary surfaces for fading */
1167 if (fade_mode & FADE_TYPE_TRANSFORM)
1169 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1170 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1172 else if (fade_mode & FADE_TYPE_FADE_IN)
1174 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1175 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1177 else /* FADE_TYPE_FADE_OUT */
1179 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1180 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1183 time_current = SDL_GetTicks();
1185 if (fade_mode == FADE_MODE_MELT)
1187 boolean done = FALSE;
1188 int melt_pixels = 2;
1189 int melt_columns = width / melt_pixels;
1190 int ypos[melt_columns];
1191 int max_steps = height / 8 + 32;
1196 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1197 #if defined(TARGET_SDL2)
1198 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1200 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1203 ypos[0] = -GetSimpleRandom(16);
1205 for (i = 1 ; i < melt_columns; i++)
1207 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1209 ypos[i] = ypos[i - 1] + r;
1222 time_last = time_current;
1223 time_current = SDL_GetTicks();
1224 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1225 steps_final = MIN(MAX(0, steps), max_steps);
1229 done = (steps_done >= steps_final);
1231 for (i = 0 ; i < melt_columns; i++)
1239 else if (ypos[i] < height)
1244 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1246 if (ypos[i] + dy >= height)
1247 dy = height - ypos[i];
1249 /* copy part of (appearing) target surface to upper area */
1250 src_rect.x = src_x + i * melt_pixels;
1251 // src_rect.y = src_y + ypos[i];
1253 src_rect.w = melt_pixels;
1255 src_rect.h = ypos[i] + dy;
1257 dst_rect.x = dst_x + i * melt_pixels;
1258 // dst_rect.y = dst_y + ypos[i];
1261 if (steps_done >= steps_final)
1262 SDL_BlitSurface(surface_target, &src_rect,
1263 surface_screen, &dst_rect);
1267 /* copy part of (disappearing) source surface to lower area */
1268 src_rect.x = src_x + i * melt_pixels;
1270 src_rect.w = melt_pixels;
1271 src_rect.h = height - ypos[i];
1273 dst_rect.x = dst_x + i * melt_pixels;
1274 dst_rect.y = dst_y + ypos[i];
1276 if (steps_done >= steps_final)
1277 SDL_BlitSurface(surface_source, &src_rect,
1278 surface_screen, &dst_rect);
1284 src_rect.x = src_x + i * melt_pixels;
1286 src_rect.w = melt_pixels;
1287 src_rect.h = height;
1289 dst_rect.x = dst_x + i * melt_pixels;
1292 if (steps_done >= steps_final)
1293 SDL_BlitSurface(surface_target, &src_rect,
1294 surface_screen, &dst_rect);
1298 if (steps_done >= steps_final)
1300 if (draw_border_function != NULL)
1301 draw_border_function();
1303 #if defined(TARGET_SDL2)
1304 // SDL_UpdateWindowSurface(sdl_window);
1305 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
1306 UpdateScreen(&dst_rect2);
1308 // SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1309 UpdateScreen(&dst_rect2);
1319 for (alpha = 0.0; alpha < 255.0;)
1321 time_last = time_current;
1322 time_current = SDL_GetTicks();
1323 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1324 alpha_final = MIN(MAX(0, alpha), 255);
1326 /* draw existing (source) image to screen buffer */
1327 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1329 /* draw new (target) image to screen buffer using alpha blending */
1330 #if defined(TARGET_SDL2)
1331 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1332 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1334 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1336 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1338 if (draw_border_function != NULL)
1339 draw_border_function();
1342 /* only update the region of the screen that is affected from fading */
1343 #if defined(TARGET_SDL2)
1344 // SDL_UpdateWindowSurface(sdl_window);
1345 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1346 UpdateScreen(&dst_rect);
1348 // SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1349 UpdateScreen(&dst_rect);
1352 SDL_Flip(surface_screen);
1360 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1361 int to_x, int to_y, Uint32 color)
1363 SDL_Surface *surface = dst_bitmap->surface;
1367 swap_numbers(&from_x, &to_x);
1370 swap_numbers(&from_y, &to_y);
1374 rect.w = (to_x - from_x + 1);
1375 rect.h = (to_y - from_y + 1);
1377 if (dst_bitmap == backbuffer || dst_bitmap == window)
1379 rect.x += video_xoffset;
1380 rect.y += video_yoffset;
1383 SDL_FillRect(surface, &rect, color);
1386 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1387 int to_x, int to_y, Uint32 color)
1389 if (dst_bitmap == backbuffer || dst_bitmap == window)
1391 from_x += video_xoffset;
1392 from_y += video_yoffset;
1393 to_x += video_xoffset;
1394 to_y += video_yoffset;
1397 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1401 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1402 int num_points, Uint32 color)
1407 for (i = 0; i < num_points - 1; i++)
1409 for (x = 0; x < line_width; x++)
1411 for (y = 0; y < line_width; y++)
1413 int dx = x - line_width / 2;
1414 int dy = y - line_width / 2;
1416 if ((x == 0 && y == 0) ||
1417 (x == 0 && y == line_width - 1) ||
1418 (x == line_width - 1 && y == 0) ||
1419 (x == line_width - 1 && y == line_width - 1))
1422 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1423 points[i+1].x + dx, points[i+1].y + dy, color);
1430 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1432 SDL_Surface *surface = src_bitmap->surface;
1434 if (src_bitmap == backbuffer || src_bitmap == window)
1440 switch (surface->format->BytesPerPixel)
1442 case 1: /* assuming 8-bpp */
1444 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1448 case 2: /* probably 15-bpp or 16-bpp */
1450 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1454 case 3: /* slow 24-bpp mode; usually not used */
1456 /* does this work? */
1457 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1461 shift = surface->format->Rshift;
1462 color |= *(pix + shift / 8) >> shift;
1463 shift = surface->format->Gshift;
1464 color |= *(pix + shift / 8) >> shift;
1465 shift = surface->format->Bshift;
1466 color |= *(pix + shift / 8) >> shift;
1472 case 4: /* probably 32-bpp */
1474 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1483 /* ========================================================================= */
1484 /* The following functions were taken from the SGE library */
1485 /* (SDL Graphics Extension Library) by Anders Lindström */
1486 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1487 /* ========================================================================= */
1489 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1491 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1493 switch (surface->format->BytesPerPixel)
1497 /* Assuming 8-bpp */
1498 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1504 /* Probably 15-bpp or 16-bpp */
1505 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1511 /* Slow 24-bpp mode, usually not used */
1515 /* Gack - slow, but endian correct */
1516 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1517 shift = surface->format->Rshift;
1518 *(pix+shift/8) = color>>shift;
1519 shift = surface->format->Gshift;
1520 *(pix+shift/8) = color>>shift;
1521 shift = surface->format->Bshift;
1522 *(pix+shift/8) = color>>shift;
1528 /* Probably 32-bpp */
1529 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1536 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1537 Uint8 R, Uint8 G, Uint8 B)
1539 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1542 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1544 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1547 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1549 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1552 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1557 /* Gack - slow, but endian correct */
1558 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1559 shift = surface->format->Rshift;
1560 *(pix+shift/8) = color>>shift;
1561 shift = surface->format->Gshift;
1562 *(pix+shift/8) = color>>shift;
1563 shift = surface->format->Bshift;
1564 *(pix+shift/8) = color>>shift;
1567 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1569 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1572 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1574 switch (dest->format->BytesPerPixel)
1577 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1581 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1585 _PutPixel24(dest,x,y,color);
1589 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1594 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1596 if (SDL_MUSTLOCK(surface))
1598 if (SDL_LockSurface(surface) < 0)
1604 _PutPixel(surface, x, y, color);
1606 if (SDL_MUSTLOCK(surface))
1608 SDL_UnlockSurface(surface);
1612 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1613 Uint8 r, Uint8 g, Uint8 b)
1615 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1618 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1620 if (y >= 0 && y <= dest->h - 1)
1622 switch (dest->format->BytesPerPixel)
1625 return y*dest->pitch;
1629 return y*dest->pitch/2;
1633 return y*dest->pitch;
1637 return y*dest->pitch/4;
1645 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1647 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1649 switch (surface->format->BytesPerPixel)
1653 /* Assuming 8-bpp */
1654 *((Uint8 *)surface->pixels + ypitch + x) = color;
1660 /* Probably 15-bpp or 16-bpp */
1661 *((Uint16 *)surface->pixels + ypitch + x) = color;
1667 /* Slow 24-bpp mode, usually not used */
1671 /* Gack - slow, but endian correct */
1672 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1673 shift = surface->format->Rshift;
1674 *(pix+shift/8) = color>>shift;
1675 shift = surface->format->Gshift;
1676 *(pix+shift/8) = color>>shift;
1677 shift = surface->format->Bshift;
1678 *(pix+shift/8) = color>>shift;
1684 /* Probably 32-bpp */
1685 *((Uint32 *)surface->pixels + ypitch + x) = color;
1692 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1697 if (SDL_MUSTLOCK(Surface))
1699 if (SDL_LockSurface(Surface) < 0)
1712 /* Do the clipping */
1713 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1717 if (x2 > Surface->w - 1)
1718 x2 = Surface->w - 1;
1725 SDL_FillRect(Surface, &l, Color);
1727 if (SDL_MUSTLOCK(Surface))
1729 SDL_UnlockSurface(Surface);
1733 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1734 Uint8 R, Uint8 G, Uint8 B)
1736 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1739 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1750 /* Do the clipping */
1751 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1755 if (x2 > Surface->w - 1)
1756 x2 = Surface->w - 1;
1763 SDL_FillRect(Surface, &l, Color);
1766 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1771 if (SDL_MUSTLOCK(Surface))
1773 if (SDL_LockSurface(Surface) < 0)
1786 /* Do the clipping */
1787 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1791 if (y2 > Surface->h - 1)
1792 y2 = Surface->h - 1;
1799 SDL_FillRect(Surface, &l, Color);
1801 if (SDL_MUSTLOCK(Surface))
1803 SDL_UnlockSurface(Surface);
1807 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1808 Uint8 R, Uint8 G, Uint8 B)
1810 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1813 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1824 /* Do the clipping */
1825 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1829 if (y2 > Surface->h - 1)
1830 y2 = Surface->h - 1;
1837 SDL_FillRect(Surface, &l, Color);
1840 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1841 Sint16 x2, Sint16 y2, Uint32 Color,
1842 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1845 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1850 sdx = (dx < 0) ? -1 : 1;
1851 sdy = (dy < 0) ? -1 : 1;
1863 for (x = 0; x < dx; x++)
1865 Callback(Surface, px, py, Color);
1879 for (y = 0; y < dy; y++)
1881 Callback(Surface, px, py, Color);
1895 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1896 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1897 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1900 sge_DoLine(Surface, X1, Y1, X2, Y2,
1901 SDL_MapRGB(Surface->format, R, G, B), Callback);
1904 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1907 if (SDL_MUSTLOCK(Surface))
1909 if (SDL_LockSurface(Surface) < 0)
1914 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1916 /* unlock the display */
1917 if (SDL_MUSTLOCK(Surface))
1919 SDL_UnlockSurface(Surface);
1923 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1924 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1926 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1929 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1931 if (dst_bitmap == backbuffer || dst_bitmap == window)
1937 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1942 -----------------------------------------------------------------------------
1943 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1944 -----------------------------------------------------------------------------
1947 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1948 int width, int height, Uint32 color)
1952 for (y = src_y; y < src_y + height; y++)
1954 for (x = src_x; x < src_x + width; x++)
1956 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1958 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1963 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1964 int src_x, int src_y, int width, int height,
1965 int dst_x, int dst_y)
1969 for (y = 0; y < height; y++)
1971 for (x = 0; x < width; x++)
1973 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1975 if (pixel != BLACK_PIXEL)
1976 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1982 /* ========================================================================= */
1983 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1984 /* (Rotozoomer) by Andreas Schiffler */
1985 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1986 /* ========================================================================= */
1989 -----------------------------------------------------------------------------
1992 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1993 -----------------------------------------------------------------------------
2004 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
2007 tColorRGBA *sp, *csp, *dp;
2014 sp = csp = (tColorRGBA *) src->pixels;
2015 dp = (tColorRGBA *) dst->pixels;
2017 sgap = src->pitch - src->w * 4;
2019 dgap = dst->pitch - dst->w * 4;
2021 for (y = 0; y < dst->h; y++)
2025 for (x = 0; x < dst->w; x++)
2027 tColorRGBA *sp0 = sp;
2028 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
2029 tColorRGBA *sp00 = &sp0[0];
2030 tColorRGBA *sp01 = &sp0[1];
2031 tColorRGBA *sp10 = &sp1[0];
2032 tColorRGBA *sp11 = &sp1[1];
2035 /* create new color pixel from all four source color pixels */
2036 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2037 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2038 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2039 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2044 /* advance source pointers */
2047 /* advance destination pointer */
2051 /* advance source pointer */
2052 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2054 /* advance destination pointers */
2055 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2061 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2063 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2064 tColorRGBA *sp, *csp, *dp;
2070 /* use specialized zoom function when scaling down to exactly half size */
2071 if (src->w == 2 * dst->w &&
2072 src->h == 2 * dst->h)
2073 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2075 /* variable setup */
2076 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
2077 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
2079 /* allocate memory for row increments */
2080 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2081 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2083 /* precalculate row increments */
2086 for (x = 0; x <= dst->w; x++)
2096 for (y = 0; y <= dst->h; y++)
2105 sp = csp = (tColorRGBA *) src->pixels;
2106 dp = (tColorRGBA *) dst->pixels;
2108 sgap = src->pitch - src->w * 4;
2110 dgap = dst->pitch - dst->w * 4;
2113 for (y = 0; y < dst->h; y++)
2118 for (x = 0; x < dst->w; x++)
2123 /* advance source pointers */
2125 sp += (*csax >> 16);
2127 /* advance destination pointer */
2131 /* advance source pointer */
2133 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
2135 /* advance destination pointers */
2136 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2146 -----------------------------------------------------------------------------
2149 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2150 -----------------------------------------------------------------------------
2153 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2155 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2156 Uint8 *sp, *dp, *csp;
2159 /* variable setup */
2160 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2161 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2163 /* allocate memory for row increments */
2164 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2165 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2167 /* precalculate row increments */
2170 for (x = 0; x < dst->w; x++)
2173 *csax = (csx >> 16);
2180 for (y = 0; y < dst->h; y++)
2183 *csay = (csy >> 16);
2190 for (x = 0; x < dst->w; x++)
2198 for (y = 0; y < dst->h; y++)
2205 sp = csp = (Uint8 *) src->pixels;
2206 dp = (Uint8 *) dst->pixels;
2207 dgap = dst->pitch - dst->w;
2211 for (y = 0; y < dst->h; y++)
2215 for (x = 0; x < dst->w; x++)
2220 /* advance source pointers */
2224 /* advance destination pointer */
2228 /* advance source pointer (for row) */
2229 csp += ((*csay) * src->pitch);
2232 /* advance destination pointers */
2243 -----------------------------------------------------------------------------
2246 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2247 'zoomx' and 'zoomy' are scaling factors for width and height.
2248 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2249 into a 32bit RGBA format on the fly.
2250 -----------------------------------------------------------------------------
2253 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2255 SDL_Surface *zoom_src = NULL;
2256 SDL_Surface *zoom_dst = NULL;
2257 boolean is_converted = FALSE;
2264 /* determine if source surface is 32 bit or 8 bit */
2265 is_32bit = (src->format->BitsPerPixel == 32);
2267 if (is_32bit || src->format->BitsPerPixel == 8)
2269 /* use source surface 'as is' */
2274 /* new source surface is 32 bit with a defined RGB ordering */
2275 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
2276 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2277 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2279 is_converted = TRUE;
2282 /* allocate surface to completely contain the zoomed surface */
2285 /* target surface is 32 bit with source RGBA/ABGR ordering */
2286 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
2287 zoom_src->format->Rmask,
2288 zoom_src->format->Gmask,
2289 zoom_src->format->Bmask, 0);
2293 /* target surface is 8 bit */
2294 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
2298 /* lock source surface */
2299 SDL_LockSurface(zoom_src);
2301 /* check which kind of surface we have */
2304 /* call the 32 bit transformation routine to do the zooming */
2305 zoomSurfaceRGBA(zoom_src, zoom_dst);
2310 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2311 zoom_dst->format->palette->colors[i] =
2312 zoom_src->format->palette->colors[i];
2313 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2315 /* call the 8 bit transformation routine to do the zooming */
2316 zoomSurfaceY(zoom_src, zoom_dst);
2319 /* unlock source surface */
2320 SDL_UnlockSurface(zoom_src);
2322 /* free temporary surface */
2324 SDL_FreeSurface(zoom_src);
2326 /* return destination surface */
2330 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
2332 SDL_Surface *sdl_surface_tmp;
2333 int dst_width = dst_bitmap->width;
2334 int dst_height = dst_bitmap->height;
2336 /* throw away old destination surface */
2337 SDL_FreeSurface(dst_bitmap->surface);
2339 /* create zoomed temporary surface from source surface */
2340 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2342 /* create native format destination surface from zoomed temporary surface */
2343 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
2345 /* free temporary surface */
2346 SDL_FreeSurface(sdl_surface_tmp);
2350 /* ========================================================================= */
2351 /* load image to bitmap */
2352 /* ========================================================================= */
2354 Bitmap *SDLLoadImage(char *filename)
2356 Bitmap *new_bitmap = CreateBitmapStruct();
2357 SDL_Surface *sdl_image_tmp;
2359 print_timestamp_init("SDLLoadImage");
2361 print_timestamp_time(getBaseNamePtr(filename));
2363 /* load image to temporary surface */
2364 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2366 SetError("IMG_Load(): %s", SDL_GetError());
2371 print_timestamp_time("IMG_Load");
2373 UPDATE_BUSY_STATE();
2375 /* create native non-transparent surface for current image */
2376 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2378 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2383 print_timestamp_time("SDL_DisplayFormat (opaque)");
2385 UPDATE_BUSY_STATE();
2387 /* create native transparent surface for current image */
2388 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2389 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2390 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2392 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2397 print_timestamp_time("SDL_DisplayFormat (masked)");
2399 UPDATE_BUSY_STATE();
2401 /* free temporary surface */
2402 SDL_FreeSurface(sdl_image_tmp);
2404 new_bitmap->width = new_bitmap->surface->w;
2405 new_bitmap->height = new_bitmap->surface->h;
2407 print_timestamp_done("SDLLoadImage");
2413 /* ------------------------------------------------------------------------- */
2414 /* custom cursor fuctions */
2415 /* ------------------------------------------------------------------------- */
2417 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2419 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2420 cursor_info->width, cursor_info->height,
2421 cursor_info->hot_x, cursor_info->hot_y);
2424 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2426 static struct MouseCursorInfo *last_cursor_info = NULL;
2427 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2428 static SDL_Cursor *cursor_default = NULL;
2429 static SDL_Cursor *cursor_current = NULL;
2431 /* if invoked for the first time, store the SDL default cursor */
2432 if (cursor_default == NULL)
2433 cursor_default = SDL_GetCursor();
2435 /* only create new cursor if cursor info (custom only) has changed */
2436 if (cursor_info != NULL && cursor_info != last_cursor_info)
2438 cursor_current = create_cursor(cursor_info);
2439 last_cursor_info = cursor_info;
2442 /* only set new cursor if cursor info (custom or NULL) has changed */
2443 if (cursor_info != last_cursor_info2)
2444 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2446 last_cursor_info2 = cursor_info;
2450 /* ========================================================================= */
2451 /* audio functions */
2452 /* ========================================================================= */
2454 void SDLOpenAudio(void)
2456 #if !defined(TARGET_SDL2)
2457 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2458 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2461 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2463 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2467 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2468 AUDIO_NUM_CHANNELS_STEREO,
2469 setup.system.audio_fragment_size) < 0)
2471 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2475 audio.sound_available = TRUE;
2476 audio.music_available = TRUE;
2477 audio.loops_available = TRUE;
2478 audio.sound_enabled = TRUE;
2480 /* set number of available mixer channels */
2481 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2482 audio.music_channel = MUSIC_CHANNEL;
2483 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2485 Mixer_InitChannels();
2488 void SDLCloseAudio(void)
2491 Mix_HaltChannel(-1);
2494 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2498 /* ========================================================================= */
2499 /* event functions */
2500 /* ========================================================================= */
2502 void SDLNextEvent(Event *event)
2504 SDL_WaitEvent(event);
2506 if (event->type == EVENT_BUTTONPRESS ||
2507 event->type == EVENT_BUTTONRELEASE)
2509 if (((ButtonEvent *)event)->x > video_xoffset)
2510 ((ButtonEvent *)event)->x -= video_xoffset;
2512 ((ButtonEvent *)event)->x = 0;
2513 if (((ButtonEvent *)event)->y > video_yoffset)
2514 ((ButtonEvent *)event)->y -= video_yoffset;
2516 ((ButtonEvent *)event)->y = 0;
2518 else if (event->type == EVENT_MOTIONNOTIFY)
2520 if (((MotionEvent *)event)->x > video_xoffset)
2521 ((MotionEvent *)event)->x -= video_xoffset;
2523 ((MotionEvent *)event)->x = 0;
2524 if (((MotionEvent *)event)->y > video_yoffset)
2525 ((MotionEvent *)event)->y -= video_yoffset;
2527 ((MotionEvent *)event)->y = 0;
2531 void SDLHandleWindowManagerEvent(Event *event)
2533 #if defined(PLATFORM_WIN32)
2534 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2535 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2537 #if defined(TARGET_SDL2)
2538 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2540 if (syswmmsg->msg == WM_DROPFILES)
2543 #if defined(TARGET_SDL2)
2544 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2546 HDROP hdrop = (HDROP)syswmmsg->wParam;
2550 printf("::: SDL_SYSWMEVENT:\n");
2552 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2554 for (i = 0; i < num_files; i++)
2556 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2557 char buffer[buffer_len + 1];
2559 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2561 printf("::: - '%s'\n", buffer);
2564 #if defined(TARGET_SDL2)
2565 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2567 DragFinish((HDROP)syswmmsg->wParam);
2574 /* ========================================================================= */
2575 /* joystick functions */
2576 /* ========================================================================= */
2578 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2579 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2580 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2582 static boolean SDLOpenJoystick(int nr)
2584 if (nr < 0 || nr > MAX_PLAYERS)
2587 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2590 static void SDLCloseJoystick(int nr)
2592 if (nr < 0 || nr > MAX_PLAYERS)
2595 SDL_JoystickClose(sdl_joystick[nr]);
2597 sdl_joystick[nr] = NULL;
2600 static boolean SDLCheckJoystickOpened(int nr)
2602 if (nr < 0 || nr > MAX_PLAYERS)
2605 #if defined(TARGET_SDL2)
2606 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2608 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2612 void HandleJoystickEvent(Event *event)
2616 case SDL_JOYAXISMOTION:
2617 if (event->jaxis.axis < 2)
2618 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2621 case SDL_JOYBUTTONDOWN:
2622 if (event->jbutton.button < 2)
2623 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2626 case SDL_JOYBUTTONUP:
2627 if (event->jbutton.button < 2)
2628 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2636 void SDLInitJoysticks()
2638 static boolean sdl_joystick_subsystem_initialized = FALSE;
2639 boolean print_warning = !sdl_joystick_subsystem_initialized;
2642 if (!sdl_joystick_subsystem_initialized)
2644 sdl_joystick_subsystem_initialized = TRUE;
2646 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2648 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2653 for (i = 0; i < MAX_PLAYERS; i++)
2655 /* get configured joystick for this player */
2656 char *device_name = setup.input[i].joy.device_name;
2657 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2659 if (joystick_nr >= SDL_NumJoysticks())
2661 if (setup.input[i].use_joystick && print_warning)
2662 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2667 /* misuse joystick file descriptor variable to store joystick number */
2668 joystick.fd[i] = joystick_nr;
2670 if (joystick_nr == -1)
2673 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2674 if (SDLCheckJoystickOpened(joystick_nr))
2675 SDLCloseJoystick(joystick_nr);
2677 if (!setup.input[i].use_joystick)
2680 if (!SDLOpenJoystick(joystick_nr))
2683 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2688 joystick.status = JOYSTICK_ACTIVATED;
2692 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2694 if (nr < 0 || nr >= MAX_PLAYERS)
2698 *x = sdl_js_axis[nr][0];
2700 *y = sdl_js_axis[nr][1];
2703 *b1 = sdl_js_button[nr][0];
2705 *b2 = sdl_js_button[nr][1];
2710 #endif /* TARGET_SDL */