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(backbuffer->surface, 1, rect);
149 SDL_UpdateRect(backbuffer->surface, 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);
1402 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1403 int to_x, int to_y, Uint32 color)
1405 SDL_Surface *surface = dst_bitmap->surface;
1409 swap_numbers(&from_x, &to_x);
1412 swap_numbers(&from_y, &to_y);
1416 rect.w = (to_x - from_x + 1);
1417 rect.h = (to_y - from_y + 1);
1419 if (dst_bitmap == backbuffer || dst_bitmap == window)
1421 rect.x += video_xoffset;
1422 rect.y += video_yoffset;
1425 SDL_FillRect(surface, &rect, color);
1428 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1429 int to_x, int to_y, Uint32 color)
1431 if (dst_bitmap == backbuffer || dst_bitmap == window)
1433 from_x += video_xoffset;
1434 from_y += video_yoffset;
1435 to_x += video_xoffset;
1436 to_y += video_yoffset;
1439 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1442 #if ENABLE_UNUSED_CODE
1443 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1444 int num_points, Uint32 color)
1449 for (i = 0; i < num_points - 1; i++)
1451 for (x = 0; x < line_width; x++)
1453 for (y = 0; y < line_width; y++)
1455 int dx = x - line_width / 2;
1456 int dy = y - line_width / 2;
1458 if ((x == 0 && y == 0) ||
1459 (x == 0 && y == line_width - 1) ||
1460 (x == line_width - 1 && y == 0) ||
1461 (x == line_width - 1 && y == line_width - 1))
1464 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1465 points[i+1].x + dx, points[i+1].y + dy, color);
1472 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1474 SDL_Surface *surface = src_bitmap->surface;
1476 if (src_bitmap == backbuffer || src_bitmap == window)
1482 switch (surface->format->BytesPerPixel)
1484 case 1: /* assuming 8-bpp */
1486 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1490 case 2: /* probably 15-bpp or 16-bpp */
1492 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1496 case 3: /* slow 24-bpp mode; usually not used */
1498 /* does this work? */
1499 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1503 shift = surface->format->Rshift;
1504 color |= *(pix + shift / 8) >> shift;
1505 shift = surface->format->Gshift;
1506 color |= *(pix + shift / 8) >> shift;
1507 shift = surface->format->Bshift;
1508 color |= *(pix + shift / 8) >> shift;
1514 case 4: /* probably 32-bpp */
1516 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1525 /* ========================================================================= */
1526 /* The following functions were taken from the SGE library */
1527 /* (SDL Graphics Extension Library) by Anders Lindström */
1528 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1529 /* ========================================================================= */
1531 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1533 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1535 switch (surface->format->BytesPerPixel)
1539 /* Assuming 8-bpp */
1540 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1546 /* Probably 15-bpp or 16-bpp */
1547 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1553 /* Slow 24-bpp mode, usually not used */
1557 /* Gack - slow, but endian correct */
1558 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1559 shift = surface->format->Rshift;
1560 *(pix+shift/8) = color>>shift;
1561 shift = surface->format->Gshift;
1562 *(pix+shift/8) = color>>shift;
1563 shift = surface->format->Bshift;
1564 *(pix+shift/8) = color>>shift;
1570 /* Probably 32-bpp */
1571 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1578 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1579 Uint8 R, Uint8 G, Uint8 B)
1581 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1584 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1586 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1589 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1591 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1594 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1599 /* Gack - slow, but endian correct */
1600 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1601 shift = surface->format->Rshift;
1602 *(pix+shift/8) = color>>shift;
1603 shift = surface->format->Gshift;
1604 *(pix+shift/8) = color>>shift;
1605 shift = surface->format->Bshift;
1606 *(pix+shift/8) = color>>shift;
1609 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1611 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1614 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1616 switch (dest->format->BytesPerPixel)
1619 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1623 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1627 _PutPixel24(dest,x,y,color);
1631 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1636 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1638 if (SDL_MUSTLOCK(surface))
1640 if (SDL_LockSurface(surface) < 0)
1646 _PutPixel(surface, x, y, color);
1648 if (SDL_MUSTLOCK(surface))
1650 SDL_UnlockSurface(surface);
1654 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1655 Uint8 r, Uint8 g, Uint8 b)
1657 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1660 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1662 if (y >= 0 && y <= dest->h - 1)
1664 switch (dest->format->BytesPerPixel)
1667 return y*dest->pitch;
1671 return y*dest->pitch/2;
1675 return y*dest->pitch;
1679 return y*dest->pitch/4;
1687 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1689 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1691 switch (surface->format->BytesPerPixel)
1695 /* Assuming 8-bpp */
1696 *((Uint8 *)surface->pixels + ypitch + x) = color;
1702 /* Probably 15-bpp or 16-bpp */
1703 *((Uint16 *)surface->pixels + ypitch + x) = color;
1709 /* Slow 24-bpp mode, usually not used */
1713 /* Gack - slow, but endian correct */
1714 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1715 shift = surface->format->Rshift;
1716 *(pix+shift/8) = color>>shift;
1717 shift = surface->format->Gshift;
1718 *(pix+shift/8) = color>>shift;
1719 shift = surface->format->Bshift;
1720 *(pix+shift/8) = color>>shift;
1726 /* Probably 32-bpp */
1727 *((Uint32 *)surface->pixels + ypitch + x) = color;
1734 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1739 if (SDL_MUSTLOCK(Surface))
1741 if (SDL_LockSurface(Surface) < 0)
1754 /* Do the clipping */
1755 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1759 if (x2 > Surface->w - 1)
1760 x2 = Surface->w - 1;
1767 SDL_FillRect(Surface, &l, Color);
1769 if (SDL_MUSTLOCK(Surface))
1771 SDL_UnlockSurface(Surface);
1775 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1776 Uint8 R, Uint8 G, Uint8 B)
1778 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1781 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1792 /* Do the clipping */
1793 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1797 if (x2 > Surface->w - 1)
1798 x2 = Surface->w - 1;
1805 SDL_FillRect(Surface, &l, Color);
1808 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1813 if (SDL_MUSTLOCK(Surface))
1815 if (SDL_LockSurface(Surface) < 0)
1828 /* Do the clipping */
1829 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1833 if (y2 > Surface->h - 1)
1834 y2 = Surface->h - 1;
1841 SDL_FillRect(Surface, &l, Color);
1843 if (SDL_MUSTLOCK(Surface))
1845 SDL_UnlockSurface(Surface);
1849 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1850 Uint8 R, Uint8 G, Uint8 B)
1852 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1855 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1866 /* Do the clipping */
1867 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1871 if (y2 > Surface->h - 1)
1872 y2 = Surface->h - 1;
1879 SDL_FillRect(Surface, &l, Color);
1882 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1883 Sint16 x2, Sint16 y2, Uint32 Color,
1884 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1887 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1892 sdx = (dx < 0) ? -1 : 1;
1893 sdy = (dy < 0) ? -1 : 1;
1905 for (x = 0; x < dx; x++)
1907 Callback(Surface, px, py, Color);
1921 for (y = 0; y < dy; y++)
1923 Callback(Surface, px, py, Color);
1937 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1938 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1939 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1942 sge_DoLine(Surface, X1, Y1, X2, Y2,
1943 SDL_MapRGB(Surface->format, R, G, B), Callback);
1946 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1949 if (SDL_MUSTLOCK(Surface))
1951 if (SDL_LockSurface(Surface) < 0)
1956 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1958 /* unlock the display */
1959 if (SDL_MUSTLOCK(Surface))
1961 SDL_UnlockSurface(Surface);
1965 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1966 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1968 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1971 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1973 if (dst_bitmap == backbuffer || dst_bitmap == window)
1979 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1984 -----------------------------------------------------------------------------
1985 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1986 -----------------------------------------------------------------------------
1989 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1990 int width, int height, Uint32 color)
1994 for (y = src_y; y < src_y + height; y++)
1996 for (x = src_x; x < src_x + width; x++)
1998 Uint32 pixel = SDLGetPixel(bitmap, x, y);
2000 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
2005 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
2006 int src_x, int src_y, int width, int height,
2007 int dst_x, int dst_y)
2011 for (y = 0; y < height; y++)
2013 for (x = 0; x < width; x++)
2015 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
2017 if (pixel != BLACK_PIXEL)
2018 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
2024 /* ========================================================================= */
2025 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
2026 /* (Rotozoomer) by Andreas Schiffler */
2027 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
2028 /* ========================================================================= */
2031 -----------------------------------------------------------------------------
2034 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
2035 -----------------------------------------------------------------------------
2046 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
2049 tColorRGBA *sp, *csp, *dp;
2053 sp = csp = (tColorRGBA *) src->pixels;
2054 dp = (tColorRGBA *) dst->pixels;
2055 dgap = dst->pitch - dst->w * 4;
2057 for (y = 0; y < dst->h; y++)
2061 for (x = 0; x < dst->w; x++)
2063 tColorRGBA *sp0 = sp;
2064 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
2065 tColorRGBA *sp00 = &sp0[0];
2066 tColorRGBA *sp01 = &sp0[1];
2067 tColorRGBA *sp10 = &sp1[0];
2068 tColorRGBA *sp11 = &sp1[1];
2071 /* create new color pixel from all four source color pixels */
2072 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2073 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2074 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2075 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2080 /* advance source pointers */
2083 /* advance destination pointer */
2087 /* advance source pointer */
2088 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2090 /* advance destination pointers */
2091 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2097 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2099 int x, y, *sax, *say, *csax, *csay;
2101 tColorRGBA *sp, *csp, *csp0, *dp;
2104 /* use specialized zoom function when scaling down to exactly half size */
2105 if (src->w == 2 * dst->w &&
2106 src->h == 2 * dst->h)
2107 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2109 /* variable setup */
2110 sx = (float) src->w / (float) dst->w;
2111 sy = (float) src->h / (float) dst->h;
2113 /* allocate memory for row increments */
2114 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2115 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2117 /* precalculate row increments */
2118 for (x = 0; x <= dst->w; x++)
2119 *csax++ = (int)(sx * x);
2121 for (y = 0; y <= dst->h; y++)
2122 *csay++ = (int)(sy * y);
2125 sp = csp = csp0 = (tColorRGBA *) src->pixels;
2126 dp = (tColorRGBA *) dst->pixels;
2127 dgap = dst->pitch - dst->w * 4;
2130 for (y = 0; y < dst->h; y++)
2135 for (x = 0; x < dst->w; x++)
2140 /* advance source pointers */
2144 /* advance destination pointer */
2148 /* advance source pointer */
2150 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
2152 /* advance destination pointers */
2153 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2163 -----------------------------------------------------------------------------
2166 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2167 -----------------------------------------------------------------------------
2170 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2172 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2173 Uint8 *sp, *dp, *csp;
2176 /* variable setup */
2177 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2178 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2180 /* allocate memory for row increments */
2181 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2182 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2184 /* precalculate row increments */
2187 for (x = 0; x < dst->w; x++)
2190 *csax = (csx >> 16);
2197 for (y = 0; y < dst->h; y++)
2200 *csay = (csy >> 16);
2207 for (x = 0; x < dst->w; x++)
2215 for (y = 0; y < dst->h; y++)
2222 sp = csp = (Uint8 *) src->pixels;
2223 dp = (Uint8 *) dst->pixels;
2224 dgap = dst->pitch - dst->w;
2228 for (y = 0; y < dst->h; y++)
2232 for (x = 0; x < dst->w; x++)
2237 /* advance source pointers */
2241 /* advance destination pointer */
2245 /* advance source pointer (for row) */
2246 csp += ((*csay) * src->pitch);
2249 /* advance destination pointers */
2260 -----------------------------------------------------------------------------
2263 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2264 'zoomx' and 'zoomy' are scaling factors for width and height.
2265 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2266 into a 32bit RGBA format on the fly.
2267 -----------------------------------------------------------------------------
2270 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2272 SDL_Surface *zoom_src = NULL;
2273 SDL_Surface *zoom_dst = NULL;
2274 boolean is_converted = FALSE;
2281 /* determine if source surface is 32 bit or 8 bit */
2282 is_32bit = (src->format->BitsPerPixel == 32);
2284 if (is_32bit || src->format->BitsPerPixel == 8)
2286 /* use source surface 'as is' */
2291 /* new source surface is 32 bit with a defined RGB ordering */
2292 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2293 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2294 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2296 is_converted = TRUE;
2299 /* allocate surface to completely contain the zoomed surface */
2302 /* target surface is 32 bit with source RGBA/ABGR ordering */
2303 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2304 zoom_src->format->Rmask,
2305 zoom_src->format->Gmask,
2306 zoom_src->format->Bmask, 0);
2310 /* target surface is 8 bit */
2311 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2315 /* lock source surface */
2316 SDL_LockSurface(zoom_src);
2318 /* check which kind of surface we have */
2321 /* call the 32 bit transformation routine to do the zooming */
2322 zoomSurfaceRGBA(zoom_src, zoom_dst);
2327 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2328 zoom_dst->format->palette->colors[i] =
2329 zoom_src->format->palette->colors[i];
2330 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2332 /* call the 8 bit transformation routine to do the zooming */
2333 zoomSurfaceY(zoom_src, zoom_dst);
2336 /* unlock source surface */
2337 SDL_UnlockSurface(zoom_src);
2339 /* free temporary surface */
2341 SDL_FreeSurface(zoom_src);
2343 /* return destination surface */
2347 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2349 Bitmap *dst_bitmap = CreateBitmapStruct();
2350 SDL_Surface **dst_surface = &dst_bitmap->surface;
2352 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2353 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2355 dst_bitmap->width = dst_width;
2356 dst_bitmap->height = dst_height;
2358 /* create zoomed temporary surface from source surface */
2359 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2361 /* create native format destination surface from zoomed temporary surface */
2362 SDLSetNativeSurface(dst_surface);
2368 /* ========================================================================= */
2369 /* load image to bitmap */
2370 /* ========================================================================= */
2372 Bitmap *SDLLoadImage(char *filename)
2374 Bitmap *new_bitmap = CreateBitmapStruct();
2375 SDL_Surface *sdl_image_tmp;
2377 print_timestamp_init("SDLLoadImage");
2379 print_timestamp_time(getBaseNamePtr(filename));
2381 /* load image to temporary surface */
2382 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2384 SetError("IMG_Load(): %s", SDL_GetError());
2389 print_timestamp_time("IMG_Load");
2391 UPDATE_BUSY_STATE();
2393 /* create native non-transparent surface for current image */
2394 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2396 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2401 print_timestamp_time("SDL_DisplayFormat (opaque)");
2403 UPDATE_BUSY_STATE();
2405 /* create native transparent surface for current image */
2406 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2407 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2409 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2411 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2416 print_timestamp_time("SDL_DisplayFormat (masked)");
2418 UPDATE_BUSY_STATE();
2420 /* free temporary surface */
2421 SDL_FreeSurface(sdl_image_tmp);
2423 new_bitmap->width = new_bitmap->surface->w;
2424 new_bitmap->height = new_bitmap->surface->h;
2426 print_timestamp_done("SDLLoadImage");
2432 /* ------------------------------------------------------------------------- */
2433 /* custom cursor fuctions */
2434 /* ------------------------------------------------------------------------- */
2436 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2438 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2439 cursor_info->width, cursor_info->height,
2440 cursor_info->hot_x, cursor_info->hot_y);
2443 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2445 static struct MouseCursorInfo *last_cursor_info = NULL;
2446 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2447 static SDL_Cursor *cursor_default = NULL;
2448 static SDL_Cursor *cursor_current = NULL;
2450 /* if invoked for the first time, store the SDL default cursor */
2451 if (cursor_default == NULL)
2452 cursor_default = SDL_GetCursor();
2454 /* only create new cursor if cursor info (custom only) has changed */
2455 if (cursor_info != NULL && cursor_info != last_cursor_info)
2457 cursor_current = create_cursor(cursor_info);
2458 last_cursor_info = cursor_info;
2461 /* only set new cursor if cursor info (custom or NULL) has changed */
2462 if (cursor_info != last_cursor_info2)
2463 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2465 last_cursor_info2 = cursor_info;
2469 /* ========================================================================= */
2470 /* audio functions */
2471 /* ========================================================================= */
2473 void SDLOpenAudio(void)
2475 #if !defined(TARGET_SDL2)
2476 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2477 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2480 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2482 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2486 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2487 AUDIO_NUM_CHANNELS_STEREO,
2488 setup.system.audio_fragment_size) < 0)
2490 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2494 audio.sound_available = TRUE;
2495 audio.music_available = TRUE;
2496 audio.loops_available = TRUE;
2497 audio.sound_enabled = TRUE;
2499 /* set number of available mixer channels */
2500 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2501 audio.music_channel = MUSIC_CHANNEL;
2502 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2504 Mixer_InitChannels();
2507 void SDLCloseAudio(void)
2510 Mix_HaltChannel(-1);
2513 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2517 /* ========================================================================= */
2518 /* event functions */
2519 /* ========================================================================= */
2521 void SDLNextEvent(Event *event)
2523 SDL_WaitEvent(event);
2525 if (event->type == EVENT_BUTTONPRESS ||
2526 event->type == EVENT_BUTTONRELEASE)
2528 if (((ButtonEvent *)event)->x > video_xoffset)
2529 ((ButtonEvent *)event)->x -= video_xoffset;
2531 ((ButtonEvent *)event)->x = 0;
2532 if (((ButtonEvent *)event)->y > video_yoffset)
2533 ((ButtonEvent *)event)->y -= video_yoffset;
2535 ((ButtonEvent *)event)->y = 0;
2537 else if (event->type == EVENT_MOTIONNOTIFY)
2539 if (((MotionEvent *)event)->x > video_xoffset)
2540 ((MotionEvent *)event)->x -= video_xoffset;
2542 ((MotionEvent *)event)->x = 0;
2543 if (((MotionEvent *)event)->y > video_yoffset)
2544 ((MotionEvent *)event)->y -= video_yoffset;
2546 ((MotionEvent *)event)->y = 0;
2550 void SDLHandleWindowManagerEvent(Event *event)
2553 #if defined(PLATFORM_WIN32)
2554 // experimental drag and drop code
2556 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2557 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2559 #if defined(TARGET_SDL2)
2560 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2562 if (syswmmsg->msg == WM_DROPFILES)
2565 #if defined(TARGET_SDL2)
2566 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2568 HDROP hdrop = (HDROP)syswmmsg->wParam;
2572 printf("::: SDL_SYSWMEVENT:\n");
2574 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2576 for (i = 0; i < num_files; i++)
2578 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2579 char buffer[buffer_len + 1];
2581 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2583 printf("::: - '%s'\n", buffer);
2586 #if defined(TARGET_SDL2)
2587 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2589 DragFinish((HDROP)syswmmsg->wParam);
2597 /* ========================================================================= */
2598 /* joystick functions */
2599 /* ========================================================================= */
2601 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2602 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2603 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2605 static boolean SDLOpenJoystick(int nr)
2607 if (nr < 0 || nr > MAX_PLAYERS)
2610 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2613 static void SDLCloseJoystick(int nr)
2615 if (nr < 0 || nr > MAX_PLAYERS)
2618 SDL_JoystickClose(sdl_joystick[nr]);
2620 sdl_joystick[nr] = NULL;
2623 static boolean SDLCheckJoystickOpened(int nr)
2625 if (nr < 0 || nr > MAX_PLAYERS)
2628 #if defined(TARGET_SDL2)
2629 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2631 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2635 void HandleJoystickEvent(Event *event)
2639 case SDL_JOYAXISMOTION:
2640 if (event->jaxis.axis < 2)
2641 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2644 case SDL_JOYBUTTONDOWN:
2645 if (event->jbutton.button < 2)
2646 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2649 case SDL_JOYBUTTONUP:
2650 if (event->jbutton.button < 2)
2651 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2659 void SDLInitJoysticks()
2661 static boolean sdl_joystick_subsystem_initialized = FALSE;
2662 boolean print_warning = !sdl_joystick_subsystem_initialized;
2665 if (!sdl_joystick_subsystem_initialized)
2667 sdl_joystick_subsystem_initialized = TRUE;
2669 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2671 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2676 for (i = 0; i < MAX_PLAYERS; i++)
2678 /* get configured joystick for this player */
2679 char *device_name = setup.input[i].joy.device_name;
2680 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2682 if (joystick_nr >= SDL_NumJoysticks())
2684 if (setup.input[i].use_joystick && print_warning)
2685 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2690 /* misuse joystick file descriptor variable to store joystick number */
2691 joystick.fd[i] = joystick_nr;
2693 if (joystick_nr == -1)
2696 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2697 if (SDLCheckJoystickOpened(joystick_nr))
2698 SDLCloseJoystick(joystick_nr);
2700 if (!setup.input[i].use_joystick)
2703 if (!SDLOpenJoystick(joystick_nr))
2706 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2711 joystick.status = JOYSTICK_ACTIVATED;
2715 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2717 if (nr < 0 || nr >= MAX_PLAYERS)
2721 *x = sdl_js_axis[nr][0];
2723 *y = sdl_js_axis[nr][1];
2726 *b1 = sdl_js_button[nr][0];
2728 *b2 = sdl_js_button[nr][1];