1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
18 #define ENABLE_UNUSED_CODE 0 /* currently unused functions */
21 /* ========================================================================= */
23 /* ========================================================================= */
25 /* SDL internal variables */
26 #if defined(TARGET_SDL2)
27 static SDL_Window *sdl_window = NULL;
28 static SDL_Renderer *sdl_renderer = NULL;
29 static SDL_Texture *sdl_texture = NULL;
30 static boolean fullscreen_enabled = FALSE;
32 #define USE_RENDERER TRUE
35 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
36 static int fullscreen_width;
37 static int fullscreen_height;
38 static int fullscreen_xoffset;
39 static int fullscreen_yoffset;
40 static int video_xoffset;
41 static int video_yoffset;
42 static boolean limit_screen_updates = FALSE;
45 /* functions from SGE library */
46 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
48 void SDLLimitScreenUpdates(boolean enable)
50 limit_screen_updates = enable;
53 static void UpdateScreen(SDL_Rect *rect)
55 static unsigned int update_screen_delay = 0;
56 unsigned int update_screen_delay_value = 20; /* (milliseconds) */
57 SDL_Surface *screen = backbuffer->surface;
59 if (limit_screen_updates &&
60 !DelayReached(&update_screen_delay, update_screen_delay_value))
63 LimitScreenUpdates(FALSE);
67 static int LastFrameCounter = 0;
68 boolean changed = (FrameCounter != LastFrameCounter);
70 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
71 (changed ? "-" : "SAME FRAME UPDATED"));
73 LastFrameCounter = FrameCounter;
82 #if USE_FINAL_SCREEN_BITMAP
83 if (gfx.final_screen_bitmap != NULL) // may not be initialized yet
86 // draw global animations using bitmaps instead of using textures
87 // to prevent texture scaling artefacts (this is potentially slower)
89 BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
90 gfx.win_xsize, gfx.win_ysize, 0, 0);
92 // copy global animations to render target buffer, if defined
93 if (gfx.draw_global_anim_function != NULL)
94 gfx.draw_global_anim_function();
96 screen = gfx.final_screen_bitmap->surface;
98 // force full window redraw
103 #if defined(TARGET_SDL2)
107 int bytes_x = screen->pitch / video.width;
108 int bytes_y = screen->pitch;
110 if (video.fullscreen_enabled)
111 bytes_x = screen->pitch / fullscreen_width;
113 SDL_UpdateTexture(sdl_texture, rect,
114 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
119 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
122 // clear render target buffer
123 SDL_RenderClear(sdl_renderer);
125 // copy backbuffer to render target buffer
126 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
128 #if !USE_FINAL_SCREEN_BITMAP
129 // copy global animations to render target buffer, if defined
130 if (gfx.draw_global_anim_function != NULL)
131 gfx.draw_global_anim_function();
134 // show render target buffer on screen
135 SDL_RenderPresent(sdl_renderer);
140 SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
142 SDL_UpdateWindowSurface(sdl_window);
147 SDL_UpdateRects(screen, 1, rect);
149 SDL_UpdateRect(screen, 0, 0, 0, 0);
153 static void setFullscreenParameters(char *fullscreen_mode_string)
155 #if defined(TARGET_SDL2)
156 fullscreen_width = video.width;
157 fullscreen_height = video.height;
158 fullscreen_xoffset = 0;
159 fullscreen_yoffset = 0;
163 struct ScreenModeInfo *fullscreen_mode;
166 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
168 if (fullscreen_mode == NULL)
171 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
173 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
174 fullscreen_mode->height == video.fullscreen_modes[i].height)
176 fullscreen_width = fullscreen_mode->width;
177 fullscreen_height = fullscreen_mode->height;
179 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
180 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
188 static void SDLSetWindowIcon(char *basename)
190 /* (setting the window icon on Mac OS X would replace the high-quality
191 dock icon with the currently smaller (and uglier) icon from file) */
193 #if !defined(PLATFORM_MACOSX)
194 char *filename = getCustomImageFilename(basename);
195 SDL_Surface *surface;
197 if (filename == NULL)
199 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
204 if ((surface = IMG_Load(filename)) == NULL)
206 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
211 /* set transparent color */
212 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
213 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
215 #if defined(TARGET_SDL2)
216 SDL_SetWindowIcon(sdl_window, surface);
218 SDL_WM_SetIcon(surface, NULL);
223 #if defined(TARGET_SDL2)
225 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
226 SDL_PixelFormat *format2)
228 return (format1->format == format2->format &&
229 format1->BitsPerPixel == format2->BitsPerPixel &&
230 format1->BytesPerPixel == format2->BytesPerPixel &&
231 format1->Rmask == format2->Rmask &&
232 format1->Gmask == format2->Gmask &&
233 format1->Bmask == format2->Bmask &&
234 format1->Amask == format2->Amask);
237 boolean SDLSetNativeSurface(SDL_Surface **surface)
239 SDL_Surface *new_surface;
241 if (surface == NULL ||
243 backbuffer == NULL ||
244 backbuffer->surface == NULL)
247 // if pixel format already optimized for destination surface, do nothing
248 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
251 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
253 if (new_surface == NULL)
254 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
256 SDL_FreeSurface(*surface);
258 *surface = new_surface;
263 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
265 SDL_Surface *new_surface;
270 if (backbuffer && backbuffer->surface)
271 new_surface = SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
273 new_surface = SDL_ConvertSurface(surface, surface->format, 0);
275 if (new_surface == NULL)
276 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
283 boolean SDLSetNativeSurface(SDL_Surface **surface)
285 SDL_Surface *new_surface;
287 if (surface == NULL ||
292 new_surface = SDL_DisplayFormat(*surface);
294 if (new_surface == NULL)
295 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
297 SDL_FreeSurface(*surface);
299 *surface = new_surface;
304 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
306 SDL_Surface *new_surface;
308 if (video.initialized)
309 new_surface = SDL_DisplayFormat(surface);
311 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
313 if (new_surface == NULL)
314 Error(ERR_EXIT, "%s() failed: %s",
315 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
323 #if defined(TARGET_SDL2)
324 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
326 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
329 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
336 void SDLCreateBitmapTextures(Bitmap *bitmap)
338 #if defined(TARGET_SDL2)
343 SDL_DestroyTexture(bitmap->texture);
344 if (bitmap->texture_masked)
345 SDL_DestroyTexture(bitmap->texture_masked);
347 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
348 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
352 void SDLFreeBitmapTextures(Bitmap *bitmap)
354 #if defined(TARGET_SDL2)
359 SDL_DestroyTexture(bitmap->texture);
360 if (bitmap->texture_masked)
361 SDL_DestroyTexture(bitmap->texture_masked);
363 bitmap->texture = NULL;
364 bitmap->texture_masked = NULL;
368 void SDLInitVideoDisplay(void)
370 #if !defined(TARGET_SDL2)
371 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
372 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
374 SDL_putenv("SDL_VIDEO_CENTERED=1");
377 /* initialize SDL video */
378 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
379 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
381 /* set default SDL depth */
382 #if !defined(TARGET_SDL2)
383 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
385 video.default_depth = 32; // (how to determine video depth in SDL2?)
389 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
392 #if !defined(TARGET_SDL2)
393 static int screen_xy[][2] =
401 SDL_Rect **modes = NULL;
402 boolean hardware_fullscreen_available = TRUE;
405 /* default: normal game window size */
406 fullscreen_width = video.width;
407 fullscreen_height = video.height;
408 fullscreen_xoffset = 0;
409 fullscreen_yoffset = 0;
411 #if !defined(TARGET_SDL2)
412 /* determine required standard fullscreen mode for game screen size */
413 for (i = 0; screen_xy[i][0] != -1; i++)
415 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
417 fullscreen_width = screen_xy[i][0];
418 fullscreen_height = screen_xy[i][1];
424 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
425 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
428 checked_free(video.fullscreen_modes);
430 video.fullscreen_modes = NULL;
431 video.fullscreen_mode_current = NULL;
433 video.window_scaling_percent = setup.window_scaling_percent;
434 video.window_scaling_quality = setup.window_scaling_quality;
436 #if defined(TARGET_SDL2)
437 int num_displays = SDL_GetNumVideoDisplays();
439 if (num_displays > 0)
441 // currently only display modes of first display supported
442 int num_modes = SDL_GetNumDisplayModes(0);
446 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
448 for (i = 0; i < num_modes; i++)
450 SDL_DisplayMode mode;
452 if (SDL_GetDisplayMode(0, i, &mode) < 0)
455 modes[i] = checked_calloc(sizeof(SDL_Rect));
457 modes[i]->w = mode.w;
458 modes[i]->h = mode.h;
463 /* get available hardware supported fullscreen modes */
464 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
469 /* no hardware screen modes available => no fullscreen mode support */
470 // video.fullscreen_available = FALSE;
471 hardware_fullscreen_available = FALSE;
473 else if (modes == (SDL_Rect **)-1)
475 /* fullscreen resolution is not restricted -- all resolutions available */
476 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
478 /* use native video buffer size for fullscreen mode */
479 video.fullscreen_modes[0].width = video.width;
480 video.fullscreen_modes[0].height = video.height;
482 video.fullscreen_modes[1].width = -1;
483 video.fullscreen_modes[1].height = -1;
487 /* in this case, a certain number of screen modes is available */
490 for (i = 0; modes[i] != NULL; i++)
492 boolean found_mode = FALSE;
494 /* screen mode is smaller than video buffer size -- skip it */
495 if (modes[i]->w < video.width || modes[i]->h < video.height)
498 if (video.fullscreen_modes != NULL)
499 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
500 if (modes[i]->w == video.fullscreen_modes[j].width &&
501 modes[i]->h == video.fullscreen_modes[j].height)
504 if (found_mode) /* screen mode already stored -- skip it */
507 /* new mode found; add it to list of available fullscreen modes */
511 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
513 sizeof(struct ScreenModeInfo));
515 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
516 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
518 video.fullscreen_modes[num_modes].width = -1;
519 video.fullscreen_modes[num_modes].height = -1;
524 /* no appropriate screen modes available => no fullscreen mode support */
525 // video.fullscreen_available = FALSE;
526 hardware_fullscreen_available = FALSE;
530 video.fullscreen_available = hardware_fullscreen_available;
532 #if USE_DESKTOP_FULLSCREEN
533 // in SDL 2.0, there is always support for desktop fullscreen mode
534 // (in SDL 1.2, there is only support for "real" fullscreen mode)
535 video.fullscreen_available = TRUE;
538 #if defined(TARGET_SDL2)
541 for (i = 0; modes[i] != NULL; i++)
542 checked_free(modes[i]);
548 /* open SDL video output device (window or fullscreen mode) */
549 if (!SDLSetVideoMode(backbuffer, fullscreen))
550 Error(ERR_EXIT, "setting video mode failed");
552 /* !!! SDL2 can only set the window icon if the window already exists !!! */
553 /* set window icon */
554 SDLSetWindowIcon(program.icon_filename);
556 /* set window and icon title */
557 #if defined(TARGET_SDL2)
558 SDL_SetWindowTitle(sdl_window, program.window_title);
560 SDL_WM_SetCaption(program.window_title, program.window_title);
563 /* SDL cannot directly draw to the visible video framebuffer like X11,
564 but always uses a backbuffer, which is then blitted to the visible
565 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
566 visible video framebuffer with 'SDL_Flip', if the hardware supports
567 this). Therefore do not use an additional backbuffer for drawing, but
568 use a symbolic buffer (distinguishable from the SDL backbuffer) called
569 'window', which indicates that the SDL backbuffer should be updated to
570 the visible video framebuffer when attempting to blit to it.
572 For convenience, it seems to be a good idea to create this symbolic
573 buffer 'window' at the same size as the SDL backbuffer. Although it
574 should never be drawn to directly, it would do no harm nevertheless. */
576 /* create additional (symbolic) buffer for double-buffering */
577 ReCreateBitmap(window, video.width, video.height, video.depth);
580 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
583 SDL_Surface *new_surface = NULL;
585 #if defined(TARGET_SDL2)
586 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
587 #if USE_DESKTOP_FULLSCREEN
588 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
590 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
594 int surface_flags_window = SURFACE_FLAGS;
595 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
598 int width = (fullscreen ? fullscreen_width : video.width);
599 int height = (fullscreen ? fullscreen_height : video.height);
600 int surface_flags = (fullscreen ? surface_flags_fullscreen :
601 surface_flags_window);
603 // default window size is unscaled
604 video.window_width = video.width;
605 video.window_height = video.height;
607 #if defined(TARGET_SDL2)
609 // store if initial screen mode is fullscreen mode when changing screen size
610 video.fullscreen_initial = fullscreen;
613 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
614 #if !USE_DESKTOP_FULLSCREEN
615 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
618 video.window_width = window_scaling_factor * width;
619 video.window_height = window_scaling_factor * height;
621 if ((*backbuffer)->surface)
623 SDL_FreeSurface((*backbuffer)->surface);
624 (*backbuffer)->surface = NULL;
629 SDL_DestroyTexture(sdl_texture);
633 if (!(fullscreen && fullscreen_enabled))
637 SDL_DestroyRenderer(sdl_renderer);
643 SDL_DestroyWindow(sdl_window);
648 if (sdl_window == NULL)
649 sdl_window = SDL_CreateWindow(program.window_title,
650 SDL_WINDOWPOS_CENTERED,
651 SDL_WINDOWPOS_CENTERED,
652 #if USE_DESKTOP_FULLSCREEN
656 (int)(screen_scaling_factor * width),
657 (int)(screen_scaling_factor * height),
661 if (sdl_window != NULL)
664 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
665 *without* enabling 2D/3D acceleration and/or guest additions installed,
666 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
667 it will try to use accelerated graphics and apparently fails miserably) */
668 if (sdl_renderer == NULL)
669 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
671 if (sdl_renderer == NULL)
672 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
675 if (sdl_renderer != NULL)
677 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
678 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
679 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
681 sdl_texture = SDL_CreateTexture(sdl_renderer,
682 SDL_PIXELFORMAT_ARGB8888,
683 SDL_TEXTUREACCESS_STREAMING,
686 if (sdl_texture != NULL)
688 // use SDL default values for RGB masks and no alpha channel
689 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
691 if (new_surface == NULL)
692 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
697 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
702 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
707 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
713 SDL_DestroyWindow(sdl_window);
715 sdl_window = SDL_CreateWindow(program.window_title,
716 SDL_WINDOWPOS_CENTERED,
717 SDL_WINDOWPOS_CENTERED,
721 if (sdl_window != NULL)
722 new_surface = SDL_GetWindowSurface(sdl_window);
726 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
729 #if defined(TARGET_SDL2)
730 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
731 if (new_surface != NULL)
732 fullscreen_enabled = fullscreen;
738 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
740 boolean success = TRUE;
741 SDL_Surface *new_surface = NULL;
745 if (*backbuffer == NULL)
746 *backbuffer = CreateBitmapStruct();
748 /* (real bitmap might be larger in fullscreen mode with video offsets) */
749 (*backbuffer)->width = video.width;
750 (*backbuffer)->height = video.height;
752 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
754 setFullscreenParameters(setup.fullscreen_mode);
756 video_xoffset = fullscreen_xoffset;
757 video_yoffset = fullscreen_yoffset;
759 /* switch display to fullscreen mode, if available */
760 new_surface = SDLCreateScreen(backbuffer, TRUE);
762 if (new_surface == NULL)
764 /* switching display to fullscreen mode failed */
765 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
767 /* do not try it again */
768 video.fullscreen_available = FALSE;
774 (*backbuffer)->surface = new_surface;
776 video.fullscreen_enabled = TRUE;
777 video.fullscreen_mode_current = setup.fullscreen_mode;
783 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
788 /* switch display to window mode */
789 new_surface = SDLCreateScreen(backbuffer, FALSE);
791 if (new_surface == NULL)
793 /* switching display to window mode failed -- should not happen */
794 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
800 (*backbuffer)->surface = new_surface;
802 video.fullscreen_enabled = FALSE;
803 video.window_scaling_percent = setup.window_scaling_percent;
804 video.window_scaling_quality = setup.window_scaling_quality;
810 #if defined(TARGET_SDL2)
811 SDLRedrawWindow(); // map window
815 #if defined(PLATFORM_WIN32)
816 // experimental drag and drop code
818 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
821 SDL_SysWMinfo wminfo;
823 boolean wminfo_success = FALSE;
825 SDL_VERSION(&wminfo.version);
826 #if defined(TARGET_SDL2)
828 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
830 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
835 #if defined(TARGET_SDL2)
836 hwnd = wminfo.info.win.window;
838 hwnd = wminfo.window;
841 DragAcceptFiles(hwnd, TRUE);
850 void SDLSetWindowTitle()
852 #if defined(TARGET_SDL2)
853 SDL_SetWindowTitle(sdl_window, program.window_title);
855 SDL_WM_SetCaption(program.window_title, program.window_title);
859 #if defined(TARGET_SDL2)
860 void SDLSetWindowScaling(int window_scaling_percent)
862 if (sdl_window == NULL)
865 float window_scaling_factor = (float)window_scaling_percent / 100;
866 int new_window_width = (int)(window_scaling_factor * video.width);
867 int new_window_height = (int)(window_scaling_factor * video.height);
869 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
871 video.window_scaling_percent = window_scaling_percent;
872 video.window_width = new_window_width;
873 video.window_height = new_window_height;
878 void SDLSetWindowScalingQuality(char *window_scaling_quality)
880 if (sdl_texture == NULL)
883 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
885 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
886 SDL_PIXELFORMAT_ARGB8888,
887 SDL_TEXTUREACCESS_STREAMING,
888 video.width, video.height);
890 if (new_texture != NULL)
892 SDL_DestroyTexture(sdl_texture);
894 sdl_texture = new_texture;
899 video.window_scaling_quality = window_scaling_quality;
902 void SDLSetWindowFullscreen(boolean fullscreen)
904 if (sdl_window == NULL)
907 #if USE_DESKTOP_FULLSCREEN
908 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
910 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
913 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
914 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
916 // if screen size was changed in fullscreen mode, correct desktop window size
917 if (!fullscreen && video.fullscreen_initial)
919 SDLSetWindowScaling(setup.window_scaling_percent);
920 SDL_SetWindowPosition(sdl_window,
921 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
923 video.fullscreen_initial = FALSE;
927 void SDLRedrawWindow()
933 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
936 SDL_Surface *surface =
937 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
940 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
942 SDLSetNativeSurface(&surface);
944 bitmap->surface = surface;
947 void SDLFreeBitmapPointers(Bitmap *bitmap)
950 SDL_FreeSurface(bitmap->surface);
951 if (bitmap->surface_masked)
952 SDL_FreeSurface(bitmap->surface_masked);
954 bitmap->surface = NULL;
955 bitmap->surface_masked = NULL;
957 #if defined(TARGET_SDL2)
959 SDL_DestroyTexture(bitmap->texture);
960 if (bitmap->texture_masked)
961 SDL_DestroyTexture(bitmap->texture_masked);
963 bitmap->texture = NULL;
964 bitmap->texture_masked = NULL;
968 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
969 int src_x, int src_y, int width, int height,
970 int dst_x, int dst_y, int mask_mode)
972 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
973 SDL_Rect src_rect, dst_rect;
975 if (src_bitmap == backbuffer)
977 src_x += video_xoffset;
978 src_y += video_yoffset;
986 if (dst_bitmap == backbuffer || dst_bitmap == window)
988 dst_x += video_xoffset;
989 dst_y += video_yoffset;
997 // if (src_bitmap != backbuffer || dst_bitmap != window)
998 if (!(src_bitmap == backbuffer && dst_bitmap == window))
999 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
1000 src_bitmap->surface_masked : src_bitmap->surface),
1001 &src_rect, real_dst_bitmap->surface, &dst_rect);
1003 #if defined(TARGET_SDL2)
1004 if (dst_bitmap == window)
1006 // SDL_UpdateWindowSurface(sdl_window);
1007 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1008 UpdateScreen(&dst_rect);
1011 if (dst_bitmap == window)
1013 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
1014 UpdateScreen(&dst_rect);
1019 void SDLBlitTexture(Bitmap *bitmap,
1020 int src_x, int src_y, int width, int height,
1021 int dst_x, int dst_y, int mask_mode)
1023 #if defined(TARGET_SDL2)
1025 SDL_Texture *texture;
1030 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
1032 if (texture == NULL)
1038 src_rect.h = height;
1043 dst_rect.h = height;
1045 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
1050 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
1053 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1056 if (dst_bitmap == backbuffer || dst_bitmap == window)
1067 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
1069 #if defined(TARGET_SDL2)
1070 if (dst_bitmap == window)
1072 // SDL_UpdateWindowSurface(sdl_window);
1073 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
1074 UpdateScreen(&rect);
1077 if (dst_bitmap == window)
1079 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
1080 UpdateScreen(&rect);
1085 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
1086 int fade_mode, int fade_delay, int post_delay,
1087 void (*draw_border_function)(void))
1089 static boolean initialization_needed = TRUE;
1090 static SDL_Surface *surface_source = NULL;
1091 static SDL_Surface *surface_target = NULL;
1092 static SDL_Surface *surface_black = NULL;
1093 SDL_Surface *surface_screen = backbuffer->surface;
1094 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
1095 SDL_Rect src_rect, dst_rect;
1097 int src_x = x, src_y = y;
1098 int dst_x = x, dst_y = y;
1099 unsigned int time_last, time_current;
1101 /* check if screen size has changed */
1102 if (surface_source != NULL && (video.width != surface_source->w ||
1103 video.height != surface_source->h))
1105 SDL_FreeSurface(surface_source);
1106 SDL_FreeSurface(surface_target);
1107 SDL_FreeSurface(surface_black);
1109 initialization_needed = TRUE;
1115 src_rect.h = height;
1117 dst_x += video_xoffset;
1118 dst_y += video_yoffset;
1122 dst_rect.w = width; /* (ignored) */
1123 dst_rect.h = height; /* (ignored) */
1125 dst_rect2 = dst_rect;
1127 if (initialization_needed)
1129 #if defined(TARGET_SDL2)
1130 unsigned int flags = 0;
1132 unsigned int flags = SDL_SRCALPHA;
1134 /* use same surface type as screen surface */
1135 if ((surface_screen->flags & SDL_HWSURFACE))
1136 flags |= SDL_HWSURFACE;
1138 flags |= SDL_SWSURFACE;
1141 /* create surface for temporary copy of screen buffer (source) */
1142 if ((surface_source =
1143 SDL_CreateRGBSurface(flags,
1146 surface_screen->format->BitsPerPixel,
1147 surface_screen->format->Rmask,
1148 surface_screen->format->Gmask,
1149 surface_screen->format->Bmask,
1150 surface_screen->format->Amask)) == NULL)
1151 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1153 /* create surface for cross-fading screen buffer (target) */
1154 if ((surface_target =
1155 SDL_CreateRGBSurface(flags,
1158 surface_screen->format->BitsPerPixel,
1159 surface_screen->format->Rmask,
1160 surface_screen->format->Gmask,
1161 surface_screen->format->Bmask,
1162 surface_screen->format->Amask)) == NULL)
1163 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1165 /* create black surface for fading from/to black */
1166 if ((surface_black =
1167 SDL_CreateRGBSurface(flags,
1170 surface_screen->format->BitsPerPixel,
1171 surface_screen->format->Rmask,
1172 surface_screen->format->Gmask,
1173 surface_screen->format->Bmask,
1174 surface_screen->format->Amask)) == NULL)
1175 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1177 /* completely fill the surface with black color pixels */
1178 SDL_FillRect(surface_black, NULL,
1179 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1181 initialization_needed = FALSE;
1184 /* copy source and target surfaces to temporary surfaces for fading */
1185 if (fade_mode & FADE_TYPE_TRANSFORM)
1187 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1188 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1190 else if (fade_mode & FADE_TYPE_FADE_IN)
1192 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1193 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1195 else /* FADE_TYPE_FADE_OUT */
1197 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1198 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1201 time_current = SDL_GetTicks();
1203 if (fade_mode == FADE_MODE_MELT)
1205 boolean done = FALSE;
1206 int melt_pixels = 2;
1207 int melt_columns = width / melt_pixels;
1208 int ypos[melt_columns];
1209 int max_steps = height / 8 + 32;
1214 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1215 #if defined(TARGET_SDL2)
1216 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1218 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1221 ypos[0] = -GetSimpleRandom(16);
1223 for (i = 1 ; i < melt_columns; i++)
1225 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1227 ypos[i] = ypos[i - 1] + r;
1240 time_last = time_current;
1241 time_current = SDL_GetTicks();
1242 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1243 steps_final = MIN(MAX(0, steps), max_steps);
1247 done = (steps_done >= steps_final);
1249 for (i = 0 ; i < melt_columns; i++)
1257 else if (ypos[i] < height)
1262 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1264 if (ypos[i] + dy >= height)
1265 dy = height - ypos[i];
1267 /* copy part of (appearing) target surface to upper area */
1268 src_rect.x = src_x + i * melt_pixels;
1269 // src_rect.y = src_y + ypos[i];
1271 src_rect.w = melt_pixels;
1273 src_rect.h = ypos[i] + dy;
1275 dst_rect.x = dst_x + i * melt_pixels;
1276 // dst_rect.y = dst_y + ypos[i];
1279 if (steps_done >= steps_final)
1280 SDL_BlitSurface(surface_target, &src_rect,
1281 surface_screen, &dst_rect);
1285 /* copy part of (disappearing) source surface to lower area */
1286 src_rect.x = src_x + i * melt_pixels;
1288 src_rect.w = melt_pixels;
1289 src_rect.h = height - ypos[i];
1291 dst_rect.x = dst_x + i * melt_pixels;
1292 dst_rect.y = dst_y + ypos[i];
1294 if (steps_done >= steps_final)
1295 SDL_BlitSurface(surface_source, &src_rect,
1296 surface_screen, &dst_rect);
1302 src_rect.x = src_x + i * melt_pixels;
1304 src_rect.w = melt_pixels;
1305 src_rect.h = height;
1307 dst_rect.x = dst_x + i * melt_pixels;
1310 if (steps_done >= steps_final)
1311 SDL_BlitSurface(surface_target, &src_rect,
1312 surface_screen, &dst_rect);
1316 if (steps_done >= steps_final)
1318 if (draw_border_function != NULL)
1319 draw_border_function();
1321 UpdateScreen(&dst_rect2);
1325 else if (fade_mode == FADE_MODE_CURTAIN)
1329 int xx_size = width / 2;
1331 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1332 #if defined(TARGET_SDL2)
1333 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1335 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1338 for (xx = 0; xx < xx_size;)
1340 time_last = time_current;
1341 time_current = SDL_GetTicks();
1342 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1343 xx_final = MIN(MAX(0, xx), xx_size);
1348 src_rect.h = height;
1353 /* draw new (target) image to screen buffer */
1354 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1356 if (xx_final < xx_size)
1358 src_rect.w = xx_size - xx_final;
1359 src_rect.h = height;
1361 /* draw old (source) image to screen buffer (left side) */
1363 src_rect.x = src_x + xx_final;
1366 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1368 /* draw old (source) image to screen buffer (right side) */
1370 src_rect.x = src_x + xx_size;
1371 dst_rect.x = dst_x + xx_size + xx_final;
1373 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1376 if (draw_border_function != NULL)
1377 draw_border_function();
1379 /* only update the region of the screen that is affected from fading */
1380 UpdateScreen(&dst_rect2);
1383 else /* fading in, fading out or cross-fading */
1388 for (alpha = 0.0; alpha < 255.0;)
1390 time_last = time_current;
1391 time_current = SDL_GetTicks();
1392 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1393 alpha_final = MIN(MAX(0, alpha), 255);
1395 /* draw existing (source) image to screen buffer */
1396 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1398 /* draw new (target) image to screen buffer using alpha blending */
1399 #if defined(TARGET_SDL2)
1400 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1401 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1403 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1405 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1407 if (draw_border_function != NULL)
1408 draw_border_function();
1410 /* only update the region of the screen that is affected from fading */
1411 UpdateScreen(&dst_rect);
1417 unsigned int time_post_delay;
1419 time_current = SDL_GetTicks();
1420 time_post_delay = time_current + post_delay;
1422 while (time_current < time_post_delay)
1424 // do not wait longer than 10 ms at a time to be able to ...
1425 Delay(MIN(10, time_post_delay - time_current));
1427 // ... continue drawing global animations during post delay
1430 time_current = SDL_GetTicks();
1435 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1436 int to_x, int to_y, Uint32 color)
1438 SDL_Surface *surface = dst_bitmap->surface;
1442 swap_numbers(&from_x, &to_x);
1445 swap_numbers(&from_y, &to_y);
1449 rect.w = (to_x - from_x + 1);
1450 rect.h = (to_y - from_y + 1);
1452 if (dst_bitmap == backbuffer || dst_bitmap == window)
1454 rect.x += video_xoffset;
1455 rect.y += video_yoffset;
1458 SDL_FillRect(surface, &rect, color);
1461 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1462 int to_x, int to_y, Uint32 color)
1464 if (dst_bitmap == backbuffer || dst_bitmap == window)
1466 from_x += video_xoffset;
1467 from_y += video_yoffset;
1468 to_x += video_xoffset;
1469 to_y += video_yoffset;
1472 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1475 #if ENABLE_UNUSED_CODE
1476 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1477 int num_points, Uint32 color)
1482 for (i = 0; i < num_points - 1; i++)
1484 for (x = 0; x < line_width; x++)
1486 for (y = 0; y < line_width; y++)
1488 int dx = x - line_width / 2;
1489 int dy = y - line_width / 2;
1491 if ((x == 0 && y == 0) ||
1492 (x == 0 && y == line_width - 1) ||
1493 (x == line_width - 1 && y == 0) ||
1494 (x == line_width - 1 && y == line_width - 1))
1497 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1498 points[i+1].x + dx, points[i+1].y + dy, color);
1505 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1507 SDL_Surface *surface = src_bitmap->surface;
1509 if (src_bitmap == backbuffer || src_bitmap == window)
1515 switch (surface->format->BytesPerPixel)
1517 case 1: /* assuming 8-bpp */
1519 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1523 case 2: /* probably 15-bpp or 16-bpp */
1525 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1529 case 3: /* slow 24-bpp mode; usually not used */
1531 /* does this work? */
1532 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1536 shift = surface->format->Rshift;
1537 color |= *(pix + shift / 8) >> shift;
1538 shift = surface->format->Gshift;
1539 color |= *(pix + shift / 8) >> shift;
1540 shift = surface->format->Bshift;
1541 color |= *(pix + shift / 8) >> shift;
1547 case 4: /* probably 32-bpp */
1549 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1558 /* ========================================================================= */
1559 /* The following functions were taken from the SGE library */
1560 /* (SDL Graphics Extension Library) by Anders Lindström */
1561 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1562 /* ========================================================================= */
1564 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1566 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1568 switch (surface->format->BytesPerPixel)
1572 /* Assuming 8-bpp */
1573 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1579 /* Probably 15-bpp or 16-bpp */
1580 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1586 /* Slow 24-bpp mode, usually not used */
1590 /* Gack - slow, but endian correct */
1591 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1592 shift = surface->format->Rshift;
1593 *(pix+shift/8) = color>>shift;
1594 shift = surface->format->Gshift;
1595 *(pix+shift/8) = color>>shift;
1596 shift = surface->format->Bshift;
1597 *(pix+shift/8) = color>>shift;
1603 /* Probably 32-bpp */
1604 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1611 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1612 Uint8 R, Uint8 G, Uint8 B)
1614 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1617 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1619 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1622 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1624 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1627 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1632 /* Gack - slow, but endian correct */
1633 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1634 shift = surface->format->Rshift;
1635 *(pix+shift/8) = color>>shift;
1636 shift = surface->format->Gshift;
1637 *(pix+shift/8) = color>>shift;
1638 shift = surface->format->Bshift;
1639 *(pix+shift/8) = color>>shift;
1642 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1644 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1647 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1649 switch (dest->format->BytesPerPixel)
1652 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1656 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1660 _PutPixel24(dest,x,y,color);
1664 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1669 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1671 if (SDL_MUSTLOCK(surface))
1673 if (SDL_LockSurface(surface) < 0)
1679 _PutPixel(surface, x, y, color);
1681 if (SDL_MUSTLOCK(surface))
1683 SDL_UnlockSurface(surface);
1687 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1688 Uint8 r, Uint8 g, Uint8 b)
1690 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1693 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1695 if (y >= 0 && y <= dest->h - 1)
1697 switch (dest->format->BytesPerPixel)
1700 return y*dest->pitch;
1704 return y*dest->pitch/2;
1708 return y*dest->pitch;
1712 return y*dest->pitch/4;
1720 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1722 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1724 switch (surface->format->BytesPerPixel)
1728 /* Assuming 8-bpp */
1729 *((Uint8 *)surface->pixels + ypitch + x) = color;
1735 /* Probably 15-bpp or 16-bpp */
1736 *((Uint16 *)surface->pixels + ypitch + x) = color;
1742 /* Slow 24-bpp mode, usually not used */
1746 /* Gack - slow, but endian correct */
1747 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1748 shift = surface->format->Rshift;
1749 *(pix+shift/8) = color>>shift;
1750 shift = surface->format->Gshift;
1751 *(pix+shift/8) = color>>shift;
1752 shift = surface->format->Bshift;
1753 *(pix+shift/8) = color>>shift;
1759 /* Probably 32-bpp */
1760 *((Uint32 *)surface->pixels + ypitch + x) = color;
1767 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1772 if (SDL_MUSTLOCK(Surface))
1774 if (SDL_LockSurface(Surface) < 0)
1787 /* Do the clipping */
1788 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1792 if (x2 > Surface->w - 1)
1793 x2 = Surface->w - 1;
1800 SDL_FillRect(Surface, &l, Color);
1802 if (SDL_MUSTLOCK(Surface))
1804 SDL_UnlockSurface(Surface);
1808 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1809 Uint8 R, Uint8 G, Uint8 B)
1811 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1814 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1825 /* Do the clipping */
1826 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1830 if (x2 > Surface->w - 1)
1831 x2 = Surface->w - 1;
1838 SDL_FillRect(Surface, &l, Color);
1841 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1846 if (SDL_MUSTLOCK(Surface))
1848 if (SDL_LockSurface(Surface) < 0)
1861 /* Do the clipping */
1862 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1866 if (y2 > Surface->h - 1)
1867 y2 = Surface->h - 1;
1874 SDL_FillRect(Surface, &l, Color);
1876 if (SDL_MUSTLOCK(Surface))
1878 SDL_UnlockSurface(Surface);
1882 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1883 Uint8 R, Uint8 G, Uint8 B)
1885 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1888 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1899 /* Do the clipping */
1900 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1904 if (y2 > Surface->h - 1)
1905 y2 = Surface->h - 1;
1912 SDL_FillRect(Surface, &l, Color);
1915 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1916 Sint16 x2, Sint16 y2, Uint32 Color,
1917 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1920 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1925 sdx = (dx < 0) ? -1 : 1;
1926 sdy = (dy < 0) ? -1 : 1;
1938 for (x = 0; x < dx; x++)
1940 Callback(Surface, px, py, Color);
1954 for (y = 0; y < dy; y++)
1956 Callback(Surface, px, py, Color);
1970 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1971 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1972 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1975 sge_DoLine(Surface, X1, Y1, X2, Y2,
1976 SDL_MapRGB(Surface->format, R, G, B), Callback);
1979 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1982 if (SDL_MUSTLOCK(Surface))
1984 if (SDL_LockSurface(Surface) < 0)
1989 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1991 /* unlock the display */
1992 if (SDL_MUSTLOCK(Surface))
1994 SDL_UnlockSurface(Surface);
1998 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1999 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
2001 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
2004 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
2006 if (dst_bitmap == backbuffer || dst_bitmap == window)
2012 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
2017 -----------------------------------------------------------------------------
2018 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
2019 -----------------------------------------------------------------------------
2022 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
2023 int width, int height, Uint32 color)
2027 for (y = src_y; y < src_y + height; y++)
2029 for (x = src_x; x < src_x + width; x++)
2031 Uint32 pixel = SDLGetPixel(bitmap, x, y);
2033 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
2038 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
2039 int src_x, int src_y, int width, int height,
2040 int dst_x, int dst_y)
2044 for (y = 0; y < height; y++)
2046 for (x = 0; x < width; x++)
2048 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
2050 if (pixel != BLACK_PIXEL)
2051 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
2057 /* ========================================================================= */
2058 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
2059 /* (Rotozoomer) by Andreas Schiffler */
2060 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
2061 /* ========================================================================= */
2064 -----------------------------------------------------------------------------
2067 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
2068 -----------------------------------------------------------------------------
2079 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
2082 tColorRGBA *sp, *csp, *dp;
2086 sp = csp = (tColorRGBA *) src->pixels;
2087 dp = (tColorRGBA *) dst->pixels;
2088 dgap = dst->pitch - dst->w * 4;
2090 for (y = 0; y < dst->h; y++)
2094 for (x = 0; x < dst->w; x++)
2096 tColorRGBA *sp0 = sp;
2097 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
2098 tColorRGBA *sp00 = &sp0[0];
2099 tColorRGBA *sp01 = &sp0[1];
2100 tColorRGBA *sp10 = &sp1[0];
2101 tColorRGBA *sp11 = &sp1[1];
2104 /* create new color pixel from all four source color pixels */
2105 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2106 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2107 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2108 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2113 /* advance source pointers */
2116 /* advance destination pointer */
2120 /* advance source pointer */
2121 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2123 /* advance destination pointers */
2124 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2130 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2132 int x, y, *sax, *say, *csax, *csay;
2134 tColorRGBA *sp, *csp, *csp0, *dp;
2137 /* use specialized zoom function when scaling down to exactly half size */
2138 if (src->w == 2 * dst->w &&
2139 src->h == 2 * dst->h)
2140 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2142 /* variable setup */
2143 sx = (float) src->w / (float) dst->w;
2144 sy = (float) src->h / (float) dst->h;
2146 /* allocate memory for row increments */
2147 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2148 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2150 /* precalculate row increments */
2151 for (x = 0; x <= dst->w; x++)
2152 *csax++ = (int)(sx * x);
2154 for (y = 0; y <= dst->h; y++)
2155 *csay++ = (int)(sy * y);
2158 sp = csp = csp0 = (tColorRGBA *) src->pixels;
2159 dp = (tColorRGBA *) dst->pixels;
2160 dgap = dst->pitch - dst->w * 4;
2163 for (y = 0; y < dst->h; y++)
2168 for (x = 0; x < dst->w; x++)
2173 /* advance source pointers */
2177 /* advance destination pointer */
2181 /* advance source pointer */
2183 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
2185 /* advance destination pointers */
2186 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2196 -----------------------------------------------------------------------------
2199 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2200 -----------------------------------------------------------------------------
2203 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2205 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2206 Uint8 *sp, *dp, *csp;
2209 /* variable setup */
2210 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2211 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2213 /* allocate memory for row increments */
2214 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2215 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2217 /* precalculate row increments */
2220 for (x = 0; x < dst->w; x++)
2223 *csax = (csx >> 16);
2230 for (y = 0; y < dst->h; y++)
2233 *csay = (csy >> 16);
2240 for (x = 0; x < dst->w; x++)
2248 for (y = 0; y < dst->h; y++)
2255 sp = csp = (Uint8 *) src->pixels;
2256 dp = (Uint8 *) dst->pixels;
2257 dgap = dst->pitch - dst->w;
2261 for (y = 0; y < dst->h; y++)
2265 for (x = 0; x < dst->w; x++)
2270 /* advance source pointers */
2274 /* advance destination pointer */
2278 /* advance source pointer (for row) */
2279 csp += ((*csay) * src->pitch);
2282 /* advance destination pointers */
2293 -----------------------------------------------------------------------------
2296 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2297 'zoomx' and 'zoomy' are scaling factors for width and height.
2298 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2299 into a 32bit RGBA format on the fly.
2300 -----------------------------------------------------------------------------
2303 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2305 SDL_Surface *zoom_src = NULL;
2306 SDL_Surface *zoom_dst = NULL;
2307 boolean is_converted = FALSE;
2314 /* determine if source surface is 32 bit or 8 bit */
2315 is_32bit = (src->format->BitsPerPixel == 32);
2317 if (is_32bit || src->format->BitsPerPixel == 8)
2319 /* use source surface 'as is' */
2324 /* new source surface is 32 bit with a defined RGB ordering */
2325 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2326 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2327 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2329 is_converted = TRUE;
2332 /* allocate surface to completely contain the zoomed surface */
2335 /* target surface is 32 bit with source RGBA/ABGR ordering */
2336 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2337 zoom_src->format->Rmask,
2338 zoom_src->format->Gmask,
2339 zoom_src->format->Bmask, 0);
2343 /* target surface is 8 bit */
2344 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2348 /* lock source surface */
2349 SDL_LockSurface(zoom_src);
2351 /* check which kind of surface we have */
2354 /* call the 32 bit transformation routine to do the zooming */
2355 zoomSurfaceRGBA(zoom_src, zoom_dst);
2360 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2361 zoom_dst->format->palette->colors[i] =
2362 zoom_src->format->palette->colors[i];
2363 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2365 /* call the 8 bit transformation routine to do the zooming */
2366 zoomSurfaceY(zoom_src, zoom_dst);
2369 /* unlock source surface */
2370 SDL_UnlockSurface(zoom_src);
2372 /* free temporary surface */
2374 SDL_FreeSurface(zoom_src);
2376 /* return destination surface */
2380 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2382 Bitmap *dst_bitmap = CreateBitmapStruct();
2383 SDL_Surface **dst_surface = &dst_bitmap->surface;
2385 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2386 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2388 dst_bitmap->width = dst_width;
2389 dst_bitmap->height = dst_height;
2391 /* create zoomed temporary surface from source surface */
2392 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2394 /* create native format destination surface from zoomed temporary surface */
2395 SDLSetNativeSurface(dst_surface);
2401 /* ========================================================================= */
2402 /* load image to bitmap */
2403 /* ========================================================================= */
2405 Bitmap *SDLLoadImage(char *filename)
2407 Bitmap *new_bitmap = CreateBitmapStruct();
2408 SDL_Surface *sdl_image_tmp;
2410 print_timestamp_init("SDLLoadImage");
2412 print_timestamp_time(getBaseNamePtr(filename));
2414 /* load image to temporary surface */
2415 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2417 SetError("IMG_Load(): %s", SDL_GetError());
2422 print_timestamp_time("IMG_Load");
2424 UPDATE_BUSY_STATE();
2426 /* create native non-transparent surface for current image */
2427 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2429 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2434 print_timestamp_time("SDL_DisplayFormat (opaque)");
2436 UPDATE_BUSY_STATE();
2438 /* create native transparent surface for current image */
2439 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2440 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2442 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2444 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2449 print_timestamp_time("SDL_DisplayFormat (masked)");
2451 UPDATE_BUSY_STATE();
2453 /* free temporary surface */
2454 SDL_FreeSurface(sdl_image_tmp);
2456 new_bitmap->width = new_bitmap->surface->w;
2457 new_bitmap->height = new_bitmap->surface->h;
2459 print_timestamp_done("SDLLoadImage");
2465 /* ------------------------------------------------------------------------- */
2466 /* custom cursor fuctions */
2467 /* ------------------------------------------------------------------------- */
2469 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2471 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2472 cursor_info->width, cursor_info->height,
2473 cursor_info->hot_x, cursor_info->hot_y);
2476 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2478 static struct MouseCursorInfo *last_cursor_info = NULL;
2479 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2480 static SDL_Cursor *cursor_default = NULL;
2481 static SDL_Cursor *cursor_current = NULL;
2483 /* if invoked for the first time, store the SDL default cursor */
2484 if (cursor_default == NULL)
2485 cursor_default = SDL_GetCursor();
2487 /* only create new cursor if cursor info (custom only) has changed */
2488 if (cursor_info != NULL && cursor_info != last_cursor_info)
2490 cursor_current = create_cursor(cursor_info);
2491 last_cursor_info = cursor_info;
2494 /* only set new cursor if cursor info (custom or NULL) has changed */
2495 if (cursor_info != last_cursor_info2)
2496 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2498 last_cursor_info2 = cursor_info;
2502 /* ========================================================================= */
2503 /* audio functions */
2504 /* ========================================================================= */
2506 void SDLOpenAudio(void)
2508 #if !defined(TARGET_SDL2)
2509 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2510 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2513 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2515 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2519 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2520 AUDIO_NUM_CHANNELS_STEREO,
2521 setup.system.audio_fragment_size) < 0)
2523 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2527 audio.sound_available = TRUE;
2528 audio.music_available = TRUE;
2529 audio.loops_available = TRUE;
2530 audio.sound_enabled = TRUE;
2532 /* set number of available mixer channels */
2533 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2534 audio.music_channel = MUSIC_CHANNEL;
2535 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2537 Mixer_InitChannels();
2540 void SDLCloseAudio(void)
2543 Mix_HaltChannel(-1);
2546 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2550 /* ========================================================================= */
2551 /* event functions */
2552 /* ========================================================================= */
2554 void SDLNextEvent(Event *event)
2556 SDL_WaitEvent(event);
2558 if (event->type == EVENT_BUTTONPRESS ||
2559 event->type == EVENT_BUTTONRELEASE)
2561 if (((ButtonEvent *)event)->x > video_xoffset)
2562 ((ButtonEvent *)event)->x -= video_xoffset;
2564 ((ButtonEvent *)event)->x = 0;
2565 if (((ButtonEvent *)event)->y > video_yoffset)
2566 ((ButtonEvent *)event)->y -= video_yoffset;
2568 ((ButtonEvent *)event)->y = 0;
2570 else if (event->type == EVENT_MOTIONNOTIFY)
2572 if (((MotionEvent *)event)->x > video_xoffset)
2573 ((MotionEvent *)event)->x -= video_xoffset;
2575 ((MotionEvent *)event)->x = 0;
2576 if (((MotionEvent *)event)->y > video_yoffset)
2577 ((MotionEvent *)event)->y -= video_yoffset;
2579 ((MotionEvent *)event)->y = 0;
2583 void SDLHandleWindowManagerEvent(Event *event)
2586 #if defined(PLATFORM_WIN32)
2587 // experimental drag and drop code
2589 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2590 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2592 #if defined(TARGET_SDL2)
2593 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2595 if (syswmmsg->msg == WM_DROPFILES)
2598 #if defined(TARGET_SDL2)
2599 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2601 HDROP hdrop = (HDROP)syswmmsg->wParam;
2605 printf("::: SDL_SYSWMEVENT:\n");
2607 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2609 for (i = 0; i < num_files; i++)
2611 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2612 char buffer[buffer_len + 1];
2614 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2616 printf("::: - '%s'\n", buffer);
2619 #if defined(TARGET_SDL2)
2620 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2622 DragFinish((HDROP)syswmmsg->wParam);
2630 /* ========================================================================= */
2631 /* joystick functions */
2632 /* ========================================================================= */
2634 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2635 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2636 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2638 static boolean SDLOpenJoystick(int nr)
2640 if (nr < 0 || nr > MAX_PLAYERS)
2643 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2646 static void SDLCloseJoystick(int nr)
2648 if (nr < 0 || nr > MAX_PLAYERS)
2651 SDL_JoystickClose(sdl_joystick[nr]);
2653 sdl_joystick[nr] = NULL;
2656 static boolean SDLCheckJoystickOpened(int nr)
2658 if (nr < 0 || nr > MAX_PLAYERS)
2661 #if defined(TARGET_SDL2)
2662 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2664 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2668 void HandleJoystickEvent(Event *event)
2672 case SDL_JOYAXISMOTION:
2673 if (event->jaxis.axis < 2)
2674 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2677 case SDL_JOYBUTTONDOWN:
2678 if (event->jbutton.button < 2)
2679 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2682 case SDL_JOYBUTTONUP:
2683 if (event->jbutton.button < 2)
2684 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2692 void SDLInitJoysticks()
2694 static boolean sdl_joystick_subsystem_initialized = FALSE;
2695 boolean print_warning = !sdl_joystick_subsystem_initialized;
2698 if (!sdl_joystick_subsystem_initialized)
2700 sdl_joystick_subsystem_initialized = TRUE;
2702 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2704 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2709 for (i = 0; i < MAX_PLAYERS; i++)
2711 /* get configured joystick for this player */
2712 char *device_name = setup.input[i].joy.device_name;
2713 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2715 if (joystick_nr >= SDL_NumJoysticks())
2717 if (setup.input[i].use_joystick && print_warning)
2718 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2723 /* misuse joystick file descriptor variable to store joystick number */
2724 joystick.fd[i] = joystick_nr;
2726 if (joystick_nr == -1)
2729 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2730 if (SDLCheckJoystickOpened(joystick_nr))
2731 SDLCloseJoystick(joystick_nr);
2733 if (!setup.input[i].use_joystick)
2736 if (!SDLOpenJoystick(joystick_nr))
2739 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2744 joystick.status = JOYSTICK_ACTIVATED;
2748 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2750 if (nr < 0 || nr >= MAX_PLAYERS)
2754 *x = sdl_js_axis[nr][0];
2756 *y = sdl_js_axis[nr][1];
2759 *b1 = sdl_js_button[nr][0];
2761 *b2 = sdl_js_button[nr][1];