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()
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_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_BORDER_TO_SCREEN);
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_GLOBAL_ANIM_STAGE_2);
60 static void UpdateScreen(SDL_Rect *rect)
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);
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 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET)
110 sdl_texture = sdl_texture_target;
114 int bytes_x = screen->pitch / video.width;
115 int bytes_y = screen->pitch;
117 SDL_UpdateTexture(sdl_texture, rect,
118 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
123 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
126 // clear render target buffer
127 SDL_RenderClear(sdl_renderer);
129 // set renderer to use target texture for rendering
130 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
131 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
132 SDL_SetRenderTarget(sdl_renderer, sdl_texture_target);
134 // copy backbuffer texture to render target buffer
135 if (video.screen_rendering_mode != SPECIAL_RENDERING_TARGET)
136 SDL_RenderCopy(sdl_renderer, sdl_texture_stream, NULL, NULL);
138 if (video.screen_rendering_mode != SPECIAL_RENDERING_BITMAP)
141 // when using target texture, copy it to screen buffer
142 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
143 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
145 SDL_SetRenderTarget(sdl_renderer, NULL);
146 SDL_RenderCopy(sdl_renderer, sdl_texture_target, NULL, NULL);
150 // global synchronization point of the game to align video frame delay
151 WaitUntilDelayReached(&video.frame_delay, video.frame_delay_value);
153 #if defined(TARGET_SDL2)
154 // show render target buffer on screen
155 SDL_RenderPresent(sdl_renderer);
158 SDL_UpdateRects(screen, 1, rect);
160 SDL_UpdateRect(screen, 0, 0, 0, 0);
164 static void SDLSetWindowIcon(char *basename)
166 /* (setting the window icon on Mac OS X would replace the high-quality
167 dock icon with the currently smaller (and uglier) icon from file) */
169 #if !defined(PLATFORM_MACOSX)
170 char *filename = getCustomImageFilename(basename);
171 SDL_Surface *surface;
173 if (filename == NULL)
175 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
180 if ((surface = IMG_Load(filename)) == NULL)
182 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
187 /* set transparent color */
188 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
189 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
191 #if defined(TARGET_SDL2)
192 SDL_SetWindowIcon(sdl_window, surface);
194 SDL_WM_SetIcon(surface, NULL);
199 #if defined(TARGET_SDL2)
201 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
202 SDL_PixelFormat *format2)
204 return (format1->format == format2->format &&
205 format1->BitsPerPixel == format2->BitsPerPixel &&
206 format1->BytesPerPixel == format2->BytesPerPixel &&
207 format1->Rmask == format2->Rmask &&
208 format1->Gmask == format2->Gmask &&
209 format1->Bmask == format2->Bmask &&
210 format1->Amask == format2->Amask);
213 boolean SDLSetNativeSurface(SDL_Surface **surface)
215 SDL_Surface *new_surface;
217 if (surface == NULL ||
219 backbuffer == NULL ||
220 backbuffer->surface == NULL)
223 // if pixel format already optimized for destination surface, do nothing
224 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
227 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
229 if (new_surface == NULL)
230 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
232 SDL_FreeSurface(*surface);
234 *surface = new_surface;
239 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
241 SDL_PixelFormat format;
242 SDL_Surface *new_surface;
247 if (backbuffer && backbuffer->surface)
249 format = *backbuffer->surface->format;
250 format.Amask = surface->format->Amask; // keep alpha channel
254 format = *surface->format;
257 new_surface = SDL_ConvertSurface(surface, &format, 0);
259 if (new_surface == NULL)
260 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
267 boolean SDLSetNativeSurface(SDL_Surface **surface)
269 SDL_Surface *new_surface;
271 if (surface == NULL ||
276 new_surface = SDL_DisplayFormat(*surface);
278 if (new_surface == NULL)
279 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
281 SDL_FreeSurface(*surface);
283 *surface = new_surface;
288 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
290 SDL_Surface *new_surface;
292 if (video.initialized)
293 new_surface = SDL_DisplayFormat(surface);
295 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
297 if (new_surface == NULL)
298 Error(ERR_EXIT, "%s() failed: %s",
299 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
307 #if defined(TARGET_SDL2)
308 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
310 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
313 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
320 void SDLCreateBitmapTextures(Bitmap *bitmap)
322 #if defined(TARGET_SDL2)
327 SDL_DestroyTexture(bitmap->texture);
328 if (bitmap->texture_masked)
329 SDL_DestroyTexture(bitmap->texture_masked);
331 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
332 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
336 void SDLFreeBitmapTextures(Bitmap *bitmap)
338 #if defined(TARGET_SDL2)
343 SDL_DestroyTexture(bitmap->texture);
344 if (bitmap->texture_masked)
345 SDL_DestroyTexture(bitmap->texture_masked);
347 bitmap->texture = NULL;
348 bitmap->texture_masked = NULL;
352 void SDLInitVideoDisplay(void)
354 #if !defined(TARGET_SDL2)
355 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
356 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
358 SDL_putenv("SDL_VIDEO_CENTERED=1");
361 /* initialize SDL video */
362 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
363 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
365 /* set default SDL depth */
366 #if !defined(TARGET_SDL2)
367 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
369 video.default_depth = 32; // (how to determine video depth in SDL2?)
373 void SDLInitVideoBuffer(boolean fullscreen)
375 video.window_scaling_percent = setup.window_scaling_percent;
376 video.window_scaling_quality = setup.window_scaling_quality;
377 video.screen_rendering_mode =
378 (strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
379 SPECIAL_RENDERING_BITMAP :
380 strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
381 SPECIAL_RENDERING_TARGET:
382 strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
383 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
385 #if defined(TARGET_SDL2)
386 // SDL 2.0: support for (desktop) fullscreen mode available
387 video.fullscreen_available = TRUE;
389 // SDL 1.2: no support for fullscreen mode in R'n'D anymore
390 video.fullscreen_available = FALSE;
393 /* open SDL video output device (window or fullscreen mode) */
394 if (!SDLSetVideoMode(fullscreen))
395 Error(ERR_EXIT, "setting video mode failed");
397 /* !!! SDL2 can only set the window icon if the window already exists !!! */
398 /* set window icon */
399 SDLSetWindowIcon(program.icon_filename);
401 /* set window and icon title */
402 #if defined(TARGET_SDL2)
403 SDL_SetWindowTitle(sdl_window, program.window_title);
405 SDL_WM_SetCaption(program.window_title, program.window_title);
408 /* SDL cannot directly draw to the visible video framebuffer like X11,
409 but always uses a backbuffer, which is then blitted to the visible
410 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
411 visible video framebuffer with 'SDL_Flip', if the hardware supports
412 this). Therefore do not use an additional backbuffer for drawing, but
413 use a symbolic buffer (distinguishable from the SDL backbuffer) called
414 'window', which indicates that the SDL backbuffer should be updated to
415 the visible video framebuffer when attempting to blit to it.
417 For convenience, it seems to be a good idea to create this symbolic
418 buffer 'window' at the same size as the SDL backbuffer. Although it
419 should never be drawn to directly, it would do no harm nevertheless. */
421 /* create additional (symbolic) buffer for double-buffering */
422 ReCreateBitmap(&window, video.width, video.height, video.depth);
425 static boolean SDLCreateScreen(boolean fullscreen)
427 SDL_Surface *new_surface = NULL;
429 #if defined(TARGET_SDL2)
430 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
431 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
433 int surface_flags_window = SURFACE_FLAGS;
434 int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2)
437 int width = video.width;
438 int height = video.height;
439 int surface_flags = (fullscreen ? surface_flags_fullscreen :
440 surface_flags_window);
442 // default window size is unscaled
443 video.window_width = video.width;
444 video.window_height = video.height;
446 #if defined(TARGET_SDL2)
448 // store if initial screen mode is fullscreen mode when changing screen size
449 video.fullscreen_initial = fullscreen;
451 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
453 video.window_width = window_scaling_factor * width;
454 video.window_height = window_scaling_factor * height;
456 if (sdl_texture_stream)
458 SDL_DestroyTexture(sdl_texture_stream);
459 sdl_texture_stream = NULL;
462 if (sdl_texture_target)
464 SDL_DestroyTexture(sdl_texture_target);
465 sdl_texture_target = NULL;
468 if (!(fullscreen && fullscreen_enabled))
472 SDL_DestroyRenderer(sdl_renderer);
478 SDL_DestroyWindow(sdl_window);
483 if (sdl_window == NULL)
484 sdl_window = SDL_CreateWindow(program.window_title,
485 SDL_WINDOWPOS_CENTERED,
486 SDL_WINDOWPOS_CENTERED,
491 if (sdl_window != NULL)
494 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
495 *without* enabling 2D/3D acceleration and/or guest additions installed,
496 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
497 it will try to use accelerated graphics and apparently fails miserably) */
498 if (sdl_renderer == NULL)
499 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
501 if (sdl_renderer == NULL)
502 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
505 if (sdl_renderer != NULL)
507 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
508 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
509 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
511 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
512 SDL_PIXELFORMAT_ARGB8888,
513 SDL_TEXTUREACCESS_STREAMING,
516 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
517 SDL_PIXELFORMAT_ARGB8888,
518 SDL_TEXTUREACCESS_TARGET,
521 if (sdl_texture_stream != NULL &&
522 sdl_texture_target != NULL)
524 // use SDL default values for RGB masks and no alpha channel
525 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
527 if (new_surface == NULL)
528 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
532 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
537 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
542 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
547 if (gfx.final_screen_bitmap == NULL)
548 gfx.final_screen_bitmap = CreateBitmapStruct();
550 gfx.final_screen_bitmap->width = width;
551 gfx.final_screen_bitmap->height = height;
553 gfx.final_screen_bitmap->surface =
554 SDL_SetVideoMode(width, height, video.depth, surface_flags);
556 if (gfx.final_screen_bitmap->surface != NULL)
559 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
561 if (new_surface == NULL)
562 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
565 new_surface = gfx.final_screen_bitmap->surface;
566 gfx.final_screen_bitmap = NULL;
572 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
576 #if defined(TARGET_SDL2)
577 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
578 if (new_surface != NULL)
579 fullscreen_enabled = fullscreen;
582 if (backbuffer == NULL)
583 backbuffer = CreateBitmapStruct();
585 backbuffer->width = video.width;
586 backbuffer->height = video.height;
588 if (backbuffer->surface)
589 SDL_FreeSurface(backbuffer->surface);
591 backbuffer->surface = new_surface;
593 return (new_surface != NULL);
596 boolean SDLSetVideoMode(boolean fullscreen)
598 boolean success = FALSE;
602 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
604 /* switch display to fullscreen mode, if available */
605 success = SDLCreateScreen(TRUE);
609 /* switching display to fullscreen mode failed -- do not try it again */
610 video.fullscreen_available = FALSE;
614 video.fullscreen_enabled = TRUE;
618 if ((!fullscreen && video.fullscreen_enabled) || !success)
620 /* switch display to window mode */
621 success = SDLCreateScreen(FALSE);
625 /* switching display to window mode failed -- should not happen */
629 video.fullscreen_enabled = FALSE;
630 video.window_scaling_percent = setup.window_scaling_percent;
631 video.window_scaling_quality = setup.window_scaling_quality;
632 video.screen_rendering_mode =
633 (strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
634 SPECIAL_RENDERING_BITMAP :
635 strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
636 SPECIAL_RENDERING_TARGET:
637 strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
638 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
642 #if defined(TARGET_SDL2)
643 SDLRedrawWindow(); // map window
647 #if defined(PLATFORM_WIN32)
648 // experimental drag and drop code
650 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
653 SDL_SysWMinfo wminfo;
655 boolean wminfo_success = FALSE;
657 SDL_VERSION(&wminfo.version);
658 #if defined(TARGET_SDL2)
660 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
662 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
667 #if defined(TARGET_SDL2)
668 hwnd = wminfo.info.win.window;
670 hwnd = wminfo.window;
673 DragAcceptFiles(hwnd, TRUE);
682 void SDLSetWindowTitle()
684 #if defined(TARGET_SDL2)
685 SDL_SetWindowTitle(sdl_window, program.window_title);
687 SDL_WM_SetCaption(program.window_title, program.window_title);
691 #if defined(TARGET_SDL2)
692 void SDLSetWindowScaling(int window_scaling_percent)
694 if (sdl_window == NULL)
697 float window_scaling_factor = (float)window_scaling_percent / 100;
698 int new_window_width = (int)(window_scaling_factor * video.width);
699 int new_window_height = (int)(window_scaling_factor * video.height);
701 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
703 video.window_scaling_percent = window_scaling_percent;
704 video.window_width = new_window_width;
705 video.window_height = new_window_height;
710 void SDLSetWindowScalingQuality(char *window_scaling_quality)
712 SDL_Texture *new_texture;
714 if (sdl_texture_stream == NULL ||
715 sdl_texture_target == NULL)
718 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
720 new_texture = SDL_CreateTexture(sdl_renderer,
721 SDL_PIXELFORMAT_ARGB8888,
722 SDL_TEXTUREACCESS_STREAMING,
723 video.width, video.height);
725 if (new_texture != NULL)
727 SDL_DestroyTexture(sdl_texture_stream);
729 sdl_texture_stream = new_texture;
732 new_texture = SDL_CreateTexture(sdl_renderer,
733 SDL_PIXELFORMAT_ARGB8888,
734 SDL_TEXTUREACCESS_TARGET,
735 video.width, video.height);
737 if (new_texture != NULL)
739 SDL_DestroyTexture(sdl_texture_target);
741 sdl_texture_target = new_texture;
746 video.window_scaling_quality = window_scaling_quality;
749 void SDLSetScreenRenderingMode(char *screen_rendering_mode)
751 video.screen_rendering_mode =
752 (strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
753 SPECIAL_RENDERING_BITMAP :
754 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
755 SPECIAL_RENDERING_TARGET:
756 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
757 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
760 void SDLSetWindowFullscreen(boolean fullscreen)
762 if (sdl_window == NULL)
765 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
767 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
768 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
770 // if screen size was changed in fullscreen mode, correct desktop window size
771 if (!fullscreen && video.fullscreen_initial)
773 SDLSetWindowScaling(setup.window_scaling_percent);
774 SDL_SetWindowPosition(sdl_window,
775 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
777 video.fullscreen_initial = FALSE;
781 void SDLRedrawWindow()
787 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
790 SDL_Surface *surface =
791 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
794 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
796 SDLSetNativeSurface(&surface);
798 bitmap->surface = surface;
801 void SDLFreeBitmapPointers(Bitmap *bitmap)
804 SDL_FreeSurface(bitmap->surface);
805 if (bitmap->surface_masked)
806 SDL_FreeSurface(bitmap->surface_masked);
808 bitmap->surface = NULL;
809 bitmap->surface_masked = NULL;
811 #if defined(TARGET_SDL2)
813 SDL_DestroyTexture(bitmap->texture);
814 if (bitmap->texture_masked)
815 SDL_DestroyTexture(bitmap->texture_masked);
817 bitmap->texture = NULL;
818 bitmap->texture_masked = NULL;
822 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
823 int src_x, int src_y, int width, int height,
824 int dst_x, int dst_y, int mask_mode)
826 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
827 SDL_Rect src_rect, dst_rect;
839 // if (src_bitmap != backbuffer || dst_bitmap != window)
840 if (!(src_bitmap == backbuffer && dst_bitmap == window))
841 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
842 src_bitmap->surface_masked : src_bitmap->surface),
843 &src_rect, real_dst_bitmap->surface, &dst_rect);
845 if (dst_bitmap == window)
846 UpdateScreen(&dst_rect);
849 void SDLBlitTexture(Bitmap *bitmap,
850 int src_x, int src_y, int width, int height,
851 int dst_x, int dst_y, int mask_mode)
853 #if defined(TARGET_SDL2)
854 SDL_Texture *texture;
859 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
874 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
878 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
881 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
889 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
891 if (dst_bitmap == window)
895 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
896 int fade_mode, int fade_delay, int post_delay,
897 void (*draw_border_function)(void))
899 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
900 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
901 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
902 SDL_Surface *surface_screen = backbuffer->surface;
903 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
904 SDL_Rect src_rect, dst_rect;
906 int src_x = x, src_y = y;
907 int dst_x = x, dst_y = y;
908 unsigned int time_last, time_current;
910 // store function for drawing global masked border
911 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
913 // deactivate drawing of global border while fading, if needed
914 if (draw_border_function == NULL)
915 gfx.draw_global_border_function = NULL;
924 dst_rect.w = width; /* (ignored) */
925 dst_rect.h = height; /* (ignored) */
927 dst_rect2 = dst_rect;
929 /* copy source and target surfaces to temporary surfaces for fading */
930 if (fade_mode & FADE_TYPE_TRANSFORM)
932 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
933 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
935 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
936 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
938 else if (fade_mode & FADE_TYPE_FADE_IN)
940 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
941 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
943 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
945 else /* FADE_TYPE_FADE_OUT */
947 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
948 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
950 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
953 time_current = SDL_GetTicks();
955 if (fade_mode == FADE_MODE_MELT)
957 boolean done = FALSE;
959 int melt_columns = width / melt_pixels;
960 int ypos[melt_columns];
961 int max_steps = height / 8 + 32;
966 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
967 #if defined(TARGET_SDL2)
968 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
970 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
973 ypos[0] = -GetSimpleRandom(16);
975 for (i = 1 ; i < melt_columns; i++)
977 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
979 ypos[i] = ypos[i - 1] + r;
992 time_last = time_current;
993 time_current = SDL_GetTicks();
994 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
995 steps_final = MIN(MAX(0, steps), max_steps);
999 done = (steps_done >= steps_final);
1001 for (i = 0 ; i < melt_columns; i++)
1009 else if (ypos[i] < height)
1014 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1016 if (ypos[i] + dy >= height)
1017 dy = height - ypos[i];
1019 /* copy part of (appearing) target surface to upper area */
1020 src_rect.x = src_x + i * melt_pixels;
1021 // src_rect.y = src_y + ypos[i];
1023 src_rect.w = melt_pixels;
1025 src_rect.h = ypos[i] + dy;
1027 dst_rect.x = dst_x + i * melt_pixels;
1028 // dst_rect.y = dst_y + ypos[i];
1031 if (steps_done >= steps_final)
1032 SDL_BlitSurface(surface_target, &src_rect,
1033 surface_screen, &dst_rect);
1037 /* copy part of (disappearing) source surface to lower area */
1038 src_rect.x = src_x + i * melt_pixels;
1040 src_rect.w = melt_pixels;
1041 src_rect.h = height - ypos[i];
1043 dst_rect.x = dst_x + i * melt_pixels;
1044 dst_rect.y = dst_y + ypos[i];
1046 if (steps_done >= steps_final)
1047 SDL_BlitSurface(surface_source, &src_rect,
1048 surface_screen, &dst_rect);
1054 src_rect.x = src_x + i * melt_pixels;
1056 src_rect.w = melt_pixels;
1057 src_rect.h = height;
1059 dst_rect.x = dst_x + i * melt_pixels;
1062 if (steps_done >= steps_final)
1063 SDL_BlitSurface(surface_target, &src_rect,
1064 surface_screen, &dst_rect);
1068 if (steps_done >= steps_final)
1070 if (draw_border_function != NULL)
1071 draw_border_function();
1073 UpdateScreen(&dst_rect2);
1077 else if (fade_mode == FADE_MODE_CURTAIN)
1081 int xx_size = width / 2;
1083 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1084 #if defined(TARGET_SDL2)
1085 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1087 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1090 for (xx = 0; xx < xx_size;)
1092 time_last = time_current;
1093 time_current = SDL_GetTicks();
1094 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1095 xx_final = MIN(MAX(0, xx), xx_size);
1100 src_rect.h = height;
1105 /* draw new (target) image to screen buffer */
1106 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1108 if (xx_final < xx_size)
1110 src_rect.w = xx_size - xx_final;
1111 src_rect.h = height;
1113 /* draw old (source) image to screen buffer (left side) */
1115 src_rect.x = src_x + xx_final;
1118 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1120 /* draw old (source) image to screen buffer (right side) */
1122 src_rect.x = src_x + xx_size;
1123 dst_rect.x = dst_x + xx_size + xx_final;
1125 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1128 if (draw_border_function != NULL)
1129 draw_border_function();
1131 /* only update the region of the screen that is affected from fading */
1132 UpdateScreen(&dst_rect2);
1135 else /* fading in, fading out or cross-fading */
1140 for (alpha = 0.0; alpha < 255.0;)
1142 time_last = time_current;
1143 time_current = SDL_GetTicks();
1144 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1145 alpha_final = MIN(MAX(0, alpha), 255);
1147 /* draw existing (source) image to screen buffer */
1148 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1150 /* draw new (target) image to screen buffer using alpha blending */
1151 #if defined(TARGET_SDL2)
1152 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1153 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1155 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1157 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1159 if (draw_border_function != NULL)
1160 draw_border_function();
1162 /* only update the region of the screen that is affected from fading */
1163 UpdateScreen(&dst_rect);
1169 unsigned int time_post_delay;
1171 time_current = SDL_GetTicks();
1172 time_post_delay = time_current + post_delay;
1174 while (time_current < time_post_delay)
1176 // updating the screen contains waiting for frame delay (non-busy)
1179 time_current = SDL_GetTicks();
1183 // restore function for drawing global masked border
1184 gfx.draw_global_border_function = draw_global_border_function;
1187 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1188 int to_x, int to_y, Uint32 color)
1190 SDL_Surface *surface = dst_bitmap->surface;
1194 swap_numbers(&from_x, &to_x);
1197 swap_numbers(&from_y, &to_y);
1201 rect.w = (to_x - from_x + 1);
1202 rect.h = (to_y - from_y + 1);
1204 SDL_FillRect(surface, &rect, color);
1207 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1208 int to_x, int to_y, Uint32 color)
1210 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1213 #if ENABLE_UNUSED_CODE
1214 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1215 int num_points, Uint32 color)
1220 for (i = 0; i < num_points - 1; i++)
1222 for (x = 0; x < line_width; x++)
1224 for (y = 0; y < line_width; y++)
1226 int dx = x - line_width / 2;
1227 int dy = y - line_width / 2;
1229 if ((x == 0 && y == 0) ||
1230 (x == 0 && y == line_width - 1) ||
1231 (x == line_width - 1 && y == 0) ||
1232 (x == line_width - 1 && y == line_width - 1))
1235 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1236 points[i+1].x + dx, points[i+1].y + dy, color);
1243 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1245 SDL_Surface *surface = src_bitmap->surface;
1247 switch (surface->format->BytesPerPixel)
1249 case 1: /* assuming 8-bpp */
1251 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1255 case 2: /* probably 15-bpp or 16-bpp */
1257 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1261 case 3: /* slow 24-bpp mode; usually not used */
1263 /* does this work? */
1264 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1268 shift = surface->format->Rshift;
1269 color |= *(pix + shift / 8) >> shift;
1270 shift = surface->format->Gshift;
1271 color |= *(pix + shift / 8) >> shift;
1272 shift = surface->format->Bshift;
1273 color |= *(pix + shift / 8) >> shift;
1279 case 4: /* probably 32-bpp */
1281 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1290 /* ========================================================================= */
1291 /* The following functions were taken from the SGE library */
1292 /* (SDL Graphics Extension Library) by Anders Lindström */
1293 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1294 /* ========================================================================= */
1296 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1298 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1300 switch (surface->format->BytesPerPixel)
1304 /* Assuming 8-bpp */
1305 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1311 /* Probably 15-bpp or 16-bpp */
1312 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1318 /* Slow 24-bpp mode, usually not used */
1322 /* Gack - slow, but endian correct */
1323 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1324 shift = surface->format->Rshift;
1325 *(pix+shift/8) = color>>shift;
1326 shift = surface->format->Gshift;
1327 *(pix+shift/8) = color>>shift;
1328 shift = surface->format->Bshift;
1329 *(pix+shift/8) = color>>shift;
1335 /* Probably 32-bpp */
1336 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1343 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1344 Uint8 R, Uint8 G, Uint8 B)
1346 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1349 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1351 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1354 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1356 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1359 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1364 /* Gack - slow, but endian correct */
1365 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1366 shift = surface->format->Rshift;
1367 *(pix+shift/8) = color>>shift;
1368 shift = surface->format->Gshift;
1369 *(pix+shift/8) = color>>shift;
1370 shift = surface->format->Bshift;
1371 *(pix+shift/8) = color>>shift;
1374 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1376 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1379 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1381 switch (dest->format->BytesPerPixel)
1384 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1388 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1392 _PutPixel24(dest,x,y,color);
1396 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1401 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1403 if (SDL_MUSTLOCK(surface))
1405 if (SDL_LockSurface(surface) < 0)
1411 _PutPixel(surface, x, y, color);
1413 if (SDL_MUSTLOCK(surface))
1415 SDL_UnlockSurface(surface);
1419 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1420 Uint8 r, Uint8 g, Uint8 b)
1422 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1425 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1427 if (y >= 0 && y <= dest->h - 1)
1429 switch (dest->format->BytesPerPixel)
1432 return y*dest->pitch;
1436 return y*dest->pitch/2;
1440 return y*dest->pitch;
1444 return y*dest->pitch/4;
1452 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1454 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1456 switch (surface->format->BytesPerPixel)
1460 /* Assuming 8-bpp */
1461 *((Uint8 *)surface->pixels + ypitch + x) = color;
1467 /* Probably 15-bpp or 16-bpp */
1468 *((Uint16 *)surface->pixels + ypitch + x) = color;
1474 /* Slow 24-bpp mode, usually not used */
1478 /* Gack - slow, but endian correct */
1479 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1480 shift = surface->format->Rshift;
1481 *(pix+shift/8) = color>>shift;
1482 shift = surface->format->Gshift;
1483 *(pix+shift/8) = color>>shift;
1484 shift = surface->format->Bshift;
1485 *(pix+shift/8) = color>>shift;
1491 /* Probably 32-bpp */
1492 *((Uint32 *)surface->pixels + ypitch + x) = color;
1499 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1504 if (SDL_MUSTLOCK(Surface))
1506 if (SDL_LockSurface(Surface) < 0)
1519 /* Do the clipping */
1520 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1524 if (x2 > Surface->w - 1)
1525 x2 = Surface->w - 1;
1532 SDL_FillRect(Surface, &l, Color);
1534 if (SDL_MUSTLOCK(Surface))
1536 SDL_UnlockSurface(Surface);
1540 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1541 Uint8 R, Uint8 G, Uint8 B)
1543 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1546 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1557 /* Do the clipping */
1558 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1562 if (x2 > Surface->w - 1)
1563 x2 = Surface->w - 1;
1570 SDL_FillRect(Surface, &l, Color);
1573 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1578 if (SDL_MUSTLOCK(Surface))
1580 if (SDL_LockSurface(Surface) < 0)
1593 /* Do the clipping */
1594 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1598 if (y2 > Surface->h - 1)
1599 y2 = Surface->h - 1;
1606 SDL_FillRect(Surface, &l, Color);
1608 if (SDL_MUSTLOCK(Surface))
1610 SDL_UnlockSurface(Surface);
1614 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1615 Uint8 R, Uint8 G, Uint8 B)
1617 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1620 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1631 /* Do the clipping */
1632 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1636 if (y2 > Surface->h - 1)
1637 y2 = Surface->h - 1;
1644 SDL_FillRect(Surface, &l, Color);
1647 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1648 Sint16 x2, Sint16 y2, Uint32 Color,
1649 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1652 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1657 sdx = (dx < 0) ? -1 : 1;
1658 sdy = (dy < 0) ? -1 : 1;
1670 for (x = 0; x < dx; x++)
1672 Callback(Surface, px, py, Color);
1686 for (y = 0; y < dy; y++)
1688 Callback(Surface, px, py, Color);
1702 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1703 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1704 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1707 sge_DoLine(Surface, X1, Y1, X2, Y2,
1708 SDL_MapRGB(Surface->format, R, G, B), Callback);
1711 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1714 if (SDL_MUSTLOCK(Surface))
1716 if (SDL_LockSurface(Surface) < 0)
1721 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1723 /* unlock the display */
1724 if (SDL_MUSTLOCK(Surface))
1726 SDL_UnlockSurface(Surface);
1730 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1731 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1733 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1736 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1738 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1743 -----------------------------------------------------------------------------
1744 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1745 -----------------------------------------------------------------------------
1748 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1749 int width, int height, Uint32 color)
1753 for (y = src_y; y < src_y + height; y++)
1755 for (x = src_x; x < src_x + width; x++)
1757 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1759 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1764 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1765 int src_x, int src_y, int width, int height,
1766 int dst_x, int dst_y)
1770 for (y = 0; y < height; y++)
1772 for (x = 0; x < width; x++)
1774 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1776 if (pixel != BLACK_PIXEL)
1777 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1783 /* ========================================================================= */
1784 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1785 /* (Rotozoomer) by Andreas Schiffler */
1786 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1787 /* ========================================================================= */
1790 -----------------------------------------------------------------------------
1793 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1794 -----------------------------------------------------------------------------
1805 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1808 tColorRGBA *sp, *csp, *dp;
1812 sp = csp = (tColorRGBA *) src->pixels;
1813 dp = (tColorRGBA *) dst->pixels;
1814 dgap = dst->pitch - dst->w * 4;
1816 for (y = 0; y < dst->h; y++)
1820 for (x = 0; x < dst->w; x++)
1822 tColorRGBA *sp0 = sp;
1823 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1824 tColorRGBA *sp00 = &sp0[0];
1825 tColorRGBA *sp01 = &sp0[1];
1826 tColorRGBA *sp10 = &sp1[0];
1827 tColorRGBA *sp11 = &sp1[1];
1830 /* create new color pixel from all four source color pixels */
1831 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1832 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1833 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1834 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1839 /* advance source pointers */
1842 /* advance destination pointer */
1846 /* advance source pointer */
1847 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1849 /* advance destination pointers */
1850 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1856 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1858 int x, y, *sax, *say, *csax, *csay;
1860 tColorRGBA *sp, *csp, *csp0, *dp;
1863 /* use specialized zoom function when scaling down to exactly half size */
1864 if (src->w == 2 * dst->w &&
1865 src->h == 2 * dst->h)
1866 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1868 /* variable setup */
1869 sx = (float) src->w / (float) dst->w;
1870 sy = (float) src->h / (float) dst->h;
1872 /* allocate memory for row increments */
1873 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1874 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1876 /* precalculate row increments */
1877 for (x = 0; x <= dst->w; x++)
1878 *csax++ = (int)(sx * x);
1880 for (y = 0; y <= dst->h; y++)
1881 *csay++ = (int)(sy * y);
1884 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1885 dp = (tColorRGBA *) dst->pixels;
1886 dgap = dst->pitch - dst->w * 4;
1889 for (y = 0; y < dst->h; y++)
1894 for (x = 0; x < dst->w; x++)
1899 /* advance source pointers */
1903 /* advance destination pointer */
1907 /* advance source pointer */
1909 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1911 /* advance destination pointers */
1912 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1922 -----------------------------------------------------------------------------
1925 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1926 -----------------------------------------------------------------------------
1929 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1931 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1932 Uint8 *sp, *dp, *csp;
1935 /* variable setup */
1936 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1937 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1939 /* allocate memory for row increments */
1940 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1941 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1943 /* precalculate row increments */
1946 for (x = 0; x < dst->w; x++)
1949 *csax = (csx >> 16);
1956 for (y = 0; y < dst->h; y++)
1959 *csay = (csy >> 16);
1966 for (x = 0; x < dst->w; x++)
1974 for (y = 0; y < dst->h; y++)
1981 sp = csp = (Uint8 *) src->pixels;
1982 dp = (Uint8 *) dst->pixels;
1983 dgap = dst->pitch - dst->w;
1987 for (y = 0; y < dst->h; y++)
1991 for (x = 0; x < dst->w; x++)
1996 /* advance source pointers */
2000 /* advance destination pointer */
2004 /* advance source pointer (for row) */
2005 csp += ((*csay) * src->pitch);
2008 /* advance destination pointers */
2019 -----------------------------------------------------------------------------
2022 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2023 'zoomx' and 'zoomy' are scaling factors for width and height.
2024 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2025 into a 32bit RGBA format on the fly.
2026 -----------------------------------------------------------------------------
2029 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2031 SDL_Surface *zoom_src = NULL;
2032 SDL_Surface *zoom_dst = NULL;
2033 boolean is_converted = FALSE;
2040 /* determine if source surface is 32 bit or 8 bit */
2041 is_32bit = (src->format->BitsPerPixel == 32);
2043 if (is_32bit || src->format->BitsPerPixel == 8)
2045 /* use source surface 'as is' */
2050 /* new source surface is 32 bit with a defined RGB ordering */
2051 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2052 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2053 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2055 is_converted = TRUE;
2058 /* allocate surface to completely contain the zoomed surface */
2061 /* target surface is 32 bit with source RGBA/ABGR ordering */
2062 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2063 zoom_src->format->Rmask,
2064 zoom_src->format->Gmask,
2065 zoom_src->format->Bmask, 0);
2069 /* target surface is 8 bit */
2070 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2074 /* lock source surface */
2075 SDL_LockSurface(zoom_src);
2077 /* check which kind of surface we have */
2080 /* call the 32 bit transformation routine to do the zooming */
2081 zoomSurfaceRGBA(zoom_src, zoom_dst);
2086 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2087 zoom_dst->format->palette->colors[i] =
2088 zoom_src->format->palette->colors[i];
2089 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2091 /* call the 8 bit transformation routine to do the zooming */
2092 zoomSurfaceY(zoom_src, zoom_dst);
2095 /* unlock source surface */
2096 SDL_UnlockSurface(zoom_src);
2098 /* free temporary surface */
2100 SDL_FreeSurface(zoom_src);
2102 /* return destination surface */
2106 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2108 Bitmap *dst_bitmap = CreateBitmapStruct();
2109 SDL_Surface **dst_surface = &dst_bitmap->surface;
2111 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2112 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2114 dst_bitmap->width = dst_width;
2115 dst_bitmap->height = dst_height;
2117 /* create zoomed temporary surface from source surface */
2118 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2120 /* create native format destination surface from zoomed temporary surface */
2121 SDLSetNativeSurface(dst_surface);
2127 /* ========================================================================= */
2128 /* load image to bitmap */
2129 /* ========================================================================= */
2131 Bitmap *SDLLoadImage(char *filename)
2133 Bitmap *new_bitmap = CreateBitmapStruct();
2134 SDL_Surface *sdl_image_tmp;
2136 print_timestamp_init("SDLLoadImage");
2138 print_timestamp_time(getBaseNamePtr(filename));
2140 /* load image to temporary surface */
2141 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2143 SetError("IMG_Load(): %s", SDL_GetError());
2148 print_timestamp_time("IMG_Load");
2150 UPDATE_BUSY_STATE();
2152 /* create native non-transparent surface for current image */
2153 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2155 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2160 print_timestamp_time("SDL_DisplayFormat (opaque)");
2162 UPDATE_BUSY_STATE();
2164 /* create native transparent surface for current image */
2165 if (sdl_image_tmp->format->Amask == 0)
2166 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2167 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2169 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2171 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2176 print_timestamp_time("SDL_DisplayFormat (masked)");
2178 UPDATE_BUSY_STATE();
2180 /* free temporary surface */
2181 SDL_FreeSurface(sdl_image_tmp);
2183 new_bitmap->width = new_bitmap->surface->w;
2184 new_bitmap->height = new_bitmap->surface->h;
2186 print_timestamp_done("SDLLoadImage");
2192 /* ------------------------------------------------------------------------- */
2193 /* custom cursor fuctions */
2194 /* ------------------------------------------------------------------------- */
2196 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2198 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2199 cursor_info->width, cursor_info->height,
2200 cursor_info->hot_x, cursor_info->hot_y);
2203 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2205 static struct MouseCursorInfo *last_cursor_info = NULL;
2206 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2207 static SDL_Cursor *cursor_default = NULL;
2208 static SDL_Cursor *cursor_current = NULL;
2210 /* if invoked for the first time, store the SDL default cursor */
2211 if (cursor_default == NULL)
2212 cursor_default = SDL_GetCursor();
2214 /* only create new cursor if cursor info (custom only) has changed */
2215 if (cursor_info != NULL && cursor_info != last_cursor_info)
2217 cursor_current = create_cursor(cursor_info);
2218 last_cursor_info = cursor_info;
2221 /* only set new cursor if cursor info (custom or NULL) has changed */
2222 if (cursor_info != last_cursor_info2)
2223 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2225 last_cursor_info2 = cursor_info;
2229 /* ========================================================================= */
2230 /* audio functions */
2231 /* ========================================================================= */
2233 void SDLOpenAudio(void)
2235 #if !defined(TARGET_SDL2)
2236 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2237 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2240 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2242 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2246 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2247 AUDIO_NUM_CHANNELS_STEREO,
2248 setup.system.audio_fragment_size) < 0)
2250 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2254 audio.sound_available = TRUE;
2255 audio.music_available = TRUE;
2256 audio.loops_available = TRUE;
2257 audio.sound_enabled = TRUE;
2259 /* set number of available mixer channels */
2260 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2261 audio.music_channel = MUSIC_CHANNEL;
2262 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2264 Mixer_InitChannels();
2267 void SDLCloseAudio(void)
2270 Mix_HaltChannel(-1);
2273 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2277 /* ========================================================================= */
2278 /* event functions */
2279 /* ========================================================================= */
2281 void SDLNextEvent(Event *event)
2283 SDL_WaitEvent(event);
2286 void SDLHandleWindowManagerEvent(Event *event)
2289 #if defined(PLATFORM_WIN32)
2290 // experimental drag and drop code
2292 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2293 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2295 #if defined(TARGET_SDL2)
2296 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2298 if (syswmmsg->msg == WM_DROPFILES)
2301 #if defined(TARGET_SDL2)
2302 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2304 HDROP hdrop = (HDROP)syswmmsg->wParam;
2308 printf("::: SDL_SYSWMEVENT:\n");
2310 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2312 for (i = 0; i < num_files; i++)
2314 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2315 char buffer[buffer_len + 1];
2317 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2319 printf("::: - '%s'\n", buffer);
2322 #if defined(TARGET_SDL2)
2323 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2325 DragFinish((HDROP)syswmmsg->wParam);
2333 /* ========================================================================= */
2334 /* joystick functions */
2335 /* ========================================================================= */
2337 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2338 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2339 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2341 static boolean SDLOpenJoystick(int nr)
2343 if (nr < 0 || nr > MAX_PLAYERS)
2346 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2349 static void SDLCloseJoystick(int nr)
2351 if (nr < 0 || nr > MAX_PLAYERS)
2354 SDL_JoystickClose(sdl_joystick[nr]);
2356 sdl_joystick[nr] = NULL;
2359 static boolean SDLCheckJoystickOpened(int nr)
2361 if (nr < 0 || nr > MAX_PLAYERS)
2364 #if defined(TARGET_SDL2)
2365 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2367 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2371 void HandleJoystickEvent(Event *event)
2375 case SDL_JOYAXISMOTION:
2376 if (event->jaxis.axis < 2)
2377 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2380 case SDL_JOYBUTTONDOWN:
2381 if (event->jbutton.button < 2)
2382 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2385 case SDL_JOYBUTTONUP:
2386 if (event->jbutton.button < 2)
2387 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2395 void SDLInitJoysticks()
2397 static boolean sdl_joystick_subsystem_initialized = FALSE;
2398 boolean print_warning = !sdl_joystick_subsystem_initialized;
2401 if (!sdl_joystick_subsystem_initialized)
2403 sdl_joystick_subsystem_initialized = TRUE;
2405 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2407 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2412 for (i = 0; i < MAX_PLAYERS; i++)
2414 /* get configured joystick for this player */
2415 char *device_name = setup.input[i].joy.device_name;
2416 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2418 if (joystick_nr >= SDL_NumJoysticks())
2420 if (setup.input[i].use_joystick && print_warning)
2421 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2426 /* misuse joystick file descriptor variable to store joystick number */
2427 joystick.fd[i] = joystick_nr;
2429 if (joystick_nr == -1)
2432 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2433 if (SDLCheckJoystickOpened(joystick_nr))
2434 SDLCloseJoystick(joystick_nr);
2436 if (!setup.input[i].use_joystick)
2439 if (!SDLOpenJoystick(joystick_nr))
2442 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2447 joystick.status = JOYSTICK_ACTIVATED;
2451 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2453 if (nr < 0 || nr >= MAX_PLAYERS)
2457 *x = sdl_js_axis[nr][0];
2459 *y = sdl_js_axis[nr][1];
2462 *b1 = sdl_js_button[nr][0];
2464 *b2 = sdl_js_button[nr][1];