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 #define USE_TARGET_TEXTURE TRUE
28 #define USE_TARGET_TEXTURE_ONLY FALSE
30 static SDL_Window *sdl_window = NULL;
31 static SDL_Renderer *sdl_renderer = NULL;
32 #if USE_TARGET_TEXTURE
33 static SDL_Texture *sdl_texture_stream = NULL;
34 static SDL_Texture *sdl_texture_target = NULL;
36 static SDL_Texture *sdl_texture = NULL;
38 static boolean fullscreen_enabled = FALSE;
41 static boolean limit_screen_updates = FALSE;
44 /* functions from SGE library */
45 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
47 void SDLLimitScreenUpdates(boolean enable)
49 limit_screen_updates = enable;
52 static void FinalizeScreen()
54 // copy global animations to render target buffer, if defined (below border)
55 if (gfx.draw_global_anim_function != NULL)
56 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
58 // copy global masked border to render target buffer, if defined
59 if (gfx.draw_global_border_function != NULL)
60 gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
62 // copy global animations to render target buffer, if defined (above border)
63 if (gfx.draw_global_anim_function != NULL)
64 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
67 static void UpdateScreen(SDL_Rect *rect)
69 static unsigned int update_screen_delay = 0;
70 unsigned int update_screen_delay_value = 50; /* (milliseconds) */
71 SDL_Surface *screen = backbuffer->surface;
73 if (limit_screen_updates &&
74 !DelayReached(&update_screen_delay, update_screen_delay_value))
77 LimitScreenUpdates(FALSE);
81 static int LastFrameCounter = 0;
82 boolean changed = (FrameCounter != LastFrameCounter);
84 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
85 (changed ? "-" : "SAME FRAME UPDATED"));
87 LastFrameCounter = FrameCounter;
96 #if USE_FINAL_SCREEN_BITMAP
97 if (gfx.final_screen_bitmap != NULL) // may not be initialized yet
100 // draw global animations using bitmaps instead of using textures
101 // to prevent texture scaling artefacts (this is potentially slower)
103 BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
104 gfx.win_xsize, gfx.win_ysize, 0, 0);
108 screen = gfx.final_screen_bitmap->surface;
110 // force full window redraw
115 #if USE_TARGET_TEXTURE
116 #if USE_TARGET_TEXTURE_ONLY
117 SDL_Texture *sdl_texture = sdl_texture_target;
119 SDL_Texture *sdl_texture = sdl_texture_stream;
123 #if defined(TARGET_SDL2)
126 int bytes_x = screen->pitch / video.width;
127 int bytes_y = screen->pitch;
129 SDL_UpdateTexture(sdl_texture, rect,
130 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
135 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
138 // clear render target buffer
139 SDL_RenderClear(sdl_renderer);
141 #if USE_TARGET_TEXTURE
142 SDL_SetRenderTarget(sdl_renderer, sdl_texture_target);
144 // copy backbuffer to render target buffer
145 if (sdl_texture != sdl_texture_target)
146 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
148 // copy backbuffer to render target buffer
149 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
152 #if !USE_FINAL_SCREEN_BITMAP
156 #if USE_TARGET_TEXTURE
157 SDL_SetRenderTarget(sdl_renderer, NULL);
158 SDL_RenderCopy(sdl_renderer, sdl_texture_target, NULL, NULL);
161 // show render target buffer on screen
162 SDL_RenderPresent(sdl_renderer);
166 SDL_UpdateRects(screen, 1, rect);
168 SDL_UpdateRect(screen, 0, 0, 0, 0);
172 static void SDLSetWindowIcon(char *basename)
174 /* (setting the window icon on Mac OS X would replace the high-quality
175 dock icon with the currently smaller (and uglier) icon from file) */
177 #if !defined(PLATFORM_MACOSX)
178 char *filename = getCustomImageFilename(basename);
179 SDL_Surface *surface;
181 if (filename == NULL)
183 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
188 if ((surface = IMG_Load(filename)) == NULL)
190 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
195 /* set transparent color */
196 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
197 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
199 #if defined(TARGET_SDL2)
200 SDL_SetWindowIcon(sdl_window, surface);
202 SDL_WM_SetIcon(surface, NULL);
207 #if defined(TARGET_SDL2)
209 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
210 SDL_PixelFormat *format2)
212 return (format1->format == format2->format &&
213 format1->BitsPerPixel == format2->BitsPerPixel &&
214 format1->BytesPerPixel == format2->BytesPerPixel &&
215 format1->Rmask == format2->Rmask &&
216 format1->Gmask == format2->Gmask &&
217 format1->Bmask == format2->Bmask &&
218 format1->Amask == format2->Amask);
221 boolean SDLSetNativeSurface(SDL_Surface **surface)
223 SDL_Surface *new_surface;
225 if (surface == NULL ||
227 backbuffer == NULL ||
228 backbuffer->surface == NULL)
231 // if pixel format already optimized for destination surface, do nothing
232 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
235 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
237 if (new_surface == NULL)
238 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
240 SDL_FreeSurface(*surface);
242 *surface = new_surface;
247 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
249 SDL_PixelFormat format;
250 SDL_Surface *new_surface;
255 if (backbuffer && backbuffer->surface)
257 format = *backbuffer->surface->format;
258 format.Amask = surface->format->Amask; // keep alpha channel
262 format = *surface->format;
265 new_surface = SDL_ConvertSurface(surface, &format, 0);
267 if (new_surface == NULL)
268 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
275 boolean SDLSetNativeSurface(SDL_Surface **surface)
277 SDL_Surface *new_surface;
279 if (surface == NULL ||
284 new_surface = SDL_DisplayFormat(*surface);
286 if (new_surface == NULL)
287 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
289 SDL_FreeSurface(*surface);
291 *surface = new_surface;
296 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
298 SDL_Surface *new_surface;
300 if (video.initialized)
301 new_surface = SDL_DisplayFormat(surface);
303 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
305 if (new_surface == NULL)
306 Error(ERR_EXIT, "%s() failed: %s",
307 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
315 #if defined(TARGET_SDL2)
316 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
318 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
321 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
328 void SDLCreateBitmapTextures(Bitmap *bitmap)
330 #if defined(TARGET_SDL2)
335 SDL_DestroyTexture(bitmap->texture);
336 if (bitmap->texture_masked)
337 SDL_DestroyTexture(bitmap->texture_masked);
339 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
340 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
344 void SDLFreeBitmapTextures(Bitmap *bitmap)
346 #if defined(TARGET_SDL2)
351 SDL_DestroyTexture(bitmap->texture);
352 if (bitmap->texture_masked)
353 SDL_DestroyTexture(bitmap->texture_masked);
355 bitmap->texture = NULL;
356 bitmap->texture_masked = NULL;
360 void SDLInitVideoDisplay(void)
362 #if !defined(TARGET_SDL2)
363 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
364 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
366 SDL_putenv("SDL_VIDEO_CENTERED=1");
369 /* initialize SDL video */
370 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
371 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
373 /* set default SDL depth */
374 #if !defined(TARGET_SDL2)
375 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
377 video.default_depth = 32; // (how to determine video depth in SDL2?)
381 void SDLInitVideoBuffer(boolean fullscreen)
383 video.window_scaling_percent = setup.window_scaling_percent;
384 video.window_scaling_quality = setup.window_scaling_quality;
386 #if defined(TARGET_SDL2)
387 // SDL 2.0: support for (desktop) fullscreen mode available
388 video.fullscreen_available = TRUE;
390 // SDL 1.2: no support for fullscreen mode in R'n'D anymore
391 video.fullscreen_available = FALSE;
394 /* open SDL video output device (window or fullscreen mode) */
395 if (!SDLSetVideoMode(fullscreen))
396 Error(ERR_EXIT, "setting video mode failed");
398 /* !!! SDL2 can only set the window icon if the window already exists !!! */
399 /* set window icon */
400 SDLSetWindowIcon(program.icon_filename);
402 /* set window and icon title */
403 #if defined(TARGET_SDL2)
404 SDL_SetWindowTitle(sdl_window, program.window_title);
406 SDL_WM_SetCaption(program.window_title, program.window_title);
409 /* SDL cannot directly draw to the visible video framebuffer like X11,
410 but always uses a backbuffer, which is then blitted to the visible
411 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
412 visible video framebuffer with 'SDL_Flip', if the hardware supports
413 this). Therefore do not use an additional backbuffer for drawing, but
414 use a symbolic buffer (distinguishable from the SDL backbuffer) called
415 'window', which indicates that the SDL backbuffer should be updated to
416 the visible video framebuffer when attempting to blit to it.
418 For convenience, it seems to be a good idea to create this symbolic
419 buffer 'window' at the same size as the SDL backbuffer. Although it
420 should never be drawn to directly, it would do no harm nevertheless. */
422 /* create additional (symbolic) buffer for double-buffering */
423 ReCreateBitmap(&window, video.width, video.height, video.depth);
426 static boolean SDLCreateScreen(boolean fullscreen)
428 SDL_Surface *new_surface = NULL;
430 #if defined(TARGET_SDL2)
431 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
432 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
434 int surface_flags_window = SURFACE_FLAGS;
435 int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2)
438 int width = video.width;
439 int height = video.height;
440 int surface_flags = (fullscreen ? surface_flags_fullscreen :
441 surface_flags_window);
443 // default window size is unscaled
444 video.window_width = video.width;
445 video.window_height = video.height;
447 #if defined(TARGET_SDL2)
449 // store if initial screen mode is fullscreen mode when changing screen size
450 video.fullscreen_initial = fullscreen;
452 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
454 video.window_width = window_scaling_factor * width;
455 video.window_height = window_scaling_factor * height;
457 #if USE_TARGET_TEXTURE
458 if (sdl_texture_stream)
460 SDL_DestroyTexture(sdl_texture_stream);
461 sdl_texture_stream = NULL;
464 if (sdl_texture_target)
466 SDL_DestroyTexture(sdl_texture_target);
467 sdl_texture_target = NULL;
472 SDL_DestroyTexture(sdl_texture);
477 if (!(fullscreen && fullscreen_enabled))
481 SDL_DestroyRenderer(sdl_renderer);
487 SDL_DestroyWindow(sdl_window);
492 if (sdl_window == NULL)
493 sdl_window = SDL_CreateWindow(program.window_title,
494 SDL_WINDOWPOS_CENTERED,
495 SDL_WINDOWPOS_CENTERED,
500 if (sdl_window != NULL)
503 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
504 *without* enabling 2D/3D acceleration and/or guest additions installed,
505 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
506 it will try to use accelerated graphics and apparently fails miserably) */
507 if (sdl_renderer == NULL)
508 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
510 if (sdl_renderer == NULL)
511 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
514 if (sdl_renderer != NULL)
516 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
517 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
518 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
520 #if USE_TARGET_TEXTURE
521 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
522 SDL_PIXELFORMAT_ARGB8888,
523 SDL_TEXTUREACCESS_STREAMING,
526 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
527 SDL_PIXELFORMAT_ARGB8888,
528 SDL_TEXTUREACCESS_TARGET,
531 sdl_texture = SDL_CreateTexture(sdl_renderer,
532 SDL_PIXELFORMAT_ARGB8888,
533 SDL_TEXTUREACCESS_STREAMING,
537 #if USE_TARGET_TEXTURE
538 if (sdl_texture_stream != NULL &&
539 sdl_texture_target != NULL)
541 if (sdl_texture != NULL)
544 // use SDL default values for RGB masks and no alpha channel
545 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
547 if (new_surface == NULL)
548 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
552 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
557 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
562 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
567 if (gfx.final_screen_bitmap == NULL)
568 gfx.final_screen_bitmap = CreateBitmapStruct();
570 gfx.final_screen_bitmap->width = width;
571 gfx.final_screen_bitmap->height = height;
573 gfx.final_screen_bitmap->surface =
574 SDL_SetVideoMode(width, height, video.depth, surface_flags);
576 if (gfx.final_screen_bitmap->surface != NULL)
579 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
581 if (new_surface == NULL)
582 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
585 new_surface = gfx.final_screen_bitmap->surface;
586 gfx.final_screen_bitmap = NULL;
592 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
596 #if defined(TARGET_SDL2)
597 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
598 if (new_surface != NULL)
599 fullscreen_enabled = fullscreen;
602 if (backbuffer == NULL)
603 backbuffer = CreateBitmapStruct();
605 backbuffer->width = video.width;
606 backbuffer->height = video.height;
608 if (backbuffer->surface)
609 SDL_FreeSurface(backbuffer->surface);
611 backbuffer->surface = new_surface;
613 return (new_surface != NULL);
616 boolean SDLSetVideoMode(boolean fullscreen)
618 boolean success = FALSE;
622 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
624 /* switch display to fullscreen mode, if available */
625 success = SDLCreateScreen(TRUE);
629 /* switching display to fullscreen mode failed -- do not try it again */
630 video.fullscreen_available = FALSE;
634 video.fullscreen_enabled = TRUE;
638 if ((!fullscreen && video.fullscreen_enabled) || !success)
640 /* switch display to window mode */
641 success = SDLCreateScreen(FALSE);
645 /* switching display to window mode failed -- should not happen */
649 video.fullscreen_enabled = FALSE;
650 video.window_scaling_percent = setup.window_scaling_percent;
651 video.window_scaling_quality = setup.window_scaling_quality;
655 #if defined(TARGET_SDL2)
656 SDLRedrawWindow(); // map window
660 #if defined(PLATFORM_WIN32)
661 // experimental drag and drop code
663 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
666 SDL_SysWMinfo wminfo;
668 boolean wminfo_success = FALSE;
670 SDL_VERSION(&wminfo.version);
671 #if defined(TARGET_SDL2)
673 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
675 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
680 #if defined(TARGET_SDL2)
681 hwnd = wminfo.info.win.window;
683 hwnd = wminfo.window;
686 DragAcceptFiles(hwnd, TRUE);
695 void SDLSetWindowTitle()
697 #if defined(TARGET_SDL2)
698 SDL_SetWindowTitle(sdl_window, program.window_title);
700 SDL_WM_SetCaption(program.window_title, program.window_title);
704 #if defined(TARGET_SDL2)
705 void SDLSetWindowScaling(int window_scaling_percent)
707 if (sdl_window == NULL)
710 float window_scaling_factor = (float)window_scaling_percent / 100;
711 int new_window_width = (int)(window_scaling_factor * video.width);
712 int new_window_height = (int)(window_scaling_factor * video.height);
714 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
716 video.window_scaling_percent = window_scaling_percent;
717 video.window_width = new_window_width;
718 video.window_height = new_window_height;
723 void SDLSetWindowScalingQuality(char *window_scaling_quality)
725 #if USE_TARGET_TEXTURE
726 SDL_Texture *new_texture;
728 if (sdl_texture_stream == NULL ||
729 sdl_texture_target == NULL)
732 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
734 new_texture = SDL_CreateTexture(sdl_renderer,
735 SDL_PIXELFORMAT_ARGB8888,
736 SDL_TEXTUREACCESS_STREAMING,
737 video.width, video.height);
739 if (new_texture != NULL)
741 SDL_DestroyTexture(sdl_texture_stream);
743 sdl_texture_stream = new_texture;
746 new_texture = SDL_CreateTexture(sdl_renderer,
747 SDL_PIXELFORMAT_ARGB8888,
748 SDL_TEXTUREACCESS_TARGET,
749 video.width, video.height);
751 if (new_texture != NULL)
753 SDL_DestroyTexture(sdl_texture_target);
755 sdl_texture_target = new_texture;
761 if (sdl_texture == NULL)
764 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
766 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
767 SDL_PIXELFORMAT_ARGB8888,
768 SDL_TEXTUREACCESS_STREAMING,
769 video.width, video.height);
771 if (new_texture != NULL)
773 SDL_DestroyTexture(sdl_texture);
775 sdl_texture = new_texture;
781 video.window_scaling_quality = window_scaling_quality;
784 void SDLSetWindowFullscreen(boolean fullscreen)
786 if (sdl_window == NULL)
789 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
791 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
792 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
794 // if screen size was changed in fullscreen mode, correct desktop window size
795 if (!fullscreen && video.fullscreen_initial)
797 SDLSetWindowScaling(setup.window_scaling_percent);
798 SDL_SetWindowPosition(sdl_window,
799 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
801 video.fullscreen_initial = FALSE;
805 void SDLRedrawWindow()
811 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
814 SDL_Surface *surface =
815 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
818 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
820 SDLSetNativeSurface(&surface);
822 bitmap->surface = surface;
825 void SDLFreeBitmapPointers(Bitmap *bitmap)
828 SDL_FreeSurface(bitmap->surface);
829 if (bitmap->surface_masked)
830 SDL_FreeSurface(bitmap->surface_masked);
832 bitmap->surface = NULL;
833 bitmap->surface_masked = NULL;
835 #if defined(TARGET_SDL2)
837 SDL_DestroyTexture(bitmap->texture);
838 if (bitmap->texture_masked)
839 SDL_DestroyTexture(bitmap->texture_masked);
841 bitmap->texture = NULL;
842 bitmap->texture_masked = NULL;
846 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
847 int src_x, int src_y, int width, int height,
848 int dst_x, int dst_y, int mask_mode)
850 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
851 SDL_Rect src_rect, dst_rect;
863 // if (src_bitmap != backbuffer || dst_bitmap != window)
864 if (!(src_bitmap == backbuffer && dst_bitmap == window))
865 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
866 src_bitmap->surface_masked : src_bitmap->surface),
867 &src_rect, real_dst_bitmap->surface, &dst_rect);
869 if (dst_bitmap == window)
870 UpdateScreen(&dst_rect);
873 void SDLBlitTexture(Bitmap *bitmap,
874 int src_x, int src_y, int width, int height,
875 int dst_x, int dst_y, int mask_mode)
877 #if defined(TARGET_SDL2)
878 SDL_Texture *texture;
883 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
898 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
902 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
905 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
913 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
915 if (dst_bitmap == window)
919 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
920 int fade_mode, int fade_delay, int post_delay,
921 void (*draw_border_function)(void))
923 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
924 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
925 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
926 SDL_Surface *surface_screen = backbuffer->surface;
927 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
928 SDL_Rect src_rect, dst_rect;
930 int src_x = x, src_y = y;
931 int dst_x = x, dst_y = y;
932 unsigned int time_last, time_current;
934 // store function for drawing global masked border
935 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
937 // deactivate drawing of global border while fading, if needed
938 if (draw_border_function == NULL)
939 gfx.draw_global_border_function = NULL;
948 dst_rect.w = width; /* (ignored) */
949 dst_rect.h = height; /* (ignored) */
951 dst_rect2 = dst_rect;
953 /* copy source and target surfaces to temporary surfaces for fading */
954 if (fade_mode & FADE_TYPE_TRANSFORM)
956 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
957 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
959 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
960 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
962 else if (fade_mode & FADE_TYPE_FADE_IN)
964 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
965 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
967 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
969 else /* FADE_TYPE_FADE_OUT */
971 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
972 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
974 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
977 time_current = SDL_GetTicks();
979 if (fade_mode == FADE_MODE_MELT)
981 boolean done = FALSE;
983 int melt_columns = width / melt_pixels;
984 int ypos[melt_columns];
985 int max_steps = height / 8 + 32;
990 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
991 #if defined(TARGET_SDL2)
992 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
994 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
997 ypos[0] = -GetSimpleRandom(16);
999 for (i = 1 ; i < melt_columns; i++)
1001 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1003 ypos[i] = ypos[i - 1] + r;
1016 time_last = time_current;
1017 time_current = SDL_GetTicks();
1018 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1019 steps_final = MIN(MAX(0, steps), max_steps);
1023 done = (steps_done >= steps_final);
1025 for (i = 0 ; i < melt_columns; i++)
1033 else if (ypos[i] < height)
1038 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1040 if (ypos[i] + dy >= height)
1041 dy = height - ypos[i];
1043 /* copy part of (appearing) target surface to upper area */
1044 src_rect.x = src_x + i * melt_pixels;
1045 // src_rect.y = src_y + ypos[i];
1047 src_rect.w = melt_pixels;
1049 src_rect.h = ypos[i] + dy;
1051 dst_rect.x = dst_x + i * melt_pixels;
1052 // dst_rect.y = dst_y + ypos[i];
1055 if (steps_done >= steps_final)
1056 SDL_BlitSurface(surface_target, &src_rect,
1057 surface_screen, &dst_rect);
1061 /* copy part of (disappearing) source surface to lower area */
1062 src_rect.x = src_x + i * melt_pixels;
1064 src_rect.w = melt_pixels;
1065 src_rect.h = height - ypos[i];
1067 dst_rect.x = dst_x + i * melt_pixels;
1068 dst_rect.y = dst_y + ypos[i];
1070 if (steps_done >= steps_final)
1071 SDL_BlitSurface(surface_source, &src_rect,
1072 surface_screen, &dst_rect);
1078 src_rect.x = src_x + i * melt_pixels;
1080 src_rect.w = melt_pixels;
1081 src_rect.h = height;
1083 dst_rect.x = dst_x + i * melt_pixels;
1086 if (steps_done >= steps_final)
1087 SDL_BlitSurface(surface_target, &src_rect,
1088 surface_screen, &dst_rect);
1092 if (steps_done >= steps_final)
1094 if (draw_border_function != NULL)
1095 draw_border_function();
1097 UpdateScreen(&dst_rect2);
1101 else if (fade_mode == FADE_MODE_CURTAIN)
1105 int xx_size = width / 2;
1107 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1108 #if defined(TARGET_SDL2)
1109 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1111 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1114 for (xx = 0; xx < xx_size;)
1116 time_last = time_current;
1117 time_current = SDL_GetTicks();
1118 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1119 xx_final = MIN(MAX(0, xx), xx_size);
1124 src_rect.h = height;
1129 /* draw new (target) image to screen buffer */
1130 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1132 if (xx_final < xx_size)
1134 src_rect.w = xx_size - xx_final;
1135 src_rect.h = height;
1137 /* draw old (source) image to screen buffer (left side) */
1139 src_rect.x = src_x + xx_final;
1142 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1144 /* draw old (source) image to screen buffer (right side) */
1146 src_rect.x = src_x + xx_size;
1147 dst_rect.x = dst_x + xx_size + xx_final;
1149 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1152 if (draw_border_function != NULL)
1153 draw_border_function();
1155 /* only update the region of the screen that is affected from fading */
1156 UpdateScreen(&dst_rect2);
1159 else /* fading in, fading out or cross-fading */
1164 for (alpha = 0.0; alpha < 255.0;)
1166 time_last = time_current;
1167 time_current = SDL_GetTicks();
1168 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1169 alpha_final = MIN(MAX(0, alpha), 255);
1171 /* draw existing (source) image to screen buffer */
1172 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1174 /* draw new (target) image to screen buffer using alpha blending */
1175 #if defined(TARGET_SDL2)
1176 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1177 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1179 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1181 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1183 if (draw_border_function != NULL)
1184 draw_border_function();
1186 /* only update the region of the screen that is affected from fading */
1187 UpdateScreen(&dst_rect);
1193 unsigned int time_post_delay;
1195 time_current = SDL_GetTicks();
1196 time_post_delay = time_current + post_delay;
1198 while (time_current < time_post_delay)
1200 // do not wait longer than 10 ms at a time to be able to ...
1201 Delay(MIN(10, time_post_delay - time_current));
1203 // ... continue drawing global animations during post delay
1206 time_current = SDL_GetTicks();
1210 // restore function for drawing global masked border
1211 gfx.draw_global_border_function = draw_global_border_function;
1214 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1215 int to_x, int to_y, Uint32 color)
1217 SDL_Surface *surface = dst_bitmap->surface;
1221 swap_numbers(&from_x, &to_x);
1224 swap_numbers(&from_y, &to_y);
1228 rect.w = (to_x - from_x + 1);
1229 rect.h = (to_y - from_y + 1);
1231 SDL_FillRect(surface, &rect, color);
1234 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1235 int to_x, int to_y, Uint32 color)
1237 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1240 #if ENABLE_UNUSED_CODE
1241 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1242 int num_points, Uint32 color)
1247 for (i = 0; i < num_points - 1; i++)
1249 for (x = 0; x < line_width; x++)
1251 for (y = 0; y < line_width; y++)
1253 int dx = x - line_width / 2;
1254 int dy = y - line_width / 2;
1256 if ((x == 0 && y == 0) ||
1257 (x == 0 && y == line_width - 1) ||
1258 (x == line_width - 1 && y == 0) ||
1259 (x == line_width - 1 && y == line_width - 1))
1262 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1263 points[i+1].x + dx, points[i+1].y + dy, color);
1270 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1272 SDL_Surface *surface = src_bitmap->surface;
1274 switch (surface->format->BytesPerPixel)
1276 case 1: /* assuming 8-bpp */
1278 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1282 case 2: /* probably 15-bpp or 16-bpp */
1284 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1288 case 3: /* slow 24-bpp mode; usually not used */
1290 /* does this work? */
1291 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1295 shift = surface->format->Rshift;
1296 color |= *(pix + shift / 8) >> shift;
1297 shift = surface->format->Gshift;
1298 color |= *(pix + shift / 8) >> shift;
1299 shift = surface->format->Bshift;
1300 color |= *(pix + shift / 8) >> shift;
1306 case 4: /* probably 32-bpp */
1308 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1317 /* ========================================================================= */
1318 /* The following functions were taken from the SGE library */
1319 /* (SDL Graphics Extension Library) by Anders Lindström */
1320 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1321 /* ========================================================================= */
1323 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1325 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1327 switch (surface->format->BytesPerPixel)
1331 /* Assuming 8-bpp */
1332 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1338 /* Probably 15-bpp or 16-bpp */
1339 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1345 /* Slow 24-bpp mode, usually not used */
1349 /* Gack - slow, but endian correct */
1350 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1351 shift = surface->format->Rshift;
1352 *(pix+shift/8) = color>>shift;
1353 shift = surface->format->Gshift;
1354 *(pix+shift/8) = color>>shift;
1355 shift = surface->format->Bshift;
1356 *(pix+shift/8) = color>>shift;
1362 /* Probably 32-bpp */
1363 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1370 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1371 Uint8 R, Uint8 G, Uint8 B)
1373 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1376 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1378 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1381 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1383 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1386 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1391 /* Gack - slow, but endian correct */
1392 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1393 shift = surface->format->Rshift;
1394 *(pix+shift/8) = color>>shift;
1395 shift = surface->format->Gshift;
1396 *(pix+shift/8) = color>>shift;
1397 shift = surface->format->Bshift;
1398 *(pix+shift/8) = color>>shift;
1401 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1403 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1406 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1408 switch (dest->format->BytesPerPixel)
1411 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1415 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1419 _PutPixel24(dest,x,y,color);
1423 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1428 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1430 if (SDL_MUSTLOCK(surface))
1432 if (SDL_LockSurface(surface) < 0)
1438 _PutPixel(surface, x, y, color);
1440 if (SDL_MUSTLOCK(surface))
1442 SDL_UnlockSurface(surface);
1446 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1447 Uint8 r, Uint8 g, Uint8 b)
1449 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1452 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1454 if (y >= 0 && y <= dest->h - 1)
1456 switch (dest->format->BytesPerPixel)
1459 return y*dest->pitch;
1463 return y*dest->pitch/2;
1467 return y*dest->pitch;
1471 return y*dest->pitch/4;
1479 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1481 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1483 switch (surface->format->BytesPerPixel)
1487 /* Assuming 8-bpp */
1488 *((Uint8 *)surface->pixels + ypitch + x) = color;
1494 /* Probably 15-bpp or 16-bpp */
1495 *((Uint16 *)surface->pixels + ypitch + x) = color;
1501 /* Slow 24-bpp mode, usually not used */
1505 /* Gack - slow, but endian correct */
1506 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1507 shift = surface->format->Rshift;
1508 *(pix+shift/8) = color>>shift;
1509 shift = surface->format->Gshift;
1510 *(pix+shift/8) = color>>shift;
1511 shift = surface->format->Bshift;
1512 *(pix+shift/8) = color>>shift;
1518 /* Probably 32-bpp */
1519 *((Uint32 *)surface->pixels + ypitch + x) = color;
1526 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1531 if (SDL_MUSTLOCK(Surface))
1533 if (SDL_LockSurface(Surface) < 0)
1546 /* Do the clipping */
1547 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1551 if (x2 > Surface->w - 1)
1552 x2 = Surface->w - 1;
1559 SDL_FillRect(Surface, &l, Color);
1561 if (SDL_MUSTLOCK(Surface))
1563 SDL_UnlockSurface(Surface);
1567 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1568 Uint8 R, Uint8 G, Uint8 B)
1570 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1573 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1584 /* Do the clipping */
1585 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1589 if (x2 > Surface->w - 1)
1590 x2 = Surface->w - 1;
1597 SDL_FillRect(Surface, &l, Color);
1600 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1605 if (SDL_MUSTLOCK(Surface))
1607 if (SDL_LockSurface(Surface) < 0)
1620 /* Do the clipping */
1621 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1625 if (y2 > Surface->h - 1)
1626 y2 = Surface->h - 1;
1633 SDL_FillRect(Surface, &l, Color);
1635 if (SDL_MUSTLOCK(Surface))
1637 SDL_UnlockSurface(Surface);
1641 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1642 Uint8 R, Uint8 G, Uint8 B)
1644 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1647 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1658 /* Do the clipping */
1659 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1663 if (y2 > Surface->h - 1)
1664 y2 = Surface->h - 1;
1671 SDL_FillRect(Surface, &l, Color);
1674 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1675 Sint16 x2, Sint16 y2, Uint32 Color,
1676 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1679 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1684 sdx = (dx < 0) ? -1 : 1;
1685 sdy = (dy < 0) ? -1 : 1;
1697 for (x = 0; x < dx; x++)
1699 Callback(Surface, px, py, Color);
1713 for (y = 0; y < dy; y++)
1715 Callback(Surface, px, py, Color);
1729 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1730 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1731 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1734 sge_DoLine(Surface, X1, Y1, X2, Y2,
1735 SDL_MapRGB(Surface->format, R, G, B), Callback);
1738 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1741 if (SDL_MUSTLOCK(Surface))
1743 if (SDL_LockSurface(Surface) < 0)
1748 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1750 /* unlock the display */
1751 if (SDL_MUSTLOCK(Surface))
1753 SDL_UnlockSurface(Surface);
1757 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1758 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1760 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1763 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1765 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1770 -----------------------------------------------------------------------------
1771 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1772 -----------------------------------------------------------------------------
1775 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1776 int width, int height, Uint32 color)
1780 for (y = src_y; y < src_y + height; y++)
1782 for (x = src_x; x < src_x + width; x++)
1784 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1786 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1791 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1792 int src_x, int src_y, int width, int height,
1793 int dst_x, int dst_y)
1797 for (y = 0; y < height; y++)
1799 for (x = 0; x < width; x++)
1801 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1803 if (pixel != BLACK_PIXEL)
1804 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1810 /* ========================================================================= */
1811 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1812 /* (Rotozoomer) by Andreas Schiffler */
1813 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1814 /* ========================================================================= */
1817 -----------------------------------------------------------------------------
1820 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1821 -----------------------------------------------------------------------------
1832 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1835 tColorRGBA *sp, *csp, *dp;
1839 sp = csp = (tColorRGBA *) src->pixels;
1840 dp = (tColorRGBA *) dst->pixels;
1841 dgap = dst->pitch - dst->w * 4;
1843 for (y = 0; y < dst->h; y++)
1847 for (x = 0; x < dst->w; x++)
1849 tColorRGBA *sp0 = sp;
1850 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1851 tColorRGBA *sp00 = &sp0[0];
1852 tColorRGBA *sp01 = &sp0[1];
1853 tColorRGBA *sp10 = &sp1[0];
1854 tColorRGBA *sp11 = &sp1[1];
1857 /* create new color pixel from all four source color pixels */
1858 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1859 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1860 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1861 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1866 /* advance source pointers */
1869 /* advance destination pointer */
1873 /* advance source pointer */
1874 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1876 /* advance destination pointers */
1877 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1883 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1885 int x, y, *sax, *say, *csax, *csay;
1887 tColorRGBA *sp, *csp, *csp0, *dp;
1890 /* use specialized zoom function when scaling down to exactly half size */
1891 if (src->w == 2 * dst->w &&
1892 src->h == 2 * dst->h)
1893 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1895 /* variable setup */
1896 sx = (float) src->w / (float) dst->w;
1897 sy = (float) src->h / (float) dst->h;
1899 /* allocate memory for row increments */
1900 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1901 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1903 /* precalculate row increments */
1904 for (x = 0; x <= dst->w; x++)
1905 *csax++ = (int)(sx * x);
1907 for (y = 0; y <= dst->h; y++)
1908 *csay++ = (int)(sy * y);
1911 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1912 dp = (tColorRGBA *) dst->pixels;
1913 dgap = dst->pitch - dst->w * 4;
1916 for (y = 0; y < dst->h; y++)
1921 for (x = 0; x < dst->w; x++)
1926 /* advance source pointers */
1930 /* advance destination pointer */
1934 /* advance source pointer */
1936 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1938 /* advance destination pointers */
1939 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1949 -----------------------------------------------------------------------------
1952 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1953 -----------------------------------------------------------------------------
1956 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1958 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1959 Uint8 *sp, *dp, *csp;
1962 /* variable setup */
1963 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1964 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1966 /* allocate memory for row increments */
1967 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1968 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1970 /* precalculate row increments */
1973 for (x = 0; x < dst->w; x++)
1976 *csax = (csx >> 16);
1983 for (y = 0; y < dst->h; y++)
1986 *csay = (csy >> 16);
1993 for (x = 0; x < dst->w; x++)
2001 for (y = 0; y < dst->h; y++)
2008 sp = csp = (Uint8 *) src->pixels;
2009 dp = (Uint8 *) dst->pixels;
2010 dgap = dst->pitch - dst->w;
2014 for (y = 0; y < dst->h; y++)
2018 for (x = 0; x < dst->w; x++)
2023 /* advance source pointers */
2027 /* advance destination pointer */
2031 /* advance source pointer (for row) */
2032 csp += ((*csay) * src->pitch);
2035 /* advance destination pointers */
2046 -----------------------------------------------------------------------------
2049 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2050 'zoomx' and 'zoomy' are scaling factors for width and height.
2051 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2052 into a 32bit RGBA format on the fly.
2053 -----------------------------------------------------------------------------
2056 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2058 SDL_Surface *zoom_src = NULL;
2059 SDL_Surface *zoom_dst = NULL;
2060 boolean is_converted = FALSE;
2067 /* determine if source surface is 32 bit or 8 bit */
2068 is_32bit = (src->format->BitsPerPixel == 32);
2070 if (is_32bit || src->format->BitsPerPixel == 8)
2072 /* use source surface 'as is' */
2077 /* new source surface is 32 bit with a defined RGB ordering */
2078 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2079 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2080 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2082 is_converted = TRUE;
2085 /* allocate surface to completely contain the zoomed surface */
2088 /* target surface is 32 bit with source RGBA/ABGR ordering */
2089 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2090 zoom_src->format->Rmask,
2091 zoom_src->format->Gmask,
2092 zoom_src->format->Bmask, 0);
2096 /* target surface is 8 bit */
2097 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2101 /* lock source surface */
2102 SDL_LockSurface(zoom_src);
2104 /* check which kind of surface we have */
2107 /* call the 32 bit transformation routine to do the zooming */
2108 zoomSurfaceRGBA(zoom_src, zoom_dst);
2113 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2114 zoom_dst->format->palette->colors[i] =
2115 zoom_src->format->palette->colors[i];
2116 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2118 /* call the 8 bit transformation routine to do the zooming */
2119 zoomSurfaceY(zoom_src, zoom_dst);
2122 /* unlock source surface */
2123 SDL_UnlockSurface(zoom_src);
2125 /* free temporary surface */
2127 SDL_FreeSurface(zoom_src);
2129 /* return destination surface */
2133 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2135 Bitmap *dst_bitmap = CreateBitmapStruct();
2136 SDL_Surface **dst_surface = &dst_bitmap->surface;
2138 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2139 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2141 dst_bitmap->width = dst_width;
2142 dst_bitmap->height = dst_height;
2144 /* create zoomed temporary surface from source surface */
2145 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2147 /* create native format destination surface from zoomed temporary surface */
2148 SDLSetNativeSurface(dst_surface);
2154 /* ========================================================================= */
2155 /* load image to bitmap */
2156 /* ========================================================================= */
2158 Bitmap *SDLLoadImage(char *filename)
2160 Bitmap *new_bitmap = CreateBitmapStruct();
2161 SDL_Surface *sdl_image_tmp;
2163 print_timestamp_init("SDLLoadImage");
2165 print_timestamp_time(getBaseNamePtr(filename));
2167 /* load image to temporary surface */
2168 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2170 SetError("IMG_Load(): %s", SDL_GetError());
2175 print_timestamp_time("IMG_Load");
2177 UPDATE_BUSY_STATE();
2179 /* create native non-transparent surface for current image */
2180 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2182 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2187 print_timestamp_time("SDL_DisplayFormat (opaque)");
2189 UPDATE_BUSY_STATE();
2191 /* create native transparent surface for current image */
2192 if (sdl_image_tmp->format->Amask == 0)
2193 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2194 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2196 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2198 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2203 print_timestamp_time("SDL_DisplayFormat (masked)");
2205 UPDATE_BUSY_STATE();
2207 /* free temporary surface */
2208 SDL_FreeSurface(sdl_image_tmp);
2210 new_bitmap->width = new_bitmap->surface->w;
2211 new_bitmap->height = new_bitmap->surface->h;
2213 print_timestamp_done("SDLLoadImage");
2219 /* ------------------------------------------------------------------------- */
2220 /* custom cursor fuctions */
2221 /* ------------------------------------------------------------------------- */
2223 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2225 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2226 cursor_info->width, cursor_info->height,
2227 cursor_info->hot_x, cursor_info->hot_y);
2230 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2232 static struct MouseCursorInfo *last_cursor_info = NULL;
2233 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2234 static SDL_Cursor *cursor_default = NULL;
2235 static SDL_Cursor *cursor_current = NULL;
2237 /* if invoked for the first time, store the SDL default cursor */
2238 if (cursor_default == NULL)
2239 cursor_default = SDL_GetCursor();
2241 /* only create new cursor if cursor info (custom only) has changed */
2242 if (cursor_info != NULL && cursor_info != last_cursor_info)
2244 cursor_current = create_cursor(cursor_info);
2245 last_cursor_info = cursor_info;
2248 /* only set new cursor if cursor info (custom or NULL) has changed */
2249 if (cursor_info != last_cursor_info2)
2250 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2252 last_cursor_info2 = cursor_info;
2256 /* ========================================================================= */
2257 /* audio functions */
2258 /* ========================================================================= */
2260 void SDLOpenAudio(void)
2262 #if !defined(TARGET_SDL2)
2263 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2264 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2267 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2269 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2273 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2274 AUDIO_NUM_CHANNELS_STEREO,
2275 setup.system.audio_fragment_size) < 0)
2277 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2281 audio.sound_available = TRUE;
2282 audio.music_available = TRUE;
2283 audio.loops_available = TRUE;
2284 audio.sound_enabled = TRUE;
2286 /* set number of available mixer channels */
2287 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2288 audio.music_channel = MUSIC_CHANNEL;
2289 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2291 Mixer_InitChannels();
2294 void SDLCloseAudio(void)
2297 Mix_HaltChannel(-1);
2300 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2304 /* ========================================================================= */
2305 /* event functions */
2306 /* ========================================================================= */
2308 void SDLNextEvent(Event *event)
2310 SDL_WaitEvent(event);
2313 void SDLHandleWindowManagerEvent(Event *event)
2316 #if defined(PLATFORM_WIN32)
2317 // experimental drag and drop code
2319 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2320 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2322 #if defined(TARGET_SDL2)
2323 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2325 if (syswmmsg->msg == WM_DROPFILES)
2328 #if defined(TARGET_SDL2)
2329 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2331 HDROP hdrop = (HDROP)syswmmsg->wParam;
2335 printf("::: SDL_SYSWMEVENT:\n");
2337 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2339 for (i = 0; i < num_files; i++)
2341 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2342 char buffer[buffer_len + 1];
2344 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2346 printf("::: - '%s'\n", buffer);
2349 #if defined(TARGET_SDL2)
2350 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2352 DragFinish((HDROP)syswmmsg->wParam);
2360 /* ========================================================================= */
2361 /* joystick functions */
2362 /* ========================================================================= */
2364 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2365 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2366 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2368 static boolean SDLOpenJoystick(int nr)
2370 if (nr < 0 || nr > MAX_PLAYERS)
2373 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2376 static void SDLCloseJoystick(int nr)
2378 if (nr < 0 || nr > MAX_PLAYERS)
2381 SDL_JoystickClose(sdl_joystick[nr]);
2383 sdl_joystick[nr] = NULL;
2386 static boolean SDLCheckJoystickOpened(int nr)
2388 if (nr < 0 || nr > MAX_PLAYERS)
2391 #if defined(TARGET_SDL2)
2392 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2394 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2398 void HandleJoystickEvent(Event *event)
2402 case SDL_JOYAXISMOTION:
2403 if (event->jaxis.axis < 2)
2404 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2407 case SDL_JOYBUTTONDOWN:
2408 if (event->jbutton.button < 2)
2409 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2412 case SDL_JOYBUTTONUP:
2413 if (event->jbutton.button < 2)
2414 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2422 void SDLInitJoysticks()
2424 static boolean sdl_joystick_subsystem_initialized = FALSE;
2425 boolean print_warning = !sdl_joystick_subsystem_initialized;
2428 if (!sdl_joystick_subsystem_initialized)
2430 sdl_joystick_subsystem_initialized = TRUE;
2432 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2434 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2439 for (i = 0; i < MAX_PLAYERS; i++)
2441 /* get configured joystick for this player */
2442 char *device_name = setup.input[i].joy.device_name;
2443 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2445 if (joystick_nr >= SDL_NumJoysticks())
2447 if (setup.input[i].use_joystick && print_warning)
2448 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2453 /* misuse joystick file descriptor variable to store joystick number */
2454 joystick.fd[i] = joystick_nr;
2456 if (joystick_nr == -1)
2459 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2460 if (SDLCheckJoystickOpened(joystick_nr))
2461 SDLCloseJoystick(joystick_nr);
2463 if (!setup.input[i].use_joystick)
2466 if (!SDLOpenJoystick(joystick_nr))
2469 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2474 joystick.status = JOYSTICK_ACTIVATED;
2478 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2480 if (nr < 0 || nr >= MAX_PLAYERS)
2484 *x = sdl_js_axis[nr][0];
2486 *y = sdl_js_axis[nr][1];
2489 *b1 = sdl_js_button[nr][0];
2491 *b2 = sdl_js_button[nr][1];