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_stream = NULL;
30 static SDL_Texture *sdl_texture_target = NULL;
31 static boolean fullscreen_enabled = FALSE;
34 static boolean limit_screen_updates = FALSE;
37 /* functions from SGE library */
38 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
40 void SDLLimitScreenUpdates(boolean enable)
42 limit_screen_updates = enable;
45 static void FinalizeScreen(int draw_target)
47 // copy global animations to render target buffer, if defined (below border)
48 if (gfx.draw_global_anim_function != NULL)
49 gfx.draw_global_anim_function(draw_target, DRAW_GLOBAL_ANIM_STAGE_1);
51 // copy global masked border to render target buffer, if defined
52 if (gfx.draw_global_border_function != NULL)
53 gfx.draw_global_border_function(draw_target);
55 // copy global animations to render target buffer, if defined (above border)
56 if (gfx.draw_global_anim_function != NULL)
57 gfx.draw_global_anim_function(draw_target, DRAW_GLOBAL_ANIM_STAGE_2);
60 static void UpdateScreenExt(SDL_Rect *rect, boolean with_frame_delay)
62 static unsigned int update_screen_delay = 0;
63 unsigned int update_screen_delay_value = 50; /* (milliseconds) */
64 SDL_Surface *screen = backbuffer->surface;
66 if (limit_screen_updates &&
67 !DelayReached(&update_screen_delay, update_screen_delay_value))
70 LimitScreenUpdates(FALSE);
74 static int LastFrameCounter = 0;
75 boolean changed = (FrameCounter != LastFrameCounter);
77 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
78 (changed ? "-" : "SAME FRAME UPDATED"));
80 LastFrameCounter = FrameCounter;
89 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP &&
90 gfx.final_screen_bitmap != NULL) // may not be initialized yet
92 // draw global animations using bitmaps instead of using textures
93 // to prevent texture scaling artefacts (this is potentially slower)
95 BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
96 gfx.win_xsize, gfx.win_ysize, 0, 0);
98 FinalizeScreen(DRAW_TO_SCREEN);
100 screen = gfx.final_screen_bitmap->surface;
102 // force full window redraw
106 #if defined(TARGET_SDL2)
107 SDL_Texture *sdl_texture = sdl_texture_stream;
109 // deactivate use of target texture if render targets are not supported
110 if ((video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
111 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE) &&
112 sdl_texture_target == NULL)
113 video.screen_rendering_mode = SPECIAL_RENDERING_OFF;
115 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET)
116 sdl_texture = sdl_texture_target;
120 int bytes_x = screen->pitch / video.width;
121 int bytes_y = screen->pitch;
123 SDL_UpdateTexture(sdl_texture, rect,
124 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
129 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
132 SDL_Rect *src_rect1 = NULL, *dst_rect1 = NULL;
133 SDL_Rect *src_rect2 = NULL, *dst_rect2 = NULL;
135 #if defined(HAS_SCREEN_KEYBOARD)
136 if (video.shifted_up || video.shifted_up_delay)
138 int time_current = SDL_GetTicks();
139 int pos = video.shifted_up_pos;
140 int pos_last = video.shifted_up_pos_last;
142 if (!DelayReachedExt(&video.shifted_up_delay, video.shifted_up_delay_value,
145 int delay = time_current - video.shifted_up_delay;
146 int delay_value = video.shifted_up_delay_value;
148 pos = pos_last + (pos - pos_last) * delay / delay_value;
152 video.shifted_up_pos_last = pos;
153 video.shifted_up_delay = 0;
156 SDL_Rect src_rect_up = { 0, pos, video.width, video.height - pos };
157 SDL_Rect dst_rect_up = { 0, 0, video.width, video.height - pos };
159 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
160 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
162 src_rect2 = &src_rect_up;
163 dst_rect2 = &dst_rect_up;
167 src_rect1 = &src_rect_up;
168 dst_rect1 = &dst_rect_up;
173 // clear render target buffer
174 SDL_RenderClear(sdl_renderer);
176 // set renderer to use target texture for rendering
177 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
178 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
179 SDL_SetRenderTarget(sdl_renderer, sdl_texture_target);
181 // copy backbuffer texture to render target buffer
182 if (video.screen_rendering_mode != SPECIAL_RENDERING_TARGET)
183 SDL_RenderCopy(sdl_renderer, sdl_texture_stream, src_rect1, dst_rect1);
185 if (video.screen_rendering_mode != SPECIAL_RENDERING_BITMAP)
186 FinalizeScreen(DRAW_TO_SCREEN);
188 // when using target texture, copy it to screen buffer
189 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
190 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
192 SDL_SetRenderTarget(sdl_renderer, NULL);
193 SDL_RenderCopy(sdl_renderer, sdl_texture_target, src_rect2, dst_rect2);
197 // global synchronization point of the game to align video frame delay
198 if (with_frame_delay)
199 WaitUntilDelayReached(&video.frame_delay, video.frame_delay_value);
201 #if defined(TARGET_SDL2)
202 // show render target buffer on screen
203 SDL_RenderPresent(sdl_renderer);
206 SDL_UpdateRects(screen, 1, rect);
208 SDL_UpdateRect(screen, 0, 0, 0, 0);
212 static void UpdateScreen_WithFrameDelay(SDL_Rect *rect)
214 UpdateScreenExt(rect, TRUE);
217 static void UpdateScreen_WithoutFrameDelay(SDL_Rect *rect)
219 UpdateScreenExt(rect, FALSE);
222 static void SDLSetWindowIcon(char *basename)
224 /* (setting the window icon on Mac OS X would replace the high-quality
225 dock icon with the currently smaller (and uglier) icon from file) */
227 #if !defined(PLATFORM_MACOSX)
228 char *filename = getCustomImageFilename(basename);
229 SDL_Surface *surface;
231 if (filename == NULL)
233 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
238 if ((surface = IMG_Load(filename)) == NULL)
240 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
245 /* set transparent color */
246 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
247 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
249 #if defined(TARGET_SDL2)
250 SDL_SetWindowIcon(sdl_window, surface);
252 SDL_WM_SetIcon(surface, NULL);
257 #if defined(TARGET_SDL2)
259 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
260 SDL_PixelFormat *format2)
262 return (format1->format == format2->format &&
263 format1->BitsPerPixel == format2->BitsPerPixel &&
264 format1->BytesPerPixel == format2->BytesPerPixel &&
265 format1->Rmask == format2->Rmask &&
266 format1->Gmask == format2->Gmask &&
267 format1->Bmask == format2->Bmask);
270 static Pixel SDLGetColorKey(SDL_Surface *surface)
274 if (SDL_GetColorKey(surface, &color_key) != 0)
280 static boolean SDLHasColorKey(SDL_Surface *surface)
282 return (SDLGetColorKey(surface) != -1);
285 static boolean SDLHasAlpha(SDL_Surface *surface)
287 SDL_BlendMode blend_mode;
289 if (SDL_GetSurfaceBlendMode(surface, &blend_mode) != 0)
292 return (blend_mode == SDL_BLENDMODE_BLEND);
295 static void SDLSetAlpha(SDL_Surface *surface, boolean set, int alpha)
297 SDL_BlendMode blend_mode = (set ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE);
299 SDL_SetSurfaceBlendMode(surface, blend_mode);
300 SDL_SetSurfaceAlphaMod(surface, alpha);
303 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
305 SDL_PixelFormat format;
306 SDL_Surface *new_surface;
311 if (backbuffer && backbuffer->surface)
313 format = *backbuffer->surface->format;
314 format.Amask = surface->format->Amask; // keep alpha channel
318 format = *surface->format;
321 new_surface = SDL_ConvertSurface(surface, &format, 0);
323 if (new_surface == NULL)
324 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
329 boolean SDLSetNativeSurface(SDL_Surface **surface)
331 SDL_Surface *new_surface;
333 if (surface == NULL ||
335 backbuffer == NULL ||
336 backbuffer->surface == NULL)
339 // if pixel format already optimized for destination surface, do nothing
340 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
343 new_surface = SDLGetNativeSurface(*surface);
345 SDL_FreeSurface(*surface);
347 *surface = new_surface;
354 static Pixel SDLGetColorKey(SDL_Surface *surface)
356 if ((surface->flags & SDL_SRCCOLORKEY) == 0)
359 return surface->format->colorkey;
362 static boolean SDLHasColorKey(SDL_Surface *surface)
364 return (SDLGetColorKey(surface) != -1);
367 static boolean SDLHasAlpha(SDL_Surface *surface)
369 return ((surface->flags & SDL_SRCALPHA) != 0);
372 static void SDLSetAlpha(SDL_Surface *surface, boolean set, int alpha)
374 SDL_SetAlpha(surface, (set ? SDL_SRCALPHA : 0), alpha);
377 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
379 SDL_Surface *new_surface;
384 if (!video.initialized)
385 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
386 else if (SDLHasAlpha(surface))
387 new_surface = SDL_DisplayFormatAlpha(surface);
389 new_surface = SDL_DisplayFormat(surface);
391 if (new_surface == NULL)
392 Error(ERR_EXIT, "%s() failed: %s",
393 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
399 boolean SDLSetNativeSurface(SDL_Surface **surface)
401 SDL_Surface *new_surface;
403 if (surface == NULL ||
408 new_surface = SDLGetNativeSurface(*surface);
410 SDL_FreeSurface(*surface);
412 *surface = new_surface;
419 #if defined(TARGET_SDL2)
420 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
422 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
425 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
432 void SDLCreateBitmapTextures(Bitmap *bitmap)
434 #if defined(TARGET_SDL2)
439 SDL_DestroyTexture(bitmap->texture);
440 if (bitmap->texture_masked)
441 SDL_DestroyTexture(bitmap->texture_masked);
443 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
444 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
448 void SDLFreeBitmapTextures(Bitmap *bitmap)
450 #if defined(TARGET_SDL2)
455 SDL_DestroyTexture(bitmap->texture);
456 if (bitmap->texture_masked)
457 SDL_DestroyTexture(bitmap->texture_masked);
459 bitmap->texture = NULL;
460 bitmap->texture_masked = NULL;
464 void SDLInitVideoDisplay(void)
466 #if !defined(TARGET_SDL2)
467 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
468 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
470 SDL_putenv("SDL_VIDEO_CENTERED=1");
473 /* initialize SDL video */
474 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
475 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
477 /* set default SDL depth */
478 #if !defined(TARGET_SDL2)
479 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
481 video.default_depth = 32; // (how to determine video depth in SDL2?)
485 void SDLInitVideoBuffer(boolean fullscreen)
487 video.window_scaling_percent = setup.window_scaling_percent;
488 video.window_scaling_quality = setup.window_scaling_quality;
490 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
492 #if defined(TARGET_SDL2)
493 // SDL 2.0: support for (desktop) fullscreen mode available
494 video.fullscreen_available = TRUE;
496 // SDL 1.2: no support for fullscreen mode in R'n'D anymore
497 video.fullscreen_available = FALSE;
500 /* open SDL video output device (window or fullscreen mode) */
501 if (!SDLSetVideoMode(fullscreen))
502 Error(ERR_EXIT, "setting video mode failed");
504 /* !!! SDL2 can only set the window icon if the window already exists !!! */
505 /* set window icon */
506 SDLSetWindowIcon(program.icon_filename);
508 /* set window and icon title */
509 #if defined(TARGET_SDL2)
510 SDL_SetWindowTitle(sdl_window, program.window_title);
512 SDL_WM_SetCaption(program.window_title, program.window_title);
515 /* SDL cannot directly draw to the visible video framebuffer like X11,
516 but always uses a backbuffer, which is then blitted to the visible
517 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
518 visible video framebuffer with 'SDL_Flip', if the hardware supports
519 this). Therefore do not use an additional backbuffer for drawing, but
520 use a symbolic buffer (distinguishable from the SDL backbuffer) called
521 'window', which indicates that the SDL backbuffer should be updated to
522 the visible video framebuffer when attempting to blit to it.
524 For convenience, it seems to be a good idea to create this symbolic
525 buffer 'window' at the same size as the SDL backbuffer. Although it
526 should never be drawn to directly, it would do no harm nevertheless. */
528 /* create additional (symbolic) buffer for double-buffering */
529 ReCreateBitmap(&window, video.width, video.height);
532 static boolean SDLCreateScreen(boolean fullscreen)
534 SDL_Surface *new_surface = NULL;
536 #if defined(TARGET_SDL2)
537 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
538 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
540 int surface_flags_window = SURFACE_FLAGS;
541 int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2)
544 #if defined(TARGET_SDL2)
546 int renderer_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
548 /* If SDL_CreateRenderer() is called from within a VirtualBox Windows VM
549 _without_ enabling 2D/3D acceleration and/or guest additions installed,
550 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
551 it will try to use accelerated graphics and apparently fails miserably) */
552 int renderer_flags = SDL_RENDERER_SOFTWARE;
556 int width = video.width;
557 int height = video.height;
558 int surface_flags = (fullscreen ? surface_flags_fullscreen :
559 surface_flags_window);
561 // default window size is unscaled
562 video.window_width = video.width;
563 video.window_height = video.height;
565 #if defined(TARGET_SDL2)
567 // store if initial screen mode is fullscreen mode when changing screen size
568 video.fullscreen_initial = fullscreen;
570 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
572 video.window_width = window_scaling_factor * width;
573 video.window_height = window_scaling_factor * height;
575 if (sdl_texture_stream)
577 SDL_DestroyTexture(sdl_texture_stream);
578 sdl_texture_stream = NULL;
581 if (sdl_texture_target)
583 SDL_DestroyTexture(sdl_texture_target);
584 sdl_texture_target = NULL;
587 if (!(fullscreen && fullscreen_enabled))
591 SDL_DestroyRenderer(sdl_renderer);
597 SDL_DestroyWindow(sdl_window);
602 if (sdl_window == NULL)
603 sdl_window = SDL_CreateWindow(program.window_title,
604 SDL_WINDOWPOS_CENTERED,
605 SDL_WINDOWPOS_CENTERED,
610 if (sdl_window != NULL)
612 if (sdl_renderer == NULL)
613 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, renderer_flags);
615 if (sdl_renderer != NULL)
617 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
618 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
619 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
621 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
622 SDL_PIXELFORMAT_ARGB8888,
623 SDL_TEXTUREACCESS_STREAMING,
626 if (SDL_RenderTargetSupported(sdl_renderer))
627 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
628 SDL_PIXELFORMAT_ARGB8888,
629 SDL_TEXTUREACCESS_TARGET,
632 if (sdl_texture_stream != NULL)
634 // use SDL default values for RGB masks and no alpha channel
635 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
637 if (new_surface == NULL)
638 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
642 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
647 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
652 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
657 if (gfx.final_screen_bitmap == NULL)
658 gfx.final_screen_bitmap = CreateBitmapStruct();
660 gfx.final_screen_bitmap->width = width;
661 gfx.final_screen_bitmap->height = height;
663 gfx.final_screen_bitmap->surface =
664 SDL_SetVideoMode(width, height, video.depth, surface_flags);
666 if (gfx.final_screen_bitmap->surface != NULL)
669 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
671 if (new_surface == NULL)
672 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
675 new_surface = gfx.final_screen_bitmap->surface;
676 gfx.final_screen_bitmap = NULL;
682 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
686 #if defined(TARGET_SDL2)
687 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
688 if (new_surface != NULL)
689 fullscreen_enabled = fullscreen;
692 if (backbuffer == NULL)
693 backbuffer = CreateBitmapStruct();
695 backbuffer->width = video.width;
696 backbuffer->height = video.height;
698 if (backbuffer->surface)
699 SDL_FreeSurface(backbuffer->surface);
701 backbuffer->surface = new_surface;
703 return (new_surface != NULL);
706 boolean SDLSetVideoMode(boolean fullscreen)
708 boolean success = FALSE;
712 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
714 /* switch display to fullscreen mode, if available */
715 success = SDLCreateScreen(TRUE);
719 /* switching display to fullscreen mode failed -- do not try it again */
720 video.fullscreen_available = FALSE;
724 video.fullscreen_enabled = TRUE;
728 if ((!fullscreen && video.fullscreen_enabled) || !success)
730 /* switch display to window mode */
731 success = SDLCreateScreen(FALSE);
735 /* switching display to window mode failed -- should not happen */
739 video.fullscreen_enabled = FALSE;
740 video.window_scaling_percent = setup.window_scaling_percent;
741 video.window_scaling_quality = setup.window_scaling_quality;
743 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
747 #if defined(TARGET_SDL2)
748 SDLRedrawWindow(); // map window
752 #if defined(PLATFORM_WIN32)
753 // experimental drag and drop code
755 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
758 SDL_SysWMinfo wminfo;
760 boolean wminfo_success = FALSE;
762 SDL_VERSION(&wminfo.version);
763 #if defined(TARGET_SDL2)
765 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
767 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
772 #if defined(TARGET_SDL2)
773 hwnd = wminfo.info.win.window;
775 hwnd = wminfo.window;
778 DragAcceptFiles(hwnd, TRUE);
787 void SDLSetWindowTitle()
789 #if defined(TARGET_SDL2)
790 SDL_SetWindowTitle(sdl_window, program.window_title);
792 SDL_WM_SetCaption(program.window_title, program.window_title);
796 #if defined(TARGET_SDL2)
797 void SDLSetWindowScaling(int window_scaling_percent)
799 if (sdl_window == NULL)
802 float window_scaling_factor = (float)window_scaling_percent / 100;
803 int new_window_width = (int)(window_scaling_factor * video.width);
804 int new_window_height = (int)(window_scaling_factor * video.height);
806 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
808 video.window_scaling_percent = window_scaling_percent;
809 video.window_width = new_window_width;
810 video.window_height = new_window_height;
815 void SDLSetWindowScalingQuality(char *window_scaling_quality)
817 SDL_Texture *new_texture;
819 if (sdl_texture_stream == NULL)
822 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
824 new_texture = SDL_CreateTexture(sdl_renderer,
825 SDL_PIXELFORMAT_ARGB8888,
826 SDL_TEXTUREACCESS_STREAMING,
827 video.width, video.height);
829 if (new_texture != NULL)
831 SDL_DestroyTexture(sdl_texture_stream);
833 sdl_texture_stream = new_texture;
836 if (SDL_RenderTargetSupported(sdl_renderer))
837 new_texture = SDL_CreateTexture(sdl_renderer,
838 SDL_PIXELFORMAT_ARGB8888,
839 SDL_TEXTUREACCESS_TARGET,
840 video.width, video.height);
844 if (new_texture != NULL)
846 SDL_DestroyTexture(sdl_texture_target);
848 sdl_texture_target = new_texture;
853 video.window_scaling_quality = window_scaling_quality;
856 void SDLSetWindowFullscreen(boolean fullscreen)
858 if (sdl_window == NULL)
861 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
863 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
864 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
866 // if screen size was changed in fullscreen mode, correct desktop window size
867 if (!fullscreen && video.fullscreen_initial)
869 SDLSetWindowScaling(setup.window_scaling_percent);
870 SDL_SetWindowPosition(sdl_window,
871 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
873 video.fullscreen_initial = FALSE;
878 void SDLSetScreenRenderingMode(char *screen_rendering_mode)
880 #if defined(TARGET_SDL2)
881 video.screen_rendering_mode =
882 (strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
883 SPECIAL_RENDERING_BITMAP :
884 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
885 SPECIAL_RENDERING_TARGET:
886 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
887 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
889 video.screen_rendering_mode = SPECIAL_RENDERING_BITMAP;
893 void SDLRedrawWindow()
895 UpdateScreen_WithoutFrameDelay(NULL);
898 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
901 SDL_Surface *surface =
902 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
905 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
907 SDLSetNativeSurface(&surface);
909 bitmap->surface = surface;
912 void SDLFreeBitmapPointers(Bitmap *bitmap)
915 SDL_FreeSurface(bitmap->surface);
916 if (bitmap->surface_masked)
917 SDL_FreeSurface(bitmap->surface_masked);
919 bitmap->surface = NULL;
920 bitmap->surface_masked = NULL;
922 #if defined(TARGET_SDL2)
924 SDL_DestroyTexture(bitmap->texture);
925 if (bitmap->texture_masked)
926 SDL_DestroyTexture(bitmap->texture_masked);
928 bitmap->texture = NULL;
929 bitmap->texture_masked = NULL;
933 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
934 int src_x, int src_y, int width, int height,
935 int dst_x, int dst_y, int mask_mode)
937 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
938 SDL_Rect src_rect, dst_rect;
950 // if (src_bitmap != backbuffer || dst_bitmap != window)
951 if (!(src_bitmap == backbuffer && dst_bitmap == window))
952 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
953 src_bitmap->surface_masked : src_bitmap->surface),
954 &src_rect, real_dst_bitmap->surface, &dst_rect);
956 if (dst_bitmap == window)
957 UpdateScreen_WithFrameDelay(&dst_rect);
960 void SDLBlitTexture(Bitmap *bitmap,
961 int src_x, int src_y, int width, int height,
962 int dst_x, int dst_y, int mask_mode)
964 #if defined(TARGET_SDL2)
965 SDL_Texture *texture;
970 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
985 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
989 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
992 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1000 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
1002 if (dst_bitmap == window)
1003 UpdateScreen_WithFrameDelay(&rect);
1006 void PrepareFadeBitmap(int draw_target)
1008 Bitmap *fade_bitmap =
1009 (draw_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
1010 draw_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
1012 if (fade_bitmap == NULL)
1015 // copy backbuffer to fading buffer
1016 BlitBitmap(backbuffer, fade_bitmap, 0, 0, gfx.win_xsize, gfx.win_ysize, 0, 0);
1018 // add border and animations to fading buffer
1019 FinalizeScreen(draw_target);
1022 void SDLFadeRectangle(int x, int y, int width, int height,
1023 int fade_mode, int fade_delay, int post_delay,
1024 void (*draw_border_function)(void))
1026 SDL_Surface *surface_backup = gfx.fade_bitmap_backup->surface;
1027 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
1028 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
1029 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
1030 SDL_Surface *surface_screen = backbuffer->surface;
1031 SDL_Rect src_rect, dst_rect;
1033 int src_x = x, src_y = y;
1034 int dst_x = x, dst_y = y;
1035 unsigned int time_last, time_current;
1037 // store function for drawing global masked border
1038 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
1040 // deactivate drawing of global border while fading, if needed
1041 if (draw_border_function == NULL)
1042 gfx.draw_global_border_function = NULL;
1047 src_rect.h = height;
1051 dst_rect.w = width; /* (ignored) */
1052 dst_rect.h = height; /* (ignored) */
1054 dst_rect2 = dst_rect;
1056 // before fading in, store backbuffer (without animation graphics)
1057 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
1058 SDL_BlitSurface(surface_screen, &dst_rect, surface_backup, &src_rect);
1060 /* copy source and target surfaces to temporary surfaces for fading */
1061 if (fade_mode & FADE_TYPE_TRANSFORM)
1063 // (source and target fading buffer already prepared)
1065 else if (fade_mode & FADE_TYPE_FADE_IN)
1067 // (target fading buffer already prepared)
1068 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1070 else /* FADE_TYPE_FADE_OUT */
1072 // (source fading buffer already prepared)
1073 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1076 time_current = SDL_GetTicks();
1078 if (fade_mode == FADE_MODE_MELT)
1080 boolean done = FALSE;
1081 int melt_pixels = 2;
1082 int melt_columns = width / melt_pixels;
1083 int ypos[melt_columns];
1084 int max_steps = height / 8 + 32;
1089 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1091 SDLSetAlpha(surface_target, FALSE, 0); /* disable alpha blending */
1093 ypos[0] = -GetSimpleRandom(16);
1095 for (i = 1 ; i < melt_columns; i++)
1097 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1099 ypos[i] = ypos[i - 1] + r;
1112 time_last = time_current;
1113 time_current = SDL_GetTicks();
1114 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1115 steps_final = MIN(MAX(0, steps), max_steps);
1119 done = (steps_done >= steps_final);
1121 for (i = 0 ; i < melt_columns; i++)
1129 else if (ypos[i] < height)
1134 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1136 if (ypos[i] + dy >= height)
1137 dy = height - ypos[i];
1139 /* copy part of (appearing) target surface to upper area */
1140 src_rect.x = src_x + i * melt_pixels;
1141 // src_rect.y = src_y + ypos[i];
1143 src_rect.w = melt_pixels;
1145 src_rect.h = ypos[i] + dy;
1147 dst_rect.x = dst_x + i * melt_pixels;
1148 // dst_rect.y = dst_y + ypos[i];
1151 if (steps_done >= steps_final)
1152 SDL_BlitSurface(surface_target, &src_rect,
1153 surface_screen, &dst_rect);
1157 /* copy part of (disappearing) source surface to lower area */
1158 src_rect.x = src_x + i * melt_pixels;
1160 src_rect.w = melt_pixels;
1161 src_rect.h = height - ypos[i];
1163 dst_rect.x = dst_x + i * melt_pixels;
1164 dst_rect.y = dst_y + ypos[i];
1166 if (steps_done >= steps_final)
1167 SDL_BlitSurface(surface_source, &src_rect,
1168 surface_screen, &dst_rect);
1174 src_rect.x = src_x + i * melt_pixels;
1176 src_rect.w = melt_pixels;
1177 src_rect.h = height;
1179 dst_rect.x = dst_x + i * melt_pixels;
1182 if (steps_done >= steps_final)
1183 SDL_BlitSurface(surface_target, &src_rect,
1184 surface_screen, &dst_rect);
1188 if (steps_done >= steps_final)
1190 if (draw_border_function != NULL)
1191 draw_border_function();
1193 UpdateScreen_WithFrameDelay(&dst_rect2);
1197 else if (fade_mode == FADE_MODE_CURTAIN)
1201 int xx_size = width / 2;
1203 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1205 SDLSetAlpha(surface_source, FALSE, 0); /* disable alpha blending */
1207 for (xx = 0; xx < xx_size;)
1209 time_last = time_current;
1210 time_current = SDL_GetTicks();
1211 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1212 xx_final = MIN(MAX(0, xx), xx_size);
1217 src_rect.h = height;
1222 /* draw new (target) image to screen buffer */
1223 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1225 if (xx_final < xx_size)
1227 src_rect.w = xx_size - xx_final;
1228 src_rect.h = height;
1230 /* draw old (source) image to screen buffer (left side) */
1232 src_rect.x = src_x + xx_final;
1235 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1237 /* draw old (source) image to screen buffer (right side) */
1239 src_rect.x = src_x + xx_size;
1240 dst_rect.x = dst_x + xx_size + xx_final;
1242 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1245 if (draw_border_function != NULL)
1246 draw_border_function();
1248 /* only update the region of the screen that is affected from fading */
1249 UpdateScreen_WithFrameDelay(&dst_rect2);
1252 else /* fading in, fading out or cross-fading */
1257 for (alpha = 0.0; alpha < 255.0;)
1259 time_last = time_current;
1260 time_current = SDL_GetTicks();
1261 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1262 alpha_final = MIN(MAX(0, alpha), 255);
1264 /* draw existing (source) image to screen buffer */
1265 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1267 /* draw new (target) image to screen buffer using alpha blending */
1268 SDLSetAlpha(surface_target, TRUE, alpha_final);
1269 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1271 if (draw_border_function != NULL)
1272 draw_border_function();
1274 /* only update the region of the screen that is affected from fading */
1275 UpdateScreen_WithFrameDelay(&dst_rect);
1281 unsigned int time_post_delay;
1283 time_current = SDL_GetTicks();
1284 time_post_delay = time_current + post_delay;
1286 while (time_current < time_post_delay)
1288 // updating the screen contains waiting for frame delay (non-busy)
1289 UpdateScreen_WithFrameDelay(NULL);
1291 time_current = SDL_GetTicks();
1295 // restore function for drawing global masked border
1296 gfx.draw_global_border_function = draw_global_border_function;
1298 // after fading in, restore backbuffer (without animation graphics)
1299 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
1300 SDL_BlitSurface(surface_backup, &dst_rect, surface_screen, &src_rect);
1303 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1304 int to_x, int to_y, Uint32 color)
1306 SDL_Surface *surface = dst_bitmap->surface;
1310 swap_numbers(&from_x, &to_x);
1313 swap_numbers(&from_y, &to_y);
1317 rect.w = (to_x - from_x + 1);
1318 rect.h = (to_y - from_y + 1);
1320 SDL_FillRect(surface, &rect, color);
1323 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1324 int to_x, int to_y, Uint32 color)
1326 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1329 #if ENABLE_UNUSED_CODE
1330 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1331 int num_points, Uint32 color)
1336 for (i = 0; i < num_points - 1; i++)
1338 for (x = 0; x < line_width; x++)
1340 for (y = 0; y < line_width; y++)
1342 int dx = x - line_width / 2;
1343 int dy = y - line_width / 2;
1345 if ((x == 0 && y == 0) ||
1346 (x == 0 && y == line_width - 1) ||
1347 (x == line_width - 1 && y == 0) ||
1348 (x == line_width - 1 && y == line_width - 1))
1351 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1352 points[i+1].x + dx, points[i+1].y + dy, color);
1359 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1361 SDL_Surface *surface = src_bitmap->surface;
1363 switch (surface->format->BytesPerPixel)
1365 case 1: /* assuming 8-bpp */
1367 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1371 case 2: /* probably 15-bpp or 16-bpp */
1373 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1377 case 3: /* slow 24-bpp mode; usually not used */
1379 /* does this work? */
1380 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1384 shift = surface->format->Rshift;
1385 color |= *(pix + shift / 8) >> shift;
1386 shift = surface->format->Gshift;
1387 color |= *(pix + shift / 8) >> shift;
1388 shift = surface->format->Bshift;
1389 color |= *(pix + shift / 8) >> shift;
1395 case 4: /* probably 32-bpp */
1397 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1406 /* ========================================================================= */
1407 /* The following functions were taken from the SGE library */
1408 /* (SDL Graphics Extension Library) by Anders Lindström */
1409 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1410 /* ========================================================================= */
1412 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1414 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1416 switch (surface->format->BytesPerPixel)
1420 /* Assuming 8-bpp */
1421 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1427 /* Probably 15-bpp or 16-bpp */
1428 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1434 /* Slow 24-bpp mode, usually not used */
1438 /* Gack - slow, but endian correct */
1439 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1440 shift = surface->format->Rshift;
1441 *(pix+shift/8) = color>>shift;
1442 shift = surface->format->Gshift;
1443 *(pix+shift/8) = color>>shift;
1444 shift = surface->format->Bshift;
1445 *(pix+shift/8) = color>>shift;
1451 /* Probably 32-bpp */
1452 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1459 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1460 Uint8 R, Uint8 G, Uint8 B)
1462 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1465 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1467 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1470 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1472 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1475 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1480 /* Gack - slow, but endian correct */
1481 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1482 shift = surface->format->Rshift;
1483 *(pix+shift/8) = color>>shift;
1484 shift = surface->format->Gshift;
1485 *(pix+shift/8) = color>>shift;
1486 shift = surface->format->Bshift;
1487 *(pix+shift/8) = color>>shift;
1490 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1492 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1495 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1497 switch (dest->format->BytesPerPixel)
1500 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1504 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1508 _PutPixel24(dest,x,y,color);
1512 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1517 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1519 if (SDL_MUSTLOCK(surface))
1521 if (SDL_LockSurface(surface) < 0)
1527 _PutPixel(surface, x, y, color);
1529 if (SDL_MUSTLOCK(surface))
1531 SDL_UnlockSurface(surface);
1535 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1536 Uint8 r, Uint8 g, Uint8 b)
1538 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1541 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1543 if (y >= 0 && y <= dest->h - 1)
1545 switch (dest->format->BytesPerPixel)
1548 return y*dest->pitch;
1552 return y*dest->pitch/2;
1556 return y*dest->pitch;
1560 return y*dest->pitch/4;
1568 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1570 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1572 switch (surface->format->BytesPerPixel)
1576 /* Assuming 8-bpp */
1577 *((Uint8 *)surface->pixels + ypitch + x) = color;
1583 /* Probably 15-bpp or 16-bpp */
1584 *((Uint16 *)surface->pixels + ypitch + x) = color;
1590 /* Slow 24-bpp mode, usually not used */
1594 /* Gack - slow, but endian correct */
1595 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1596 shift = surface->format->Rshift;
1597 *(pix+shift/8) = color>>shift;
1598 shift = surface->format->Gshift;
1599 *(pix+shift/8) = color>>shift;
1600 shift = surface->format->Bshift;
1601 *(pix+shift/8) = color>>shift;
1607 /* Probably 32-bpp */
1608 *((Uint32 *)surface->pixels + ypitch + x) = color;
1615 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1620 if (SDL_MUSTLOCK(Surface))
1622 if (SDL_LockSurface(Surface) < 0)
1635 /* Do the clipping */
1636 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1640 if (x2 > Surface->w - 1)
1641 x2 = Surface->w - 1;
1648 SDL_FillRect(Surface, &l, Color);
1650 if (SDL_MUSTLOCK(Surface))
1652 SDL_UnlockSurface(Surface);
1656 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1657 Uint8 R, Uint8 G, Uint8 B)
1659 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1662 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1673 /* Do the clipping */
1674 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1678 if (x2 > Surface->w - 1)
1679 x2 = Surface->w - 1;
1686 SDL_FillRect(Surface, &l, Color);
1689 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1694 if (SDL_MUSTLOCK(Surface))
1696 if (SDL_LockSurface(Surface) < 0)
1709 /* Do the clipping */
1710 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1714 if (y2 > Surface->h - 1)
1715 y2 = Surface->h - 1;
1722 SDL_FillRect(Surface, &l, Color);
1724 if (SDL_MUSTLOCK(Surface))
1726 SDL_UnlockSurface(Surface);
1730 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1731 Uint8 R, Uint8 G, Uint8 B)
1733 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1736 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1747 /* Do the clipping */
1748 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1752 if (y2 > Surface->h - 1)
1753 y2 = Surface->h - 1;
1760 SDL_FillRect(Surface, &l, Color);
1763 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1764 Sint16 x2, Sint16 y2, Uint32 Color,
1765 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1768 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1773 sdx = (dx < 0) ? -1 : 1;
1774 sdy = (dy < 0) ? -1 : 1;
1786 for (x = 0; x < dx; x++)
1788 Callback(Surface, px, py, Color);
1802 for (y = 0; y < dy; y++)
1804 Callback(Surface, px, py, Color);
1818 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1819 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1820 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1823 sge_DoLine(Surface, X1, Y1, X2, Y2,
1824 SDL_MapRGB(Surface->format, R, G, B), Callback);
1827 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1830 if (SDL_MUSTLOCK(Surface))
1832 if (SDL_LockSurface(Surface) < 0)
1837 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1839 /* unlock the display */
1840 if (SDL_MUSTLOCK(Surface))
1842 SDL_UnlockSurface(Surface);
1846 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1847 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1849 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1852 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1854 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1859 -----------------------------------------------------------------------------
1860 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1861 -----------------------------------------------------------------------------
1864 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1865 int width, int height, Uint32 color)
1869 for (y = src_y; y < src_y + height; y++)
1871 for (x = src_x; x < src_x + width; x++)
1873 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1875 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1880 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1881 int src_x, int src_y, int width, int height,
1882 int dst_x, int dst_y)
1886 for (y = 0; y < height; y++)
1888 for (x = 0; x < width; x++)
1890 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1892 if (pixel != BLACK_PIXEL)
1893 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1899 /* ========================================================================= */
1900 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1901 /* (Rotozoomer) by Andreas Schiffler */
1902 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1903 /* ========================================================================= */
1906 -----------------------------------------------------------------------------
1909 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1910 -----------------------------------------------------------------------------
1921 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1924 tColorRGBA *sp, *csp, *dp;
1928 sp = csp = (tColorRGBA *) src->pixels;
1929 dp = (tColorRGBA *) dst->pixels;
1930 dgap = dst->pitch - dst->w * 4;
1932 for (y = 0; y < dst->h; y++)
1936 for (x = 0; x < dst->w; x++)
1938 tColorRGBA *sp0 = sp;
1939 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1940 tColorRGBA *sp00 = &sp0[0];
1941 tColorRGBA *sp01 = &sp0[1];
1942 tColorRGBA *sp10 = &sp1[0];
1943 tColorRGBA *sp11 = &sp1[1];
1946 /* create new color pixel from all four source color pixels */
1947 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1948 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1949 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1950 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1955 /* advance source pointers */
1958 /* advance destination pointer */
1962 /* advance source pointer */
1963 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1965 /* advance destination pointers */
1966 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1972 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1974 int x, y, *sax, *say, *csax, *csay;
1976 tColorRGBA *sp, *csp, *csp0, *dp;
1979 /* use specialized zoom function when scaling down to exactly half size */
1980 if (src->w == 2 * dst->w &&
1981 src->h == 2 * dst->h)
1982 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1984 /* variable setup */
1985 sx = (float) src->w / (float) dst->w;
1986 sy = (float) src->h / (float) dst->h;
1988 /* allocate memory for row increments */
1989 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1990 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1992 /* precalculate row increments */
1993 for (x = 0; x <= dst->w; x++)
1994 *csax++ = (int)(sx * x);
1996 for (y = 0; y <= dst->h; y++)
1997 *csay++ = (int)(sy * y);
2000 sp = csp = csp0 = (tColorRGBA *) src->pixels;
2001 dp = (tColorRGBA *) dst->pixels;
2002 dgap = dst->pitch - dst->w * 4;
2005 for (y = 0; y < dst->h; y++)
2010 for (x = 0; x < dst->w; x++)
2015 /* advance source pointers */
2019 /* advance destination pointer */
2023 /* advance source pointer */
2025 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
2027 /* advance destination pointers */
2028 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2038 -----------------------------------------------------------------------------
2041 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2042 -----------------------------------------------------------------------------
2045 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2047 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2048 Uint8 *sp, *dp, *csp;
2051 /* variable setup */
2052 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2053 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2055 /* allocate memory for row increments */
2056 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2057 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2059 /* precalculate row increments */
2062 for (x = 0; x < dst->w; x++)
2065 *csax = (csx >> 16);
2072 for (y = 0; y < dst->h; y++)
2075 *csay = (csy >> 16);
2082 for (x = 0; x < dst->w; x++)
2090 for (y = 0; y < dst->h; y++)
2097 sp = csp = (Uint8 *) src->pixels;
2098 dp = (Uint8 *) dst->pixels;
2099 dgap = dst->pitch - dst->w;
2103 for (y = 0; y < dst->h; y++)
2107 for (x = 0; x < dst->w; x++)
2112 /* advance source pointers */
2116 /* advance destination pointer */
2120 /* advance source pointer (for row) */
2121 csp += ((*csay) * src->pitch);
2124 /* advance destination pointers */
2135 -----------------------------------------------------------------------------
2138 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2139 'zoomx' and 'zoomy' are scaling factors for width and height.
2140 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2141 into a 32bit RGBA format on the fly.
2142 -----------------------------------------------------------------------------
2145 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2147 SDL_Surface *zoom_src = NULL;
2148 SDL_Surface *zoom_dst = NULL;
2149 boolean is_converted = FALSE;
2156 /* determine if source surface is 32 bit or 8 bit */
2157 is_32bit = (src->format->BitsPerPixel == 32);
2159 if (is_32bit || src->format->BitsPerPixel == 8)
2161 /* use source surface 'as is' */
2166 /* new source surface is 32 bit with a defined RGB ordering */
2167 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2168 0x000000ff, 0x0000ff00, 0x00ff0000,
2169 (src->format->Amask ? 0xff000000 : 0));
2170 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2172 is_converted = TRUE;
2175 /* allocate surface to completely contain the zoomed surface */
2178 /* target surface is 32 bit with source RGBA/ABGR ordering */
2179 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2180 zoom_src->format->Rmask,
2181 zoom_src->format->Gmask,
2182 zoom_src->format->Bmask,
2183 zoom_src->format->Amask);
2187 /* target surface is 8 bit */
2188 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2192 /* lock source surface */
2193 SDL_LockSurface(zoom_src);
2195 /* check which kind of surface we have */
2198 /* call the 32 bit transformation routine to do the zooming */
2199 zoomSurfaceRGBA(zoom_src, zoom_dst);
2204 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2205 zoom_dst->format->palette->colors[i] =
2206 zoom_src->format->palette->colors[i];
2207 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2209 /* call the 8 bit transformation routine to do the zooming */
2210 zoomSurfaceY(zoom_src, zoom_dst);
2213 /* unlock source surface */
2214 SDL_UnlockSurface(zoom_src);
2216 /* free temporary surface */
2218 SDL_FreeSurface(zoom_src);
2220 /* return destination surface */
2224 static SDL_Surface *SDLGetOpaqueSurface(SDL_Surface *surface)
2226 SDL_Surface *new_surface;
2228 if (surface == NULL)
2231 if ((new_surface = SDLGetNativeSurface(surface)) == NULL)
2232 Error(ERR_EXIT, "SDLGetNativeSurface() failed");
2234 /* remove alpha channel from native non-transparent surface, if defined */
2235 SDLSetAlpha(new_surface, FALSE, 0);
2237 /* remove transparent color from native non-transparent surface, if defined */
2238 SDL_SetColorKey(new_surface, UNSET_TRANSPARENT_PIXEL, 0);
2243 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2245 Bitmap *dst_bitmap = CreateBitmapStruct();
2246 SDL_Surface *src_surface = src_bitmap->surface_masked;
2247 SDL_Surface *dst_surface;
2249 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2250 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2252 dst_bitmap->width = dst_width;
2253 dst_bitmap->height = dst_height;
2255 /* create zoomed temporary surface from source surface */
2256 dst_surface = zoomSurface(src_surface, dst_width, dst_height);
2258 /* create native format destination surface from zoomed temporary surface */
2259 SDLSetNativeSurface(&dst_surface);
2261 /* set color key for zoomed surface from source surface, if defined */
2262 if (SDLHasColorKey(src_surface))
2263 SDL_SetColorKey(dst_surface, SET_TRANSPARENT_PIXEL,
2264 SDLGetColorKey(src_surface));
2266 /* create native non-transparent surface for opaque blitting */
2267 dst_bitmap->surface = SDLGetOpaqueSurface(dst_surface);
2269 /* set native transparent surface for masked blitting */
2270 dst_bitmap->surface_masked = dst_surface;
2276 /* ========================================================================= */
2277 /* load image to bitmap */
2278 /* ========================================================================= */
2280 Bitmap *SDLLoadImage(char *filename)
2282 Bitmap *new_bitmap = CreateBitmapStruct();
2283 SDL_Surface *sdl_image_tmp;
2285 print_timestamp_init("SDLLoadImage");
2287 print_timestamp_time(getBaseNamePtr(filename));
2289 /* load image to temporary surface */
2290 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2291 Error(ERR_EXIT, "IMG_Load() failed: %s", SDL_GetError());
2293 print_timestamp_time("IMG_Load");
2295 UPDATE_BUSY_STATE();
2297 /* create native non-transparent surface for current image */
2298 if ((new_bitmap->surface = SDLGetOpaqueSurface(sdl_image_tmp)) == NULL)
2299 Error(ERR_EXIT, "SDLGetOpaqueSurface() failed");
2301 print_timestamp_time("SDLGetNativeSurface (opaque)");
2303 UPDATE_BUSY_STATE();
2305 /* set black pixel to transparent if no alpha channel / transparent color */
2306 if (!SDLHasAlpha(sdl_image_tmp) &&
2307 !SDLHasColorKey(sdl_image_tmp))
2308 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2309 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2311 /* create native transparent surface for current image */
2312 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2313 Error(ERR_EXIT, "SDLGetNativeSurface() failed");
2315 print_timestamp_time("SDLGetNativeSurface (masked)");
2317 UPDATE_BUSY_STATE();
2319 /* free temporary surface */
2320 SDL_FreeSurface(sdl_image_tmp);
2322 new_bitmap->width = new_bitmap->surface->w;
2323 new_bitmap->height = new_bitmap->surface->h;
2325 print_timestamp_done("SDLLoadImage");
2331 /* ------------------------------------------------------------------------- */
2332 /* custom cursor fuctions */
2333 /* ------------------------------------------------------------------------- */
2335 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2337 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2338 cursor_info->width, cursor_info->height,
2339 cursor_info->hot_x, cursor_info->hot_y);
2342 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2344 static struct MouseCursorInfo *last_cursor_info = NULL;
2345 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2346 static SDL_Cursor *cursor_default = NULL;
2347 static SDL_Cursor *cursor_current = NULL;
2349 /* if invoked for the first time, store the SDL default cursor */
2350 if (cursor_default == NULL)
2351 cursor_default = SDL_GetCursor();
2353 /* only create new cursor if cursor info (custom only) has changed */
2354 if (cursor_info != NULL && cursor_info != last_cursor_info)
2356 cursor_current = create_cursor(cursor_info);
2357 last_cursor_info = cursor_info;
2360 /* only set new cursor if cursor info (custom or NULL) has changed */
2361 if (cursor_info != last_cursor_info2)
2362 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2364 last_cursor_info2 = cursor_info;
2368 /* ========================================================================= */
2369 /* audio functions */
2370 /* ========================================================================= */
2372 void SDLOpenAudio(void)
2374 #if !defined(TARGET_SDL2)
2375 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2376 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2379 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2381 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2385 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2386 AUDIO_NUM_CHANNELS_STEREO,
2387 setup.system.audio_fragment_size) < 0)
2389 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2393 audio.sound_available = TRUE;
2394 audio.music_available = TRUE;
2395 audio.loops_available = TRUE;
2396 audio.sound_enabled = TRUE;
2398 /* set number of available mixer channels */
2399 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2400 audio.music_channel = MUSIC_CHANNEL;
2401 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2403 Mixer_InitChannels();
2406 void SDLCloseAudio(void)
2409 Mix_HaltChannel(-1);
2412 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2416 /* ========================================================================= */
2417 /* event functions */
2418 /* ========================================================================= */
2420 void SDLNextEvent(Event *event)
2422 SDL_WaitEvent(event);
2425 void SDLHandleWindowManagerEvent(Event *event)
2428 #if defined(PLATFORM_WIN32)
2429 // experimental drag and drop code
2431 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2432 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2434 #if defined(TARGET_SDL2)
2435 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2437 if (syswmmsg->msg == WM_DROPFILES)
2440 #if defined(TARGET_SDL2)
2441 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2443 HDROP hdrop = (HDROP)syswmmsg->wParam;
2447 printf("::: SDL_SYSWMEVENT:\n");
2449 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2451 for (i = 0; i < num_files; i++)
2453 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2454 char buffer[buffer_len + 1];
2456 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2458 printf("::: - '%s'\n", buffer);
2461 #if defined(TARGET_SDL2)
2462 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2464 DragFinish((HDROP)syswmmsg->wParam);
2472 /* ========================================================================= */
2473 /* joystick functions */
2474 /* ========================================================================= */
2476 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2477 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2478 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2480 static boolean SDLOpenJoystick(int nr)
2482 if (nr < 0 || nr > MAX_PLAYERS)
2485 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2488 static void SDLCloseJoystick(int nr)
2490 if (nr < 0 || nr > MAX_PLAYERS)
2493 SDL_JoystickClose(sdl_joystick[nr]);
2495 sdl_joystick[nr] = NULL;
2498 static boolean SDLCheckJoystickOpened(int nr)
2500 if (nr < 0 || nr > MAX_PLAYERS)
2503 #if defined(TARGET_SDL2)
2504 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2506 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2510 void HandleJoystickEvent(Event *event)
2514 case SDL_JOYAXISMOTION:
2515 if (event->jaxis.axis < 2)
2516 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2519 case SDL_JOYBUTTONDOWN:
2520 if (event->jbutton.button < 2)
2521 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2524 case SDL_JOYBUTTONUP:
2525 if (event->jbutton.button < 2)
2526 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2534 void SDLInitJoysticks()
2536 static boolean sdl_joystick_subsystem_initialized = FALSE;
2537 boolean print_warning = !sdl_joystick_subsystem_initialized;
2540 if (!sdl_joystick_subsystem_initialized)
2542 sdl_joystick_subsystem_initialized = TRUE;
2544 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2546 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2551 for (i = 0; i < MAX_PLAYERS; i++)
2553 /* get configured joystick for this player */
2554 char *device_name = setup.input[i].joy.device_name;
2555 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2557 if (joystick_nr >= SDL_NumJoysticks())
2559 if (setup.input[i].use_joystick && print_warning)
2560 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2565 /* misuse joystick file descriptor variable to store joystick number */
2566 joystick.fd[i] = joystick_nr;
2568 if (joystick_nr == -1)
2571 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2572 if (SDLCheckJoystickOpened(joystick_nr))
2573 SDLCloseJoystick(joystick_nr);
2575 if (!setup.input[i].use_joystick)
2578 if (!SDLOpenJoystick(joystick_nr))
2581 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2586 joystick.status = JOYSTICK_ACTIVATED;
2590 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2592 if (nr < 0 || nr >= MAX_PLAYERS)
2596 *x = sdl_js_axis[nr][0];
2598 *y = sdl_js_axis[nr][1];
2601 *b1 = sdl_js_button[nr][0];
2603 *b2 = sdl_js_button[nr][1];