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)
518 if (sdl_renderer == NULL)
519 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
521 if (sdl_renderer != NULL)
523 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
524 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
525 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
527 sdl_texture = SDL_CreateTexture(sdl_renderer,
528 SDL_PIXELFORMAT_ARGB8888,
529 SDL_TEXTUREACCESS_STREAMING,
532 if (sdl_texture != NULL)
535 // (do not use alpha channel)
536 new_surface = SDL_CreateRGBSurface(0, width, height, 32,
542 // (this uses an alpha channel, which we don't want here)
543 new_surface = SDL_CreateRGBSurface(0, width, height, 32,
550 if (new_surface == NULL)
551 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
556 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
561 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
566 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
572 SDL_DestroyWindow(sdl_window);
574 sdl_window = SDL_CreateWindow(program.window_title,
575 SDL_WINDOWPOS_CENTERED,
576 SDL_WINDOWPOS_CENTERED,
580 if (sdl_window != NULL)
581 new_surface = SDL_GetWindowSurface(sdl_window);
585 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
588 #if defined(TARGET_SDL2)
589 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
590 if (new_surface != NULL)
591 fullscreen_enabled = fullscreen;
597 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
599 boolean success = TRUE;
602 #if defined(TARGET_SDL2)
603 // int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
604 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
605 int surface_flags_window = SURFACE_FLAGS;
607 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
608 int surface_flags_window = SURFACE_FLAGS;
611 SDL_Surface *new_surface = NULL;
615 if (*backbuffer == NULL)
616 *backbuffer = CreateBitmapStruct();
618 /* (real bitmap might be larger in fullscreen mode with video offsets) */
619 (*backbuffer)->width = video.width;
620 (*backbuffer)->height = video.height;
622 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
624 setFullscreenParameters(setup.fullscreen_mode);
626 video_xoffset = fullscreen_xoffset;
627 video_yoffset = fullscreen_yoffset;
629 /* switch display to fullscreen mode, if available */
631 new_surface = SDLCreateScreen(backbuffer, TRUE);
634 #if defined(TARGET_SDL2)
635 sdl_window = SDL_CreateWindow(program.window_title,
636 SDL_WINDOWPOS_CENTERED,
637 SDL_WINDOWPOS_CENTERED,
638 fullscreen_width, fullscreen_height,
639 surface_flags_fullscreen);
640 if (sdl_window != NULL)
642 new_surface = SDL_GetWindowSurface(sdl_window);
644 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
645 // UpdateScreen(NULL); // immediately map window
648 new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
649 video.depth, surface_flags_fullscreen);
653 if (new_surface == NULL)
655 /* switching display to fullscreen mode failed */
656 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
658 /* do not try it again */
659 video.fullscreen_available = FALSE;
665 (*backbuffer)->surface = new_surface;
667 video.fullscreen_enabled = TRUE;
668 video.fullscreen_mode_current = setup.fullscreen_mode;
674 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
679 /* switch display to window mode */
681 new_surface = SDLCreateScreen(backbuffer, FALSE);
684 #if defined(TARGET_SDL2)
687 float screen_scaling_factor = 1.2;
688 int test_fullscreen = 0;
689 int surface_flags = (test_fullscreen ? surface_flags_fullscreen :
690 surface_flags_window);
692 if ((*backbuffer)->surface)
693 SDL_FreeSurface((*backbuffer)->surface);
696 SDL_DestroyTexture(sdl_texture);
699 SDL_DestroyRenderer(sdl_renderer);
702 SDL_DestroyWindow(sdl_window);
704 sdl_window = SDL_CreateWindow(program.window_title,
705 SDL_WINDOWPOS_CENTERED,
706 SDL_WINDOWPOS_CENTERED,
707 (int)(screen_scaling_factor * video.width),
708 (int)(screen_scaling_factor * video.height),
711 if (sdl_window != NULL)
713 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
715 if (sdl_renderer != NULL)
717 SDL_RenderSetLogicalSize(sdl_renderer, video.width, video.height);
718 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
720 sdl_texture = SDL_CreateTexture(sdl_renderer,
721 SDL_PIXELFORMAT_ARGB8888,
722 SDL_TEXTUREACCESS_STREAMING,
723 video.width, video.height);
725 if (sdl_texture != NULL)
728 // (do not use alpha channel)
729 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
735 // (this uses an alpha channel, which we don't want here)
736 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
743 if (new_surface == NULL)
744 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
749 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
754 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
759 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
765 SDL_DestroyWindow(sdl_window);
767 sdl_window = SDL_CreateWindow(program.window_title,
768 SDL_WINDOWPOS_CENTERED,
769 SDL_WINDOWPOS_CENTERED,
770 video.width, video.height,
771 surface_flags_window);
773 if (sdl_window != NULL)
775 new_surface = SDL_GetWindowSurface(sdl_window);
777 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
778 // UpdateScreen(NULL); // immediately map window
783 new_surface = SDL_SetVideoMode(video.width, video.height,
784 video.depth, surface_flags_window);
788 if (new_surface == NULL)
790 /* switching display to window mode failed -- should not happen */
791 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
797 (*backbuffer)->surface = new_surface;
799 video.fullscreen_enabled = FALSE;
800 video.window_scaling_percent = setup.window_scaling_percent;
801 video.window_scaling_quality = setup.window_scaling_quality;
807 #if defined(TARGET_SDL2)
808 SDLRedrawWindow(); // map window
809 // UpdateScreen(NULL); // map window
813 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
815 #if defined(PLATFORM_WIN32)
817 SDL_SysWMinfo wminfo;
819 boolean wminfo_success = FALSE;
821 SDL_VERSION(&wminfo.version);
822 #if defined(TARGET_SDL2)
824 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
826 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
831 #if defined(TARGET_SDL2)
832 hwnd = wminfo.info.win.window;
834 hwnd = wminfo.window;
837 DragAcceptFiles(hwnd, TRUE);
846 void SDLSetWindowTitle()
848 #if defined(TARGET_SDL2)
849 SDL_SetWindowTitle(sdl_window, program.window_title);
851 SDL_WM_SetCaption(program.window_title, program.window_title);
855 #if defined(TARGET_SDL2)
856 void SDLSetWindowScaling(int window_scaling_percent)
858 if (sdl_window == NULL)
861 float window_scaling_factor = (float)window_scaling_percent / 100;
862 int new_window_width = (int)(window_scaling_factor * video.width);
863 int new_window_height = (int)(window_scaling_factor * video.height);
866 Error(ERR_DEBUG, "::: SDLSetWindowScaling(%d) ...", window_scaling_percent);
869 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
871 video.window_scaling_percent = window_scaling_percent;
872 video.window_width = new_window_width;
873 video.window_height = new_window_height;
878 void SDLSetWindowScalingQuality(char *window_scaling_quality)
880 if (sdl_texture == NULL)
883 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
885 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
886 SDL_PIXELFORMAT_ARGB8888,
887 SDL_TEXTUREACCESS_STREAMING,
888 video.width, video.height);
890 if (new_texture != NULL)
892 SDL_DestroyTexture(sdl_texture);
894 sdl_texture = new_texture;
899 video.window_scaling_quality = window_scaling_quality;
902 void SDLSetWindowFullscreen(boolean fullscreen)
904 if (sdl_window == NULL)
907 #if USE_DESKTOP_FULLSCREEN
908 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
910 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
914 Error(ERR_DEBUG, "::: SDL_SetWindowFullscreen(%d) ...", fullscreen);
917 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
918 video.fullscreen_enabled = fullscreen;
921 printf("::: SDLSetWindowFullscreen: %d, %d\n",
922 fullscreen, video.fullscreen_initial);
926 // if game started in fullscreen mode, window will also get fullscreen size
927 if (!fullscreen && video.fullscreen_initial)
929 SDLSetWindowScaling(setup.window_scaling_percent);
930 SDL_SetWindowPosition(sdl_window,
931 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
933 video.fullscreen_initial = FALSE;
938 void SDLRedrawWindow()
944 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
947 SDL_Surface *surface_tmp, *surface_native;
949 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
952 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
954 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
955 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
957 SDL_FreeSurface(surface_tmp);
959 new_bitmap->surface = surface_native;
962 void SDLFreeBitmapPointers(Bitmap *bitmap)
965 SDL_FreeSurface(bitmap->surface);
966 if (bitmap->surface_masked)
967 SDL_FreeSurface(bitmap->surface_masked);
968 bitmap->surface = NULL;
969 bitmap->surface_masked = NULL;
972 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
973 int src_x, int src_y, int width, int height,
974 int dst_x, int dst_y, int mask_mode)
976 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
977 SDL_Rect src_rect, dst_rect;
979 if (src_bitmap == backbuffer)
981 src_x += video_xoffset;
982 src_y += video_yoffset;
990 if (dst_bitmap == backbuffer || dst_bitmap == window)
992 dst_x += video_xoffset;
993 dst_y += video_yoffset;
1001 // if (src_bitmap != backbuffer || dst_bitmap != window)
1002 if (!(src_bitmap == backbuffer && dst_bitmap == window))
1003 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
1004 src_bitmap->surface_masked : src_bitmap->surface),
1005 &src_rect, real_dst_bitmap->surface, &dst_rect);
1007 #if defined(TARGET_SDL2)
1008 if (dst_bitmap == window)
1010 // SDL_UpdateWindowSurface(sdl_window);
1011 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1012 UpdateScreen(&dst_rect);
1015 if (dst_bitmap == window)
1017 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
1018 UpdateScreen(&dst_rect);
1023 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
1026 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1029 if (dst_bitmap == backbuffer || dst_bitmap == window)
1040 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
1042 #if defined(TARGET_SDL2)
1043 if (dst_bitmap == window)
1045 // SDL_UpdateWindowSurface(sdl_window);
1046 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
1047 UpdateScreen(&rect);
1050 if (dst_bitmap == window)
1052 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
1053 UpdateScreen(&rect);
1058 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
1059 int fade_mode, int fade_delay, int post_delay,
1060 void (*draw_border_function)(void))
1062 static boolean initialization_needed = TRUE;
1063 static SDL_Surface *surface_source = NULL;
1064 static SDL_Surface *surface_target = NULL;
1065 static SDL_Surface *surface_black = NULL;
1066 SDL_Surface *surface_screen = backbuffer->surface;
1067 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
1068 SDL_Rect src_rect, dst_rect;
1070 int src_x = x, src_y = y;
1071 int dst_x = x, dst_y = y;
1072 unsigned int time_last, time_current;
1074 /* check if screen size has changed */
1075 if (surface_source != NULL && (video.width != surface_source->w ||
1076 video.height != surface_source->h))
1078 SDL_FreeSurface(surface_source);
1079 SDL_FreeSurface(surface_target);
1080 SDL_FreeSurface(surface_black);
1082 initialization_needed = TRUE;
1088 src_rect.h = height;
1090 dst_x += video_xoffset;
1091 dst_y += video_yoffset;
1095 dst_rect.w = width; /* (ignored) */
1096 dst_rect.h = height; /* (ignored) */
1098 dst_rect2 = dst_rect;
1100 if (initialization_needed)
1102 #if defined(TARGET_SDL2)
1103 unsigned int flags = 0;
1105 unsigned int flags = SDL_SRCALPHA;
1107 /* use same surface type as screen surface */
1108 if ((surface_screen->flags & SDL_HWSURFACE))
1109 flags |= SDL_HWSURFACE;
1111 flags |= SDL_SWSURFACE;
1114 /* create surface for temporary copy of screen buffer (source) */
1115 if ((surface_source =
1116 SDL_CreateRGBSurface(flags,
1119 surface_screen->format->BitsPerPixel,
1120 surface_screen->format->Rmask,
1121 surface_screen->format->Gmask,
1122 surface_screen->format->Bmask,
1123 surface_screen->format->Amask)) == NULL)
1124 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1126 /* create surface for cross-fading screen buffer (target) */
1127 if ((surface_target =
1128 SDL_CreateRGBSurface(flags,
1131 surface_screen->format->BitsPerPixel,
1132 surface_screen->format->Rmask,
1133 surface_screen->format->Gmask,
1134 surface_screen->format->Bmask,
1135 surface_screen->format->Amask)) == NULL)
1136 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1138 /* create black surface for fading from/to black */
1139 if ((surface_black =
1140 SDL_CreateRGBSurface(flags,
1143 surface_screen->format->BitsPerPixel,
1144 surface_screen->format->Rmask,
1145 surface_screen->format->Gmask,
1146 surface_screen->format->Bmask,
1147 surface_screen->format->Amask)) == NULL)
1148 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1150 /* completely fill the surface with black color pixels */
1151 SDL_FillRect(surface_black, NULL,
1152 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1154 initialization_needed = FALSE;
1157 /* copy source and target surfaces to temporary surfaces for fading */
1158 if (fade_mode & FADE_TYPE_TRANSFORM)
1160 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1161 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1163 else if (fade_mode & FADE_TYPE_FADE_IN)
1165 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1166 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1168 else /* FADE_TYPE_FADE_OUT */
1170 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1171 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1174 time_current = SDL_GetTicks();
1176 if (fade_mode == FADE_MODE_MELT)
1178 boolean done = FALSE;
1179 int melt_pixels = 2;
1180 int melt_columns = width / melt_pixels;
1181 int ypos[melt_columns];
1182 int max_steps = height / 8 + 32;
1187 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1188 #if defined(TARGET_SDL2)
1189 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1191 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1194 ypos[0] = -GetSimpleRandom(16);
1196 for (i = 1 ; i < melt_columns; i++)
1198 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1200 ypos[i] = ypos[i - 1] + r;
1213 time_last = time_current;
1214 time_current = SDL_GetTicks();
1215 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1216 steps_final = MIN(MAX(0, steps), max_steps);
1220 done = (steps_done >= steps_final);
1222 for (i = 0 ; i < melt_columns; i++)
1230 else if (ypos[i] < height)
1235 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1237 if (ypos[i] + dy >= height)
1238 dy = height - ypos[i];
1240 /* copy part of (appearing) target surface to upper area */
1241 src_rect.x = src_x + i * melt_pixels;
1242 // src_rect.y = src_y + ypos[i];
1244 src_rect.w = melt_pixels;
1246 src_rect.h = ypos[i] + dy;
1248 dst_rect.x = dst_x + i * melt_pixels;
1249 // dst_rect.y = dst_y + ypos[i];
1252 if (steps_done >= steps_final)
1253 SDL_BlitSurface(surface_target, &src_rect,
1254 surface_screen, &dst_rect);
1258 /* copy part of (disappearing) source surface to lower area */
1259 src_rect.x = src_x + i * melt_pixels;
1261 src_rect.w = melt_pixels;
1262 src_rect.h = height - ypos[i];
1264 dst_rect.x = dst_x + i * melt_pixels;
1265 dst_rect.y = dst_y + ypos[i];
1267 if (steps_done >= steps_final)
1268 SDL_BlitSurface(surface_source, &src_rect,
1269 surface_screen, &dst_rect);
1275 src_rect.x = src_x + i * melt_pixels;
1277 src_rect.w = melt_pixels;
1278 src_rect.h = height;
1280 dst_rect.x = dst_x + i * melt_pixels;
1283 if (steps_done >= steps_final)
1284 SDL_BlitSurface(surface_target, &src_rect,
1285 surface_screen, &dst_rect);
1289 if (steps_done >= steps_final)
1291 if (draw_border_function != NULL)
1292 draw_border_function();
1294 #if defined(TARGET_SDL2)
1295 // SDL_UpdateWindowSurface(sdl_window);
1296 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
1297 UpdateScreen(&dst_rect2);
1299 // SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1300 UpdateScreen(&dst_rect2);
1310 for (alpha = 0.0; alpha < 255.0;)
1312 time_last = time_current;
1313 time_current = SDL_GetTicks();
1314 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1315 alpha_final = MIN(MAX(0, alpha), 255);
1317 /* draw existing (source) image to screen buffer */
1318 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1320 /* draw new (target) image to screen buffer using alpha blending */
1321 #if defined(TARGET_SDL2)
1322 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1323 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1325 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1327 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1329 if (draw_border_function != NULL)
1330 draw_border_function();
1333 /* only update the region of the screen that is affected from fading */
1334 #if defined(TARGET_SDL2)
1335 // SDL_UpdateWindowSurface(sdl_window);
1336 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1337 UpdateScreen(&dst_rect);
1339 // SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1340 UpdateScreen(&dst_rect);
1343 SDL_Flip(surface_screen);
1351 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1352 int to_x, int to_y, Uint32 color)
1354 SDL_Surface *surface = dst_bitmap->surface;
1358 swap_numbers(&from_x, &to_x);
1361 swap_numbers(&from_y, &to_y);
1365 rect.w = (to_x - from_x + 1);
1366 rect.h = (to_y - from_y + 1);
1368 if (dst_bitmap == backbuffer || dst_bitmap == window)
1370 rect.x += video_xoffset;
1371 rect.y += video_yoffset;
1374 SDL_FillRect(surface, &rect, color);
1377 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1378 int to_x, int to_y, Uint32 color)
1380 if (dst_bitmap == backbuffer || dst_bitmap == window)
1382 from_x += video_xoffset;
1383 from_y += video_yoffset;
1384 to_x += video_xoffset;
1385 to_y += video_yoffset;
1388 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1392 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1393 int num_points, Uint32 color)
1398 for (i = 0; i < num_points - 1; i++)
1400 for (x = 0; x < line_width; x++)
1402 for (y = 0; y < line_width; y++)
1404 int dx = x - line_width / 2;
1405 int dy = y - line_width / 2;
1407 if ((x == 0 && y == 0) ||
1408 (x == 0 && y == line_width - 1) ||
1409 (x == line_width - 1 && y == 0) ||
1410 (x == line_width - 1 && y == line_width - 1))
1413 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1414 points[i+1].x + dx, points[i+1].y + dy, color);
1421 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1423 SDL_Surface *surface = src_bitmap->surface;
1425 if (src_bitmap == backbuffer || src_bitmap == window)
1431 switch (surface->format->BytesPerPixel)
1433 case 1: /* assuming 8-bpp */
1435 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1439 case 2: /* probably 15-bpp or 16-bpp */
1441 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1445 case 3: /* slow 24-bpp mode; usually not used */
1447 /* does this work? */
1448 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1452 shift = surface->format->Rshift;
1453 color |= *(pix + shift / 8) >> shift;
1454 shift = surface->format->Gshift;
1455 color |= *(pix + shift / 8) >> shift;
1456 shift = surface->format->Bshift;
1457 color |= *(pix + shift / 8) >> shift;
1463 case 4: /* probably 32-bpp */
1465 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1474 /* ========================================================================= */
1475 /* The following functions were taken from the SGE library */
1476 /* (SDL Graphics Extension Library) by Anders Lindström */
1477 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1478 /* ========================================================================= */
1480 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1482 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1484 switch (surface->format->BytesPerPixel)
1488 /* Assuming 8-bpp */
1489 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1495 /* Probably 15-bpp or 16-bpp */
1496 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1502 /* Slow 24-bpp mode, usually not used */
1506 /* Gack - slow, but endian correct */
1507 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1508 shift = surface->format->Rshift;
1509 *(pix+shift/8) = color>>shift;
1510 shift = surface->format->Gshift;
1511 *(pix+shift/8) = color>>shift;
1512 shift = surface->format->Bshift;
1513 *(pix+shift/8) = color>>shift;
1519 /* Probably 32-bpp */
1520 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1527 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1528 Uint8 R, Uint8 G, Uint8 B)
1530 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1533 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1535 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1538 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1540 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1543 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1548 /* Gack - slow, but endian correct */
1549 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1550 shift = surface->format->Rshift;
1551 *(pix+shift/8) = color>>shift;
1552 shift = surface->format->Gshift;
1553 *(pix+shift/8) = color>>shift;
1554 shift = surface->format->Bshift;
1555 *(pix+shift/8) = color>>shift;
1558 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1560 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1563 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1565 switch (dest->format->BytesPerPixel)
1568 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1572 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1576 _PutPixel24(dest,x,y,color);
1580 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1585 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1587 if (SDL_MUSTLOCK(surface))
1589 if (SDL_LockSurface(surface) < 0)
1595 _PutPixel(surface, x, y, color);
1597 if (SDL_MUSTLOCK(surface))
1599 SDL_UnlockSurface(surface);
1603 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1604 Uint8 r, Uint8 g, Uint8 b)
1606 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1609 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1611 if (y >= 0 && y <= dest->h - 1)
1613 switch (dest->format->BytesPerPixel)
1616 return y*dest->pitch;
1620 return y*dest->pitch/2;
1624 return y*dest->pitch;
1628 return y*dest->pitch/4;
1636 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1638 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1640 switch (surface->format->BytesPerPixel)
1644 /* Assuming 8-bpp */
1645 *((Uint8 *)surface->pixels + ypitch + x) = color;
1651 /* Probably 15-bpp or 16-bpp */
1652 *((Uint16 *)surface->pixels + ypitch + x) = color;
1658 /* Slow 24-bpp mode, usually not used */
1662 /* Gack - slow, but endian correct */
1663 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1664 shift = surface->format->Rshift;
1665 *(pix+shift/8) = color>>shift;
1666 shift = surface->format->Gshift;
1667 *(pix+shift/8) = color>>shift;
1668 shift = surface->format->Bshift;
1669 *(pix+shift/8) = color>>shift;
1675 /* Probably 32-bpp */
1676 *((Uint32 *)surface->pixels + ypitch + x) = color;
1683 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1688 if (SDL_MUSTLOCK(Surface))
1690 if (SDL_LockSurface(Surface) < 0)
1703 /* Do the clipping */
1704 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1708 if (x2 > Surface->w - 1)
1709 x2 = Surface->w - 1;
1716 SDL_FillRect(Surface, &l, Color);
1718 if (SDL_MUSTLOCK(Surface))
1720 SDL_UnlockSurface(Surface);
1724 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1725 Uint8 R, Uint8 G, Uint8 B)
1727 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1730 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1741 /* Do the clipping */
1742 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1746 if (x2 > Surface->w - 1)
1747 x2 = Surface->w - 1;
1754 SDL_FillRect(Surface, &l, Color);
1757 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1762 if (SDL_MUSTLOCK(Surface))
1764 if (SDL_LockSurface(Surface) < 0)
1777 /* Do the clipping */
1778 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1782 if (y2 > Surface->h - 1)
1783 y2 = Surface->h - 1;
1790 SDL_FillRect(Surface, &l, Color);
1792 if (SDL_MUSTLOCK(Surface))
1794 SDL_UnlockSurface(Surface);
1798 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1799 Uint8 R, Uint8 G, Uint8 B)
1801 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1804 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1815 /* Do the clipping */
1816 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1820 if (y2 > Surface->h - 1)
1821 y2 = Surface->h - 1;
1828 SDL_FillRect(Surface, &l, Color);
1831 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1832 Sint16 x2, Sint16 y2, Uint32 Color,
1833 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1836 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1841 sdx = (dx < 0) ? -1 : 1;
1842 sdy = (dy < 0) ? -1 : 1;
1854 for (x = 0; x < dx; x++)
1856 Callback(Surface, px, py, Color);
1870 for (y = 0; y < dy; y++)
1872 Callback(Surface, px, py, Color);
1886 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1887 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1888 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1891 sge_DoLine(Surface, X1, Y1, X2, Y2,
1892 SDL_MapRGB(Surface->format, R, G, B), Callback);
1895 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1898 if (SDL_MUSTLOCK(Surface))
1900 if (SDL_LockSurface(Surface) < 0)
1905 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1907 /* unlock the display */
1908 if (SDL_MUSTLOCK(Surface))
1910 SDL_UnlockSurface(Surface);
1914 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1915 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1917 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1920 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1922 if (dst_bitmap == backbuffer || dst_bitmap == window)
1928 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1933 -----------------------------------------------------------------------------
1934 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1935 -----------------------------------------------------------------------------
1938 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1939 int width, int height, Uint32 color)
1943 for (y = src_y; y < src_y + height; y++)
1945 for (x = src_x; x < src_x + width; x++)
1947 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1949 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1954 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1955 int src_x, int src_y, int width, int height,
1956 int dst_x, int dst_y)
1960 for (y = 0; y < height; y++)
1962 for (x = 0; x < width; x++)
1964 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1966 if (pixel != BLACK_PIXEL)
1967 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1973 /* ========================================================================= */
1974 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1975 /* (Rotozoomer) by Andreas Schiffler */
1976 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1977 /* ========================================================================= */
1980 -----------------------------------------------------------------------------
1983 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1984 -----------------------------------------------------------------------------
1995 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1998 tColorRGBA *sp, *csp, *dp;
2005 sp = csp = (tColorRGBA *) src->pixels;
2006 dp = (tColorRGBA *) dst->pixels;
2008 sgap = src->pitch - src->w * 4;
2010 dgap = dst->pitch - dst->w * 4;
2012 for (y = 0; y < dst->h; y++)
2016 for (x = 0; x < dst->w; x++)
2018 tColorRGBA *sp0 = sp;
2019 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
2020 tColorRGBA *sp00 = &sp0[0];
2021 tColorRGBA *sp01 = &sp0[1];
2022 tColorRGBA *sp10 = &sp1[0];
2023 tColorRGBA *sp11 = &sp1[1];
2026 /* create new color pixel from all four source color pixels */
2027 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2028 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2029 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2030 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2035 /* advance source pointers */
2038 /* advance destination pointer */
2042 /* advance source pointer */
2043 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2045 /* advance destination pointers */
2046 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2052 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2054 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2055 tColorRGBA *sp, *csp, *dp;
2061 /* use specialized zoom function when scaling down to exactly half size */
2062 if (src->w == 2 * dst->w &&
2063 src->h == 2 * dst->h)
2064 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2066 /* variable setup */
2067 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
2068 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
2070 /* allocate memory for row increments */
2071 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2072 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2074 /* precalculate row increments */
2077 for (x = 0; x <= dst->w; x++)
2087 for (y = 0; y <= dst->h; y++)
2096 sp = csp = (tColorRGBA *) src->pixels;
2097 dp = (tColorRGBA *) dst->pixels;
2099 sgap = src->pitch - src->w * 4;
2101 dgap = dst->pitch - dst->w * 4;
2104 for (y = 0; y < dst->h; y++)
2109 for (x = 0; x < dst->w; x++)
2114 /* advance source pointers */
2116 sp += (*csax >> 16);
2118 /* advance destination pointer */
2122 /* advance source pointer */
2124 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
2126 /* advance destination pointers */
2127 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2137 -----------------------------------------------------------------------------
2140 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2141 -----------------------------------------------------------------------------
2144 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2146 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2147 Uint8 *sp, *dp, *csp;
2150 /* variable setup */
2151 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2152 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2154 /* allocate memory for row increments */
2155 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2156 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2158 /* precalculate row increments */
2161 for (x = 0; x < dst->w; x++)
2164 *csax = (csx >> 16);
2171 for (y = 0; y < dst->h; y++)
2174 *csay = (csy >> 16);
2181 for (x = 0; x < dst->w; x++)
2189 for (y = 0; y < dst->h; y++)
2196 sp = csp = (Uint8 *) src->pixels;
2197 dp = (Uint8 *) dst->pixels;
2198 dgap = dst->pitch - dst->w;
2202 for (y = 0; y < dst->h; y++)
2206 for (x = 0; x < dst->w; x++)
2211 /* advance source pointers */
2215 /* advance destination pointer */
2219 /* advance source pointer (for row) */
2220 csp += ((*csay) * src->pitch);
2223 /* advance destination pointers */
2234 -----------------------------------------------------------------------------
2237 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2238 'zoomx' and 'zoomy' are scaling factors for width and height.
2239 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2240 into a 32bit RGBA format on the fly.
2241 -----------------------------------------------------------------------------
2244 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2246 SDL_Surface *zoom_src = NULL;
2247 SDL_Surface *zoom_dst = NULL;
2248 boolean is_converted = FALSE;
2255 /* determine if source surface is 32 bit or 8 bit */
2256 is_32bit = (src->format->BitsPerPixel == 32);
2258 if (is_32bit || src->format->BitsPerPixel == 8)
2260 /* use source surface 'as is' */
2265 /* new source surface is 32 bit with a defined RGB ordering */
2266 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
2267 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2268 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2270 is_converted = TRUE;
2273 /* allocate surface to completely contain the zoomed surface */
2276 /* target surface is 32 bit with source RGBA/ABGR ordering */
2277 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
2278 zoom_src->format->Rmask,
2279 zoom_src->format->Gmask,
2280 zoom_src->format->Bmask, 0);
2284 /* target surface is 8 bit */
2285 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
2289 /* lock source surface */
2290 SDL_LockSurface(zoom_src);
2292 /* check which kind of surface we have */
2295 /* call the 32 bit transformation routine to do the zooming */
2296 zoomSurfaceRGBA(zoom_src, zoom_dst);
2301 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2302 zoom_dst->format->palette->colors[i] =
2303 zoom_src->format->palette->colors[i];
2304 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2306 /* call the 8 bit transformation routine to do the zooming */
2307 zoomSurfaceY(zoom_src, zoom_dst);
2310 /* unlock source surface */
2311 SDL_UnlockSurface(zoom_src);
2313 /* free temporary surface */
2315 SDL_FreeSurface(zoom_src);
2317 /* return destination surface */
2321 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
2323 SDL_Surface *sdl_surface_tmp;
2324 int dst_width = dst_bitmap->width;
2325 int dst_height = dst_bitmap->height;
2327 /* throw away old destination surface */
2328 SDL_FreeSurface(dst_bitmap->surface);
2330 /* create zoomed temporary surface from source surface */
2331 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2333 /* create native format destination surface from zoomed temporary surface */
2334 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
2336 /* free temporary surface */
2337 SDL_FreeSurface(sdl_surface_tmp);
2341 /* ========================================================================= */
2342 /* load image to bitmap */
2343 /* ========================================================================= */
2345 Bitmap *SDLLoadImage(char *filename)
2347 Bitmap *new_bitmap = CreateBitmapStruct();
2348 SDL_Surface *sdl_image_tmp;
2350 print_timestamp_init("SDLLoadImage");
2352 print_timestamp_time(getBaseNamePtr(filename));
2354 /* load image to temporary surface */
2355 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2357 SetError("IMG_Load(): %s", SDL_GetError());
2362 print_timestamp_time("IMG_Load");
2364 UPDATE_BUSY_STATE();
2366 /* create native non-transparent surface for current image */
2367 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2369 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2374 print_timestamp_time("SDL_DisplayFormat (opaque)");
2376 UPDATE_BUSY_STATE();
2378 /* create native transparent surface for current image */
2379 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2380 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2381 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2383 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2388 print_timestamp_time("SDL_DisplayFormat (masked)");
2390 UPDATE_BUSY_STATE();
2392 /* free temporary surface */
2393 SDL_FreeSurface(sdl_image_tmp);
2395 new_bitmap->width = new_bitmap->surface->w;
2396 new_bitmap->height = new_bitmap->surface->h;
2398 print_timestamp_done("SDLLoadImage");
2404 /* ------------------------------------------------------------------------- */
2405 /* custom cursor fuctions */
2406 /* ------------------------------------------------------------------------- */
2408 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2410 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2411 cursor_info->width, cursor_info->height,
2412 cursor_info->hot_x, cursor_info->hot_y);
2415 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2417 static struct MouseCursorInfo *last_cursor_info = NULL;
2418 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2419 static SDL_Cursor *cursor_default = NULL;
2420 static SDL_Cursor *cursor_current = NULL;
2422 /* if invoked for the first time, store the SDL default cursor */
2423 if (cursor_default == NULL)
2424 cursor_default = SDL_GetCursor();
2426 /* only create new cursor if cursor info (custom only) has changed */
2427 if (cursor_info != NULL && cursor_info != last_cursor_info)
2429 cursor_current = create_cursor(cursor_info);
2430 last_cursor_info = cursor_info;
2433 /* only set new cursor if cursor info (custom or NULL) has changed */
2434 if (cursor_info != last_cursor_info2)
2435 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2437 last_cursor_info2 = cursor_info;
2441 /* ========================================================================= */
2442 /* audio functions */
2443 /* ========================================================================= */
2445 void SDLOpenAudio(void)
2447 #if !defined(TARGET_SDL2)
2448 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2449 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2452 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2454 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2458 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2459 AUDIO_NUM_CHANNELS_STEREO,
2460 setup.system.audio_fragment_size) < 0)
2462 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2466 audio.sound_available = TRUE;
2467 audio.music_available = TRUE;
2468 audio.loops_available = TRUE;
2469 audio.sound_enabled = TRUE;
2471 /* set number of available mixer channels */
2472 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2473 audio.music_channel = MUSIC_CHANNEL;
2474 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2476 Mixer_InitChannels();
2479 void SDLCloseAudio(void)
2482 Mix_HaltChannel(-1);
2485 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2489 /* ========================================================================= */
2490 /* event functions */
2491 /* ========================================================================= */
2493 void SDLNextEvent(Event *event)
2495 SDL_WaitEvent(event);
2497 if (event->type == EVENT_BUTTONPRESS ||
2498 event->type == EVENT_BUTTONRELEASE)
2500 if (((ButtonEvent *)event)->x > video_xoffset)
2501 ((ButtonEvent *)event)->x -= video_xoffset;
2503 ((ButtonEvent *)event)->x = 0;
2504 if (((ButtonEvent *)event)->y > video_yoffset)
2505 ((ButtonEvent *)event)->y -= video_yoffset;
2507 ((ButtonEvent *)event)->y = 0;
2509 else if (event->type == EVENT_MOTIONNOTIFY)
2511 if (((MotionEvent *)event)->x > video_xoffset)
2512 ((MotionEvent *)event)->x -= video_xoffset;
2514 ((MotionEvent *)event)->x = 0;
2515 if (((MotionEvent *)event)->y > video_yoffset)
2516 ((MotionEvent *)event)->y -= video_yoffset;
2518 ((MotionEvent *)event)->y = 0;
2522 void SDLHandleWindowManagerEvent(Event *event)
2524 #if defined(PLATFORM_WIN32)
2525 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2526 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2528 #if defined(TARGET_SDL2)
2529 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2531 if (syswmmsg->msg == WM_DROPFILES)
2534 #if defined(TARGET_SDL2)
2535 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2537 HDROP hdrop = (HDROP)syswmmsg->wParam;
2541 printf("::: SDL_SYSWMEVENT:\n");
2543 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2545 for (i = 0; i < num_files; i++)
2547 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2548 char buffer[buffer_len + 1];
2550 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2552 printf("::: - '%s'\n", buffer);
2555 #if defined(TARGET_SDL2)
2556 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2558 DragFinish((HDROP)syswmmsg->wParam);
2565 /* ========================================================================= */
2566 /* joystick functions */
2567 /* ========================================================================= */
2569 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2570 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2571 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2573 static boolean SDLOpenJoystick(int nr)
2575 if (nr < 0 || nr > MAX_PLAYERS)
2578 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2581 static void SDLCloseJoystick(int nr)
2583 if (nr < 0 || nr > MAX_PLAYERS)
2586 SDL_JoystickClose(sdl_joystick[nr]);
2588 sdl_joystick[nr] = NULL;
2591 static boolean SDLCheckJoystickOpened(int nr)
2593 if (nr < 0 || nr > MAX_PLAYERS)
2596 #if defined(TARGET_SDL2)
2597 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2599 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2603 void HandleJoystickEvent(Event *event)
2607 case SDL_JOYAXISMOTION:
2608 if (event->jaxis.axis < 2)
2609 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2612 case SDL_JOYBUTTONDOWN:
2613 if (event->jbutton.button < 2)
2614 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2617 case SDL_JOYBUTTONUP:
2618 if (event->jbutton.button < 2)
2619 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2627 void SDLInitJoysticks()
2629 static boolean sdl_joystick_subsystem_initialized = FALSE;
2630 boolean print_warning = !sdl_joystick_subsystem_initialized;
2633 if (!sdl_joystick_subsystem_initialized)
2635 sdl_joystick_subsystem_initialized = TRUE;
2637 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2639 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2644 for (i = 0; i < MAX_PLAYERS; i++)
2646 /* get configured joystick for this player */
2647 char *device_name = setup.input[i].joy.device_name;
2648 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2650 if (joystick_nr >= SDL_NumJoysticks())
2652 if (setup.input[i].use_joystick && print_warning)
2653 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2658 /* misuse joystick file descriptor variable to store joystick number */
2659 joystick.fd[i] = joystick_nr;
2661 if (joystick_nr == -1)
2664 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2665 if (SDLCheckJoystickOpened(joystick_nr))
2666 SDLCloseJoystick(joystick_nr);
2668 if (!setup.input[i].use_joystick)
2671 if (!SDLOpenJoystick(joystick_nr))
2674 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2679 joystick.status = JOYSTICK_ACTIVATED;
2683 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2685 if (nr < 0 || nr >= MAX_PLAYERS)
2689 *x = sdl_js_axis[nr][0];
2691 *y = sdl_js_axis[nr][1];
2694 *b1 = sdl_js_button[nr][0];
2696 *b2 = sdl_js_button[nr][1];
2701 #endif /* TARGET_SDL */