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;
613 if (*backbuffer == NULL)
614 *backbuffer = CreateBitmapStruct();
616 /* (real bitmap might be larger in fullscreen mode with video offsets) */
617 (*backbuffer)->width = video.width;
618 (*backbuffer)->height = video.height;
620 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
622 setFullscreenParameters(setup.fullscreen_mode);
624 video_xoffset = fullscreen_xoffset;
625 video_yoffset = fullscreen_yoffset;
627 /* switch display to fullscreen mode, if available */
629 new_surface = SDLCreateScreen(backbuffer, TRUE);
632 #if defined(TARGET_SDL2)
633 sdl_window = SDL_CreateWindow(program.window_title,
634 SDL_WINDOWPOS_CENTERED,
635 SDL_WINDOWPOS_CENTERED,
636 fullscreen_width, fullscreen_height,
637 surface_flags_fullscreen);
638 if (sdl_window != NULL)
640 new_surface = SDL_GetWindowSurface(sdl_window);
642 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
643 // UpdateScreen(NULL); // immediately map window
646 new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
647 video.depth, surface_flags_fullscreen);
651 if (new_surface == NULL)
653 /* switching display to fullscreen mode failed */
654 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
656 /* do not try it again */
657 video.fullscreen_available = FALSE;
663 (*backbuffer)->surface = new_surface;
665 video.fullscreen_enabled = TRUE;
666 video.fullscreen_mode_current = setup.fullscreen_mode;
672 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
677 /* switch display to window mode */
679 new_surface = SDLCreateScreen(backbuffer, FALSE);
682 #if defined(TARGET_SDL2)
685 float screen_scaling_factor = 1.2;
686 int test_fullscreen = 0;
687 int surface_flags = (test_fullscreen ? surface_flags_fullscreen :
688 surface_flags_window);
690 if ((*backbuffer)->surface)
691 SDL_FreeSurface((*backbuffer)->surface);
694 SDL_DestroyTexture(sdl_texture);
697 SDL_DestroyRenderer(sdl_renderer);
700 SDL_DestroyWindow(sdl_window);
702 sdl_window = SDL_CreateWindow(program.window_title,
703 SDL_WINDOWPOS_CENTERED,
704 SDL_WINDOWPOS_CENTERED,
705 (int)(screen_scaling_factor * video.width),
706 (int)(screen_scaling_factor * video.height),
709 if (sdl_window != NULL)
711 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
713 if (sdl_renderer != NULL)
715 SDL_RenderSetLogicalSize(sdl_renderer, video.width, video.height);
716 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
718 sdl_texture = SDL_CreateTexture(sdl_renderer,
719 SDL_PIXELFORMAT_ARGB8888,
720 SDL_TEXTUREACCESS_STREAMING,
721 video.width, video.height);
723 if (sdl_texture != NULL)
726 // (do not use alpha channel)
727 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
733 // (this uses an alpha channel, which we don't want here)
734 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
741 if (new_surface == NULL)
742 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
747 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
752 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
757 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
763 SDL_DestroyWindow(sdl_window);
765 sdl_window = SDL_CreateWindow(program.window_title,
766 SDL_WINDOWPOS_CENTERED,
767 SDL_WINDOWPOS_CENTERED,
768 video.width, video.height,
769 surface_flags_window);
771 if (sdl_window != NULL)
773 new_surface = SDL_GetWindowSurface(sdl_window);
775 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
776 // UpdateScreen(NULL); // immediately map window
781 new_surface = SDL_SetVideoMode(video.width, video.height,
782 video.depth, surface_flags_window);
786 if (new_surface == NULL)
788 /* switching display to window mode failed -- should not happen */
789 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
795 (*backbuffer)->surface = new_surface;
797 video.fullscreen_enabled = FALSE;
798 video.window_scaling_percent = setup.window_scaling_percent;
799 video.window_scaling_quality = setup.window_scaling_quality;
805 #if defined(TARGET_SDL2)
806 SDLRedrawWindow(); // map window
807 // UpdateScreen(NULL); // map window
811 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
813 #if defined(PLATFORM_WIN32)
815 SDL_SysWMinfo wminfo;
818 SDL_VERSION(&wminfo.version);
819 SDL_GetWMInfo(&wminfo);
821 hwnd = wminfo.window;
823 DragAcceptFiles(hwnd, TRUE);
831 #if defined(TARGET_SDL2)
832 void SDLSetWindowScaling(int window_scaling_percent)
834 if (sdl_window == NULL)
837 float window_scaling_factor = (float)window_scaling_percent / 100;
838 int new_window_width = (int)(window_scaling_factor * video.width);
839 int new_window_height = (int)(window_scaling_factor * video.height);
842 Error(ERR_DEBUG, "::: SDLSetWindowScaling(%d) ...", window_scaling_percent);
845 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
847 video.window_scaling_percent = window_scaling_percent;
848 video.window_width = new_window_width;
849 video.window_height = new_window_height;
852 void SDLSetWindowScalingQuality(char *window_scaling_quality)
854 if (sdl_texture == NULL)
857 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
859 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
860 SDL_PIXELFORMAT_ARGB8888,
861 SDL_TEXTUREACCESS_STREAMING,
862 video.width, video.height);
864 if (new_texture != NULL)
866 SDL_DestroyTexture(sdl_texture);
868 sdl_texture = new_texture;
873 video.window_scaling_quality = window_scaling_quality;
876 void SDLSetWindowFullscreen(boolean fullscreen)
878 if (sdl_window == NULL)
881 #if USE_DESKTOP_FULLSCREEN
882 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
884 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
888 Error(ERR_DEBUG, "::: SDL_SetWindowFullscreen(%d) ...", fullscreen);
891 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
892 video.fullscreen_enabled = fullscreen;
895 printf("::: SDLSetWindowFullscreen: %d, %d\n",
896 fullscreen, video.fullscreen_initial);
900 // if game started in fullscreen mode, window will also get fullscreen size
901 if (!fullscreen && video.fullscreen_initial)
903 SDLSetWindowScaling(setup.window_scaling_percent);
904 SDL_SetWindowPosition(sdl_window,
905 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
907 video.fullscreen_initial = FALSE;
912 void SDLRedrawWindow()
918 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
921 SDL_Surface *surface_tmp, *surface_native;
923 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
926 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
928 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
929 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
931 SDL_FreeSurface(surface_tmp);
933 new_bitmap->surface = surface_native;
936 void SDLFreeBitmapPointers(Bitmap *bitmap)
939 SDL_FreeSurface(bitmap->surface);
940 if (bitmap->surface_masked)
941 SDL_FreeSurface(bitmap->surface_masked);
942 bitmap->surface = NULL;
943 bitmap->surface_masked = NULL;
946 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
947 int src_x, int src_y, int width, int height,
948 int dst_x, int dst_y, int mask_mode)
950 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
951 SDL_Rect src_rect, dst_rect;
953 if (src_bitmap == backbuffer)
955 src_x += video_xoffset;
956 src_y += video_yoffset;
964 if (dst_bitmap == backbuffer || dst_bitmap == window)
966 dst_x += video_xoffset;
967 dst_y += video_yoffset;
975 // if (src_bitmap != backbuffer || dst_bitmap != window)
976 if (!(src_bitmap == backbuffer && dst_bitmap == window))
977 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
978 src_bitmap->surface_masked : src_bitmap->surface),
979 &src_rect, real_dst_bitmap->surface, &dst_rect);
981 #if defined(TARGET_SDL2)
982 if (dst_bitmap == window)
984 // SDL_UpdateWindowSurface(sdl_window);
985 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
986 UpdateScreen(&dst_rect);
989 if (dst_bitmap == window)
991 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
992 UpdateScreen(&dst_rect);
997 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
1000 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1003 if (dst_bitmap == backbuffer || dst_bitmap == window)
1014 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
1016 #if defined(TARGET_SDL2)
1017 if (dst_bitmap == window)
1019 // SDL_UpdateWindowSurface(sdl_window);
1020 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
1021 UpdateScreen(&rect);
1024 if (dst_bitmap == window)
1026 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
1027 UpdateScreen(&rect);
1032 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
1033 int fade_mode, int fade_delay, int post_delay,
1034 void (*draw_border_function)(void))
1036 static boolean initialization_needed = TRUE;
1037 static SDL_Surface *surface_source = NULL;
1038 static SDL_Surface *surface_target = NULL;
1039 static SDL_Surface *surface_black = NULL;
1040 SDL_Surface *surface_screen = backbuffer->surface;
1041 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
1042 SDL_Rect src_rect, dst_rect;
1044 int src_x = x, src_y = y;
1045 int dst_x = x, dst_y = y;
1046 unsigned int time_last, time_current;
1048 /* check if screen size has changed */
1049 if (surface_source != NULL && (video.width != surface_source->w ||
1050 video.height != surface_source->h))
1052 SDL_FreeSurface(surface_source);
1053 SDL_FreeSurface(surface_target);
1054 SDL_FreeSurface(surface_black);
1056 initialization_needed = TRUE;
1062 src_rect.h = height;
1064 dst_x += video_xoffset;
1065 dst_y += video_yoffset;
1069 dst_rect.w = width; /* (ignored) */
1070 dst_rect.h = height; /* (ignored) */
1072 dst_rect2 = dst_rect;
1074 if (initialization_needed)
1076 #if defined(TARGET_SDL2)
1077 unsigned int flags = 0;
1079 unsigned int flags = SDL_SRCALPHA;
1081 /* use same surface type as screen surface */
1082 if ((surface_screen->flags & SDL_HWSURFACE))
1083 flags |= SDL_HWSURFACE;
1085 flags |= SDL_SWSURFACE;
1088 /* create surface for temporary copy of screen buffer (source) */
1089 if ((surface_source =
1090 SDL_CreateRGBSurface(flags,
1093 surface_screen->format->BitsPerPixel,
1094 surface_screen->format->Rmask,
1095 surface_screen->format->Gmask,
1096 surface_screen->format->Bmask,
1097 surface_screen->format->Amask)) == NULL)
1098 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1100 /* create surface for cross-fading screen buffer (target) */
1101 if ((surface_target =
1102 SDL_CreateRGBSurface(flags,
1105 surface_screen->format->BitsPerPixel,
1106 surface_screen->format->Rmask,
1107 surface_screen->format->Gmask,
1108 surface_screen->format->Bmask,
1109 surface_screen->format->Amask)) == NULL)
1110 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1112 /* create black surface for fading from/to black */
1113 if ((surface_black =
1114 SDL_CreateRGBSurface(flags,
1117 surface_screen->format->BitsPerPixel,
1118 surface_screen->format->Rmask,
1119 surface_screen->format->Gmask,
1120 surface_screen->format->Bmask,
1121 surface_screen->format->Amask)) == NULL)
1122 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1124 /* completely fill the surface with black color pixels */
1125 SDL_FillRect(surface_black, NULL,
1126 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1128 initialization_needed = FALSE;
1131 /* copy source and target surfaces to temporary surfaces for fading */
1132 if (fade_mode & FADE_TYPE_TRANSFORM)
1134 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1135 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1137 else if (fade_mode & FADE_TYPE_FADE_IN)
1139 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1140 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1142 else /* FADE_TYPE_FADE_OUT */
1144 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1145 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1148 time_current = SDL_GetTicks();
1150 if (fade_mode == FADE_MODE_MELT)
1152 boolean done = FALSE;
1153 int melt_pixels = 2;
1154 int melt_columns = width / melt_pixels;
1155 int ypos[melt_columns];
1156 int max_steps = height / 8 + 32;
1161 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1162 #if defined(TARGET_SDL2)
1163 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1165 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1168 ypos[0] = -GetSimpleRandom(16);
1170 for (i = 1 ; i < melt_columns; i++)
1172 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1174 ypos[i] = ypos[i - 1] + r;
1187 time_last = time_current;
1188 time_current = SDL_GetTicks();
1189 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1190 steps_final = MIN(MAX(0, steps), max_steps);
1194 done = (steps_done >= steps_final);
1196 for (i = 0 ; i < melt_columns; i++)
1204 else if (ypos[i] < height)
1209 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1211 if (ypos[i] + dy >= height)
1212 dy = height - ypos[i];
1214 /* copy part of (appearing) target surface to upper area */
1215 src_rect.x = src_x + i * melt_pixels;
1216 // src_rect.y = src_y + ypos[i];
1218 src_rect.w = melt_pixels;
1220 src_rect.h = ypos[i] + dy;
1222 dst_rect.x = dst_x + i * melt_pixels;
1223 // dst_rect.y = dst_y + ypos[i];
1226 if (steps_done >= steps_final)
1227 SDL_BlitSurface(surface_target, &src_rect,
1228 surface_screen, &dst_rect);
1232 /* copy part of (disappearing) source surface to lower area */
1233 src_rect.x = src_x + i * melt_pixels;
1235 src_rect.w = melt_pixels;
1236 src_rect.h = height - ypos[i];
1238 dst_rect.x = dst_x + i * melt_pixels;
1239 dst_rect.y = dst_y + ypos[i];
1241 if (steps_done >= steps_final)
1242 SDL_BlitSurface(surface_source, &src_rect,
1243 surface_screen, &dst_rect);
1249 src_rect.x = src_x + i * melt_pixels;
1251 src_rect.w = melt_pixels;
1252 src_rect.h = height;
1254 dst_rect.x = dst_x + i * melt_pixels;
1257 if (steps_done >= steps_final)
1258 SDL_BlitSurface(surface_target, &src_rect,
1259 surface_screen, &dst_rect);
1263 if (steps_done >= steps_final)
1265 if (draw_border_function != NULL)
1266 draw_border_function();
1268 #if defined(TARGET_SDL2)
1269 // SDL_UpdateWindowSurface(sdl_window);
1270 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
1271 UpdateScreen(&dst_rect2);
1273 // SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1274 UpdateScreen(&dst_rect2);
1284 for (alpha = 0.0; alpha < 255.0;)
1286 time_last = time_current;
1287 time_current = SDL_GetTicks();
1288 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1289 alpha_final = MIN(MAX(0, alpha), 255);
1291 /* draw existing (source) image to screen buffer */
1292 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1294 /* draw new (target) image to screen buffer using alpha blending */
1295 #if defined(TARGET_SDL2)
1296 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1297 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1299 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1301 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1303 if (draw_border_function != NULL)
1304 draw_border_function();
1307 /* only update the region of the screen that is affected from fading */
1308 #if defined(TARGET_SDL2)
1309 // SDL_UpdateWindowSurface(sdl_window);
1310 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1311 UpdateScreen(&dst_rect);
1313 // SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1314 UpdateScreen(&dst_rect);
1317 SDL_Flip(surface_screen);
1325 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1326 int to_x, int to_y, Uint32 color)
1328 SDL_Surface *surface = dst_bitmap->surface;
1332 swap_numbers(&from_x, &to_x);
1335 swap_numbers(&from_y, &to_y);
1339 rect.w = (to_x - from_x + 1);
1340 rect.h = (to_y - from_y + 1);
1342 if (dst_bitmap == backbuffer || dst_bitmap == window)
1344 rect.x += video_xoffset;
1345 rect.y += video_yoffset;
1348 SDL_FillRect(surface, &rect, color);
1351 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1352 int to_x, int to_y, Uint32 color)
1354 if (dst_bitmap == backbuffer || dst_bitmap == window)
1356 from_x += video_xoffset;
1357 from_y += video_yoffset;
1358 to_x += video_xoffset;
1359 to_y += video_yoffset;
1362 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1366 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1367 int num_points, Uint32 color)
1372 for (i = 0; i < num_points - 1; i++)
1374 for (x = 0; x < line_width; x++)
1376 for (y = 0; y < line_width; y++)
1378 int dx = x - line_width / 2;
1379 int dy = y - line_width / 2;
1381 if ((x == 0 && y == 0) ||
1382 (x == 0 && y == line_width - 1) ||
1383 (x == line_width - 1 && y == 0) ||
1384 (x == line_width - 1 && y == line_width - 1))
1387 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1388 points[i+1].x + dx, points[i+1].y + dy, color);
1395 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1397 SDL_Surface *surface = src_bitmap->surface;
1399 if (src_bitmap == backbuffer || src_bitmap == window)
1405 switch (surface->format->BytesPerPixel)
1407 case 1: /* assuming 8-bpp */
1409 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1413 case 2: /* probably 15-bpp or 16-bpp */
1415 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1419 case 3: /* slow 24-bpp mode; usually not used */
1421 /* does this work? */
1422 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1426 shift = surface->format->Rshift;
1427 color |= *(pix + shift / 8) >> shift;
1428 shift = surface->format->Gshift;
1429 color |= *(pix + shift / 8) >> shift;
1430 shift = surface->format->Bshift;
1431 color |= *(pix + shift / 8) >> shift;
1437 case 4: /* probably 32-bpp */
1439 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1448 /* ========================================================================= */
1449 /* The following functions were taken from the SGE library */
1450 /* (SDL Graphics Extension Library) by Anders Lindström */
1451 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1452 /* ========================================================================= */
1454 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1456 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1458 switch (surface->format->BytesPerPixel)
1462 /* Assuming 8-bpp */
1463 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1469 /* Probably 15-bpp or 16-bpp */
1470 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1476 /* Slow 24-bpp mode, usually not used */
1480 /* Gack - slow, but endian correct */
1481 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1482 shift = surface->format->Rshift;
1483 *(pix+shift/8) = color>>shift;
1484 shift = surface->format->Gshift;
1485 *(pix+shift/8) = color>>shift;
1486 shift = surface->format->Bshift;
1487 *(pix+shift/8) = color>>shift;
1493 /* Probably 32-bpp */
1494 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1501 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1502 Uint8 R, Uint8 G, Uint8 B)
1504 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1507 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1509 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1512 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1514 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1517 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1522 /* Gack - slow, but endian correct */
1523 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1524 shift = surface->format->Rshift;
1525 *(pix+shift/8) = color>>shift;
1526 shift = surface->format->Gshift;
1527 *(pix+shift/8) = color>>shift;
1528 shift = surface->format->Bshift;
1529 *(pix+shift/8) = color>>shift;
1532 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1534 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1537 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1539 switch (dest->format->BytesPerPixel)
1542 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1546 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1550 _PutPixel24(dest,x,y,color);
1554 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1559 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1561 if (SDL_MUSTLOCK(surface))
1563 if (SDL_LockSurface(surface) < 0)
1569 _PutPixel(surface, x, y, color);
1571 if (SDL_MUSTLOCK(surface))
1573 SDL_UnlockSurface(surface);
1577 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1578 Uint8 r, Uint8 g, Uint8 b)
1580 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1583 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1585 if (y >= 0 && y <= dest->h - 1)
1587 switch (dest->format->BytesPerPixel)
1590 return y*dest->pitch;
1594 return y*dest->pitch/2;
1598 return y*dest->pitch;
1602 return y*dest->pitch/4;
1610 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1612 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1614 switch (surface->format->BytesPerPixel)
1618 /* Assuming 8-bpp */
1619 *((Uint8 *)surface->pixels + ypitch + x) = color;
1625 /* Probably 15-bpp or 16-bpp */
1626 *((Uint16 *)surface->pixels + ypitch + x) = color;
1632 /* Slow 24-bpp mode, usually not used */
1636 /* Gack - slow, but endian correct */
1637 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1638 shift = surface->format->Rshift;
1639 *(pix+shift/8) = color>>shift;
1640 shift = surface->format->Gshift;
1641 *(pix+shift/8) = color>>shift;
1642 shift = surface->format->Bshift;
1643 *(pix+shift/8) = color>>shift;
1649 /* Probably 32-bpp */
1650 *((Uint32 *)surface->pixels + ypitch + x) = color;
1657 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1662 if (SDL_MUSTLOCK(Surface))
1664 if (SDL_LockSurface(Surface) < 0)
1677 /* Do the clipping */
1678 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1682 if (x2 > Surface->w - 1)
1683 x2 = Surface->w - 1;
1690 SDL_FillRect(Surface, &l, Color);
1692 if (SDL_MUSTLOCK(Surface))
1694 SDL_UnlockSurface(Surface);
1698 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1699 Uint8 R, Uint8 G, Uint8 B)
1701 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1704 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1715 /* Do the clipping */
1716 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1720 if (x2 > Surface->w - 1)
1721 x2 = Surface->w - 1;
1728 SDL_FillRect(Surface, &l, Color);
1731 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1736 if (SDL_MUSTLOCK(Surface))
1738 if (SDL_LockSurface(Surface) < 0)
1751 /* Do the clipping */
1752 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1756 if (y2 > Surface->h - 1)
1757 y2 = Surface->h - 1;
1764 SDL_FillRect(Surface, &l, Color);
1766 if (SDL_MUSTLOCK(Surface))
1768 SDL_UnlockSurface(Surface);
1772 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1773 Uint8 R, Uint8 G, Uint8 B)
1775 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1778 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1789 /* Do the clipping */
1790 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1794 if (y2 > Surface->h - 1)
1795 y2 = Surface->h - 1;
1802 SDL_FillRect(Surface, &l, Color);
1805 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1806 Sint16 x2, Sint16 y2, Uint32 Color,
1807 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1810 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1815 sdx = (dx < 0) ? -1 : 1;
1816 sdy = (dy < 0) ? -1 : 1;
1828 for (x = 0; x < dx; x++)
1830 Callback(Surface, px, py, Color);
1844 for (y = 0; y < dy; y++)
1846 Callback(Surface, px, py, Color);
1860 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1861 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1862 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1865 sge_DoLine(Surface, X1, Y1, X2, Y2,
1866 SDL_MapRGB(Surface->format, R, G, B), Callback);
1869 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1872 if (SDL_MUSTLOCK(Surface))
1874 if (SDL_LockSurface(Surface) < 0)
1879 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1881 /* unlock the display */
1882 if (SDL_MUSTLOCK(Surface))
1884 SDL_UnlockSurface(Surface);
1888 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1889 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1891 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1894 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1896 if (dst_bitmap == backbuffer || dst_bitmap == window)
1902 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1907 -----------------------------------------------------------------------------
1908 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1909 -----------------------------------------------------------------------------
1912 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1913 int width, int height, Uint32 color)
1917 for (y = src_y; y < src_y + height; y++)
1919 for (x = src_x; x < src_x + width; x++)
1921 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1923 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1928 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1929 int src_x, int src_y, int width, int height,
1930 int dst_x, int dst_y)
1934 for (y = 0; y < height; y++)
1936 for (x = 0; x < width; x++)
1938 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1940 if (pixel != BLACK_PIXEL)
1941 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1947 /* ========================================================================= */
1948 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1949 /* (Rotozoomer) by Andreas Schiffler */
1950 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1951 /* ========================================================================= */
1954 -----------------------------------------------------------------------------
1957 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1958 -----------------------------------------------------------------------------
1969 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1972 tColorRGBA *sp, *csp, *dp;
1979 sp = csp = (tColorRGBA *) src->pixels;
1980 dp = (tColorRGBA *) dst->pixels;
1982 sgap = src->pitch - src->w * 4;
1984 dgap = dst->pitch - dst->w * 4;
1986 for (y = 0; y < dst->h; y++)
1990 for (x = 0; x < dst->w; x++)
1992 tColorRGBA *sp0 = sp;
1993 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1994 tColorRGBA *sp00 = &sp0[0];
1995 tColorRGBA *sp01 = &sp0[1];
1996 tColorRGBA *sp10 = &sp1[0];
1997 tColorRGBA *sp11 = &sp1[1];
2000 /* create new color pixel from all four source color pixels */
2001 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2002 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2003 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2004 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2009 /* advance source pointers */
2012 /* advance destination pointer */
2016 /* advance source pointer */
2017 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2019 /* advance destination pointers */
2020 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2026 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2028 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2029 tColorRGBA *sp, *csp, *dp;
2035 /* use specialized zoom function when scaling down to exactly half size */
2036 if (src->w == 2 * dst->w &&
2037 src->h == 2 * dst->h)
2038 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2040 /* variable setup */
2041 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
2042 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
2044 /* allocate memory for row increments */
2045 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2046 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2048 /* precalculate row increments */
2051 for (x = 0; x <= dst->w; x++)
2061 for (y = 0; y <= dst->h; y++)
2070 sp = csp = (tColorRGBA *) src->pixels;
2071 dp = (tColorRGBA *) dst->pixels;
2073 sgap = src->pitch - src->w * 4;
2075 dgap = dst->pitch - dst->w * 4;
2078 for (y = 0; y < dst->h; y++)
2083 for (x = 0; x < dst->w; x++)
2088 /* advance source pointers */
2090 sp += (*csax >> 16);
2092 /* advance destination pointer */
2096 /* advance source pointer */
2098 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
2100 /* advance destination pointers */
2101 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2111 -----------------------------------------------------------------------------
2114 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2115 -----------------------------------------------------------------------------
2118 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2120 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2121 Uint8 *sp, *dp, *csp;
2124 /* variable setup */
2125 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2126 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2128 /* allocate memory for row increments */
2129 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2130 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2132 /* precalculate row increments */
2135 for (x = 0; x < dst->w; x++)
2138 *csax = (csx >> 16);
2145 for (y = 0; y < dst->h; y++)
2148 *csay = (csy >> 16);
2155 for (x = 0; x < dst->w; x++)
2163 for (y = 0; y < dst->h; y++)
2170 sp = csp = (Uint8 *) src->pixels;
2171 dp = (Uint8 *) dst->pixels;
2172 dgap = dst->pitch - dst->w;
2176 for (y = 0; y < dst->h; y++)
2180 for (x = 0; x < dst->w; x++)
2185 /* advance source pointers */
2189 /* advance destination pointer */
2193 /* advance source pointer (for row) */
2194 csp += ((*csay) * src->pitch);
2197 /* advance destination pointers */
2208 -----------------------------------------------------------------------------
2211 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2212 'zoomx' and 'zoomy' are scaling factors for width and height.
2213 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2214 into a 32bit RGBA format on the fly.
2215 -----------------------------------------------------------------------------
2218 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2220 SDL_Surface *zoom_src = NULL;
2221 SDL_Surface *zoom_dst = NULL;
2222 boolean is_converted = FALSE;
2229 /* determine if source surface is 32 bit or 8 bit */
2230 is_32bit = (src->format->BitsPerPixel == 32);
2232 if (is_32bit || src->format->BitsPerPixel == 8)
2234 /* use source surface 'as is' */
2239 /* new source surface is 32 bit with a defined RGB ordering */
2240 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
2241 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2242 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2244 is_converted = TRUE;
2247 /* allocate surface to completely contain the zoomed surface */
2250 /* target surface is 32 bit with source RGBA/ABGR ordering */
2251 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
2252 zoom_src->format->Rmask,
2253 zoom_src->format->Gmask,
2254 zoom_src->format->Bmask, 0);
2258 /* target surface is 8 bit */
2259 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
2263 /* lock source surface */
2264 SDL_LockSurface(zoom_src);
2266 /* check which kind of surface we have */
2269 /* call the 32 bit transformation routine to do the zooming */
2270 zoomSurfaceRGBA(zoom_src, zoom_dst);
2275 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2276 zoom_dst->format->palette->colors[i] =
2277 zoom_src->format->palette->colors[i];
2278 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2280 /* call the 8 bit transformation routine to do the zooming */
2281 zoomSurfaceY(zoom_src, zoom_dst);
2284 /* unlock source surface */
2285 SDL_UnlockSurface(zoom_src);
2287 /* free temporary surface */
2289 SDL_FreeSurface(zoom_src);
2291 /* return destination surface */
2295 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
2297 SDL_Surface *sdl_surface_tmp;
2298 int dst_width = dst_bitmap->width;
2299 int dst_height = dst_bitmap->height;
2301 /* throw away old destination surface */
2302 SDL_FreeSurface(dst_bitmap->surface);
2304 /* create zoomed temporary surface from source surface */
2305 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2307 /* create native format destination surface from zoomed temporary surface */
2308 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
2310 /* free temporary surface */
2311 SDL_FreeSurface(sdl_surface_tmp);
2315 /* ========================================================================= */
2316 /* load image to bitmap */
2317 /* ========================================================================= */
2319 Bitmap *SDLLoadImage(char *filename)
2321 Bitmap *new_bitmap = CreateBitmapStruct();
2322 SDL_Surface *sdl_image_tmp;
2324 print_timestamp_init("SDLLoadImage");
2326 print_timestamp_time(getBaseNamePtr(filename));
2328 /* load image to temporary surface */
2329 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2331 SetError("IMG_Load(): %s", SDL_GetError());
2336 print_timestamp_time("IMG_Load");
2338 UPDATE_BUSY_STATE();
2340 /* create native non-transparent surface for current image */
2341 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2343 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2348 print_timestamp_time("SDL_DisplayFormat (opaque)");
2350 UPDATE_BUSY_STATE();
2352 /* create native transparent surface for current image */
2353 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2354 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2355 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2357 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2362 print_timestamp_time("SDL_DisplayFormat (masked)");
2364 UPDATE_BUSY_STATE();
2366 /* free temporary surface */
2367 SDL_FreeSurface(sdl_image_tmp);
2369 new_bitmap->width = new_bitmap->surface->w;
2370 new_bitmap->height = new_bitmap->surface->h;
2372 print_timestamp_done("SDLLoadImage");
2378 /* ------------------------------------------------------------------------- */
2379 /* custom cursor fuctions */
2380 /* ------------------------------------------------------------------------- */
2382 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2384 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2385 cursor_info->width, cursor_info->height,
2386 cursor_info->hot_x, cursor_info->hot_y);
2389 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2391 static struct MouseCursorInfo *last_cursor_info = NULL;
2392 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2393 static SDL_Cursor *cursor_default = NULL;
2394 static SDL_Cursor *cursor_current = NULL;
2396 /* if invoked for the first time, store the SDL default cursor */
2397 if (cursor_default == NULL)
2398 cursor_default = SDL_GetCursor();
2400 /* only create new cursor if cursor info (custom only) has changed */
2401 if (cursor_info != NULL && cursor_info != last_cursor_info)
2403 cursor_current = create_cursor(cursor_info);
2404 last_cursor_info = cursor_info;
2407 /* only set new cursor if cursor info (custom or NULL) has changed */
2408 if (cursor_info != last_cursor_info2)
2409 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2411 last_cursor_info2 = cursor_info;
2415 /* ========================================================================= */
2416 /* audio functions */
2417 /* ========================================================================= */
2419 void SDLOpenAudio(void)
2421 #if !defined(TARGET_SDL2)
2422 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2423 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2426 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2428 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2432 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2433 AUDIO_NUM_CHANNELS_STEREO,
2434 setup.system.audio_fragment_size) < 0)
2436 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2440 audio.sound_available = TRUE;
2441 audio.music_available = TRUE;
2442 audio.loops_available = TRUE;
2443 audio.sound_enabled = TRUE;
2445 /* set number of available mixer channels */
2446 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2447 audio.music_channel = MUSIC_CHANNEL;
2448 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2450 Mixer_InitChannels();
2453 void SDLCloseAudio(void)
2456 Mix_HaltChannel(-1);
2459 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2463 /* ========================================================================= */
2464 /* event functions */
2465 /* ========================================================================= */
2467 void SDLNextEvent(Event *event)
2469 SDL_WaitEvent(event);
2471 if (event->type == EVENT_BUTTONPRESS ||
2472 event->type == EVENT_BUTTONRELEASE)
2474 if (((ButtonEvent *)event)->x > video_xoffset)
2475 ((ButtonEvent *)event)->x -= video_xoffset;
2477 ((ButtonEvent *)event)->x = 0;
2478 if (((ButtonEvent *)event)->y > video_yoffset)
2479 ((ButtonEvent *)event)->y -= video_yoffset;
2481 ((ButtonEvent *)event)->y = 0;
2483 else if (event->type == EVENT_MOTIONNOTIFY)
2485 if (((MotionEvent *)event)->x > video_xoffset)
2486 ((MotionEvent *)event)->x -= video_xoffset;
2488 ((MotionEvent *)event)->x = 0;
2489 if (((MotionEvent *)event)->y > video_yoffset)
2490 ((MotionEvent *)event)->y -= video_yoffset;
2492 ((MotionEvent *)event)->y = 0;
2496 void SDLHandleWindowManagerEvent(Event *event)
2498 #if defined(PLATFORM_WIN32)
2499 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2500 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2502 if (syswmmsg->msg == WM_DROPFILES)
2504 HDROP hdrop = (HDROP)syswmmsg->wParam;
2507 printf("::: SDL_SYSWMEVENT:\n");
2509 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2511 for (i = 0; i < num_files; i++)
2513 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2514 char buffer[buffer_len + 1];
2516 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2518 printf("::: - '%s'\n", buffer);
2521 DragFinish((HDROP)syswmmsg->wParam);
2527 /* ========================================================================= */
2528 /* joystick functions */
2529 /* ========================================================================= */
2531 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2532 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2533 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2535 static boolean SDLOpenJoystick(int nr)
2537 if (nr < 0 || nr > MAX_PLAYERS)
2540 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2543 static void SDLCloseJoystick(int nr)
2545 if (nr < 0 || nr > MAX_PLAYERS)
2548 SDL_JoystickClose(sdl_joystick[nr]);
2550 sdl_joystick[nr] = NULL;
2553 static boolean SDLCheckJoystickOpened(int nr)
2555 if (nr < 0 || nr > MAX_PLAYERS)
2558 #if defined(TARGET_SDL2)
2559 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2561 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2565 void HandleJoystickEvent(Event *event)
2569 case SDL_JOYAXISMOTION:
2570 if (event->jaxis.axis < 2)
2571 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2574 case SDL_JOYBUTTONDOWN:
2575 if (event->jbutton.button < 2)
2576 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2579 case SDL_JOYBUTTONUP:
2580 if (event->jbutton.button < 2)
2581 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2589 void SDLInitJoysticks()
2591 static boolean sdl_joystick_subsystem_initialized = FALSE;
2592 boolean print_warning = !sdl_joystick_subsystem_initialized;
2595 if (!sdl_joystick_subsystem_initialized)
2597 sdl_joystick_subsystem_initialized = TRUE;
2599 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2601 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2606 for (i = 0; i < MAX_PLAYERS; i++)
2608 /* get configured joystick for this player */
2609 char *device_name = setup.input[i].joy.device_name;
2610 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2612 if (joystick_nr >= SDL_NumJoysticks())
2614 if (setup.input[i].use_joystick && print_warning)
2615 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2620 /* misuse joystick file descriptor variable to store joystick number */
2621 joystick.fd[i] = joystick_nr;
2623 if (joystick_nr == -1)
2626 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2627 if (SDLCheckJoystickOpened(joystick_nr))
2628 SDLCloseJoystick(joystick_nr);
2630 if (!setup.input[i].use_joystick)
2633 if (!SDLOpenJoystick(joystick_nr))
2636 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2641 joystick.status = JOYSTICK_ACTIVATED;
2645 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2647 if (nr < 0 || nr >= MAX_PLAYERS)
2651 *x = sdl_js_axis[nr][0];
2653 *y = sdl_js_axis[nr][1];
2656 *b1 = sdl_js_button[nr][0];
2658 *b2 = sdl_js_button[nr][1];
2663 #endif /* TARGET_SDL */