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 int xoff = video.screen_xoffset;
133 int yoff = video.screen_yoffset;
134 SDL_Rect dst_rect_screen = { xoff, yoff, video.width, video.height };
135 SDL_Rect *src_rect1 = NULL, *dst_rect1 = NULL;
136 SDL_Rect *src_rect2 = NULL, *dst_rect2 = NULL;
138 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
139 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
140 dst_rect2 = &dst_rect_screen;
142 dst_rect1 = &dst_rect_screen;
144 #if defined(HAS_SCREEN_KEYBOARD)
145 if (video.shifted_up || video.shifted_up_delay)
147 int time_current = SDL_GetTicks();
148 int pos = video.shifted_up_pos;
149 int pos_last = video.shifted_up_pos_last;
151 if (!DelayReachedExt(&video.shifted_up_delay, video.shifted_up_delay_value,
154 int delay = time_current - video.shifted_up_delay;
155 int delay_value = video.shifted_up_delay_value;
157 pos = pos_last + (pos - pos_last) * delay / delay_value;
161 video.shifted_up_pos_last = pos;
162 video.shifted_up_delay = 0;
165 SDL_Rect src_rect_up = { 0, pos, video.width, video.height - pos };
166 SDL_Rect dst_rect_up = { xoff, yoff, video.width, video.height - pos };
168 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
169 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
171 src_rect2 = &src_rect_up;
172 dst_rect2 = &dst_rect_up;
176 src_rect1 = &src_rect_up;
177 dst_rect1 = &dst_rect_up;
182 // clear render target buffer
183 SDL_RenderClear(sdl_renderer);
185 // set renderer to use target texture for rendering
186 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
187 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
188 SDL_SetRenderTarget(sdl_renderer, sdl_texture_target);
190 // copy backbuffer texture to render target buffer
191 if (video.screen_rendering_mode != SPECIAL_RENDERING_TARGET)
192 SDL_RenderCopy(sdl_renderer, sdl_texture_stream, src_rect1, dst_rect1);
194 if (video.screen_rendering_mode != SPECIAL_RENDERING_BITMAP)
195 FinalizeScreen(DRAW_TO_SCREEN);
197 // when using target texture, copy it to screen buffer
198 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
199 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
201 SDL_SetRenderTarget(sdl_renderer, NULL);
202 SDL_RenderCopy(sdl_renderer, sdl_texture_target, src_rect2, dst_rect2);
206 // global synchronization point of the game to align video frame delay
207 if (with_frame_delay)
208 WaitUntilDelayReached(&video.frame_delay, video.frame_delay_value);
210 #if defined(TARGET_SDL2)
211 // show render target buffer on screen
212 SDL_RenderPresent(sdl_renderer);
215 SDL_UpdateRects(screen, 1, rect);
217 SDL_UpdateRect(screen, 0, 0, 0, 0);
221 static void UpdateScreen_WithFrameDelay(SDL_Rect *rect)
223 UpdateScreenExt(rect, TRUE);
226 static void UpdateScreen_WithoutFrameDelay(SDL_Rect *rect)
228 UpdateScreenExt(rect, FALSE);
231 static void SDLSetWindowIcon(char *basename)
233 /* (setting the window icon on Mac OS X would replace the high-quality
234 dock icon with the currently smaller (and uglier) icon from file) */
236 #if !defined(PLATFORM_MACOSX)
237 char *filename = getCustomImageFilename(basename);
238 SDL_Surface *surface;
240 if (filename == NULL)
242 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
247 if ((surface = IMG_Load(filename)) == NULL)
249 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
254 /* set transparent color */
255 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
256 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
258 #if defined(TARGET_SDL2)
259 SDL_SetWindowIcon(sdl_window, surface);
261 SDL_WM_SetIcon(surface, NULL);
266 #if defined(TARGET_SDL2)
268 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
269 SDL_PixelFormat *format2)
271 return (format1->format == format2->format &&
272 format1->BitsPerPixel == format2->BitsPerPixel &&
273 format1->BytesPerPixel == format2->BytesPerPixel &&
274 format1->Rmask == format2->Rmask &&
275 format1->Gmask == format2->Gmask &&
276 format1->Bmask == format2->Bmask);
279 static Pixel SDLGetColorKey(SDL_Surface *surface)
283 if (SDL_GetColorKey(surface, &color_key) != 0)
289 static boolean SDLHasColorKey(SDL_Surface *surface)
291 return (SDLGetColorKey(surface) != -1);
294 static boolean SDLHasAlpha(SDL_Surface *surface)
296 SDL_BlendMode blend_mode;
298 if (SDL_GetSurfaceBlendMode(surface, &blend_mode) != 0)
301 return (blend_mode == SDL_BLENDMODE_BLEND);
304 static void SDLSetAlpha(SDL_Surface *surface, boolean set, int alpha)
306 SDL_BlendMode blend_mode = (set ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE);
308 SDL_SetSurfaceBlendMode(surface, blend_mode);
309 SDL_SetSurfaceAlphaMod(surface, alpha);
312 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
314 SDL_PixelFormat format;
315 SDL_Surface *new_surface;
320 if (backbuffer && backbuffer->surface)
322 format = *backbuffer->surface->format;
323 format.Amask = surface->format->Amask; // keep alpha channel
327 format = *surface->format;
330 new_surface = SDL_ConvertSurface(surface, &format, 0);
332 if (new_surface == NULL)
333 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
338 boolean SDLSetNativeSurface(SDL_Surface **surface)
340 SDL_Surface *new_surface;
342 if (surface == NULL ||
344 backbuffer == NULL ||
345 backbuffer->surface == NULL)
348 // if pixel format already optimized for destination surface, do nothing
349 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
352 new_surface = SDLGetNativeSurface(*surface);
354 SDL_FreeSurface(*surface);
356 *surface = new_surface;
363 static Pixel SDLGetColorKey(SDL_Surface *surface)
365 if ((surface->flags & SDL_SRCCOLORKEY) == 0)
368 return surface->format->colorkey;
371 static boolean SDLHasColorKey(SDL_Surface *surface)
373 return (SDLGetColorKey(surface) != -1);
376 static boolean SDLHasAlpha(SDL_Surface *surface)
378 return ((surface->flags & SDL_SRCALPHA) != 0);
381 static void SDLSetAlpha(SDL_Surface *surface, boolean set, int alpha)
383 SDL_SetAlpha(surface, (set ? SDL_SRCALPHA : 0), alpha);
386 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
388 SDL_Surface *new_surface;
393 if (!video.initialized)
394 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
395 else if (SDLHasAlpha(surface))
396 new_surface = SDL_DisplayFormatAlpha(surface);
398 new_surface = SDL_DisplayFormat(surface);
400 if (new_surface == NULL)
401 Error(ERR_EXIT, "%s() failed: %s",
402 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
408 boolean SDLSetNativeSurface(SDL_Surface **surface)
410 SDL_Surface *new_surface;
412 if (surface == NULL ||
417 new_surface = SDLGetNativeSurface(*surface);
419 SDL_FreeSurface(*surface);
421 *surface = new_surface;
428 #if defined(TARGET_SDL2)
429 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
431 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
434 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
441 void SDLCreateBitmapTextures(Bitmap *bitmap)
443 #if defined(TARGET_SDL2)
448 SDL_DestroyTexture(bitmap->texture);
449 if (bitmap->texture_masked)
450 SDL_DestroyTexture(bitmap->texture_masked);
452 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
453 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
457 void SDLFreeBitmapTextures(Bitmap *bitmap)
459 #if defined(TARGET_SDL2)
464 SDL_DestroyTexture(bitmap->texture);
465 if (bitmap->texture_masked)
466 SDL_DestroyTexture(bitmap->texture_masked);
468 bitmap->texture = NULL;
469 bitmap->texture_masked = NULL;
473 void SDLInitVideoDisplay(void)
475 #if !defined(TARGET_SDL2)
476 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
477 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
479 SDL_putenv("SDL_VIDEO_CENTERED=1");
482 /* initialize SDL video */
483 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
484 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
486 /* set default SDL depth */
487 #if !defined(TARGET_SDL2)
488 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
490 video.default_depth = 32; // (how to determine video depth in SDL2?)
494 void SDLInitVideoBuffer(boolean fullscreen)
496 video.window_scaling_percent = setup.window_scaling_percent;
497 video.window_scaling_quality = setup.window_scaling_quality;
499 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
501 #if defined(TARGET_SDL2)
502 // SDL 2.0: support for (desktop) fullscreen mode available
503 video.fullscreen_available = TRUE;
505 // SDL 1.2: no support for fullscreen mode in R'n'D anymore
506 video.fullscreen_available = FALSE;
509 /* open SDL video output device (window or fullscreen mode) */
510 if (!SDLSetVideoMode(fullscreen))
511 Error(ERR_EXIT, "setting video mode failed");
513 /* !!! SDL2 can only set the window icon if the window already exists !!! */
514 /* set window icon */
515 SDLSetWindowIcon(program.icon_filename);
517 /* set window and icon title */
518 #if defined(TARGET_SDL2)
519 SDL_SetWindowTitle(sdl_window, program.window_title);
521 SDL_WM_SetCaption(program.window_title, program.window_title);
524 /* SDL cannot directly draw to the visible video framebuffer like X11,
525 but always uses a backbuffer, which is then blitted to the visible
526 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
527 visible video framebuffer with 'SDL_Flip', if the hardware supports
528 this). Therefore do not use an additional backbuffer for drawing, but
529 use a symbolic buffer (distinguishable from the SDL backbuffer) called
530 'window', which indicates that the SDL backbuffer should be updated to
531 the visible video framebuffer when attempting to blit to it.
533 For convenience, it seems to be a good idea to create this symbolic
534 buffer 'window' at the same size as the SDL backbuffer. Although it
535 should never be drawn to directly, it would do no harm nevertheless. */
537 /* create additional (symbolic) buffer for double-buffering */
538 ReCreateBitmap(&window, video.width, video.height);
541 static boolean SDLCreateScreen(boolean fullscreen)
543 SDL_Surface *new_surface = NULL;
545 #if defined(TARGET_SDL2)
546 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
547 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
549 int surface_flags_window = SURFACE_FLAGS;
550 int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2)
553 #if defined(TARGET_SDL2)
555 int renderer_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
557 /* If SDL_CreateRenderer() is called from within a VirtualBox Windows VM
558 _without_ enabling 2D/3D acceleration and/or guest additions installed,
559 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
560 it will try to use accelerated graphics and apparently fails miserably) */
561 int renderer_flags = SDL_RENDERER_SOFTWARE;
565 SDLSetScreenSizeAndOffsets(video.width, video.height);
567 int width = video.width;
568 int height = video.height;
569 int screen_width = video.screen_width;
570 int screen_height = video.screen_height;
571 int surface_flags = (fullscreen ? surface_flags_fullscreen :
572 surface_flags_window);
574 // default window size is unscaled
575 video.window_width = screen_width;
576 video.window_height = screen_height;
578 #if defined(TARGET_SDL2)
580 // store if initial screen mode is fullscreen mode when changing screen size
581 video.fullscreen_initial = fullscreen;
583 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
585 video.window_width = window_scaling_factor * screen_width;
586 video.window_height = window_scaling_factor * screen_height;
588 if (sdl_texture_stream)
590 SDL_DestroyTexture(sdl_texture_stream);
591 sdl_texture_stream = NULL;
594 if (sdl_texture_target)
596 SDL_DestroyTexture(sdl_texture_target);
597 sdl_texture_target = NULL;
600 if (!(fullscreen && fullscreen_enabled))
604 SDL_DestroyRenderer(sdl_renderer);
610 SDL_DestroyWindow(sdl_window);
615 if (sdl_window == NULL)
616 sdl_window = SDL_CreateWindow(program.window_title,
617 SDL_WINDOWPOS_CENTERED,
618 SDL_WINDOWPOS_CENTERED,
623 if (sdl_window != NULL)
625 if (sdl_renderer == NULL)
626 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, renderer_flags);
628 if (sdl_renderer != NULL)
630 SDL_RenderSetLogicalSize(sdl_renderer, screen_width, screen_height);
631 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
632 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
634 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
635 SDL_PIXELFORMAT_ARGB8888,
636 SDL_TEXTUREACCESS_STREAMING,
639 if (SDL_RenderTargetSupported(sdl_renderer))
640 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
641 SDL_PIXELFORMAT_ARGB8888,
642 SDL_TEXTUREACCESS_TARGET,
645 if (sdl_texture_stream != NULL)
647 // use SDL default values for RGB masks and no alpha channel
648 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
650 if (new_surface == NULL)
651 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
655 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
660 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
665 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
670 if (gfx.final_screen_bitmap == NULL)
671 gfx.final_screen_bitmap = CreateBitmapStruct();
673 gfx.final_screen_bitmap->width = width;
674 gfx.final_screen_bitmap->height = height;
676 gfx.final_screen_bitmap->surface =
677 SDL_SetVideoMode(width, height, video.depth, surface_flags);
679 if (gfx.final_screen_bitmap->surface != NULL)
682 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
684 if (new_surface == NULL)
685 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
688 new_surface = gfx.final_screen_bitmap->surface;
689 gfx.final_screen_bitmap = NULL;
695 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
699 #if defined(TARGET_SDL2)
700 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
701 if (new_surface != NULL)
702 fullscreen_enabled = fullscreen;
705 if (backbuffer == NULL)
706 backbuffer = CreateBitmapStruct();
708 backbuffer->width = video.width;
709 backbuffer->height = video.height;
711 if (backbuffer->surface)
712 SDL_FreeSurface(backbuffer->surface);
714 backbuffer->surface = new_surface;
716 return (new_surface != NULL);
719 boolean SDLSetVideoMode(boolean fullscreen)
721 boolean success = FALSE;
725 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
727 /* switch display to fullscreen mode, if available */
728 success = SDLCreateScreen(TRUE);
732 /* switching display to fullscreen mode failed -- do not try it again */
733 video.fullscreen_available = FALSE;
737 video.fullscreen_enabled = TRUE;
741 if ((!fullscreen && video.fullscreen_enabled) || !success)
743 /* switch display to window mode */
744 success = SDLCreateScreen(FALSE);
748 /* switching display to window mode failed -- should not happen */
752 video.fullscreen_enabled = FALSE;
753 video.window_scaling_percent = setup.window_scaling_percent;
754 video.window_scaling_quality = setup.window_scaling_quality;
756 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
760 #if defined(TARGET_SDL2)
761 SDLRedrawWindow(); // map window
765 #if defined(PLATFORM_WIN32)
766 // experimental drag and drop code
768 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
771 SDL_SysWMinfo wminfo;
773 boolean wminfo_success = FALSE;
775 SDL_VERSION(&wminfo.version);
776 #if defined(TARGET_SDL2)
778 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
780 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
785 #if defined(TARGET_SDL2)
786 hwnd = wminfo.info.win.window;
788 hwnd = wminfo.window;
791 DragAcceptFiles(hwnd, TRUE);
800 void SDLSetWindowTitle()
802 #if defined(TARGET_SDL2)
803 SDL_SetWindowTitle(sdl_window, program.window_title);
805 SDL_WM_SetCaption(program.window_title, program.window_title);
809 #if defined(TARGET_SDL2)
810 void SDLSetWindowScaling(int window_scaling_percent)
812 if (sdl_window == NULL)
815 float window_scaling_factor = (float)window_scaling_percent / 100;
816 int new_window_width = (int)(window_scaling_factor * video.screen_width);
817 int new_window_height = (int)(window_scaling_factor * video.screen_height);
819 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
821 video.window_scaling_percent = window_scaling_percent;
822 video.window_width = new_window_width;
823 video.window_height = new_window_height;
828 void SDLSetWindowScalingQuality(char *window_scaling_quality)
830 SDL_Texture *new_texture;
832 if (sdl_texture_stream == NULL)
835 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
837 new_texture = SDL_CreateTexture(sdl_renderer,
838 SDL_PIXELFORMAT_ARGB8888,
839 SDL_TEXTUREACCESS_STREAMING,
840 video.width, video.height);
842 if (new_texture != NULL)
844 SDL_DestroyTexture(sdl_texture_stream);
846 sdl_texture_stream = new_texture;
849 if (SDL_RenderTargetSupported(sdl_renderer))
850 new_texture = SDL_CreateTexture(sdl_renderer,
851 SDL_PIXELFORMAT_ARGB8888,
852 SDL_TEXTUREACCESS_TARGET,
853 video.width, video.height);
857 if (new_texture != NULL)
859 SDL_DestroyTexture(sdl_texture_target);
861 sdl_texture_target = new_texture;
866 video.window_scaling_quality = window_scaling_quality;
869 void SDLSetWindowFullscreen(boolean fullscreen)
871 if (sdl_window == NULL)
874 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
876 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
877 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
879 // if screen size was changed in fullscreen mode, correct desktop window size
880 if (!fullscreen && video.fullscreen_initial)
882 SDLSetWindowScaling(setup.window_scaling_percent);
883 SDL_SetWindowPosition(sdl_window,
884 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
886 video.fullscreen_initial = FALSE;
890 void SDLSetDisplaySize()
892 SDL_Rect display_bounds;
894 SDL_GetDisplayBounds(0, &display_bounds);
896 video.display_width = display_bounds.w;
897 video.display_height = display_bounds.h;
900 Error(ERR_DEBUG, "SDL real screen size: %d x %d",
901 video.display_width, video.display_height);
905 void SDLSetScreenSizeAndOffsets(int width, int height)
907 // set default video screen size and offsets
908 video.screen_width = width;
909 video.screen_height = height;
910 video.screen_xoffset = 0;
911 video.screen_yoffset = 0;
913 #if defined(PLATFORM_ANDROID)
914 float ratio_video = (float) width / height;
915 float ratio_display = (float) video.display_width / video.display_height;
917 if (ratio_video != ratio_display)
919 // adjust drawable screen size to cover the whole device display
921 if (ratio_video < ratio_display)
922 video.screen_width *= ratio_display / ratio_video;
924 video.screen_height *= ratio_video / ratio_display;
926 video.screen_xoffset = (video.screen_width - width) / 2;
927 video.screen_yoffset = (video.screen_height - height) / 2;
930 Error(ERR_DEBUG, "Changing screen from %dx%d to %dx%d (%.2f to %.2f)",
932 video.screen_width, video.screen_height,
933 ratio_video, ratio_display);
939 void SDLSetScreenSizeForRenderer(int width, int height)
941 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
944 void SDLSetScreenProperties()
946 SDLSetScreenSizeAndOffsets(video.width, video.height);
947 SDLSetScreenSizeForRenderer(video.screen_width, video.screen_height);
952 void SDLSetScreenRenderingMode(char *screen_rendering_mode)
954 #if defined(TARGET_SDL2)
955 video.screen_rendering_mode =
956 (strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
957 SPECIAL_RENDERING_BITMAP :
958 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
959 SPECIAL_RENDERING_TARGET:
960 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
961 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
963 video.screen_rendering_mode = SPECIAL_RENDERING_BITMAP;
967 void SDLRedrawWindow()
969 UpdateScreen_WithoutFrameDelay(NULL);
972 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
975 SDL_Surface *surface =
976 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
979 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
981 SDLSetNativeSurface(&surface);
983 bitmap->surface = surface;
986 void SDLFreeBitmapPointers(Bitmap *bitmap)
989 SDL_FreeSurface(bitmap->surface);
990 if (bitmap->surface_masked)
991 SDL_FreeSurface(bitmap->surface_masked);
993 bitmap->surface = NULL;
994 bitmap->surface_masked = NULL;
996 #if defined(TARGET_SDL2)
998 SDL_DestroyTexture(bitmap->texture);
999 if (bitmap->texture_masked)
1000 SDL_DestroyTexture(bitmap->texture_masked);
1002 bitmap->texture = NULL;
1003 bitmap->texture_masked = NULL;
1007 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1008 int src_x, int src_y, int width, int height,
1009 int dst_x, int dst_y, int mask_mode)
1011 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1012 SDL_Rect src_rect, dst_rect;
1017 src_rect.h = height;
1022 dst_rect.h = height;
1024 // if (src_bitmap != backbuffer || dst_bitmap != window)
1025 if (!(src_bitmap == backbuffer && dst_bitmap == window))
1026 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
1027 src_bitmap->surface_masked : src_bitmap->surface),
1028 &src_rect, real_dst_bitmap->surface, &dst_rect);
1030 if (dst_bitmap == window)
1031 UpdateScreen_WithFrameDelay(&dst_rect);
1034 void SDLBlitTexture(Bitmap *bitmap,
1035 int src_x, int src_y, int width, int height,
1036 int dst_x, int dst_y, int mask_mode)
1038 #if defined(TARGET_SDL2)
1039 SDL_Texture *texture;
1044 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
1046 if (texture == NULL)
1052 src_rect.h = height;
1057 dst_rect.h = height;
1059 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
1063 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
1066 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1074 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
1076 if (dst_bitmap == window)
1077 UpdateScreen_WithFrameDelay(&rect);
1080 void PrepareFadeBitmap(int draw_target)
1082 Bitmap *fade_bitmap =
1083 (draw_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
1084 draw_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
1086 if (fade_bitmap == NULL)
1089 // copy backbuffer to fading buffer
1090 BlitBitmap(backbuffer, fade_bitmap, 0, 0, gfx.win_xsize, gfx.win_ysize, 0, 0);
1092 // add border and animations to fading buffer
1093 FinalizeScreen(draw_target);
1096 void SDLFadeRectangle(int x, int y, int width, int height,
1097 int fade_mode, int fade_delay, int post_delay,
1098 void (*draw_border_function)(void))
1100 SDL_Surface *surface_backup = gfx.fade_bitmap_backup->surface;
1101 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
1102 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
1103 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
1104 SDL_Surface *surface_screen = backbuffer->surface;
1105 SDL_Rect src_rect, dst_rect;
1107 int src_x = x, src_y = y;
1108 int dst_x = x, dst_y = y;
1109 unsigned int time_last, time_current;
1111 // store function for drawing global masked border
1112 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
1114 // deactivate drawing of global border while fading, if needed
1115 if (draw_border_function == NULL)
1116 gfx.draw_global_border_function = NULL;
1121 src_rect.h = height;
1125 dst_rect.w = width; /* (ignored) */
1126 dst_rect.h = height; /* (ignored) */
1128 dst_rect2 = dst_rect;
1130 // before fading in, store backbuffer (without animation graphics)
1131 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
1132 SDL_BlitSurface(surface_screen, &dst_rect, surface_backup, &src_rect);
1134 /* copy source and target surfaces to temporary surfaces for fading */
1135 if (fade_mode & FADE_TYPE_TRANSFORM)
1137 // (source and target fading buffer already prepared)
1139 else if (fade_mode & FADE_TYPE_FADE_IN)
1141 // (target fading buffer already prepared)
1142 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1144 else /* FADE_TYPE_FADE_OUT */
1146 // (source fading buffer already prepared)
1147 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1150 time_current = SDL_GetTicks();
1152 if (fade_mode == FADE_MODE_MELT)
1154 boolean done = FALSE;
1155 int melt_pixels = 2;
1156 int melt_columns = width / melt_pixels;
1157 int ypos[melt_columns];
1158 int max_steps = height / 8 + 32;
1163 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1165 SDLSetAlpha(surface_target, FALSE, 0); /* disable alpha blending */
1167 ypos[0] = -GetSimpleRandom(16);
1169 for (i = 1 ; i < melt_columns; i++)
1171 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1173 ypos[i] = ypos[i - 1] + r;
1186 time_last = time_current;
1187 time_current = SDL_GetTicks();
1188 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1189 steps_final = MIN(MAX(0, steps), max_steps);
1193 done = (steps_done >= steps_final);
1195 for (i = 0 ; i < melt_columns; i++)
1203 else if (ypos[i] < height)
1208 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1210 if (ypos[i] + dy >= height)
1211 dy = height - ypos[i];
1213 /* copy part of (appearing) target surface to upper area */
1214 src_rect.x = src_x + i * melt_pixels;
1215 // src_rect.y = src_y + ypos[i];
1217 src_rect.w = melt_pixels;
1219 src_rect.h = ypos[i] + dy;
1221 dst_rect.x = dst_x + i * melt_pixels;
1222 // dst_rect.y = dst_y + ypos[i];
1225 if (steps_done >= steps_final)
1226 SDL_BlitSurface(surface_target, &src_rect,
1227 surface_screen, &dst_rect);
1231 /* copy part of (disappearing) source surface to lower area */
1232 src_rect.x = src_x + i * melt_pixels;
1234 src_rect.w = melt_pixels;
1235 src_rect.h = height - ypos[i];
1237 dst_rect.x = dst_x + i * melt_pixels;
1238 dst_rect.y = dst_y + ypos[i];
1240 if (steps_done >= steps_final)
1241 SDL_BlitSurface(surface_source, &src_rect,
1242 surface_screen, &dst_rect);
1248 src_rect.x = src_x + i * melt_pixels;
1250 src_rect.w = melt_pixels;
1251 src_rect.h = height;
1253 dst_rect.x = dst_x + i * melt_pixels;
1256 if (steps_done >= steps_final)
1257 SDL_BlitSurface(surface_target, &src_rect,
1258 surface_screen, &dst_rect);
1262 if (steps_done >= steps_final)
1264 if (draw_border_function != NULL)
1265 draw_border_function();
1267 UpdateScreen_WithFrameDelay(&dst_rect2);
1271 else if (fade_mode == FADE_MODE_CURTAIN)
1275 int xx_size = width / 2;
1277 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1279 SDLSetAlpha(surface_source, FALSE, 0); /* disable alpha blending */
1281 for (xx = 0; xx < xx_size;)
1283 time_last = time_current;
1284 time_current = SDL_GetTicks();
1285 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1286 xx_final = MIN(MAX(0, xx), xx_size);
1291 src_rect.h = height;
1296 /* draw new (target) image to screen buffer */
1297 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1299 if (xx_final < xx_size)
1301 src_rect.w = xx_size - xx_final;
1302 src_rect.h = height;
1304 /* draw old (source) image to screen buffer (left side) */
1306 src_rect.x = src_x + xx_final;
1309 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1311 /* draw old (source) image to screen buffer (right side) */
1313 src_rect.x = src_x + xx_size;
1314 dst_rect.x = dst_x + xx_size + xx_final;
1316 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1319 if (draw_border_function != NULL)
1320 draw_border_function();
1322 /* only update the region of the screen that is affected from fading */
1323 UpdateScreen_WithFrameDelay(&dst_rect2);
1326 else /* fading in, fading out or cross-fading */
1331 for (alpha = 0.0; alpha < 255.0;)
1333 time_last = time_current;
1334 time_current = SDL_GetTicks();
1335 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1336 alpha_final = MIN(MAX(0, alpha), 255);
1338 /* draw existing (source) image to screen buffer */
1339 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1341 /* draw new (target) image to screen buffer using alpha blending */
1342 SDLSetAlpha(surface_target, TRUE, alpha_final);
1343 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1345 if (draw_border_function != NULL)
1346 draw_border_function();
1348 /* only update the region of the screen that is affected from fading */
1349 UpdateScreen_WithFrameDelay(&dst_rect);
1355 unsigned int time_post_delay;
1357 time_current = SDL_GetTicks();
1358 time_post_delay = time_current + post_delay;
1360 while (time_current < time_post_delay)
1362 // updating the screen contains waiting for frame delay (non-busy)
1363 UpdateScreen_WithFrameDelay(NULL);
1365 time_current = SDL_GetTicks();
1369 // restore function for drawing global masked border
1370 gfx.draw_global_border_function = draw_global_border_function;
1372 // after fading in, restore backbuffer (without animation graphics)
1373 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
1374 SDL_BlitSurface(surface_backup, &dst_rect, surface_screen, &src_rect);
1377 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1378 int to_x, int to_y, Uint32 color)
1380 SDL_Surface *surface = dst_bitmap->surface;
1384 swap_numbers(&from_x, &to_x);
1387 swap_numbers(&from_y, &to_y);
1391 rect.w = (to_x - from_x + 1);
1392 rect.h = (to_y - from_y + 1);
1394 SDL_FillRect(surface, &rect, color);
1397 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1398 int to_x, int to_y, Uint32 color)
1400 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1403 #if ENABLE_UNUSED_CODE
1404 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1405 int num_points, Uint32 color)
1410 for (i = 0; i < num_points - 1; i++)
1412 for (x = 0; x < line_width; x++)
1414 for (y = 0; y < line_width; y++)
1416 int dx = x - line_width / 2;
1417 int dy = y - line_width / 2;
1419 if ((x == 0 && y == 0) ||
1420 (x == 0 && y == line_width - 1) ||
1421 (x == line_width - 1 && y == 0) ||
1422 (x == line_width - 1 && y == line_width - 1))
1425 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1426 points[i+1].x + dx, points[i+1].y + dy, color);
1433 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1435 SDL_Surface *surface = src_bitmap->surface;
1437 switch (surface->format->BytesPerPixel)
1439 case 1: /* assuming 8-bpp */
1441 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1445 case 2: /* probably 15-bpp or 16-bpp */
1447 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1451 case 3: /* slow 24-bpp mode; usually not used */
1453 /* does this work? */
1454 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1458 shift = surface->format->Rshift;
1459 color |= *(pix + shift / 8) >> shift;
1460 shift = surface->format->Gshift;
1461 color |= *(pix + shift / 8) >> shift;
1462 shift = surface->format->Bshift;
1463 color |= *(pix + shift / 8) >> shift;
1469 case 4: /* probably 32-bpp */
1471 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1480 /* ========================================================================= */
1481 /* The following functions were taken from the SGE library */
1482 /* (SDL Graphics Extension Library) by Anders Lindström */
1483 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1484 /* ========================================================================= */
1486 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1488 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1490 switch (surface->format->BytesPerPixel)
1494 /* Assuming 8-bpp */
1495 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1501 /* Probably 15-bpp or 16-bpp */
1502 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1508 /* Slow 24-bpp mode, usually not used */
1512 /* Gack - slow, but endian correct */
1513 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1514 shift = surface->format->Rshift;
1515 *(pix+shift/8) = color>>shift;
1516 shift = surface->format->Gshift;
1517 *(pix+shift/8) = color>>shift;
1518 shift = surface->format->Bshift;
1519 *(pix+shift/8) = color>>shift;
1525 /* Probably 32-bpp */
1526 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1533 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1534 Uint8 R, Uint8 G, Uint8 B)
1536 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1539 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1541 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1544 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1546 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1549 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1554 /* Gack - slow, but endian correct */
1555 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1556 shift = surface->format->Rshift;
1557 *(pix+shift/8) = color>>shift;
1558 shift = surface->format->Gshift;
1559 *(pix+shift/8) = color>>shift;
1560 shift = surface->format->Bshift;
1561 *(pix+shift/8) = color>>shift;
1564 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1566 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1569 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1571 switch (dest->format->BytesPerPixel)
1574 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1578 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1582 _PutPixel24(dest,x,y,color);
1586 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1591 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1593 if (SDL_MUSTLOCK(surface))
1595 if (SDL_LockSurface(surface) < 0)
1601 _PutPixel(surface, x, y, color);
1603 if (SDL_MUSTLOCK(surface))
1605 SDL_UnlockSurface(surface);
1609 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1610 Uint8 r, Uint8 g, Uint8 b)
1612 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1615 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1617 if (y >= 0 && y <= dest->h - 1)
1619 switch (dest->format->BytesPerPixel)
1622 return y*dest->pitch;
1626 return y*dest->pitch/2;
1630 return y*dest->pitch;
1634 return y*dest->pitch/4;
1642 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1644 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1646 switch (surface->format->BytesPerPixel)
1650 /* Assuming 8-bpp */
1651 *((Uint8 *)surface->pixels + ypitch + x) = color;
1657 /* Probably 15-bpp or 16-bpp */
1658 *((Uint16 *)surface->pixels + ypitch + x) = color;
1664 /* Slow 24-bpp mode, usually not used */
1668 /* Gack - slow, but endian correct */
1669 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1670 shift = surface->format->Rshift;
1671 *(pix+shift/8) = color>>shift;
1672 shift = surface->format->Gshift;
1673 *(pix+shift/8) = color>>shift;
1674 shift = surface->format->Bshift;
1675 *(pix+shift/8) = color>>shift;
1681 /* Probably 32-bpp */
1682 *((Uint32 *)surface->pixels + ypitch + x) = color;
1689 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1694 if (SDL_MUSTLOCK(Surface))
1696 if (SDL_LockSurface(Surface) < 0)
1709 /* Do the clipping */
1710 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1714 if (x2 > Surface->w - 1)
1715 x2 = Surface->w - 1;
1722 SDL_FillRect(Surface, &l, Color);
1724 if (SDL_MUSTLOCK(Surface))
1726 SDL_UnlockSurface(Surface);
1730 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1731 Uint8 R, Uint8 G, Uint8 B)
1733 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1736 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1747 /* Do the clipping */
1748 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1752 if (x2 > Surface->w - 1)
1753 x2 = Surface->w - 1;
1760 SDL_FillRect(Surface, &l, Color);
1763 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1768 if (SDL_MUSTLOCK(Surface))
1770 if (SDL_LockSurface(Surface) < 0)
1783 /* Do the clipping */
1784 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1788 if (y2 > Surface->h - 1)
1789 y2 = Surface->h - 1;
1796 SDL_FillRect(Surface, &l, Color);
1798 if (SDL_MUSTLOCK(Surface))
1800 SDL_UnlockSurface(Surface);
1804 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1805 Uint8 R, Uint8 G, Uint8 B)
1807 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1810 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1821 /* Do the clipping */
1822 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1826 if (y2 > Surface->h - 1)
1827 y2 = Surface->h - 1;
1834 SDL_FillRect(Surface, &l, Color);
1837 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1838 Sint16 x2, Sint16 y2, Uint32 Color,
1839 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1842 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1847 sdx = (dx < 0) ? -1 : 1;
1848 sdy = (dy < 0) ? -1 : 1;
1860 for (x = 0; x < dx; x++)
1862 Callback(Surface, px, py, Color);
1876 for (y = 0; y < dy; y++)
1878 Callback(Surface, px, py, Color);
1892 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1893 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1894 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1897 sge_DoLine(Surface, X1, Y1, X2, Y2,
1898 SDL_MapRGB(Surface->format, R, G, B), Callback);
1901 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1904 if (SDL_MUSTLOCK(Surface))
1906 if (SDL_LockSurface(Surface) < 0)
1911 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1913 /* unlock the display */
1914 if (SDL_MUSTLOCK(Surface))
1916 SDL_UnlockSurface(Surface);
1920 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1921 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1923 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1926 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1928 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1933 -----------------------------------------------------------------------------
1934 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1935 -----------------------------------------------------------------------------
1938 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1939 int width, int height, Uint32 color)
1943 for (y = src_y; y < src_y + height; y++)
1945 for (x = src_x; x < src_x + width; x++)
1947 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1949 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1954 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1955 int src_x, int src_y, int width, int height,
1956 int dst_x, int dst_y)
1960 for (y = 0; y < height; y++)
1962 for (x = 0; x < width; x++)
1964 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1966 if (pixel != BLACK_PIXEL)
1967 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1973 /* ========================================================================= */
1974 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1975 /* (Rotozoomer) by Andreas Schiffler */
1976 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1977 /* ========================================================================= */
1980 -----------------------------------------------------------------------------
1983 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1984 -----------------------------------------------------------------------------
1995 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1998 tColorRGBA *sp, *csp, *dp;
2002 sp = csp = (tColorRGBA *) src->pixels;
2003 dp = (tColorRGBA *) dst->pixels;
2004 dgap = dst->pitch - dst->w * 4;
2006 for (y = 0; y < dst->h; y++)
2010 for (x = 0; x < dst->w; x++)
2012 tColorRGBA *sp0 = sp;
2013 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
2014 tColorRGBA *sp00 = &sp0[0];
2015 tColorRGBA *sp01 = &sp0[1];
2016 tColorRGBA *sp10 = &sp1[0];
2017 tColorRGBA *sp11 = &sp1[1];
2020 /* create new color pixel from all four source color pixels */
2021 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2022 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2023 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2024 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2029 /* advance source pointers */
2032 /* advance destination pointer */
2036 /* advance source pointer */
2037 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2039 /* advance destination pointers */
2040 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2046 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2048 int x, y, *sax, *say, *csax, *csay;
2050 tColorRGBA *sp, *csp, *csp0, *dp;
2053 /* use specialized zoom function when scaling down to exactly half size */
2054 if (src->w == 2 * dst->w &&
2055 src->h == 2 * dst->h)
2056 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2058 /* variable setup */
2059 sx = (float) src->w / (float) dst->w;
2060 sy = (float) src->h / (float) dst->h;
2062 /* allocate memory for row increments */
2063 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2064 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2066 /* precalculate row increments */
2067 for (x = 0; x <= dst->w; x++)
2068 *csax++ = (int)(sx * x);
2070 for (y = 0; y <= dst->h; y++)
2071 *csay++ = (int)(sy * y);
2074 sp = csp = csp0 = (tColorRGBA *) src->pixels;
2075 dp = (tColorRGBA *) dst->pixels;
2076 dgap = dst->pitch - dst->w * 4;
2079 for (y = 0; y < dst->h; y++)
2084 for (x = 0; x < dst->w; x++)
2089 /* advance source pointers */
2093 /* advance destination pointer */
2097 /* advance source pointer */
2099 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
2101 /* advance destination pointers */
2102 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2112 -----------------------------------------------------------------------------
2115 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2116 -----------------------------------------------------------------------------
2119 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2121 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2122 Uint8 *sp, *dp, *csp;
2125 /* variable setup */
2126 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2127 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2129 /* allocate memory for row increments */
2130 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2131 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2133 /* precalculate row increments */
2136 for (x = 0; x < dst->w; x++)
2139 *csax = (csx >> 16);
2146 for (y = 0; y < dst->h; y++)
2149 *csay = (csy >> 16);
2156 for (x = 0; x < dst->w; x++)
2164 for (y = 0; y < dst->h; y++)
2171 sp = csp = (Uint8 *) src->pixels;
2172 dp = (Uint8 *) dst->pixels;
2173 dgap = dst->pitch - dst->w;
2177 for (y = 0; y < dst->h; y++)
2181 for (x = 0; x < dst->w; x++)
2186 /* advance source pointers */
2190 /* advance destination pointer */
2194 /* advance source pointer (for row) */
2195 csp += ((*csay) * src->pitch);
2198 /* advance destination pointers */
2209 -----------------------------------------------------------------------------
2212 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2213 'zoomx' and 'zoomy' are scaling factors for width and height.
2214 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2215 into a 32bit RGBA format on the fly.
2216 -----------------------------------------------------------------------------
2219 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2221 SDL_Surface *zoom_src = NULL;
2222 SDL_Surface *zoom_dst = NULL;
2223 boolean is_converted = FALSE;
2230 /* determine if source surface is 32 bit or 8 bit */
2231 is_32bit = (src->format->BitsPerPixel == 32);
2233 if (is_32bit || src->format->BitsPerPixel == 8)
2235 /* use source surface 'as is' */
2240 /* new source surface is 32 bit with a defined RGB ordering */
2241 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2242 0x000000ff, 0x0000ff00, 0x00ff0000,
2243 (src->format->Amask ? 0xff000000 : 0));
2244 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2246 is_converted = TRUE;
2249 /* allocate surface to completely contain the zoomed surface */
2252 /* target surface is 32 bit with source RGBA/ABGR ordering */
2253 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2254 zoom_src->format->Rmask,
2255 zoom_src->format->Gmask,
2256 zoom_src->format->Bmask,
2257 zoom_src->format->Amask);
2261 /* target surface is 8 bit */
2262 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2266 /* lock source surface */
2267 SDL_LockSurface(zoom_src);
2269 /* check which kind of surface we have */
2272 /* call the 32 bit transformation routine to do the zooming */
2273 zoomSurfaceRGBA(zoom_src, zoom_dst);
2278 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2279 zoom_dst->format->palette->colors[i] =
2280 zoom_src->format->palette->colors[i];
2281 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2283 /* call the 8 bit transformation routine to do the zooming */
2284 zoomSurfaceY(zoom_src, zoom_dst);
2287 /* unlock source surface */
2288 SDL_UnlockSurface(zoom_src);
2290 /* free temporary surface */
2292 SDL_FreeSurface(zoom_src);
2294 /* return destination surface */
2298 static SDL_Surface *SDLGetOpaqueSurface(SDL_Surface *surface)
2300 SDL_Surface *new_surface;
2302 if (surface == NULL)
2305 if ((new_surface = SDLGetNativeSurface(surface)) == NULL)
2306 Error(ERR_EXIT, "SDLGetNativeSurface() failed");
2308 /* remove alpha channel from native non-transparent surface, if defined */
2309 SDLSetAlpha(new_surface, FALSE, 0);
2311 /* remove transparent color from native non-transparent surface, if defined */
2312 SDL_SetColorKey(new_surface, UNSET_TRANSPARENT_PIXEL, 0);
2317 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2319 Bitmap *dst_bitmap = CreateBitmapStruct();
2320 SDL_Surface *src_surface = src_bitmap->surface_masked;
2321 SDL_Surface *dst_surface;
2323 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2324 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2326 dst_bitmap->width = dst_width;
2327 dst_bitmap->height = dst_height;
2329 /* create zoomed temporary surface from source surface */
2330 dst_surface = zoomSurface(src_surface, dst_width, dst_height);
2332 /* create native format destination surface from zoomed temporary surface */
2333 SDLSetNativeSurface(&dst_surface);
2335 /* set color key for zoomed surface from source surface, if defined */
2336 if (SDLHasColorKey(src_surface))
2337 SDL_SetColorKey(dst_surface, SET_TRANSPARENT_PIXEL,
2338 SDLGetColorKey(src_surface));
2340 /* create native non-transparent surface for opaque blitting */
2341 dst_bitmap->surface = SDLGetOpaqueSurface(dst_surface);
2343 /* set native transparent surface for masked blitting */
2344 dst_bitmap->surface_masked = dst_surface;
2350 /* ========================================================================= */
2351 /* load image to bitmap */
2352 /* ========================================================================= */
2354 Bitmap *SDLLoadImage(char *filename)
2356 Bitmap *new_bitmap = CreateBitmapStruct();
2357 SDL_Surface *sdl_image_tmp;
2359 print_timestamp_init("SDLLoadImage");
2361 print_timestamp_time(getBaseNamePtr(filename));
2363 /* load image to temporary surface */
2364 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2365 Error(ERR_EXIT, "IMG_Load() failed: %s", SDL_GetError());
2367 print_timestamp_time("IMG_Load");
2369 UPDATE_BUSY_STATE();
2371 /* create native non-transparent surface for current image */
2372 if ((new_bitmap->surface = SDLGetOpaqueSurface(sdl_image_tmp)) == NULL)
2373 Error(ERR_EXIT, "SDLGetOpaqueSurface() failed");
2375 print_timestamp_time("SDLGetNativeSurface (opaque)");
2377 UPDATE_BUSY_STATE();
2379 /* set black pixel to transparent if no alpha channel / transparent color */
2380 if (!SDLHasAlpha(sdl_image_tmp) &&
2381 !SDLHasColorKey(sdl_image_tmp))
2382 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2383 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2385 /* create native transparent surface for current image */
2386 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2387 Error(ERR_EXIT, "SDLGetNativeSurface() failed");
2389 print_timestamp_time("SDLGetNativeSurface (masked)");
2391 UPDATE_BUSY_STATE();
2393 /* free temporary surface */
2394 SDL_FreeSurface(sdl_image_tmp);
2396 new_bitmap->width = new_bitmap->surface->w;
2397 new_bitmap->height = new_bitmap->surface->h;
2399 print_timestamp_done("SDLLoadImage");
2405 /* ------------------------------------------------------------------------- */
2406 /* custom cursor fuctions */
2407 /* ------------------------------------------------------------------------- */
2409 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2411 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2412 cursor_info->width, cursor_info->height,
2413 cursor_info->hot_x, cursor_info->hot_y);
2416 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2418 static struct MouseCursorInfo *last_cursor_info = NULL;
2419 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2420 static SDL_Cursor *cursor_default = NULL;
2421 static SDL_Cursor *cursor_current = NULL;
2423 /* if invoked for the first time, store the SDL default cursor */
2424 if (cursor_default == NULL)
2425 cursor_default = SDL_GetCursor();
2427 /* only create new cursor if cursor info (custom only) has changed */
2428 if (cursor_info != NULL && cursor_info != last_cursor_info)
2430 cursor_current = create_cursor(cursor_info);
2431 last_cursor_info = cursor_info;
2434 /* only set new cursor if cursor info (custom or NULL) has changed */
2435 if (cursor_info != last_cursor_info2)
2436 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2438 last_cursor_info2 = cursor_info;
2442 /* ========================================================================= */
2443 /* audio functions */
2444 /* ========================================================================= */
2446 void SDLOpenAudio(void)
2448 #if !defined(TARGET_SDL2)
2449 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2450 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2453 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2455 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2459 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2460 AUDIO_NUM_CHANNELS_STEREO,
2461 setup.system.audio_fragment_size) < 0)
2463 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2467 audio.sound_available = TRUE;
2468 audio.music_available = TRUE;
2469 audio.loops_available = TRUE;
2470 audio.sound_enabled = TRUE;
2472 /* set number of available mixer channels */
2473 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2474 audio.music_channel = MUSIC_CHANNEL;
2475 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2477 Mixer_InitChannels();
2480 void SDLCloseAudio(void)
2483 Mix_HaltChannel(-1);
2486 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2490 /* ========================================================================= */
2491 /* event functions */
2492 /* ========================================================================= */
2494 void SDLNextEvent(Event *event)
2496 SDL_WaitEvent(event);
2499 void SDLHandleWindowManagerEvent(Event *event)
2502 #if defined(PLATFORM_WIN32)
2503 // experimental drag and drop code
2505 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2506 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2508 #if defined(TARGET_SDL2)
2509 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2511 if (syswmmsg->msg == WM_DROPFILES)
2514 #if defined(TARGET_SDL2)
2515 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2517 HDROP hdrop = (HDROP)syswmmsg->wParam;
2521 printf("::: SDL_SYSWMEVENT:\n");
2523 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2525 for (i = 0; i < num_files; i++)
2527 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2528 char buffer[buffer_len + 1];
2530 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2532 printf("::: - '%s'\n", buffer);
2535 #if defined(TARGET_SDL2)
2536 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2538 DragFinish((HDROP)syswmmsg->wParam);
2546 /* ========================================================================= */
2547 /* joystick functions */
2548 /* ========================================================================= */
2550 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2551 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2552 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2554 static boolean SDLOpenJoystick(int nr)
2556 if (nr < 0 || nr > MAX_PLAYERS)
2559 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2562 static void SDLCloseJoystick(int nr)
2564 if (nr < 0 || nr > MAX_PLAYERS)
2567 SDL_JoystickClose(sdl_joystick[nr]);
2569 sdl_joystick[nr] = NULL;
2572 static boolean SDLCheckJoystickOpened(int nr)
2574 if (nr < 0 || nr > MAX_PLAYERS)
2577 #if defined(TARGET_SDL2)
2578 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2580 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2584 void HandleJoystickEvent(Event *event)
2588 case SDL_JOYAXISMOTION:
2589 if (event->jaxis.axis < 2)
2590 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2593 case SDL_JOYBUTTONDOWN:
2594 if (event->jbutton.button < 2)
2595 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2598 case SDL_JOYBUTTONUP:
2599 if (event->jbutton.button < 2)
2600 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2608 void SDLInitJoysticks()
2610 static boolean sdl_joystick_subsystem_initialized = FALSE;
2611 boolean print_warning = !sdl_joystick_subsystem_initialized;
2614 if (!sdl_joystick_subsystem_initialized)
2616 sdl_joystick_subsystem_initialized = TRUE;
2618 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2620 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2625 for (i = 0; i < MAX_PLAYERS; i++)
2627 /* get configured joystick for this player */
2628 char *device_name = setup.input[i].joy.device_name;
2629 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2631 if (joystick_nr >= SDL_NumJoysticks())
2633 if (setup.input[i].use_joystick && print_warning)
2634 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2639 /* misuse joystick file descriptor variable to store joystick number */
2640 joystick.fd[i] = joystick_nr;
2642 if (joystick_nr == -1)
2645 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2646 if (SDLCheckJoystickOpened(joystick_nr))
2647 SDLCloseJoystick(joystick_nr);
2649 if (!setup.input[i].use_joystick)
2652 if (!SDLOpenJoystick(joystick_nr))
2655 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2660 joystick.status = JOYSTICK_ACTIVATED;
2664 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2666 if (nr < 0 || nr >= MAX_PLAYERS)
2670 *x = sdl_js_axis[nr][0];
2672 *y = sdl_js_axis[nr][1];
2675 *b1 = sdl_js_button[nr][0];
2677 *b2 = sdl_js_button[nr][1];