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 SDLInitVideoDisplay(void)
354 #if !defined(TARGET_SDL2)
355 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
356 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
358 SDL_putenv("SDL_VIDEO_CENTERED=1");
361 /* initialize SDL video */
362 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
363 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
365 /* set default SDL depth */
366 #if !defined(TARGET_SDL2)
367 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
369 video.default_depth = 32; // (how to determine video depth in SDL2?)
373 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
376 #if !defined(TARGET_SDL2)
377 static int screen_xy[][2] =
385 SDL_Rect **modes = NULL;
386 boolean hardware_fullscreen_available = TRUE;
389 /* default: normal game window size */
390 fullscreen_width = video.width;
391 fullscreen_height = video.height;
392 fullscreen_xoffset = 0;
393 fullscreen_yoffset = 0;
395 #if !defined(TARGET_SDL2)
396 /* determine required standard fullscreen mode for game screen size */
397 for (i = 0; screen_xy[i][0] != -1; i++)
399 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
401 fullscreen_width = screen_xy[i][0];
402 fullscreen_height = screen_xy[i][1];
408 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
409 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
412 checked_free(video.fullscreen_modes);
414 video.fullscreen_modes = NULL;
415 video.fullscreen_mode_current = NULL;
417 video.window_scaling_percent = setup.window_scaling_percent;
418 video.window_scaling_quality = setup.window_scaling_quality;
420 #if defined(TARGET_SDL2)
421 int num_displays = SDL_GetNumVideoDisplays();
423 if (num_displays > 0)
425 // currently only display modes of first display supported
426 int num_modes = SDL_GetNumDisplayModes(0);
430 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
432 for (i = 0; i < num_modes; i++)
434 SDL_DisplayMode mode;
436 if (SDL_GetDisplayMode(0, i, &mode) < 0)
439 modes[i] = checked_calloc(sizeof(SDL_Rect));
441 modes[i]->w = mode.w;
442 modes[i]->h = mode.h;
447 /* get available hardware supported fullscreen modes */
448 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
453 /* no hardware screen modes available => no fullscreen mode support */
454 // video.fullscreen_available = FALSE;
455 hardware_fullscreen_available = FALSE;
457 else if (modes == (SDL_Rect **)-1)
459 /* fullscreen resolution is not restricted -- all resolutions available */
460 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
462 /* use native video buffer size for fullscreen mode */
463 video.fullscreen_modes[0].width = video.width;
464 video.fullscreen_modes[0].height = video.height;
466 video.fullscreen_modes[1].width = -1;
467 video.fullscreen_modes[1].height = -1;
471 /* in this case, a certain number of screen modes is available */
474 for (i = 0; modes[i] != NULL; i++)
476 boolean found_mode = FALSE;
478 /* screen mode is smaller than video buffer size -- skip it */
479 if (modes[i]->w < video.width || modes[i]->h < video.height)
482 if (video.fullscreen_modes != NULL)
483 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
484 if (modes[i]->w == video.fullscreen_modes[j].width &&
485 modes[i]->h == video.fullscreen_modes[j].height)
488 if (found_mode) /* screen mode already stored -- skip it */
491 /* new mode found; add it to list of available fullscreen modes */
495 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
497 sizeof(struct ScreenModeInfo));
499 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
500 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
502 video.fullscreen_modes[num_modes].width = -1;
503 video.fullscreen_modes[num_modes].height = -1;
508 /* no appropriate screen modes available => no fullscreen mode support */
509 // video.fullscreen_available = FALSE;
510 hardware_fullscreen_available = FALSE;
514 video.fullscreen_available = hardware_fullscreen_available;
516 #if USE_DESKTOP_FULLSCREEN
517 // in SDL 2.0, there is always support for desktop fullscreen mode
518 // (in SDL 1.2, there is only support for "real" fullscreen mode)
519 video.fullscreen_available = TRUE;
522 #if defined(TARGET_SDL2)
525 for (i = 0; modes[i] != NULL; i++)
526 checked_free(modes[i]);
532 /* open SDL video output device (window or fullscreen mode) */
533 if (!SDLSetVideoMode(backbuffer, fullscreen))
534 Error(ERR_EXIT, "setting video mode failed");
536 /* !!! SDL2 can only set the window icon if the window already exists !!! */
537 /* set window icon */
538 SDLSetWindowIcon(program.icon_filename);
540 /* set window and icon title */
541 #if defined(TARGET_SDL2)
542 SDL_SetWindowTitle(sdl_window, program.window_title);
544 SDL_WM_SetCaption(program.window_title, program.window_title);
547 /* SDL cannot directly draw to the visible video framebuffer like X11,
548 but always uses a backbuffer, which is then blitted to the visible
549 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
550 visible video framebuffer with 'SDL_Flip', if the hardware supports
551 this). Therefore do not use an additional backbuffer for drawing, but
552 use a symbolic buffer (distinguishable from the SDL backbuffer) called
553 'window', which indicates that the SDL backbuffer should be updated to
554 the visible video framebuffer when attempting to blit to it.
556 For convenience, it seems to be a good idea to create this symbolic
557 buffer 'window' at the same size as the SDL backbuffer. Although it
558 should never be drawn to directly, it would do no harm nevertheless. */
560 /* create additional (symbolic) buffer for double-buffering */
561 ReCreateBitmap(window, video.width, video.height, video.depth);
564 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
567 SDL_Surface *new_surface = NULL;
569 #if defined(TARGET_SDL2)
570 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
571 #if USE_DESKTOP_FULLSCREEN
572 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
574 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
578 int surface_flags_window = SURFACE_FLAGS;
579 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
582 int width = (fullscreen ? fullscreen_width : video.width);
583 int height = (fullscreen ? fullscreen_height : video.height);
584 int surface_flags = (fullscreen ? surface_flags_fullscreen :
585 surface_flags_window);
587 // default window size is unscaled
588 video.window_width = video.width;
589 video.window_height = video.height;
591 #if defined(TARGET_SDL2)
593 // store if initial screen mode is fullscreen mode when changing screen size
594 video.fullscreen_initial = fullscreen;
597 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
598 #if !USE_DESKTOP_FULLSCREEN
599 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
602 video.window_width = window_scaling_factor * width;
603 video.window_height = window_scaling_factor * height;
605 if ((*backbuffer)->surface)
607 SDL_FreeSurface((*backbuffer)->surface);
608 (*backbuffer)->surface = NULL;
613 SDL_DestroyTexture(sdl_texture);
617 if (!(fullscreen && fullscreen_enabled))
621 SDL_DestroyRenderer(sdl_renderer);
627 SDL_DestroyWindow(sdl_window);
632 if (sdl_window == NULL)
633 sdl_window = SDL_CreateWindow(program.window_title,
634 SDL_WINDOWPOS_CENTERED,
635 SDL_WINDOWPOS_CENTERED,
636 #if USE_DESKTOP_FULLSCREEN
640 (int)(screen_scaling_factor * width),
641 (int)(screen_scaling_factor * height),
645 if (sdl_window != NULL)
648 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
649 *without* enabling 2D/3D acceleration and/or guest additions installed,
650 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
651 it will try to use accelerated graphics and apparently fails miserably) */
652 if (sdl_renderer == NULL)
653 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
655 if (sdl_renderer == NULL)
656 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
659 if (sdl_renderer != NULL)
661 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
662 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
663 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
665 sdl_texture = SDL_CreateTexture(sdl_renderer,
666 SDL_PIXELFORMAT_ARGB8888,
667 SDL_TEXTUREACCESS_STREAMING,
670 if (sdl_texture != NULL)
672 // use SDL default values for RGB masks and no alpha channel
673 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
675 if (new_surface == NULL)
676 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
681 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
686 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
691 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
697 SDL_DestroyWindow(sdl_window);
699 sdl_window = SDL_CreateWindow(program.window_title,
700 SDL_WINDOWPOS_CENTERED,
701 SDL_WINDOWPOS_CENTERED,
705 if (sdl_window != NULL)
706 new_surface = SDL_GetWindowSurface(sdl_window);
710 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
713 #if defined(TARGET_SDL2)
714 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
715 if (new_surface != NULL)
716 fullscreen_enabled = fullscreen;
722 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
724 boolean success = TRUE;
725 SDL_Surface *new_surface = NULL;
729 if (*backbuffer == NULL)
730 *backbuffer = CreateBitmapStruct();
732 /* (real bitmap might be larger in fullscreen mode with video offsets) */
733 (*backbuffer)->width = video.width;
734 (*backbuffer)->height = video.height;
736 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
738 setFullscreenParameters(setup.fullscreen_mode);
740 video_xoffset = fullscreen_xoffset;
741 video_yoffset = fullscreen_yoffset;
743 /* switch display to fullscreen mode, if available */
744 new_surface = SDLCreateScreen(backbuffer, TRUE);
746 if (new_surface == NULL)
748 /* switching display to fullscreen mode failed */
749 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
751 /* do not try it again */
752 video.fullscreen_available = FALSE;
758 (*backbuffer)->surface = new_surface;
760 video.fullscreen_enabled = TRUE;
761 video.fullscreen_mode_current = setup.fullscreen_mode;
767 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
772 /* switch display to window mode */
773 new_surface = SDLCreateScreen(backbuffer, FALSE);
775 if (new_surface == NULL)
777 /* switching display to window mode failed -- should not happen */
778 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
784 (*backbuffer)->surface = new_surface;
786 video.fullscreen_enabled = FALSE;
787 video.window_scaling_percent = setup.window_scaling_percent;
788 video.window_scaling_quality = setup.window_scaling_quality;
794 #if defined(TARGET_SDL2)
795 SDLRedrawWindow(); // map window
799 #if defined(PLATFORM_WIN32)
800 // experimental drag and drop code
802 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
805 SDL_SysWMinfo wminfo;
807 boolean wminfo_success = FALSE;
809 SDL_VERSION(&wminfo.version);
810 #if defined(TARGET_SDL2)
812 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
814 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
819 #if defined(TARGET_SDL2)
820 hwnd = wminfo.info.win.window;
822 hwnd = wminfo.window;
825 DragAcceptFiles(hwnd, TRUE);
834 void SDLSetWindowTitle()
836 #if defined(TARGET_SDL2)
837 SDL_SetWindowTitle(sdl_window, program.window_title);
839 SDL_WM_SetCaption(program.window_title, program.window_title);
843 #if defined(TARGET_SDL2)
844 void SDLSetWindowScaling(int window_scaling_percent)
846 if (sdl_window == NULL)
849 float window_scaling_factor = (float)window_scaling_percent / 100;
850 int new_window_width = (int)(window_scaling_factor * video.width);
851 int new_window_height = (int)(window_scaling_factor * video.height);
853 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
855 video.window_scaling_percent = window_scaling_percent;
856 video.window_width = new_window_width;
857 video.window_height = new_window_height;
862 void SDLSetWindowScalingQuality(char *window_scaling_quality)
864 if (sdl_texture == NULL)
867 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
869 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
870 SDL_PIXELFORMAT_ARGB8888,
871 SDL_TEXTUREACCESS_STREAMING,
872 video.width, video.height);
874 if (new_texture != NULL)
876 SDL_DestroyTexture(sdl_texture);
878 sdl_texture = new_texture;
883 video.window_scaling_quality = window_scaling_quality;
886 void SDLSetWindowFullscreen(boolean fullscreen)
888 if (sdl_window == NULL)
891 #if USE_DESKTOP_FULLSCREEN
892 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
894 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
897 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
898 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
900 // if screen size was changed in fullscreen mode, correct desktop window 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;
911 void SDLRedrawWindow()
917 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
920 SDL_Surface *surface =
921 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
924 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
926 SDLSetNativeSurface(&surface);
928 bitmap->surface = surface;
931 void SDLFreeBitmapPointers(Bitmap *bitmap)
934 SDL_FreeSurface(bitmap->surface);
935 if (bitmap->surface_masked)
936 SDL_FreeSurface(bitmap->surface_masked);
938 bitmap->surface = NULL;
939 bitmap->surface_masked = NULL;
941 #if defined(TARGET_SDL2)
943 SDL_DestroyTexture(bitmap->texture);
944 if (bitmap->texture_masked)
945 SDL_DestroyTexture(bitmap->texture_masked);
947 bitmap->texture = NULL;
948 bitmap->texture_masked = NULL;
952 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
953 int src_x, int src_y, int width, int height,
954 int dst_x, int dst_y, int mask_mode)
956 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
957 SDL_Rect src_rect, dst_rect;
959 if (src_bitmap == backbuffer)
961 src_x += video_xoffset;
962 src_y += video_yoffset;
970 if (dst_bitmap == backbuffer || dst_bitmap == window)
972 dst_x += video_xoffset;
973 dst_y += video_yoffset;
981 // if (src_bitmap != backbuffer || dst_bitmap != window)
982 if (!(src_bitmap == backbuffer && dst_bitmap == window))
983 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
984 src_bitmap->surface_masked : src_bitmap->surface),
985 &src_rect, real_dst_bitmap->surface, &dst_rect);
987 #if defined(TARGET_SDL2)
988 if (dst_bitmap == window)
990 // SDL_UpdateWindowSurface(sdl_window);
991 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
992 UpdateScreen(&dst_rect);
995 if (dst_bitmap == window)
997 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
998 UpdateScreen(&dst_rect);
1003 void SDLBlitTexture(Bitmap *bitmap,
1004 int src_x, int src_y, int width, int height,
1005 int dst_x, int dst_y, int mask_mode)
1007 #if defined(TARGET_SDL2)
1009 SDL_Texture *texture;
1014 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
1016 if (texture == NULL)
1022 src_rect.h = height;
1027 dst_rect.h = height;
1029 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
1034 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
1037 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1040 if (dst_bitmap == backbuffer || dst_bitmap == window)
1051 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
1053 #if defined(TARGET_SDL2)
1054 if (dst_bitmap == window)
1056 // SDL_UpdateWindowSurface(sdl_window);
1057 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
1058 UpdateScreen(&rect);
1061 if (dst_bitmap == window)
1063 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
1064 UpdateScreen(&rect);
1069 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
1070 int fade_mode, int fade_delay, int post_delay,
1071 void (*draw_border_function)(void))
1073 static boolean initialization_needed = TRUE;
1074 static SDL_Surface *surface_source = NULL;
1075 static SDL_Surface *surface_target = NULL;
1076 static SDL_Surface *surface_black = NULL;
1077 SDL_Surface *surface_screen = backbuffer->surface;
1078 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
1079 SDL_Rect src_rect, dst_rect;
1081 int src_x = x, src_y = y;
1082 int dst_x = x, dst_y = y;
1083 unsigned int time_last, time_current;
1085 /* check if screen size has changed */
1086 if (surface_source != NULL && (video.width != surface_source->w ||
1087 video.height != surface_source->h))
1089 SDL_FreeSurface(surface_source);
1090 SDL_FreeSurface(surface_target);
1091 SDL_FreeSurface(surface_black);
1093 initialization_needed = TRUE;
1099 src_rect.h = height;
1101 dst_x += video_xoffset;
1102 dst_y += video_yoffset;
1106 dst_rect.w = width; /* (ignored) */
1107 dst_rect.h = height; /* (ignored) */
1109 dst_rect2 = dst_rect;
1111 if (initialization_needed)
1113 #if defined(TARGET_SDL2)
1114 unsigned int flags = 0;
1116 unsigned int flags = SDL_SRCALPHA;
1118 /* use same surface type as screen surface */
1119 if ((surface_screen->flags & SDL_HWSURFACE))
1120 flags |= SDL_HWSURFACE;
1122 flags |= SDL_SWSURFACE;
1125 /* create surface for temporary copy of screen buffer (source) */
1126 if ((surface_source =
1127 SDL_CreateRGBSurface(flags,
1130 surface_screen->format->BitsPerPixel,
1131 surface_screen->format->Rmask,
1132 surface_screen->format->Gmask,
1133 surface_screen->format->Bmask,
1134 surface_screen->format->Amask)) == NULL)
1135 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1137 /* create surface for cross-fading screen buffer (target) */
1138 if ((surface_target =
1139 SDL_CreateRGBSurface(flags,
1142 surface_screen->format->BitsPerPixel,
1143 surface_screen->format->Rmask,
1144 surface_screen->format->Gmask,
1145 surface_screen->format->Bmask,
1146 surface_screen->format->Amask)) == NULL)
1147 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1149 /* create black surface for fading from/to black */
1150 if ((surface_black =
1151 SDL_CreateRGBSurface(flags,
1154 surface_screen->format->BitsPerPixel,
1155 surface_screen->format->Rmask,
1156 surface_screen->format->Gmask,
1157 surface_screen->format->Bmask,
1158 surface_screen->format->Amask)) == NULL)
1159 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1161 /* completely fill the surface with black color pixels */
1162 SDL_FillRect(surface_black, NULL,
1163 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1165 initialization_needed = FALSE;
1168 /* copy source and target surfaces to temporary surfaces for fading */
1169 if (fade_mode & FADE_TYPE_TRANSFORM)
1171 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1172 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1174 else if (fade_mode & FADE_TYPE_FADE_IN)
1176 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1177 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1179 else /* FADE_TYPE_FADE_OUT */
1181 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1182 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1185 time_current = SDL_GetTicks();
1187 if (fade_mode == FADE_MODE_MELT)
1189 boolean done = FALSE;
1190 int melt_pixels = 2;
1191 int melt_columns = width / melt_pixels;
1192 int ypos[melt_columns];
1193 int max_steps = height / 8 + 32;
1198 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1199 #if defined(TARGET_SDL2)
1200 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1202 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1205 ypos[0] = -GetSimpleRandom(16);
1207 for (i = 1 ; i < melt_columns; i++)
1209 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1211 ypos[i] = ypos[i - 1] + r;
1224 time_last = time_current;
1225 time_current = SDL_GetTicks();
1226 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1227 steps_final = MIN(MAX(0, steps), max_steps);
1231 done = (steps_done >= steps_final);
1233 for (i = 0 ; i < melt_columns; i++)
1241 else if (ypos[i] < height)
1246 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1248 if (ypos[i] + dy >= height)
1249 dy = height - ypos[i];
1251 /* copy part of (appearing) target surface to upper area */
1252 src_rect.x = src_x + i * melt_pixels;
1253 // src_rect.y = src_y + ypos[i];
1255 src_rect.w = melt_pixels;
1257 src_rect.h = ypos[i] + dy;
1259 dst_rect.x = dst_x + i * melt_pixels;
1260 // dst_rect.y = dst_y + ypos[i];
1263 if (steps_done >= steps_final)
1264 SDL_BlitSurface(surface_target, &src_rect,
1265 surface_screen, &dst_rect);
1269 /* copy part of (disappearing) source surface to lower area */
1270 src_rect.x = src_x + i * melt_pixels;
1272 src_rect.w = melt_pixels;
1273 src_rect.h = height - ypos[i];
1275 dst_rect.x = dst_x + i * melt_pixels;
1276 dst_rect.y = dst_y + ypos[i];
1278 if (steps_done >= steps_final)
1279 SDL_BlitSurface(surface_source, &src_rect,
1280 surface_screen, &dst_rect);
1286 src_rect.x = src_x + i * melt_pixels;
1288 src_rect.w = melt_pixels;
1289 src_rect.h = height;
1291 dst_rect.x = dst_x + i * melt_pixels;
1294 if (steps_done >= steps_final)
1295 SDL_BlitSurface(surface_target, &src_rect,
1296 surface_screen, &dst_rect);
1300 if (steps_done >= steps_final)
1302 if (draw_border_function != NULL)
1303 draw_border_function();
1305 UpdateScreen(&dst_rect2);
1309 else if (fade_mode == FADE_MODE_CURTAIN)
1313 int xx_size = width / 2;
1315 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1316 #if defined(TARGET_SDL2)
1317 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1319 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1322 for (xx = 0; xx < xx_size;)
1324 time_last = time_current;
1325 time_current = SDL_GetTicks();
1326 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1327 xx_final = MIN(MAX(0, xx), xx_size);
1332 src_rect.h = height;
1337 /* draw new (target) image to screen buffer */
1338 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1340 if (xx_final < xx_size)
1342 src_rect.w = xx_size - xx_final;
1343 src_rect.h = height;
1345 /* draw old (source) image to screen buffer (left side) */
1347 src_rect.x = src_x + xx_final;
1350 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1352 /* draw old (source) image to screen buffer (right side) */
1354 src_rect.x = src_x + xx_size;
1355 dst_rect.x = dst_x + xx_size + xx_final;
1357 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1360 if (draw_border_function != NULL)
1361 draw_border_function();
1363 /* only update the region of the screen that is affected from fading */
1364 UpdateScreen(&dst_rect2);
1367 else /* fading in, fading out or cross-fading */
1372 for (alpha = 0.0; alpha < 255.0;)
1374 time_last = time_current;
1375 time_current = SDL_GetTicks();
1376 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1377 alpha_final = MIN(MAX(0, alpha), 255);
1379 /* draw existing (source) image to screen buffer */
1380 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1382 /* draw new (target) image to screen buffer using alpha blending */
1383 #if defined(TARGET_SDL2)
1384 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1385 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1387 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1389 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1391 if (draw_border_function != NULL)
1392 draw_border_function();
1394 /* only update the region of the screen that is affected from fading */
1395 UpdateScreen(&dst_rect);
1401 unsigned int time_post_delay;
1403 time_current = SDL_GetTicks();
1404 time_post_delay = time_current + post_delay;
1406 while (time_current < time_post_delay)
1408 // do not wait longer than 10 ms at a time to be able to ...
1409 Delay(MIN(10, time_post_delay - time_current));
1411 // ... continue drawing global animations during post delay
1414 time_current = SDL_GetTicks();
1419 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1420 int to_x, int to_y, Uint32 color)
1422 SDL_Surface *surface = dst_bitmap->surface;
1426 swap_numbers(&from_x, &to_x);
1429 swap_numbers(&from_y, &to_y);
1433 rect.w = (to_x - from_x + 1);
1434 rect.h = (to_y - from_y + 1);
1436 if (dst_bitmap == backbuffer || dst_bitmap == window)
1438 rect.x += video_xoffset;
1439 rect.y += video_yoffset;
1442 SDL_FillRect(surface, &rect, color);
1445 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1446 int to_x, int to_y, Uint32 color)
1448 if (dst_bitmap == backbuffer || dst_bitmap == window)
1450 from_x += video_xoffset;
1451 from_y += video_yoffset;
1452 to_x += video_xoffset;
1453 to_y += video_yoffset;
1456 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1459 #if ENABLE_UNUSED_CODE
1460 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1461 int num_points, Uint32 color)
1466 for (i = 0; i < num_points - 1; i++)
1468 for (x = 0; x < line_width; x++)
1470 for (y = 0; y < line_width; y++)
1472 int dx = x - line_width / 2;
1473 int dy = y - line_width / 2;
1475 if ((x == 0 && y == 0) ||
1476 (x == 0 && y == line_width - 1) ||
1477 (x == line_width - 1 && y == 0) ||
1478 (x == line_width - 1 && y == line_width - 1))
1481 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1482 points[i+1].x + dx, points[i+1].y + dy, color);
1489 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1491 SDL_Surface *surface = src_bitmap->surface;
1493 if (src_bitmap == backbuffer || src_bitmap == window)
1499 switch (surface->format->BytesPerPixel)
1501 case 1: /* assuming 8-bpp */
1503 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1507 case 2: /* probably 15-bpp or 16-bpp */
1509 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1513 case 3: /* slow 24-bpp mode; usually not used */
1515 /* does this work? */
1516 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1520 shift = surface->format->Rshift;
1521 color |= *(pix + shift / 8) >> shift;
1522 shift = surface->format->Gshift;
1523 color |= *(pix + shift / 8) >> shift;
1524 shift = surface->format->Bshift;
1525 color |= *(pix + shift / 8) >> shift;
1531 case 4: /* probably 32-bpp */
1533 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1542 /* ========================================================================= */
1543 /* The following functions were taken from the SGE library */
1544 /* (SDL Graphics Extension Library) by Anders Lindström */
1545 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1546 /* ========================================================================= */
1548 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1550 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1552 switch (surface->format->BytesPerPixel)
1556 /* Assuming 8-bpp */
1557 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1563 /* Probably 15-bpp or 16-bpp */
1564 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1570 /* Slow 24-bpp mode, usually not used */
1574 /* Gack - slow, but endian correct */
1575 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1576 shift = surface->format->Rshift;
1577 *(pix+shift/8) = color>>shift;
1578 shift = surface->format->Gshift;
1579 *(pix+shift/8) = color>>shift;
1580 shift = surface->format->Bshift;
1581 *(pix+shift/8) = color>>shift;
1587 /* Probably 32-bpp */
1588 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1595 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1596 Uint8 R, Uint8 G, Uint8 B)
1598 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1601 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1603 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1606 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1608 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1611 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1616 /* Gack - slow, but endian correct */
1617 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1618 shift = surface->format->Rshift;
1619 *(pix+shift/8) = color>>shift;
1620 shift = surface->format->Gshift;
1621 *(pix+shift/8) = color>>shift;
1622 shift = surface->format->Bshift;
1623 *(pix+shift/8) = color>>shift;
1626 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1628 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1631 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1633 switch (dest->format->BytesPerPixel)
1636 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1640 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1644 _PutPixel24(dest,x,y,color);
1648 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1653 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1655 if (SDL_MUSTLOCK(surface))
1657 if (SDL_LockSurface(surface) < 0)
1663 _PutPixel(surface, x, y, color);
1665 if (SDL_MUSTLOCK(surface))
1667 SDL_UnlockSurface(surface);
1671 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1672 Uint8 r, Uint8 g, Uint8 b)
1674 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1677 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1679 if (y >= 0 && y <= dest->h - 1)
1681 switch (dest->format->BytesPerPixel)
1684 return y*dest->pitch;
1688 return y*dest->pitch/2;
1692 return y*dest->pitch;
1696 return y*dest->pitch/4;
1704 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1706 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1708 switch (surface->format->BytesPerPixel)
1712 /* Assuming 8-bpp */
1713 *((Uint8 *)surface->pixels + ypitch + x) = color;
1719 /* Probably 15-bpp or 16-bpp */
1720 *((Uint16 *)surface->pixels + ypitch + x) = color;
1726 /* Slow 24-bpp mode, usually not used */
1730 /* Gack - slow, but endian correct */
1731 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1732 shift = surface->format->Rshift;
1733 *(pix+shift/8) = color>>shift;
1734 shift = surface->format->Gshift;
1735 *(pix+shift/8) = color>>shift;
1736 shift = surface->format->Bshift;
1737 *(pix+shift/8) = color>>shift;
1743 /* Probably 32-bpp */
1744 *((Uint32 *)surface->pixels + ypitch + x) = color;
1751 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1756 if (SDL_MUSTLOCK(Surface))
1758 if (SDL_LockSurface(Surface) < 0)
1771 /* Do the clipping */
1772 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1776 if (x2 > Surface->w - 1)
1777 x2 = Surface->w - 1;
1784 SDL_FillRect(Surface, &l, Color);
1786 if (SDL_MUSTLOCK(Surface))
1788 SDL_UnlockSurface(Surface);
1792 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1793 Uint8 R, Uint8 G, Uint8 B)
1795 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1798 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1809 /* Do the clipping */
1810 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1814 if (x2 > Surface->w - 1)
1815 x2 = Surface->w - 1;
1822 SDL_FillRect(Surface, &l, Color);
1825 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1830 if (SDL_MUSTLOCK(Surface))
1832 if (SDL_LockSurface(Surface) < 0)
1845 /* Do the clipping */
1846 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1850 if (y2 > Surface->h - 1)
1851 y2 = Surface->h - 1;
1858 SDL_FillRect(Surface, &l, Color);
1860 if (SDL_MUSTLOCK(Surface))
1862 SDL_UnlockSurface(Surface);
1866 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1867 Uint8 R, Uint8 G, Uint8 B)
1869 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1872 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1883 /* Do the clipping */
1884 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1888 if (y2 > Surface->h - 1)
1889 y2 = Surface->h - 1;
1896 SDL_FillRect(Surface, &l, Color);
1899 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1900 Sint16 x2, Sint16 y2, Uint32 Color,
1901 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1904 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1909 sdx = (dx < 0) ? -1 : 1;
1910 sdy = (dy < 0) ? -1 : 1;
1922 for (x = 0; x < dx; x++)
1924 Callback(Surface, px, py, Color);
1938 for (y = 0; y < dy; y++)
1940 Callback(Surface, px, py, Color);
1954 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1955 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1956 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1959 sge_DoLine(Surface, X1, Y1, X2, Y2,
1960 SDL_MapRGB(Surface->format, R, G, B), Callback);
1963 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1966 if (SDL_MUSTLOCK(Surface))
1968 if (SDL_LockSurface(Surface) < 0)
1973 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1975 /* unlock the display */
1976 if (SDL_MUSTLOCK(Surface))
1978 SDL_UnlockSurface(Surface);
1982 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1983 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1985 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1988 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1990 if (dst_bitmap == backbuffer || dst_bitmap == window)
1996 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
2001 -----------------------------------------------------------------------------
2002 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
2003 -----------------------------------------------------------------------------
2006 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
2007 int width, int height, Uint32 color)
2011 for (y = src_y; y < src_y + height; y++)
2013 for (x = src_x; x < src_x + width; x++)
2015 Uint32 pixel = SDLGetPixel(bitmap, x, y);
2017 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
2022 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
2023 int src_x, int src_y, int width, int height,
2024 int dst_x, int dst_y)
2028 for (y = 0; y < height; y++)
2030 for (x = 0; x < width; x++)
2032 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
2034 if (pixel != BLACK_PIXEL)
2035 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
2041 /* ========================================================================= */
2042 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
2043 /* (Rotozoomer) by Andreas Schiffler */
2044 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
2045 /* ========================================================================= */
2048 -----------------------------------------------------------------------------
2051 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
2052 -----------------------------------------------------------------------------
2063 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
2066 tColorRGBA *sp, *csp, *dp;
2070 sp = csp = (tColorRGBA *) src->pixels;
2071 dp = (tColorRGBA *) dst->pixels;
2072 dgap = dst->pitch - dst->w * 4;
2074 for (y = 0; y < dst->h; y++)
2078 for (x = 0; x < dst->w; x++)
2080 tColorRGBA *sp0 = sp;
2081 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
2082 tColorRGBA *sp00 = &sp0[0];
2083 tColorRGBA *sp01 = &sp0[1];
2084 tColorRGBA *sp10 = &sp1[0];
2085 tColorRGBA *sp11 = &sp1[1];
2088 /* create new color pixel from all four source color pixels */
2089 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2090 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2091 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2092 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2097 /* advance source pointers */
2100 /* advance destination pointer */
2104 /* advance source pointer */
2105 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2107 /* advance destination pointers */
2108 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2114 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2116 int x, y, *sax, *say, *csax, *csay;
2118 tColorRGBA *sp, *csp, *csp0, *dp;
2121 /* use specialized zoom function when scaling down to exactly half size */
2122 if (src->w == 2 * dst->w &&
2123 src->h == 2 * dst->h)
2124 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2126 /* variable setup */
2127 sx = (float) src->w / (float) dst->w;
2128 sy = (float) src->h / (float) dst->h;
2130 /* allocate memory for row increments */
2131 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2132 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2134 /* precalculate row increments */
2135 for (x = 0; x <= dst->w; x++)
2136 *csax++ = (int)(sx * x);
2138 for (y = 0; y <= dst->h; y++)
2139 *csay++ = (int)(sy * y);
2142 sp = csp = csp0 = (tColorRGBA *) src->pixels;
2143 dp = (tColorRGBA *) dst->pixels;
2144 dgap = dst->pitch - dst->w * 4;
2147 for (y = 0; y < dst->h; y++)
2152 for (x = 0; x < dst->w; x++)
2157 /* advance source pointers */
2161 /* advance destination pointer */
2165 /* advance source pointer */
2167 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
2169 /* advance destination pointers */
2170 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2180 -----------------------------------------------------------------------------
2183 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2184 -----------------------------------------------------------------------------
2187 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2189 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2190 Uint8 *sp, *dp, *csp;
2193 /* variable setup */
2194 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2195 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2197 /* allocate memory for row increments */
2198 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2199 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2201 /* precalculate row increments */
2204 for (x = 0; x < dst->w; x++)
2207 *csax = (csx >> 16);
2214 for (y = 0; y < dst->h; y++)
2217 *csay = (csy >> 16);
2224 for (x = 0; x < dst->w; x++)
2232 for (y = 0; y < dst->h; y++)
2239 sp = csp = (Uint8 *) src->pixels;
2240 dp = (Uint8 *) dst->pixels;
2241 dgap = dst->pitch - dst->w;
2245 for (y = 0; y < dst->h; y++)
2249 for (x = 0; x < dst->w; x++)
2254 /* advance source pointers */
2258 /* advance destination pointer */
2262 /* advance source pointer (for row) */
2263 csp += ((*csay) * src->pitch);
2266 /* advance destination pointers */
2277 -----------------------------------------------------------------------------
2280 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2281 'zoomx' and 'zoomy' are scaling factors for width and height.
2282 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2283 into a 32bit RGBA format on the fly.
2284 -----------------------------------------------------------------------------
2287 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2289 SDL_Surface *zoom_src = NULL;
2290 SDL_Surface *zoom_dst = NULL;
2291 boolean is_converted = FALSE;
2298 /* determine if source surface is 32 bit or 8 bit */
2299 is_32bit = (src->format->BitsPerPixel == 32);
2301 if (is_32bit || src->format->BitsPerPixel == 8)
2303 /* use source surface 'as is' */
2308 /* new source surface is 32 bit with a defined RGB ordering */
2309 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2310 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2311 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2313 is_converted = TRUE;
2316 /* allocate surface to completely contain the zoomed surface */
2319 /* target surface is 32 bit with source RGBA/ABGR ordering */
2320 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2321 zoom_src->format->Rmask,
2322 zoom_src->format->Gmask,
2323 zoom_src->format->Bmask, 0);
2327 /* target surface is 8 bit */
2328 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2332 /* lock source surface */
2333 SDL_LockSurface(zoom_src);
2335 /* check which kind of surface we have */
2338 /* call the 32 bit transformation routine to do the zooming */
2339 zoomSurfaceRGBA(zoom_src, zoom_dst);
2344 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2345 zoom_dst->format->palette->colors[i] =
2346 zoom_src->format->palette->colors[i];
2347 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2349 /* call the 8 bit transformation routine to do the zooming */
2350 zoomSurfaceY(zoom_src, zoom_dst);
2353 /* unlock source surface */
2354 SDL_UnlockSurface(zoom_src);
2356 /* free temporary surface */
2358 SDL_FreeSurface(zoom_src);
2360 /* return destination surface */
2364 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2366 Bitmap *dst_bitmap = CreateBitmapStruct();
2367 SDL_Surface **dst_surface = &dst_bitmap->surface;
2369 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2370 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2372 dst_bitmap->width = dst_width;
2373 dst_bitmap->height = dst_height;
2375 /* create zoomed temporary surface from source surface */
2376 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2378 /* create native format destination surface from zoomed temporary surface */
2379 SDLSetNativeSurface(dst_surface);
2385 /* ========================================================================= */
2386 /* load image to bitmap */
2387 /* ========================================================================= */
2389 Bitmap *SDLLoadImage(char *filename)
2391 Bitmap *new_bitmap = CreateBitmapStruct();
2392 SDL_Surface *sdl_image_tmp;
2394 print_timestamp_init("SDLLoadImage");
2396 print_timestamp_time(getBaseNamePtr(filename));
2398 /* load image to temporary surface */
2399 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2401 SetError("IMG_Load(): %s", SDL_GetError());
2406 print_timestamp_time("IMG_Load");
2408 UPDATE_BUSY_STATE();
2410 /* create native non-transparent surface for current image */
2411 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2413 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2418 print_timestamp_time("SDL_DisplayFormat (opaque)");
2420 UPDATE_BUSY_STATE();
2422 /* create native transparent surface for current image */
2423 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2424 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2426 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2428 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2433 print_timestamp_time("SDL_DisplayFormat (masked)");
2435 UPDATE_BUSY_STATE();
2437 /* free temporary surface */
2438 SDL_FreeSurface(sdl_image_tmp);
2440 new_bitmap->width = new_bitmap->surface->w;
2441 new_bitmap->height = new_bitmap->surface->h;
2443 print_timestamp_done("SDLLoadImage");
2449 /* ------------------------------------------------------------------------- */
2450 /* custom cursor fuctions */
2451 /* ------------------------------------------------------------------------- */
2453 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2455 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2456 cursor_info->width, cursor_info->height,
2457 cursor_info->hot_x, cursor_info->hot_y);
2460 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2462 static struct MouseCursorInfo *last_cursor_info = NULL;
2463 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2464 static SDL_Cursor *cursor_default = NULL;
2465 static SDL_Cursor *cursor_current = NULL;
2467 /* if invoked for the first time, store the SDL default cursor */
2468 if (cursor_default == NULL)
2469 cursor_default = SDL_GetCursor();
2471 /* only create new cursor if cursor info (custom only) has changed */
2472 if (cursor_info != NULL && cursor_info != last_cursor_info)
2474 cursor_current = create_cursor(cursor_info);
2475 last_cursor_info = cursor_info;
2478 /* only set new cursor if cursor info (custom or NULL) has changed */
2479 if (cursor_info != last_cursor_info2)
2480 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2482 last_cursor_info2 = cursor_info;
2486 /* ========================================================================= */
2487 /* audio functions */
2488 /* ========================================================================= */
2490 void SDLOpenAudio(void)
2492 #if !defined(TARGET_SDL2)
2493 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2494 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2497 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2499 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2503 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2504 AUDIO_NUM_CHANNELS_STEREO,
2505 setup.system.audio_fragment_size) < 0)
2507 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2511 audio.sound_available = TRUE;
2512 audio.music_available = TRUE;
2513 audio.loops_available = TRUE;
2514 audio.sound_enabled = TRUE;
2516 /* set number of available mixer channels */
2517 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2518 audio.music_channel = MUSIC_CHANNEL;
2519 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2521 Mixer_InitChannels();
2524 void SDLCloseAudio(void)
2527 Mix_HaltChannel(-1);
2530 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2534 /* ========================================================================= */
2535 /* event functions */
2536 /* ========================================================================= */
2538 void SDLNextEvent(Event *event)
2540 SDL_WaitEvent(event);
2542 if (event->type == EVENT_BUTTONPRESS ||
2543 event->type == EVENT_BUTTONRELEASE)
2545 if (((ButtonEvent *)event)->x > video_xoffset)
2546 ((ButtonEvent *)event)->x -= video_xoffset;
2548 ((ButtonEvent *)event)->x = 0;
2549 if (((ButtonEvent *)event)->y > video_yoffset)
2550 ((ButtonEvent *)event)->y -= video_yoffset;
2552 ((ButtonEvent *)event)->y = 0;
2554 else if (event->type == EVENT_MOTIONNOTIFY)
2556 if (((MotionEvent *)event)->x > video_xoffset)
2557 ((MotionEvent *)event)->x -= video_xoffset;
2559 ((MotionEvent *)event)->x = 0;
2560 if (((MotionEvent *)event)->y > video_yoffset)
2561 ((MotionEvent *)event)->y -= video_yoffset;
2563 ((MotionEvent *)event)->y = 0;
2567 void SDLHandleWindowManagerEvent(Event *event)
2570 #if defined(PLATFORM_WIN32)
2571 // experimental drag and drop code
2573 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2574 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2576 #if defined(TARGET_SDL2)
2577 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2579 if (syswmmsg->msg == WM_DROPFILES)
2582 #if defined(TARGET_SDL2)
2583 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2585 HDROP hdrop = (HDROP)syswmmsg->wParam;
2589 printf("::: SDL_SYSWMEVENT:\n");
2591 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2593 for (i = 0; i < num_files; i++)
2595 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2596 char buffer[buffer_len + 1];
2598 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2600 printf("::: - '%s'\n", buffer);
2603 #if defined(TARGET_SDL2)
2604 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2606 DragFinish((HDROP)syswmmsg->wParam);
2614 /* ========================================================================= */
2615 /* joystick functions */
2616 /* ========================================================================= */
2618 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2619 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2620 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2622 static boolean SDLOpenJoystick(int nr)
2624 if (nr < 0 || nr > MAX_PLAYERS)
2627 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2630 static void SDLCloseJoystick(int nr)
2632 if (nr < 0 || nr > MAX_PLAYERS)
2635 SDL_JoystickClose(sdl_joystick[nr]);
2637 sdl_joystick[nr] = NULL;
2640 static boolean SDLCheckJoystickOpened(int nr)
2642 if (nr < 0 || nr > MAX_PLAYERS)
2645 #if defined(TARGET_SDL2)
2646 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2648 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2652 void HandleJoystickEvent(Event *event)
2656 case SDL_JOYAXISMOTION:
2657 if (event->jaxis.axis < 2)
2658 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2661 case SDL_JOYBUTTONDOWN:
2662 if (event->jbutton.button < 2)
2663 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2666 case SDL_JOYBUTTONUP:
2667 if (event->jbutton.button < 2)
2668 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2676 void SDLInitJoysticks()
2678 static boolean sdl_joystick_subsystem_initialized = FALSE;
2679 boolean print_warning = !sdl_joystick_subsystem_initialized;
2682 if (!sdl_joystick_subsystem_initialized)
2684 sdl_joystick_subsystem_initialized = TRUE;
2686 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2688 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2693 for (i = 0; i < MAX_PLAYERS; i++)
2695 /* get configured joystick for this player */
2696 char *device_name = setup.input[i].joy.device_name;
2697 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2699 if (joystick_nr >= SDL_NumJoysticks())
2701 if (setup.input[i].use_joystick && print_warning)
2702 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2707 /* misuse joystick file descriptor variable to store joystick number */
2708 joystick.fd[i] = joystick_nr;
2710 if (joystick_nr == -1)
2713 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2714 if (SDLCheckJoystickOpened(joystick_nr))
2715 SDLCloseJoystick(joystick_nr);
2717 if (!setup.input[i].use_joystick)
2720 if (!SDLOpenJoystick(joystick_nr))
2723 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2728 joystick.status = JOYSTICK_ACTIVATED;
2732 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2734 if (nr < 0 || nr >= MAX_PLAYERS)
2738 *x = sdl_js_axis[nr][0];
2740 *y = sdl_js_axis[nr][1];
2743 *b1 = sdl_js_button[nr][0];
2745 *b2 = sdl_js_button[nr][1];