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;
820 SDL_VERSION(&wminfo.version);
821 SDL_GetWMInfo(&wminfo);
823 hwnd = wminfo.window;
825 DragAcceptFiles(hwnd, TRUE);
833 #if defined(TARGET_SDL2)
834 void SDLSetWindowTitle()
836 SDL_SetWindowTitle(sdl_window, program.window_title);
839 void SDLSetWindowScaling(int window_scaling_percent)
841 if (sdl_window == NULL)
844 float window_scaling_factor = (float)window_scaling_percent / 100;
845 int new_window_width = (int)(window_scaling_factor * video.width);
846 int new_window_height = (int)(window_scaling_factor * video.height);
849 Error(ERR_DEBUG, "::: SDLSetWindowScaling(%d) ...", window_scaling_percent);
852 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
854 video.window_scaling_percent = window_scaling_percent;
855 video.window_width = new_window_width;
856 video.window_height = new_window_height;
861 void SDLSetWindowScalingQuality(char *window_scaling_quality)
863 if (sdl_texture == NULL)
866 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
868 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
869 SDL_PIXELFORMAT_ARGB8888,
870 SDL_TEXTUREACCESS_STREAMING,
871 video.width, video.height);
873 if (new_texture != NULL)
875 SDL_DestroyTexture(sdl_texture);
877 sdl_texture = new_texture;
882 video.window_scaling_quality = window_scaling_quality;
885 void SDLSetWindowFullscreen(boolean fullscreen)
887 if (sdl_window == NULL)
890 #if USE_DESKTOP_FULLSCREEN
891 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
893 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
897 Error(ERR_DEBUG, "::: SDL_SetWindowFullscreen(%d) ...", fullscreen);
900 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
901 video.fullscreen_enabled = fullscreen;
904 printf("::: SDLSetWindowFullscreen: %d, %d\n",
905 fullscreen, video.fullscreen_initial);
909 // if game started in fullscreen mode, window will also get fullscreen size
910 if (!fullscreen && video.fullscreen_initial)
912 SDLSetWindowScaling(setup.window_scaling_percent);
913 SDL_SetWindowPosition(sdl_window,
914 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
916 video.fullscreen_initial = FALSE;
921 void SDLRedrawWindow()
927 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
930 SDL_Surface *surface_tmp, *surface_native;
932 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
935 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
937 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
938 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
940 SDL_FreeSurface(surface_tmp);
942 new_bitmap->surface = surface_native;
945 void SDLFreeBitmapPointers(Bitmap *bitmap)
948 SDL_FreeSurface(bitmap->surface);
949 if (bitmap->surface_masked)
950 SDL_FreeSurface(bitmap->surface_masked);
951 bitmap->surface = NULL;
952 bitmap->surface_masked = NULL;
955 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
956 int src_x, int src_y, int width, int height,
957 int dst_x, int dst_y, int mask_mode)
959 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
960 SDL_Rect src_rect, dst_rect;
962 if (src_bitmap == backbuffer)
964 src_x += video_xoffset;
965 src_y += video_yoffset;
973 if (dst_bitmap == backbuffer || dst_bitmap == window)
975 dst_x += video_xoffset;
976 dst_y += video_yoffset;
984 // if (src_bitmap != backbuffer || dst_bitmap != window)
985 if (!(src_bitmap == backbuffer && dst_bitmap == window))
986 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
987 src_bitmap->surface_masked : src_bitmap->surface),
988 &src_rect, real_dst_bitmap->surface, &dst_rect);
990 #if defined(TARGET_SDL2)
991 if (dst_bitmap == window)
993 // SDL_UpdateWindowSurface(sdl_window);
994 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
995 UpdateScreen(&dst_rect);
998 if (dst_bitmap == window)
1000 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
1001 UpdateScreen(&dst_rect);
1006 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
1009 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1012 if (dst_bitmap == backbuffer || dst_bitmap == window)
1023 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
1025 #if defined(TARGET_SDL2)
1026 if (dst_bitmap == window)
1028 // SDL_UpdateWindowSurface(sdl_window);
1029 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
1030 UpdateScreen(&rect);
1033 if (dst_bitmap == window)
1035 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
1036 UpdateScreen(&rect);
1041 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
1042 int fade_mode, int fade_delay, int post_delay,
1043 void (*draw_border_function)(void))
1045 static boolean initialization_needed = TRUE;
1046 static SDL_Surface *surface_source = NULL;
1047 static SDL_Surface *surface_target = NULL;
1048 static SDL_Surface *surface_black = NULL;
1049 SDL_Surface *surface_screen = backbuffer->surface;
1050 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
1051 SDL_Rect src_rect, dst_rect;
1053 int src_x = x, src_y = y;
1054 int dst_x = x, dst_y = y;
1055 unsigned int time_last, time_current;
1057 /* check if screen size has changed */
1058 if (surface_source != NULL && (video.width != surface_source->w ||
1059 video.height != surface_source->h))
1061 SDL_FreeSurface(surface_source);
1062 SDL_FreeSurface(surface_target);
1063 SDL_FreeSurface(surface_black);
1065 initialization_needed = TRUE;
1071 src_rect.h = height;
1073 dst_x += video_xoffset;
1074 dst_y += video_yoffset;
1078 dst_rect.w = width; /* (ignored) */
1079 dst_rect.h = height; /* (ignored) */
1081 dst_rect2 = dst_rect;
1083 if (initialization_needed)
1085 #if defined(TARGET_SDL2)
1086 unsigned int flags = 0;
1088 unsigned int flags = SDL_SRCALPHA;
1090 /* use same surface type as screen surface */
1091 if ((surface_screen->flags & SDL_HWSURFACE))
1092 flags |= SDL_HWSURFACE;
1094 flags |= SDL_SWSURFACE;
1097 /* create surface for temporary copy of screen buffer (source) */
1098 if ((surface_source =
1099 SDL_CreateRGBSurface(flags,
1102 surface_screen->format->BitsPerPixel,
1103 surface_screen->format->Rmask,
1104 surface_screen->format->Gmask,
1105 surface_screen->format->Bmask,
1106 surface_screen->format->Amask)) == NULL)
1107 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1109 /* create surface for cross-fading screen buffer (target) */
1110 if ((surface_target =
1111 SDL_CreateRGBSurface(flags,
1114 surface_screen->format->BitsPerPixel,
1115 surface_screen->format->Rmask,
1116 surface_screen->format->Gmask,
1117 surface_screen->format->Bmask,
1118 surface_screen->format->Amask)) == NULL)
1119 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1121 /* create black surface for fading from/to black */
1122 if ((surface_black =
1123 SDL_CreateRGBSurface(flags,
1126 surface_screen->format->BitsPerPixel,
1127 surface_screen->format->Rmask,
1128 surface_screen->format->Gmask,
1129 surface_screen->format->Bmask,
1130 surface_screen->format->Amask)) == NULL)
1131 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1133 /* completely fill the surface with black color pixels */
1134 SDL_FillRect(surface_black, NULL,
1135 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1137 initialization_needed = FALSE;
1140 /* copy source and target surfaces to temporary surfaces for fading */
1141 if (fade_mode & FADE_TYPE_TRANSFORM)
1143 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1144 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1146 else if (fade_mode & FADE_TYPE_FADE_IN)
1148 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1149 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1151 else /* FADE_TYPE_FADE_OUT */
1153 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1154 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1157 time_current = SDL_GetTicks();
1159 if (fade_mode == FADE_MODE_MELT)
1161 boolean done = FALSE;
1162 int melt_pixels = 2;
1163 int melt_columns = width / melt_pixels;
1164 int ypos[melt_columns];
1165 int max_steps = height / 8 + 32;
1170 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1171 #if defined(TARGET_SDL2)
1172 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1174 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1177 ypos[0] = -GetSimpleRandom(16);
1179 for (i = 1 ; i < melt_columns; i++)
1181 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1183 ypos[i] = ypos[i - 1] + r;
1196 time_last = time_current;
1197 time_current = SDL_GetTicks();
1198 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1199 steps_final = MIN(MAX(0, steps), max_steps);
1203 done = (steps_done >= steps_final);
1205 for (i = 0 ; i < melt_columns; i++)
1213 else if (ypos[i] < height)
1218 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1220 if (ypos[i] + dy >= height)
1221 dy = height - ypos[i];
1223 /* copy part of (appearing) target surface to upper area */
1224 src_rect.x = src_x + i * melt_pixels;
1225 // src_rect.y = src_y + ypos[i];
1227 src_rect.w = melt_pixels;
1229 src_rect.h = ypos[i] + dy;
1231 dst_rect.x = dst_x + i * melt_pixels;
1232 // dst_rect.y = dst_y + ypos[i];
1235 if (steps_done >= steps_final)
1236 SDL_BlitSurface(surface_target, &src_rect,
1237 surface_screen, &dst_rect);
1241 /* copy part of (disappearing) source surface to lower area */
1242 src_rect.x = src_x + i * melt_pixels;
1244 src_rect.w = melt_pixels;
1245 src_rect.h = height - ypos[i];
1247 dst_rect.x = dst_x + i * melt_pixels;
1248 dst_rect.y = dst_y + ypos[i];
1250 if (steps_done >= steps_final)
1251 SDL_BlitSurface(surface_source, &src_rect,
1252 surface_screen, &dst_rect);
1258 src_rect.x = src_x + i * melt_pixels;
1260 src_rect.w = melt_pixels;
1261 src_rect.h = height;
1263 dst_rect.x = dst_x + i * melt_pixels;
1266 if (steps_done >= steps_final)
1267 SDL_BlitSurface(surface_target, &src_rect,
1268 surface_screen, &dst_rect);
1272 if (steps_done >= steps_final)
1274 if (draw_border_function != NULL)
1275 draw_border_function();
1277 #if defined(TARGET_SDL2)
1278 // SDL_UpdateWindowSurface(sdl_window);
1279 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
1280 UpdateScreen(&dst_rect2);
1282 // SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1283 UpdateScreen(&dst_rect2);
1293 for (alpha = 0.0; alpha < 255.0;)
1295 time_last = time_current;
1296 time_current = SDL_GetTicks();
1297 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1298 alpha_final = MIN(MAX(0, alpha), 255);
1300 /* draw existing (source) image to screen buffer */
1301 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1303 /* draw new (target) image to screen buffer using alpha blending */
1304 #if defined(TARGET_SDL2)
1305 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1306 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1308 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1310 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1312 if (draw_border_function != NULL)
1313 draw_border_function();
1316 /* only update the region of the screen that is affected from fading */
1317 #if defined(TARGET_SDL2)
1318 // SDL_UpdateWindowSurface(sdl_window);
1319 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1320 UpdateScreen(&dst_rect);
1322 // SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1323 UpdateScreen(&dst_rect);
1326 SDL_Flip(surface_screen);
1334 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1335 int to_x, int to_y, Uint32 color)
1337 SDL_Surface *surface = dst_bitmap->surface;
1341 swap_numbers(&from_x, &to_x);
1344 swap_numbers(&from_y, &to_y);
1348 rect.w = (to_x - from_x + 1);
1349 rect.h = (to_y - from_y + 1);
1351 if (dst_bitmap == backbuffer || dst_bitmap == window)
1353 rect.x += video_xoffset;
1354 rect.y += video_yoffset;
1357 SDL_FillRect(surface, &rect, color);
1360 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1361 int to_x, int to_y, Uint32 color)
1363 if (dst_bitmap == backbuffer || dst_bitmap == window)
1365 from_x += video_xoffset;
1366 from_y += video_yoffset;
1367 to_x += video_xoffset;
1368 to_y += video_yoffset;
1371 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1375 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1376 int num_points, Uint32 color)
1381 for (i = 0; i < num_points - 1; i++)
1383 for (x = 0; x < line_width; x++)
1385 for (y = 0; y < line_width; y++)
1387 int dx = x - line_width / 2;
1388 int dy = y - line_width / 2;
1390 if ((x == 0 && y == 0) ||
1391 (x == 0 && y == line_width - 1) ||
1392 (x == line_width - 1 && y == 0) ||
1393 (x == line_width - 1 && y == line_width - 1))
1396 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1397 points[i+1].x + dx, points[i+1].y + dy, color);
1404 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1406 SDL_Surface *surface = src_bitmap->surface;
1408 if (src_bitmap == backbuffer || src_bitmap == window)
1414 switch (surface->format->BytesPerPixel)
1416 case 1: /* assuming 8-bpp */
1418 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1422 case 2: /* probably 15-bpp or 16-bpp */
1424 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1428 case 3: /* slow 24-bpp mode; usually not used */
1430 /* does this work? */
1431 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1435 shift = surface->format->Rshift;
1436 color |= *(pix + shift / 8) >> shift;
1437 shift = surface->format->Gshift;
1438 color |= *(pix + shift / 8) >> shift;
1439 shift = surface->format->Bshift;
1440 color |= *(pix + shift / 8) >> shift;
1446 case 4: /* probably 32-bpp */
1448 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1457 /* ========================================================================= */
1458 /* The following functions were taken from the SGE library */
1459 /* (SDL Graphics Extension Library) by Anders Lindström */
1460 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1461 /* ========================================================================= */
1463 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1465 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1467 switch (surface->format->BytesPerPixel)
1471 /* Assuming 8-bpp */
1472 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1478 /* Probably 15-bpp or 16-bpp */
1479 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1485 /* Slow 24-bpp mode, usually not used */
1489 /* Gack - slow, but endian correct */
1490 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1491 shift = surface->format->Rshift;
1492 *(pix+shift/8) = color>>shift;
1493 shift = surface->format->Gshift;
1494 *(pix+shift/8) = color>>shift;
1495 shift = surface->format->Bshift;
1496 *(pix+shift/8) = color>>shift;
1502 /* Probably 32-bpp */
1503 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1510 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1511 Uint8 R, Uint8 G, Uint8 B)
1513 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1516 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1518 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1521 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1523 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1526 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1531 /* Gack - slow, but endian correct */
1532 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1533 shift = surface->format->Rshift;
1534 *(pix+shift/8) = color>>shift;
1535 shift = surface->format->Gshift;
1536 *(pix+shift/8) = color>>shift;
1537 shift = surface->format->Bshift;
1538 *(pix+shift/8) = color>>shift;
1541 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1543 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1546 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1548 switch (dest->format->BytesPerPixel)
1551 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1555 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1559 _PutPixel24(dest,x,y,color);
1563 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1568 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1570 if (SDL_MUSTLOCK(surface))
1572 if (SDL_LockSurface(surface) < 0)
1578 _PutPixel(surface, x, y, color);
1580 if (SDL_MUSTLOCK(surface))
1582 SDL_UnlockSurface(surface);
1586 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1587 Uint8 r, Uint8 g, Uint8 b)
1589 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1592 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1594 if (y >= 0 && y <= dest->h - 1)
1596 switch (dest->format->BytesPerPixel)
1599 return y*dest->pitch;
1603 return y*dest->pitch/2;
1607 return y*dest->pitch;
1611 return y*dest->pitch/4;
1619 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1621 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1623 switch (surface->format->BytesPerPixel)
1627 /* Assuming 8-bpp */
1628 *((Uint8 *)surface->pixels + ypitch + x) = color;
1634 /* Probably 15-bpp or 16-bpp */
1635 *((Uint16 *)surface->pixels + ypitch + x) = color;
1641 /* Slow 24-bpp mode, usually not used */
1645 /* Gack - slow, but endian correct */
1646 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1647 shift = surface->format->Rshift;
1648 *(pix+shift/8) = color>>shift;
1649 shift = surface->format->Gshift;
1650 *(pix+shift/8) = color>>shift;
1651 shift = surface->format->Bshift;
1652 *(pix+shift/8) = color>>shift;
1658 /* Probably 32-bpp */
1659 *((Uint32 *)surface->pixels + ypitch + x) = color;
1666 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1671 if (SDL_MUSTLOCK(Surface))
1673 if (SDL_LockSurface(Surface) < 0)
1686 /* Do the clipping */
1687 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1691 if (x2 > Surface->w - 1)
1692 x2 = Surface->w - 1;
1699 SDL_FillRect(Surface, &l, Color);
1701 if (SDL_MUSTLOCK(Surface))
1703 SDL_UnlockSurface(Surface);
1707 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1708 Uint8 R, Uint8 G, Uint8 B)
1710 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1713 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1724 /* Do the clipping */
1725 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1729 if (x2 > Surface->w - 1)
1730 x2 = Surface->w - 1;
1737 SDL_FillRect(Surface, &l, Color);
1740 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1745 if (SDL_MUSTLOCK(Surface))
1747 if (SDL_LockSurface(Surface) < 0)
1760 /* Do the clipping */
1761 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1765 if (y2 > Surface->h - 1)
1766 y2 = Surface->h - 1;
1773 SDL_FillRect(Surface, &l, Color);
1775 if (SDL_MUSTLOCK(Surface))
1777 SDL_UnlockSurface(Surface);
1781 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1782 Uint8 R, Uint8 G, Uint8 B)
1784 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1787 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1798 /* Do the clipping */
1799 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1803 if (y2 > Surface->h - 1)
1804 y2 = Surface->h - 1;
1811 SDL_FillRect(Surface, &l, Color);
1814 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1815 Sint16 x2, Sint16 y2, Uint32 Color,
1816 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1819 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1824 sdx = (dx < 0) ? -1 : 1;
1825 sdy = (dy < 0) ? -1 : 1;
1837 for (x = 0; x < dx; x++)
1839 Callback(Surface, px, py, Color);
1853 for (y = 0; y < dy; y++)
1855 Callback(Surface, px, py, Color);
1869 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1870 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1871 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1874 sge_DoLine(Surface, X1, Y1, X2, Y2,
1875 SDL_MapRGB(Surface->format, R, G, B), Callback);
1878 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1881 if (SDL_MUSTLOCK(Surface))
1883 if (SDL_LockSurface(Surface) < 0)
1888 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1890 /* unlock the display */
1891 if (SDL_MUSTLOCK(Surface))
1893 SDL_UnlockSurface(Surface);
1897 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1898 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1900 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1903 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1905 if (dst_bitmap == backbuffer || dst_bitmap == window)
1911 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1916 -----------------------------------------------------------------------------
1917 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1918 -----------------------------------------------------------------------------
1921 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1922 int width, int height, Uint32 color)
1926 for (y = src_y; y < src_y + height; y++)
1928 for (x = src_x; x < src_x + width; x++)
1930 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1932 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1937 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1938 int src_x, int src_y, int width, int height,
1939 int dst_x, int dst_y)
1943 for (y = 0; y < height; y++)
1945 for (x = 0; x < width; x++)
1947 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1949 if (pixel != BLACK_PIXEL)
1950 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1956 /* ========================================================================= */
1957 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1958 /* (Rotozoomer) by Andreas Schiffler */
1959 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1960 /* ========================================================================= */
1963 -----------------------------------------------------------------------------
1966 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1967 -----------------------------------------------------------------------------
1978 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1981 tColorRGBA *sp, *csp, *dp;
1988 sp = csp = (tColorRGBA *) src->pixels;
1989 dp = (tColorRGBA *) dst->pixels;
1991 sgap = src->pitch - src->w * 4;
1993 dgap = dst->pitch - dst->w * 4;
1995 for (y = 0; y < dst->h; y++)
1999 for (x = 0; x < dst->w; x++)
2001 tColorRGBA *sp0 = sp;
2002 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
2003 tColorRGBA *sp00 = &sp0[0];
2004 tColorRGBA *sp01 = &sp0[1];
2005 tColorRGBA *sp10 = &sp1[0];
2006 tColorRGBA *sp11 = &sp1[1];
2009 /* create new color pixel from all four source color pixels */
2010 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2011 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2012 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2013 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2018 /* advance source pointers */
2021 /* advance destination pointer */
2025 /* advance source pointer */
2026 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2028 /* advance destination pointers */
2029 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2035 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2037 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2038 tColorRGBA *sp, *csp, *dp;
2044 /* use specialized zoom function when scaling down to exactly half size */
2045 if (src->w == 2 * dst->w &&
2046 src->h == 2 * dst->h)
2047 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2049 /* variable setup */
2050 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
2051 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
2053 /* allocate memory for row increments */
2054 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2055 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2057 /* precalculate row increments */
2060 for (x = 0; x <= dst->w; x++)
2070 for (y = 0; y <= dst->h; y++)
2079 sp = csp = (tColorRGBA *) src->pixels;
2080 dp = (tColorRGBA *) dst->pixels;
2082 sgap = src->pitch - src->w * 4;
2084 dgap = dst->pitch - dst->w * 4;
2087 for (y = 0; y < dst->h; y++)
2092 for (x = 0; x < dst->w; x++)
2097 /* advance source pointers */
2099 sp += (*csax >> 16);
2101 /* advance destination pointer */
2105 /* advance source pointer */
2107 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
2109 /* advance destination pointers */
2110 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2120 -----------------------------------------------------------------------------
2123 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2124 -----------------------------------------------------------------------------
2127 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2129 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2130 Uint8 *sp, *dp, *csp;
2133 /* variable setup */
2134 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2135 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2137 /* allocate memory for row increments */
2138 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2139 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2141 /* precalculate row increments */
2144 for (x = 0; x < dst->w; x++)
2147 *csax = (csx >> 16);
2154 for (y = 0; y < dst->h; y++)
2157 *csay = (csy >> 16);
2164 for (x = 0; x < dst->w; x++)
2172 for (y = 0; y < dst->h; y++)
2179 sp = csp = (Uint8 *) src->pixels;
2180 dp = (Uint8 *) dst->pixels;
2181 dgap = dst->pitch - dst->w;
2185 for (y = 0; y < dst->h; y++)
2189 for (x = 0; x < dst->w; x++)
2194 /* advance source pointers */
2198 /* advance destination pointer */
2202 /* advance source pointer (for row) */
2203 csp += ((*csay) * src->pitch);
2206 /* advance destination pointers */
2217 -----------------------------------------------------------------------------
2220 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2221 'zoomx' and 'zoomy' are scaling factors for width and height.
2222 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2223 into a 32bit RGBA format on the fly.
2224 -----------------------------------------------------------------------------
2227 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2229 SDL_Surface *zoom_src = NULL;
2230 SDL_Surface *zoom_dst = NULL;
2231 boolean is_converted = FALSE;
2238 /* determine if source surface is 32 bit or 8 bit */
2239 is_32bit = (src->format->BitsPerPixel == 32);
2241 if (is_32bit || src->format->BitsPerPixel == 8)
2243 /* use source surface 'as is' */
2248 /* new source surface is 32 bit with a defined RGB ordering */
2249 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
2250 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2251 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2253 is_converted = TRUE;
2256 /* allocate surface to completely contain the zoomed surface */
2259 /* target surface is 32 bit with source RGBA/ABGR ordering */
2260 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
2261 zoom_src->format->Rmask,
2262 zoom_src->format->Gmask,
2263 zoom_src->format->Bmask, 0);
2267 /* target surface is 8 bit */
2268 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
2272 /* lock source surface */
2273 SDL_LockSurface(zoom_src);
2275 /* check which kind of surface we have */
2278 /* call the 32 bit transformation routine to do the zooming */
2279 zoomSurfaceRGBA(zoom_src, zoom_dst);
2284 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2285 zoom_dst->format->palette->colors[i] =
2286 zoom_src->format->palette->colors[i];
2287 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2289 /* call the 8 bit transformation routine to do the zooming */
2290 zoomSurfaceY(zoom_src, zoom_dst);
2293 /* unlock source surface */
2294 SDL_UnlockSurface(zoom_src);
2296 /* free temporary surface */
2298 SDL_FreeSurface(zoom_src);
2300 /* return destination surface */
2304 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
2306 SDL_Surface *sdl_surface_tmp;
2307 int dst_width = dst_bitmap->width;
2308 int dst_height = dst_bitmap->height;
2310 /* throw away old destination surface */
2311 SDL_FreeSurface(dst_bitmap->surface);
2313 /* create zoomed temporary surface from source surface */
2314 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2316 /* create native format destination surface from zoomed temporary surface */
2317 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
2319 /* free temporary surface */
2320 SDL_FreeSurface(sdl_surface_tmp);
2324 /* ========================================================================= */
2325 /* load image to bitmap */
2326 /* ========================================================================= */
2328 Bitmap *SDLLoadImage(char *filename)
2330 Bitmap *new_bitmap = CreateBitmapStruct();
2331 SDL_Surface *sdl_image_tmp;
2333 print_timestamp_init("SDLLoadImage");
2335 print_timestamp_time(getBaseNamePtr(filename));
2337 /* load image to temporary surface */
2338 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2340 SetError("IMG_Load(): %s", SDL_GetError());
2345 print_timestamp_time("IMG_Load");
2347 UPDATE_BUSY_STATE();
2349 /* create native non-transparent surface for current image */
2350 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2352 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2357 print_timestamp_time("SDL_DisplayFormat (opaque)");
2359 UPDATE_BUSY_STATE();
2361 /* create native transparent surface for current image */
2362 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2363 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2364 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2366 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2371 print_timestamp_time("SDL_DisplayFormat (masked)");
2373 UPDATE_BUSY_STATE();
2375 /* free temporary surface */
2376 SDL_FreeSurface(sdl_image_tmp);
2378 new_bitmap->width = new_bitmap->surface->w;
2379 new_bitmap->height = new_bitmap->surface->h;
2381 print_timestamp_done("SDLLoadImage");
2387 /* ------------------------------------------------------------------------- */
2388 /* custom cursor fuctions */
2389 /* ------------------------------------------------------------------------- */
2391 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2393 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2394 cursor_info->width, cursor_info->height,
2395 cursor_info->hot_x, cursor_info->hot_y);
2398 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2400 static struct MouseCursorInfo *last_cursor_info = NULL;
2401 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2402 static SDL_Cursor *cursor_default = NULL;
2403 static SDL_Cursor *cursor_current = NULL;
2405 /* if invoked for the first time, store the SDL default cursor */
2406 if (cursor_default == NULL)
2407 cursor_default = SDL_GetCursor();
2409 /* only create new cursor if cursor info (custom only) has changed */
2410 if (cursor_info != NULL && cursor_info != last_cursor_info)
2412 cursor_current = create_cursor(cursor_info);
2413 last_cursor_info = cursor_info;
2416 /* only set new cursor if cursor info (custom or NULL) has changed */
2417 if (cursor_info != last_cursor_info2)
2418 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2420 last_cursor_info2 = cursor_info;
2424 /* ========================================================================= */
2425 /* audio functions */
2426 /* ========================================================================= */
2428 void SDLOpenAudio(void)
2430 #if !defined(TARGET_SDL2)
2431 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2432 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2435 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2437 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2441 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2442 AUDIO_NUM_CHANNELS_STEREO,
2443 setup.system.audio_fragment_size) < 0)
2445 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2449 audio.sound_available = TRUE;
2450 audio.music_available = TRUE;
2451 audio.loops_available = TRUE;
2452 audio.sound_enabled = TRUE;
2454 /* set number of available mixer channels */
2455 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2456 audio.music_channel = MUSIC_CHANNEL;
2457 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2459 Mixer_InitChannels();
2462 void SDLCloseAudio(void)
2465 Mix_HaltChannel(-1);
2468 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2472 /* ========================================================================= */
2473 /* event functions */
2474 /* ========================================================================= */
2476 void SDLNextEvent(Event *event)
2478 SDL_WaitEvent(event);
2480 if (event->type == EVENT_BUTTONPRESS ||
2481 event->type == EVENT_BUTTONRELEASE)
2483 if (((ButtonEvent *)event)->x > video_xoffset)
2484 ((ButtonEvent *)event)->x -= video_xoffset;
2486 ((ButtonEvent *)event)->x = 0;
2487 if (((ButtonEvent *)event)->y > video_yoffset)
2488 ((ButtonEvent *)event)->y -= video_yoffset;
2490 ((ButtonEvent *)event)->y = 0;
2492 else if (event->type == EVENT_MOTIONNOTIFY)
2494 if (((MotionEvent *)event)->x > video_xoffset)
2495 ((MotionEvent *)event)->x -= video_xoffset;
2497 ((MotionEvent *)event)->x = 0;
2498 if (((MotionEvent *)event)->y > video_yoffset)
2499 ((MotionEvent *)event)->y -= video_yoffset;
2501 ((MotionEvent *)event)->y = 0;
2505 void SDLHandleWindowManagerEvent(Event *event)
2507 #if defined(PLATFORM_WIN32)
2508 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2509 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2511 if (syswmmsg->msg == WM_DROPFILES)
2513 HDROP hdrop = (HDROP)syswmmsg->wParam;
2516 printf("::: SDL_SYSWMEVENT:\n");
2518 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2520 for (i = 0; i < num_files; i++)
2522 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2523 char buffer[buffer_len + 1];
2525 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2527 printf("::: - '%s'\n", buffer);
2530 DragFinish((HDROP)syswmmsg->wParam);
2536 /* ========================================================================= */
2537 /* joystick functions */
2538 /* ========================================================================= */
2540 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2541 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2542 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2544 static boolean SDLOpenJoystick(int nr)
2546 if (nr < 0 || nr > MAX_PLAYERS)
2549 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2552 static void SDLCloseJoystick(int nr)
2554 if (nr < 0 || nr > MAX_PLAYERS)
2557 SDL_JoystickClose(sdl_joystick[nr]);
2559 sdl_joystick[nr] = NULL;
2562 static boolean SDLCheckJoystickOpened(int nr)
2564 if (nr < 0 || nr > MAX_PLAYERS)
2567 #if defined(TARGET_SDL2)
2568 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2570 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2574 void HandleJoystickEvent(Event *event)
2578 case SDL_JOYAXISMOTION:
2579 if (event->jaxis.axis < 2)
2580 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2583 case SDL_JOYBUTTONDOWN:
2584 if (event->jbutton.button < 2)
2585 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2588 case SDL_JOYBUTTONUP:
2589 if (event->jbutton.button < 2)
2590 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2598 void SDLInitJoysticks()
2600 static boolean sdl_joystick_subsystem_initialized = FALSE;
2601 boolean print_warning = !sdl_joystick_subsystem_initialized;
2604 if (!sdl_joystick_subsystem_initialized)
2606 sdl_joystick_subsystem_initialized = TRUE;
2608 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2610 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2615 for (i = 0; i < MAX_PLAYERS; i++)
2617 /* get configured joystick for this player */
2618 char *device_name = setup.input[i].joy.device_name;
2619 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2621 if (joystick_nr >= SDL_NumJoysticks())
2623 if (setup.input[i].use_joystick && print_warning)
2624 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2629 /* misuse joystick file descriptor variable to store joystick number */
2630 joystick.fd[i] = joystick_nr;
2632 if (joystick_nr == -1)
2635 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2636 if (SDLCheckJoystickOpened(joystick_nr))
2637 SDLCloseJoystick(joystick_nr);
2639 if (!setup.input[i].use_joystick)
2642 if (!SDLOpenJoystick(joystick_nr))
2645 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2650 joystick.status = JOYSTICK_ACTIVATED;
2654 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2656 if (nr < 0 || nr >= MAX_PLAYERS)
2660 *x = sdl_js_axis[nr][0];
2662 *y = sdl_js_axis[nr][1];
2665 *b1 = sdl_js_button[nr][0];
2667 *b2 = sdl_js_button[nr][1];
2672 #endif /* TARGET_SDL */