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);
149 // show render target buffer on screen
150 SDL_RenderPresent(sdl_renderer);
154 SDL_UpdateRects(screen, 1, rect);
156 SDL_UpdateRect(screen, 0, 0, 0, 0);
160 static void SDLSetWindowIcon(char *basename)
162 /* (setting the window icon on Mac OS X would replace the high-quality
163 dock icon with the currently smaller (and uglier) icon from file) */
165 #if !defined(PLATFORM_MACOSX)
166 char *filename = getCustomImageFilename(basename);
167 SDL_Surface *surface;
169 if (filename == NULL)
171 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
176 if ((surface = IMG_Load(filename)) == NULL)
178 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
183 /* set transparent color */
184 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
185 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
187 #if defined(TARGET_SDL2)
188 SDL_SetWindowIcon(sdl_window, surface);
190 SDL_WM_SetIcon(surface, NULL);
195 #if defined(TARGET_SDL2)
197 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
198 SDL_PixelFormat *format2)
200 return (format1->format == format2->format &&
201 format1->BitsPerPixel == format2->BitsPerPixel &&
202 format1->BytesPerPixel == format2->BytesPerPixel &&
203 format1->Rmask == format2->Rmask &&
204 format1->Gmask == format2->Gmask &&
205 format1->Bmask == format2->Bmask &&
206 format1->Amask == format2->Amask);
209 boolean SDLSetNativeSurface(SDL_Surface **surface)
211 SDL_Surface *new_surface;
213 if (surface == NULL ||
215 backbuffer == NULL ||
216 backbuffer->surface == NULL)
219 // if pixel format already optimized for destination surface, do nothing
220 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
223 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
225 if (new_surface == NULL)
226 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
228 SDL_FreeSurface(*surface);
230 *surface = new_surface;
235 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
237 SDL_PixelFormat format;
238 SDL_Surface *new_surface;
243 if (backbuffer && backbuffer->surface)
245 format = *backbuffer->surface->format;
246 format.Amask = surface->format->Amask; // keep alpha channel
250 format = *surface->format;
253 new_surface = SDL_ConvertSurface(surface, &format, 0);
255 if (new_surface == NULL)
256 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
263 boolean SDLSetNativeSurface(SDL_Surface **surface)
265 SDL_Surface *new_surface;
267 if (surface == NULL ||
272 new_surface = SDL_DisplayFormat(*surface);
274 if (new_surface == NULL)
275 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
277 SDL_FreeSurface(*surface);
279 *surface = new_surface;
284 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
286 SDL_Surface *new_surface;
288 if (video.initialized)
289 new_surface = SDL_DisplayFormat(surface);
291 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
293 if (new_surface == NULL)
294 Error(ERR_EXIT, "%s() failed: %s",
295 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
303 #if defined(TARGET_SDL2)
304 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
306 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
309 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
316 void SDLCreateBitmapTextures(Bitmap *bitmap)
318 #if defined(TARGET_SDL2)
323 SDL_DestroyTexture(bitmap->texture);
324 if (bitmap->texture_masked)
325 SDL_DestroyTexture(bitmap->texture_masked);
327 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
328 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
332 void SDLFreeBitmapTextures(Bitmap *bitmap)
334 #if defined(TARGET_SDL2)
339 SDL_DestroyTexture(bitmap->texture);
340 if (bitmap->texture_masked)
341 SDL_DestroyTexture(bitmap->texture_masked);
343 bitmap->texture = NULL;
344 bitmap->texture_masked = NULL;
348 void SDLInitVideoDisplay(void)
350 #if !defined(TARGET_SDL2)
351 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
352 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
354 SDL_putenv("SDL_VIDEO_CENTERED=1");
357 /* initialize SDL video */
358 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
359 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
361 /* set default SDL depth */
362 #if !defined(TARGET_SDL2)
363 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
365 video.default_depth = 32; // (how to determine video depth in SDL2?)
369 void SDLInitVideoBuffer(boolean fullscreen)
371 video.window_scaling_percent = setup.window_scaling_percent;
372 video.window_scaling_quality = setup.window_scaling_quality;
373 video.screen_rendering_mode =
374 (strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
375 SPECIAL_RENDERING_BITMAP :
376 strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
377 SPECIAL_RENDERING_TARGET:
378 strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
379 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
381 #if defined(TARGET_SDL2)
382 // SDL 2.0: support for (desktop) fullscreen mode available
383 video.fullscreen_available = TRUE;
385 // SDL 1.2: no support for fullscreen mode in R'n'D anymore
386 video.fullscreen_available = FALSE;
389 /* open SDL video output device (window or fullscreen mode) */
390 if (!SDLSetVideoMode(fullscreen))
391 Error(ERR_EXIT, "setting video mode failed");
393 /* !!! SDL2 can only set the window icon if the window already exists !!! */
394 /* set window icon */
395 SDLSetWindowIcon(program.icon_filename);
397 /* set window and icon title */
398 #if defined(TARGET_SDL2)
399 SDL_SetWindowTitle(sdl_window, program.window_title);
401 SDL_WM_SetCaption(program.window_title, program.window_title);
404 /* SDL cannot directly draw to the visible video framebuffer like X11,
405 but always uses a backbuffer, which is then blitted to the visible
406 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
407 visible video framebuffer with 'SDL_Flip', if the hardware supports
408 this). Therefore do not use an additional backbuffer for drawing, but
409 use a symbolic buffer (distinguishable from the SDL backbuffer) called
410 'window', which indicates that the SDL backbuffer should be updated to
411 the visible video framebuffer when attempting to blit to it.
413 For convenience, it seems to be a good idea to create this symbolic
414 buffer 'window' at the same size as the SDL backbuffer. Although it
415 should never be drawn to directly, it would do no harm nevertheless. */
417 /* create additional (symbolic) buffer for double-buffering */
418 ReCreateBitmap(&window, video.width, video.height, video.depth);
421 static boolean SDLCreateScreen(boolean fullscreen)
423 SDL_Surface *new_surface = NULL;
425 #if defined(TARGET_SDL2)
426 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
427 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
429 int surface_flags_window = SURFACE_FLAGS;
430 int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2)
433 int width = video.width;
434 int height = video.height;
435 int surface_flags = (fullscreen ? surface_flags_fullscreen :
436 surface_flags_window);
438 // default window size is unscaled
439 video.window_width = video.width;
440 video.window_height = video.height;
442 #if defined(TARGET_SDL2)
444 // store if initial screen mode is fullscreen mode when changing screen size
445 video.fullscreen_initial = fullscreen;
447 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
449 video.window_width = window_scaling_factor * width;
450 video.window_height = window_scaling_factor * height;
452 if (sdl_texture_stream)
454 SDL_DestroyTexture(sdl_texture_stream);
455 sdl_texture_stream = NULL;
458 if (sdl_texture_target)
460 SDL_DestroyTexture(sdl_texture_target);
461 sdl_texture_target = NULL;
464 if (!(fullscreen && fullscreen_enabled))
468 SDL_DestroyRenderer(sdl_renderer);
474 SDL_DestroyWindow(sdl_window);
479 if (sdl_window == NULL)
480 sdl_window = SDL_CreateWindow(program.window_title,
481 SDL_WINDOWPOS_CENTERED,
482 SDL_WINDOWPOS_CENTERED,
487 if (sdl_window != NULL)
490 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
491 *without* enabling 2D/3D acceleration and/or guest additions installed,
492 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
493 it will try to use accelerated graphics and apparently fails miserably) */
494 if (sdl_renderer == NULL)
495 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
497 if (sdl_renderer == NULL)
498 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
501 if (sdl_renderer != NULL)
503 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
504 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
505 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
507 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
508 SDL_PIXELFORMAT_ARGB8888,
509 SDL_TEXTUREACCESS_STREAMING,
512 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
513 SDL_PIXELFORMAT_ARGB8888,
514 SDL_TEXTUREACCESS_TARGET,
517 if (sdl_texture_stream != NULL &&
518 sdl_texture_target != NULL)
520 // use SDL default values for RGB masks and no alpha channel
521 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
523 if (new_surface == NULL)
524 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
528 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
533 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
538 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
543 if (gfx.final_screen_bitmap == NULL)
544 gfx.final_screen_bitmap = CreateBitmapStruct();
546 gfx.final_screen_bitmap->width = width;
547 gfx.final_screen_bitmap->height = height;
549 gfx.final_screen_bitmap->surface =
550 SDL_SetVideoMode(width, height, video.depth, surface_flags);
552 if (gfx.final_screen_bitmap->surface != NULL)
555 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
557 if (new_surface == NULL)
558 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
561 new_surface = gfx.final_screen_bitmap->surface;
562 gfx.final_screen_bitmap = NULL;
568 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
572 #if defined(TARGET_SDL2)
573 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
574 if (new_surface != NULL)
575 fullscreen_enabled = fullscreen;
578 if (backbuffer == NULL)
579 backbuffer = CreateBitmapStruct();
581 backbuffer->width = video.width;
582 backbuffer->height = video.height;
584 if (backbuffer->surface)
585 SDL_FreeSurface(backbuffer->surface);
587 backbuffer->surface = new_surface;
589 return (new_surface != NULL);
592 boolean SDLSetVideoMode(boolean fullscreen)
594 boolean success = FALSE;
598 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
600 /* switch display to fullscreen mode, if available */
601 success = SDLCreateScreen(TRUE);
605 /* switching display to fullscreen mode failed -- do not try it again */
606 video.fullscreen_available = FALSE;
610 video.fullscreen_enabled = TRUE;
614 if ((!fullscreen && video.fullscreen_enabled) || !success)
616 /* switch display to window mode */
617 success = SDLCreateScreen(FALSE);
621 /* switching display to window mode failed -- should not happen */
625 video.fullscreen_enabled = FALSE;
626 video.window_scaling_percent = setup.window_scaling_percent;
627 video.window_scaling_quality = setup.window_scaling_quality;
628 video.screen_rendering_mode =
629 (strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
630 SPECIAL_RENDERING_BITMAP :
631 strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
632 SPECIAL_RENDERING_TARGET:
633 strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
634 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
638 #if defined(TARGET_SDL2)
639 SDLRedrawWindow(); // map window
643 #if defined(PLATFORM_WIN32)
644 // experimental drag and drop code
646 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
649 SDL_SysWMinfo wminfo;
651 boolean wminfo_success = FALSE;
653 SDL_VERSION(&wminfo.version);
654 #if defined(TARGET_SDL2)
656 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
658 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
663 #if defined(TARGET_SDL2)
664 hwnd = wminfo.info.win.window;
666 hwnd = wminfo.window;
669 DragAcceptFiles(hwnd, TRUE);
678 void SDLSetWindowTitle()
680 #if defined(TARGET_SDL2)
681 SDL_SetWindowTitle(sdl_window, program.window_title);
683 SDL_WM_SetCaption(program.window_title, program.window_title);
687 #if defined(TARGET_SDL2)
688 void SDLSetWindowScaling(int window_scaling_percent)
690 if (sdl_window == NULL)
693 float window_scaling_factor = (float)window_scaling_percent / 100;
694 int new_window_width = (int)(window_scaling_factor * video.width);
695 int new_window_height = (int)(window_scaling_factor * video.height);
697 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
699 video.window_scaling_percent = window_scaling_percent;
700 video.window_width = new_window_width;
701 video.window_height = new_window_height;
706 void SDLSetWindowScalingQuality(char *window_scaling_quality)
708 SDL_Texture *new_texture;
710 if (sdl_texture_stream == NULL ||
711 sdl_texture_target == NULL)
714 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
716 new_texture = SDL_CreateTexture(sdl_renderer,
717 SDL_PIXELFORMAT_ARGB8888,
718 SDL_TEXTUREACCESS_STREAMING,
719 video.width, video.height);
721 if (new_texture != NULL)
723 SDL_DestroyTexture(sdl_texture_stream);
725 sdl_texture_stream = new_texture;
728 new_texture = SDL_CreateTexture(sdl_renderer,
729 SDL_PIXELFORMAT_ARGB8888,
730 SDL_TEXTUREACCESS_TARGET,
731 video.width, video.height);
733 if (new_texture != NULL)
735 SDL_DestroyTexture(sdl_texture_target);
737 sdl_texture_target = new_texture;
742 video.window_scaling_quality = window_scaling_quality;
745 void SDLSetWindowFullscreen(boolean fullscreen)
747 if (sdl_window == NULL)
750 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
752 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
753 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
755 // if screen size was changed in fullscreen mode, correct desktop window size
756 if (!fullscreen && video.fullscreen_initial)
758 SDLSetWindowScaling(setup.window_scaling_percent);
759 SDL_SetWindowPosition(sdl_window,
760 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
762 video.fullscreen_initial = FALSE;
766 void SDLRedrawWindow()
772 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
775 SDL_Surface *surface =
776 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
779 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
781 SDLSetNativeSurface(&surface);
783 bitmap->surface = surface;
786 void SDLFreeBitmapPointers(Bitmap *bitmap)
789 SDL_FreeSurface(bitmap->surface);
790 if (bitmap->surface_masked)
791 SDL_FreeSurface(bitmap->surface_masked);
793 bitmap->surface = NULL;
794 bitmap->surface_masked = NULL;
796 #if defined(TARGET_SDL2)
798 SDL_DestroyTexture(bitmap->texture);
799 if (bitmap->texture_masked)
800 SDL_DestroyTexture(bitmap->texture_masked);
802 bitmap->texture = NULL;
803 bitmap->texture_masked = NULL;
807 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
808 int src_x, int src_y, int width, int height,
809 int dst_x, int dst_y, int mask_mode)
811 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
812 SDL_Rect src_rect, dst_rect;
824 // if (src_bitmap != backbuffer || dst_bitmap != window)
825 if (!(src_bitmap == backbuffer && dst_bitmap == window))
826 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
827 src_bitmap->surface_masked : src_bitmap->surface),
828 &src_rect, real_dst_bitmap->surface, &dst_rect);
830 if (dst_bitmap == window)
831 UpdateScreen(&dst_rect);
834 void SDLBlitTexture(Bitmap *bitmap,
835 int src_x, int src_y, int width, int height,
836 int dst_x, int dst_y, int mask_mode)
838 #if defined(TARGET_SDL2)
839 SDL_Texture *texture;
844 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
859 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
863 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
866 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
874 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
876 if (dst_bitmap == window)
880 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
881 int fade_mode, int fade_delay, int post_delay,
882 void (*draw_border_function)(void))
884 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
885 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
886 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
887 SDL_Surface *surface_screen = backbuffer->surface;
888 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
889 SDL_Rect src_rect, dst_rect;
891 int src_x = x, src_y = y;
892 int dst_x = x, dst_y = y;
893 unsigned int time_last, time_current;
895 // store function for drawing global masked border
896 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
898 // deactivate drawing of global border while fading, if needed
899 if (draw_border_function == NULL)
900 gfx.draw_global_border_function = NULL;
909 dst_rect.w = width; /* (ignored) */
910 dst_rect.h = height; /* (ignored) */
912 dst_rect2 = dst_rect;
914 /* copy source and target surfaces to temporary surfaces for fading */
915 if (fade_mode & FADE_TYPE_TRANSFORM)
917 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
918 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
920 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
921 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
923 else if (fade_mode & FADE_TYPE_FADE_IN)
925 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
926 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
928 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
930 else /* FADE_TYPE_FADE_OUT */
932 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
933 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
935 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
938 time_current = SDL_GetTicks();
940 if (fade_mode == FADE_MODE_MELT)
942 boolean done = FALSE;
944 int melt_columns = width / melt_pixels;
945 int ypos[melt_columns];
946 int max_steps = height / 8 + 32;
951 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
952 #if defined(TARGET_SDL2)
953 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
955 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
958 ypos[0] = -GetSimpleRandom(16);
960 for (i = 1 ; i < melt_columns; i++)
962 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
964 ypos[i] = ypos[i - 1] + r;
977 time_last = time_current;
978 time_current = SDL_GetTicks();
979 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
980 steps_final = MIN(MAX(0, steps), max_steps);
984 done = (steps_done >= steps_final);
986 for (i = 0 ; i < melt_columns; i++)
994 else if (ypos[i] < height)
999 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1001 if (ypos[i] + dy >= height)
1002 dy = height - ypos[i];
1004 /* copy part of (appearing) target surface to upper area */
1005 src_rect.x = src_x + i * melt_pixels;
1006 // src_rect.y = src_y + ypos[i];
1008 src_rect.w = melt_pixels;
1010 src_rect.h = ypos[i] + dy;
1012 dst_rect.x = dst_x + i * melt_pixels;
1013 // dst_rect.y = dst_y + ypos[i];
1016 if (steps_done >= steps_final)
1017 SDL_BlitSurface(surface_target, &src_rect,
1018 surface_screen, &dst_rect);
1022 /* copy part of (disappearing) source surface to lower area */
1023 src_rect.x = src_x + i * melt_pixels;
1025 src_rect.w = melt_pixels;
1026 src_rect.h = height - ypos[i];
1028 dst_rect.x = dst_x + i * melt_pixels;
1029 dst_rect.y = dst_y + ypos[i];
1031 if (steps_done >= steps_final)
1032 SDL_BlitSurface(surface_source, &src_rect,
1033 surface_screen, &dst_rect);
1039 src_rect.x = src_x + i * melt_pixels;
1041 src_rect.w = melt_pixels;
1042 src_rect.h = height;
1044 dst_rect.x = dst_x + i * melt_pixels;
1047 if (steps_done >= steps_final)
1048 SDL_BlitSurface(surface_target, &src_rect,
1049 surface_screen, &dst_rect);
1053 if (steps_done >= steps_final)
1055 if (draw_border_function != NULL)
1056 draw_border_function();
1058 UpdateScreen(&dst_rect2);
1062 else if (fade_mode == FADE_MODE_CURTAIN)
1066 int xx_size = width / 2;
1068 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1069 #if defined(TARGET_SDL2)
1070 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1072 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1075 for (xx = 0; xx < xx_size;)
1077 time_last = time_current;
1078 time_current = SDL_GetTicks();
1079 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1080 xx_final = MIN(MAX(0, xx), xx_size);
1085 src_rect.h = height;
1090 /* draw new (target) image to screen buffer */
1091 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1093 if (xx_final < xx_size)
1095 src_rect.w = xx_size - xx_final;
1096 src_rect.h = height;
1098 /* draw old (source) image to screen buffer (left side) */
1100 src_rect.x = src_x + xx_final;
1103 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1105 /* draw old (source) image to screen buffer (right side) */
1107 src_rect.x = src_x + xx_size;
1108 dst_rect.x = dst_x + xx_size + xx_final;
1110 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1113 if (draw_border_function != NULL)
1114 draw_border_function();
1116 /* only update the region of the screen that is affected from fading */
1117 UpdateScreen(&dst_rect2);
1120 else /* fading in, fading out or cross-fading */
1125 for (alpha = 0.0; alpha < 255.0;)
1127 time_last = time_current;
1128 time_current = SDL_GetTicks();
1129 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1130 alpha_final = MIN(MAX(0, alpha), 255);
1132 /* draw existing (source) image to screen buffer */
1133 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1135 /* draw new (target) image to screen buffer using alpha blending */
1136 #if defined(TARGET_SDL2)
1137 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1138 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1140 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1142 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1144 if (draw_border_function != NULL)
1145 draw_border_function();
1147 /* only update the region of the screen that is affected from fading */
1148 UpdateScreen(&dst_rect);
1154 unsigned int time_post_delay;
1156 time_current = SDL_GetTicks();
1157 time_post_delay = time_current + post_delay;
1159 while (time_current < time_post_delay)
1161 // do not wait longer than 10 ms at a time to be able to ...
1162 Delay(MIN(10, time_post_delay - time_current));
1164 // ... continue drawing global animations during post delay
1167 time_current = SDL_GetTicks();
1171 // restore function for drawing global masked border
1172 gfx.draw_global_border_function = draw_global_border_function;
1175 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1176 int to_x, int to_y, Uint32 color)
1178 SDL_Surface *surface = dst_bitmap->surface;
1182 swap_numbers(&from_x, &to_x);
1185 swap_numbers(&from_y, &to_y);
1189 rect.w = (to_x - from_x + 1);
1190 rect.h = (to_y - from_y + 1);
1192 SDL_FillRect(surface, &rect, color);
1195 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1196 int to_x, int to_y, Uint32 color)
1198 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1201 #if ENABLE_UNUSED_CODE
1202 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1203 int num_points, Uint32 color)
1208 for (i = 0; i < num_points - 1; i++)
1210 for (x = 0; x < line_width; x++)
1212 for (y = 0; y < line_width; y++)
1214 int dx = x - line_width / 2;
1215 int dy = y - line_width / 2;
1217 if ((x == 0 && y == 0) ||
1218 (x == 0 && y == line_width - 1) ||
1219 (x == line_width - 1 && y == 0) ||
1220 (x == line_width - 1 && y == line_width - 1))
1223 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1224 points[i+1].x + dx, points[i+1].y + dy, color);
1231 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1233 SDL_Surface *surface = src_bitmap->surface;
1235 switch (surface->format->BytesPerPixel)
1237 case 1: /* assuming 8-bpp */
1239 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1243 case 2: /* probably 15-bpp or 16-bpp */
1245 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1249 case 3: /* slow 24-bpp mode; usually not used */
1251 /* does this work? */
1252 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1256 shift = surface->format->Rshift;
1257 color |= *(pix + shift / 8) >> shift;
1258 shift = surface->format->Gshift;
1259 color |= *(pix + shift / 8) >> shift;
1260 shift = surface->format->Bshift;
1261 color |= *(pix + shift / 8) >> shift;
1267 case 4: /* probably 32-bpp */
1269 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1278 /* ========================================================================= */
1279 /* The following functions were taken from the SGE library */
1280 /* (SDL Graphics Extension Library) by Anders Lindström */
1281 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1282 /* ========================================================================= */
1284 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1286 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1288 switch (surface->format->BytesPerPixel)
1292 /* Assuming 8-bpp */
1293 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1299 /* Probably 15-bpp or 16-bpp */
1300 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1306 /* Slow 24-bpp mode, usually not used */
1310 /* Gack - slow, but endian correct */
1311 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1312 shift = surface->format->Rshift;
1313 *(pix+shift/8) = color>>shift;
1314 shift = surface->format->Gshift;
1315 *(pix+shift/8) = color>>shift;
1316 shift = surface->format->Bshift;
1317 *(pix+shift/8) = color>>shift;
1323 /* Probably 32-bpp */
1324 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1331 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1332 Uint8 R, Uint8 G, Uint8 B)
1334 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1337 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1339 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1342 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1344 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1347 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1352 /* Gack - slow, but endian correct */
1353 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1354 shift = surface->format->Rshift;
1355 *(pix+shift/8) = color>>shift;
1356 shift = surface->format->Gshift;
1357 *(pix+shift/8) = color>>shift;
1358 shift = surface->format->Bshift;
1359 *(pix+shift/8) = color>>shift;
1362 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1364 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1367 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1369 switch (dest->format->BytesPerPixel)
1372 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1376 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1380 _PutPixel24(dest,x,y,color);
1384 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1389 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1391 if (SDL_MUSTLOCK(surface))
1393 if (SDL_LockSurface(surface) < 0)
1399 _PutPixel(surface, x, y, color);
1401 if (SDL_MUSTLOCK(surface))
1403 SDL_UnlockSurface(surface);
1407 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1408 Uint8 r, Uint8 g, Uint8 b)
1410 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1413 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1415 if (y >= 0 && y <= dest->h - 1)
1417 switch (dest->format->BytesPerPixel)
1420 return y*dest->pitch;
1424 return y*dest->pitch/2;
1428 return y*dest->pitch;
1432 return y*dest->pitch/4;
1440 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1442 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1444 switch (surface->format->BytesPerPixel)
1448 /* Assuming 8-bpp */
1449 *((Uint8 *)surface->pixels + ypitch + x) = color;
1455 /* Probably 15-bpp or 16-bpp */
1456 *((Uint16 *)surface->pixels + ypitch + x) = color;
1462 /* Slow 24-bpp mode, usually not used */
1466 /* Gack - slow, but endian correct */
1467 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1468 shift = surface->format->Rshift;
1469 *(pix+shift/8) = color>>shift;
1470 shift = surface->format->Gshift;
1471 *(pix+shift/8) = color>>shift;
1472 shift = surface->format->Bshift;
1473 *(pix+shift/8) = color>>shift;
1479 /* Probably 32-bpp */
1480 *((Uint32 *)surface->pixels + ypitch + x) = color;
1487 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1492 if (SDL_MUSTLOCK(Surface))
1494 if (SDL_LockSurface(Surface) < 0)
1507 /* Do the clipping */
1508 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1512 if (x2 > Surface->w - 1)
1513 x2 = Surface->w - 1;
1520 SDL_FillRect(Surface, &l, Color);
1522 if (SDL_MUSTLOCK(Surface))
1524 SDL_UnlockSurface(Surface);
1528 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1529 Uint8 R, Uint8 G, Uint8 B)
1531 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1534 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1545 /* Do the clipping */
1546 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1550 if (x2 > Surface->w - 1)
1551 x2 = Surface->w - 1;
1558 SDL_FillRect(Surface, &l, Color);
1561 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1566 if (SDL_MUSTLOCK(Surface))
1568 if (SDL_LockSurface(Surface) < 0)
1581 /* Do the clipping */
1582 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1586 if (y2 > Surface->h - 1)
1587 y2 = Surface->h - 1;
1594 SDL_FillRect(Surface, &l, Color);
1596 if (SDL_MUSTLOCK(Surface))
1598 SDL_UnlockSurface(Surface);
1602 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1603 Uint8 R, Uint8 G, Uint8 B)
1605 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1608 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1619 /* Do the clipping */
1620 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1624 if (y2 > Surface->h - 1)
1625 y2 = Surface->h - 1;
1632 SDL_FillRect(Surface, &l, Color);
1635 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1636 Sint16 x2, Sint16 y2, Uint32 Color,
1637 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1640 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1645 sdx = (dx < 0) ? -1 : 1;
1646 sdy = (dy < 0) ? -1 : 1;
1658 for (x = 0; x < dx; x++)
1660 Callback(Surface, px, py, Color);
1674 for (y = 0; y < dy; y++)
1676 Callback(Surface, px, py, Color);
1690 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1691 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1692 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1695 sge_DoLine(Surface, X1, Y1, X2, Y2,
1696 SDL_MapRGB(Surface->format, R, G, B), Callback);
1699 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1702 if (SDL_MUSTLOCK(Surface))
1704 if (SDL_LockSurface(Surface) < 0)
1709 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1711 /* unlock the display */
1712 if (SDL_MUSTLOCK(Surface))
1714 SDL_UnlockSurface(Surface);
1718 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1719 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1721 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1724 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1726 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1731 -----------------------------------------------------------------------------
1732 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1733 -----------------------------------------------------------------------------
1736 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1737 int width, int height, Uint32 color)
1741 for (y = src_y; y < src_y + height; y++)
1743 for (x = src_x; x < src_x + width; x++)
1745 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1747 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1752 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1753 int src_x, int src_y, int width, int height,
1754 int dst_x, int dst_y)
1758 for (y = 0; y < height; y++)
1760 for (x = 0; x < width; x++)
1762 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1764 if (pixel != BLACK_PIXEL)
1765 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1771 /* ========================================================================= */
1772 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1773 /* (Rotozoomer) by Andreas Schiffler */
1774 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1775 /* ========================================================================= */
1778 -----------------------------------------------------------------------------
1781 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1782 -----------------------------------------------------------------------------
1793 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1796 tColorRGBA *sp, *csp, *dp;
1800 sp = csp = (tColorRGBA *) src->pixels;
1801 dp = (tColorRGBA *) dst->pixels;
1802 dgap = dst->pitch - dst->w * 4;
1804 for (y = 0; y < dst->h; y++)
1808 for (x = 0; x < dst->w; x++)
1810 tColorRGBA *sp0 = sp;
1811 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1812 tColorRGBA *sp00 = &sp0[0];
1813 tColorRGBA *sp01 = &sp0[1];
1814 tColorRGBA *sp10 = &sp1[0];
1815 tColorRGBA *sp11 = &sp1[1];
1818 /* create new color pixel from all four source color pixels */
1819 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1820 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1821 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1822 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1827 /* advance source pointers */
1830 /* advance destination pointer */
1834 /* advance source pointer */
1835 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1837 /* advance destination pointers */
1838 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1844 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1846 int x, y, *sax, *say, *csax, *csay;
1848 tColorRGBA *sp, *csp, *csp0, *dp;
1851 /* use specialized zoom function when scaling down to exactly half size */
1852 if (src->w == 2 * dst->w &&
1853 src->h == 2 * dst->h)
1854 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1856 /* variable setup */
1857 sx = (float) src->w / (float) dst->w;
1858 sy = (float) src->h / (float) dst->h;
1860 /* allocate memory for row increments */
1861 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1862 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1864 /* precalculate row increments */
1865 for (x = 0; x <= dst->w; x++)
1866 *csax++ = (int)(sx * x);
1868 for (y = 0; y <= dst->h; y++)
1869 *csay++ = (int)(sy * y);
1872 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1873 dp = (tColorRGBA *) dst->pixels;
1874 dgap = dst->pitch - dst->w * 4;
1877 for (y = 0; y < dst->h; y++)
1882 for (x = 0; x < dst->w; x++)
1887 /* advance source pointers */
1891 /* advance destination pointer */
1895 /* advance source pointer */
1897 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1899 /* advance destination pointers */
1900 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1910 -----------------------------------------------------------------------------
1913 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1914 -----------------------------------------------------------------------------
1917 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1919 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1920 Uint8 *sp, *dp, *csp;
1923 /* variable setup */
1924 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1925 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1927 /* allocate memory for row increments */
1928 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1929 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1931 /* precalculate row increments */
1934 for (x = 0; x < dst->w; x++)
1937 *csax = (csx >> 16);
1944 for (y = 0; y < dst->h; y++)
1947 *csay = (csy >> 16);
1954 for (x = 0; x < dst->w; x++)
1962 for (y = 0; y < dst->h; y++)
1969 sp = csp = (Uint8 *) src->pixels;
1970 dp = (Uint8 *) dst->pixels;
1971 dgap = dst->pitch - dst->w;
1975 for (y = 0; y < dst->h; y++)
1979 for (x = 0; x < dst->w; x++)
1984 /* advance source pointers */
1988 /* advance destination pointer */
1992 /* advance source pointer (for row) */
1993 csp += ((*csay) * src->pitch);
1996 /* advance destination pointers */
2007 -----------------------------------------------------------------------------
2010 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2011 'zoomx' and 'zoomy' are scaling factors for width and height.
2012 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2013 into a 32bit RGBA format on the fly.
2014 -----------------------------------------------------------------------------
2017 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2019 SDL_Surface *zoom_src = NULL;
2020 SDL_Surface *zoom_dst = NULL;
2021 boolean is_converted = FALSE;
2028 /* determine if source surface is 32 bit or 8 bit */
2029 is_32bit = (src->format->BitsPerPixel == 32);
2031 if (is_32bit || src->format->BitsPerPixel == 8)
2033 /* use source surface 'as is' */
2038 /* new source surface is 32 bit with a defined RGB ordering */
2039 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2040 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2041 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2043 is_converted = TRUE;
2046 /* allocate surface to completely contain the zoomed surface */
2049 /* target surface is 32 bit with source RGBA/ABGR ordering */
2050 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2051 zoom_src->format->Rmask,
2052 zoom_src->format->Gmask,
2053 zoom_src->format->Bmask, 0);
2057 /* target surface is 8 bit */
2058 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2062 /* lock source surface */
2063 SDL_LockSurface(zoom_src);
2065 /* check which kind of surface we have */
2068 /* call the 32 bit transformation routine to do the zooming */
2069 zoomSurfaceRGBA(zoom_src, zoom_dst);
2074 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2075 zoom_dst->format->palette->colors[i] =
2076 zoom_src->format->palette->colors[i];
2077 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2079 /* call the 8 bit transformation routine to do the zooming */
2080 zoomSurfaceY(zoom_src, zoom_dst);
2083 /* unlock source surface */
2084 SDL_UnlockSurface(zoom_src);
2086 /* free temporary surface */
2088 SDL_FreeSurface(zoom_src);
2090 /* return destination surface */
2094 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2096 Bitmap *dst_bitmap = CreateBitmapStruct();
2097 SDL_Surface **dst_surface = &dst_bitmap->surface;
2099 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2100 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2102 dst_bitmap->width = dst_width;
2103 dst_bitmap->height = dst_height;
2105 /* create zoomed temporary surface from source surface */
2106 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2108 /* create native format destination surface from zoomed temporary surface */
2109 SDLSetNativeSurface(dst_surface);
2115 /* ========================================================================= */
2116 /* load image to bitmap */
2117 /* ========================================================================= */
2119 Bitmap *SDLLoadImage(char *filename)
2121 Bitmap *new_bitmap = CreateBitmapStruct();
2122 SDL_Surface *sdl_image_tmp;
2124 print_timestamp_init("SDLLoadImage");
2126 print_timestamp_time(getBaseNamePtr(filename));
2128 /* load image to temporary surface */
2129 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2131 SetError("IMG_Load(): %s", SDL_GetError());
2136 print_timestamp_time("IMG_Load");
2138 UPDATE_BUSY_STATE();
2140 /* create native non-transparent surface for current image */
2141 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2143 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2148 print_timestamp_time("SDL_DisplayFormat (opaque)");
2150 UPDATE_BUSY_STATE();
2152 /* create native transparent surface for current image */
2153 if (sdl_image_tmp->format->Amask == 0)
2154 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2155 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2157 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2159 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2164 print_timestamp_time("SDL_DisplayFormat (masked)");
2166 UPDATE_BUSY_STATE();
2168 /* free temporary surface */
2169 SDL_FreeSurface(sdl_image_tmp);
2171 new_bitmap->width = new_bitmap->surface->w;
2172 new_bitmap->height = new_bitmap->surface->h;
2174 print_timestamp_done("SDLLoadImage");
2180 /* ------------------------------------------------------------------------- */
2181 /* custom cursor fuctions */
2182 /* ------------------------------------------------------------------------- */
2184 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2186 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2187 cursor_info->width, cursor_info->height,
2188 cursor_info->hot_x, cursor_info->hot_y);
2191 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2193 static struct MouseCursorInfo *last_cursor_info = NULL;
2194 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2195 static SDL_Cursor *cursor_default = NULL;
2196 static SDL_Cursor *cursor_current = NULL;
2198 /* if invoked for the first time, store the SDL default cursor */
2199 if (cursor_default == NULL)
2200 cursor_default = SDL_GetCursor();
2202 /* only create new cursor if cursor info (custom only) has changed */
2203 if (cursor_info != NULL && cursor_info != last_cursor_info)
2205 cursor_current = create_cursor(cursor_info);
2206 last_cursor_info = cursor_info;
2209 /* only set new cursor if cursor info (custom or NULL) has changed */
2210 if (cursor_info != last_cursor_info2)
2211 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2213 last_cursor_info2 = cursor_info;
2217 /* ========================================================================= */
2218 /* audio functions */
2219 /* ========================================================================= */
2221 void SDLOpenAudio(void)
2223 #if !defined(TARGET_SDL2)
2224 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2225 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2228 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2230 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2234 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2235 AUDIO_NUM_CHANNELS_STEREO,
2236 setup.system.audio_fragment_size) < 0)
2238 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2242 audio.sound_available = TRUE;
2243 audio.music_available = TRUE;
2244 audio.loops_available = TRUE;
2245 audio.sound_enabled = TRUE;
2247 /* set number of available mixer channels */
2248 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2249 audio.music_channel = MUSIC_CHANNEL;
2250 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2252 Mixer_InitChannels();
2255 void SDLCloseAudio(void)
2258 Mix_HaltChannel(-1);
2261 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2265 /* ========================================================================= */
2266 /* event functions */
2267 /* ========================================================================= */
2269 void SDLNextEvent(Event *event)
2271 SDL_WaitEvent(event);
2274 void SDLHandleWindowManagerEvent(Event *event)
2277 #if defined(PLATFORM_WIN32)
2278 // experimental drag and drop code
2280 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2281 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2283 #if defined(TARGET_SDL2)
2284 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2286 if (syswmmsg->msg == WM_DROPFILES)
2289 #if defined(TARGET_SDL2)
2290 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2292 HDROP hdrop = (HDROP)syswmmsg->wParam;
2296 printf("::: SDL_SYSWMEVENT:\n");
2298 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2300 for (i = 0; i < num_files; i++)
2302 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2303 char buffer[buffer_len + 1];
2305 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2307 printf("::: - '%s'\n", buffer);
2310 #if defined(TARGET_SDL2)
2311 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2313 DragFinish((HDROP)syswmmsg->wParam);
2321 /* ========================================================================= */
2322 /* joystick functions */
2323 /* ========================================================================= */
2325 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2326 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2327 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2329 static boolean SDLOpenJoystick(int nr)
2331 if (nr < 0 || nr > MAX_PLAYERS)
2334 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2337 static void SDLCloseJoystick(int nr)
2339 if (nr < 0 || nr > MAX_PLAYERS)
2342 SDL_JoystickClose(sdl_joystick[nr]);
2344 sdl_joystick[nr] = NULL;
2347 static boolean SDLCheckJoystickOpened(int nr)
2349 if (nr < 0 || nr > MAX_PLAYERS)
2352 #if defined(TARGET_SDL2)
2353 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2355 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2359 void HandleJoystickEvent(Event *event)
2363 case SDL_JOYAXISMOTION:
2364 if (event->jaxis.axis < 2)
2365 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2368 case SDL_JOYBUTTONDOWN:
2369 if (event->jbutton.button < 2)
2370 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2373 case SDL_JOYBUTTONUP:
2374 if (event->jbutton.button < 2)
2375 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2383 void SDLInitJoysticks()
2385 static boolean sdl_joystick_subsystem_initialized = FALSE;
2386 boolean print_warning = !sdl_joystick_subsystem_initialized;
2389 if (!sdl_joystick_subsystem_initialized)
2391 sdl_joystick_subsystem_initialized = TRUE;
2393 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2395 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2400 for (i = 0; i < MAX_PLAYERS; i++)
2402 /* get configured joystick for this player */
2403 char *device_name = setup.input[i].joy.device_name;
2404 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2406 if (joystick_nr >= SDL_NumJoysticks())
2408 if (setup.input[i].use_joystick && print_warning)
2409 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2414 /* misuse joystick file descriptor variable to store joystick number */
2415 joystick.fd[i] = joystick_nr;
2417 if (joystick_nr == -1)
2420 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2421 if (SDLCheckJoystickOpened(joystick_nr))
2422 SDLCloseJoystick(joystick_nr);
2424 if (!setup.input[i].use_joystick)
2427 if (!SDLOpenJoystick(joystick_nr))
2430 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2435 joystick.status = JOYSTICK_ACTIVATED;
2439 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2441 if (nr < 0 || nr >= MAX_PLAYERS)
2445 *x = sdl_js_axis[nr][0];
2447 *y = sdl_js_axis[nr][1];
2450 *b1 = sdl_js_button[nr][0];
2452 *b2 = sdl_js_button[nr][1];