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 UpdateScreen(SDL_Rect *rect)
54 static unsigned int update_screen_delay = 0;
55 unsigned int update_screen_delay_value = 50; /* (milliseconds) */
56 SDL_Surface *screen = backbuffer->surface;
58 if (limit_screen_updates &&
59 !DelayReached(&update_screen_delay, update_screen_delay_value))
62 LimitScreenUpdates(FALSE);
66 static int LastFrameCounter = 0;
67 boolean changed = (FrameCounter != LastFrameCounter);
69 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
70 (changed ? "-" : "SAME FRAME UPDATED"));
72 LastFrameCounter = FrameCounter;
81 #if USE_FINAL_SCREEN_BITMAP
82 if (gfx.final_screen_bitmap != NULL) // may not be initialized yet
85 // draw global animations using bitmaps instead of using textures
86 // to prevent texture scaling artefacts (this is potentially slower)
88 BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
89 gfx.win_xsize, gfx.win_ysize, 0, 0);
91 // copy global animations to render target buffer, if defined (below border)
92 if (gfx.draw_global_anim_function != NULL)
93 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
95 // copy global masked border to render target buffer, if defined
96 if (gfx.draw_global_border_function != NULL)
97 gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
99 // copy global animations to render target buffer, if defined (above border)
100 if (gfx.draw_global_anim_function != NULL)
101 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
103 screen = gfx.final_screen_bitmap->surface;
105 // force full window redraw
110 #if USE_TARGET_TEXTURE
111 #if USE_TARGET_TEXTURE_ONLY
112 SDL_Texture *sdl_texture = sdl_texture_target;
114 SDL_Texture *sdl_texture = sdl_texture_stream;
118 #if defined(TARGET_SDL2)
121 int bytes_x = screen->pitch / video.width;
122 int bytes_y = screen->pitch;
124 SDL_UpdateTexture(sdl_texture, rect,
125 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
130 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
133 // clear render target buffer
134 SDL_RenderClear(sdl_renderer);
136 #if USE_TARGET_TEXTURE
137 SDL_SetRenderTarget(sdl_renderer, sdl_texture_target);
139 // copy backbuffer to render target buffer
140 if (sdl_texture != sdl_texture_target)
141 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
143 // copy backbuffer to render target buffer
144 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
147 #if !USE_FINAL_SCREEN_BITMAP
148 // copy global animations to render target buffer, if defined (below border)
149 if (gfx.draw_global_anim_function != NULL)
150 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
152 // copy global masked border to render target buffer, if defined
153 if (gfx.draw_global_border_function != NULL)
154 gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
156 // copy global animations to render target buffer, if defined (above border)
157 if (gfx.draw_global_anim_function != NULL)
158 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
161 #if USE_TARGET_TEXTURE
162 SDL_SetRenderTarget(sdl_renderer, NULL);
163 SDL_RenderCopy(sdl_renderer, sdl_texture_target, NULL, NULL);
166 // show render target buffer on screen
167 SDL_RenderPresent(sdl_renderer);
171 SDL_UpdateRects(screen, 1, rect);
173 SDL_UpdateRect(screen, 0, 0, 0, 0);
177 static void SDLSetWindowIcon(char *basename)
179 /* (setting the window icon on Mac OS X would replace the high-quality
180 dock icon with the currently smaller (and uglier) icon from file) */
182 #if !defined(PLATFORM_MACOSX)
183 char *filename = getCustomImageFilename(basename);
184 SDL_Surface *surface;
186 if (filename == NULL)
188 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
193 if ((surface = IMG_Load(filename)) == NULL)
195 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
200 /* set transparent color */
201 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
202 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
204 #if defined(TARGET_SDL2)
205 SDL_SetWindowIcon(sdl_window, surface);
207 SDL_WM_SetIcon(surface, NULL);
212 #if defined(TARGET_SDL2)
214 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
215 SDL_PixelFormat *format2)
217 return (format1->format == format2->format &&
218 format1->BitsPerPixel == format2->BitsPerPixel &&
219 format1->BytesPerPixel == format2->BytesPerPixel &&
220 format1->Rmask == format2->Rmask &&
221 format1->Gmask == format2->Gmask &&
222 format1->Bmask == format2->Bmask &&
223 format1->Amask == format2->Amask);
226 boolean SDLSetNativeSurface(SDL_Surface **surface)
228 SDL_Surface *new_surface;
230 if (surface == NULL ||
232 backbuffer == NULL ||
233 backbuffer->surface == NULL)
236 // if pixel format already optimized for destination surface, do nothing
237 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
240 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
242 if (new_surface == NULL)
243 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
245 SDL_FreeSurface(*surface);
247 *surface = new_surface;
252 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
254 SDL_PixelFormat format;
255 SDL_Surface *new_surface;
260 if (backbuffer && backbuffer->surface)
262 format = *backbuffer->surface->format;
263 format.Amask = surface->format->Amask; // keep alpha channel
267 format = *surface->format;
270 new_surface = SDL_ConvertSurface(surface, &format, 0);
272 if (new_surface == NULL)
273 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
280 boolean SDLSetNativeSurface(SDL_Surface **surface)
282 SDL_Surface *new_surface;
284 if (surface == NULL ||
289 new_surface = SDL_DisplayFormat(*surface);
291 if (new_surface == NULL)
292 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
294 SDL_FreeSurface(*surface);
296 *surface = new_surface;
301 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
303 SDL_Surface *new_surface;
305 if (video.initialized)
306 new_surface = SDL_DisplayFormat(surface);
308 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
310 if (new_surface == NULL)
311 Error(ERR_EXIT, "%s() failed: %s",
312 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
320 #if defined(TARGET_SDL2)
321 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
323 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
326 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
333 void SDLCreateBitmapTextures(Bitmap *bitmap)
335 #if defined(TARGET_SDL2)
340 SDL_DestroyTexture(bitmap->texture);
341 if (bitmap->texture_masked)
342 SDL_DestroyTexture(bitmap->texture_masked);
344 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
345 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
349 void SDLFreeBitmapTextures(Bitmap *bitmap)
351 #if defined(TARGET_SDL2)
356 SDL_DestroyTexture(bitmap->texture);
357 if (bitmap->texture_masked)
358 SDL_DestroyTexture(bitmap->texture_masked);
360 bitmap->texture = NULL;
361 bitmap->texture_masked = NULL;
365 void SDLInitVideoDisplay(void)
367 #if !defined(TARGET_SDL2)
368 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
369 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
371 SDL_putenv("SDL_VIDEO_CENTERED=1");
374 /* initialize SDL video */
375 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
376 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
378 /* set default SDL depth */
379 #if !defined(TARGET_SDL2)
380 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
382 video.default_depth = 32; // (how to determine video depth in SDL2?)
386 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
389 video.window_scaling_percent = setup.window_scaling_percent;
390 video.window_scaling_quality = setup.window_scaling_quality;
392 #if defined(TARGET_SDL2)
393 // SDL 2.0: support for (desktop) fullscreen mode available
394 video.fullscreen_available = TRUE;
396 // SDL 1.2: no support for fullscreen mode in R'n'D anymore
397 video.fullscreen_available = FALSE;
400 /* open SDL video output device (window or fullscreen mode) */
401 if (!SDLSetVideoMode(backbuffer, fullscreen))
402 Error(ERR_EXIT, "setting video mode failed");
404 /* !!! SDL2 can only set the window icon if the window already exists !!! */
405 /* set window icon */
406 SDLSetWindowIcon(program.icon_filename);
408 /* set window and icon title */
409 #if defined(TARGET_SDL2)
410 SDL_SetWindowTitle(sdl_window, program.window_title);
412 SDL_WM_SetCaption(program.window_title, program.window_title);
415 /* SDL cannot directly draw to the visible video framebuffer like X11,
416 but always uses a backbuffer, which is then blitted to the visible
417 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
418 visible video framebuffer with 'SDL_Flip', if the hardware supports
419 this). Therefore do not use an additional backbuffer for drawing, but
420 use a symbolic buffer (distinguishable from the SDL backbuffer) called
421 'window', which indicates that the SDL backbuffer should be updated to
422 the visible video framebuffer when attempting to blit to it.
424 For convenience, it seems to be a good idea to create this symbolic
425 buffer 'window' at the same size as the SDL backbuffer. Although it
426 should never be drawn to directly, it would do no harm nevertheless. */
428 /* create additional (symbolic) buffer for double-buffering */
429 ReCreateBitmap(window, video.width, video.height, video.depth);
432 static boolean SDLCreateScreen(DrawBuffer **backbuffer, boolean fullscreen)
434 SDL_Surface *new_surface = NULL;
436 #if defined(TARGET_SDL2)
437 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
438 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
440 int surface_flags_window = SURFACE_FLAGS;
441 int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2)
444 int width = video.width;
445 int height = video.height;
446 int surface_flags = (fullscreen ? surface_flags_fullscreen :
447 surface_flags_window);
449 // default window size is unscaled
450 video.window_width = video.width;
451 video.window_height = video.height;
453 #if defined(TARGET_SDL2)
455 // store if initial screen mode is fullscreen mode when changing screen size
456 video.fullscreen_initial = fullscreen;
458 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
460 video.window_width = window_scaling_factor * width;
461 video.window_height = window_scaling_factor * height;
463 #if USE_TARGET_TEXTURE
464 if (sdl_texture_stream)
466 SDL_DestroyTexture(sdl_texture_stream);
467 sdl_texture_stream = NULL;
470 if (sdl_texture_target)
472 SDL_DestroyTexture(sdl_texture_target);
473 sdl_texture_target = NULL;
478 SDL_DestroyTexture(sdl_texture);
483 if (!(fullscreen && fullscreen_enabled))
487 SDL_DestroyRenderer(sdl_renderer);
493 SDL_DestroyWindow(sdl_window);
498 if (sdl_window == NULL)
499 sdl_window = SDL_CreateWindow(program.window_title,
500 SDL_WINDOWPOS_CENTERED,
501 SDL_WINDOWPOS_CENTERED,
506 if (sdl_window != NULL)
509 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
510 *without* enabling 2D/3D acceleration and/or guest additions installed,
511 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
512 it will try to use accelerated graphics and apparently fails miserably) */
513 if (sdl_renderer == NULL)
514 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
516 if (sdl_renderer == NULL)
517 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
520 if (sdl_renderer != NULL)
522 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
523 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
524 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
526 #if USE_TARGET_TEXTURE
527 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
528 SDL_PIXELFORMAT_ARGB8888,
529 SDL_TEXTUREACCESS_STREAMING,
532 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
533 SDL_PIXELFORMAT_ARGB8888,
534 SDL_TEXTUREACCESS_TARGET,
537 sdl_texture = SDL_CreateTexture(sdl_renderer,
538 SDL_PIXELFORMAT_ARGB8888,
539 SDL_TEXTUREACCESS_STREAMING,
543 #if USE_TARGET_TEXTURE
544 if (sdl_texture_stream != NULL &&
545 sdl_texture_target != NULL)
547 if (sdl_texture != NULL)
550 // use SDL default values for RGB masks and no alpha channel
551 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
553 if (new_surface == NULL)
554 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
558 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
563 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
568 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
573 if (gfx.final_screen_bitmap == NULL)
574 gfx.final_screen_bitmap = CreateBitmapStruct();
576 gfx.final_screen_bitmap->width = width;
577 gfx.final_screen_bitmap->height = height;
579 gfx.final_screen_bitmap->surface =
580 SDL_SetVideoMode(width, height, video.depth, surface_flags);
582 if (gfx.final_screen_bitmap->surface != NULL)
585 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
587 if (new_surface == NULL)
588 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
591 new_surface = gfx.final_screen_bitmap->surface;
592 gfx.final_screen_bitmap = NULL;
598 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
602 #if defined(TARGET_SDL2)
603 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
604 if (new_surface != NULL)
605 fullscreen_enabled = fullscreen;
608 if (*backbuffer == NULL)
609 *backbuffer = CreateBitmapStruct();
611 (*backbuffer)->width = video.width;
612 (*backbuffer)->height = video.height;
614 if ((*backbuffer)->surface)
615 SDL_FreeSurface((*backbuffer)->surface);
617 (*backbuffer)->surface = new_surface;
619 return (new_surface != NULL);
622 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
624 boolean success = FALSE;
628 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
630 /* switch display to fullscreen mode, if available */
631 success = SDLCreateScreen(backbuffer, TRUE);
635 /* switching display to fullscreen mode failed -- do not try it again */
636 video.fullscreen_available = FALSE;
640 video.fullscreen_enabled = TRUE;
644 if ((!fullscreen && video.fullscreen_enabled) || !success)
646 /* switch display to window mode */
647 success = SDLCreateScreen(backbuffer, FALSE);
651 /* switching display to window mode failed -- should not happen */
655 video.fullscreen_enabled = FALSE;
656 video.window_scaling_percent = setup.window_scaling_percent;
657 video.window_scaling_quality = setup.window_scaling_quality;
661 #if defined(TARGET_SDL2)
662 SDLRedrawWindow(); // map window
666 #if defined(PLATFORM_WIN32)
667 // experimental drag and drop code
669 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
672 SDL_SysWMinfo wminfo;
674 boolean wminfo_success = FALSE;
676 SDL_VERSION(&wminfo.version);
677 #if defined(TARGET_SDL2)
679 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
681 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
686 #if defined(TARGET_SDL2)
687 hwnd = wminfo.info.win.window;
689 hwnd = wminfo.window;
692 DragAcceptFiles(hwnd, TRUE);
701 void SDLSetWindowTitle()
703 #if defined(TARGET_SDL2)
704 SDL_SetWindowTitle(sdl_window, program.window_title);
706 SDL_WM_SetCaption(program.window_title, program.window_title);
710 #if defined(TARGET_SDL2)
711 void SDLSetWindowScaling(int window_scaling_percent)
713 if (sdl_window == NULL)
716 float window_scaling_factor = (float)window_scaling_percent / 100;
717 int new_window_width = (int)(window_scaling_factor * video.width);
718 int new_window_height = (int)(window_scaling_factor * video.height);
720 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
722 video.window_scaling_percent = window_scaling_percent;
723 video.window_width = new_window_width;
724 video.window_height = new_window_height;
729 void SDLSetWindowScalingQuality(char *window_scaling_quality)
731 #if USE_TARGET_TEXTURE
732 SDL_Texture *new_texture;
734 if (sdl_texture_stream == NULL ||
735 sdl_texture_target == NULL)
738 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
740 new_texture = SDL_CreateTexture(sdl_renderer,
741 SDL_PIXELFORMAT_ARGB8888,
742 SDL_TEXTUREACCESS_STREAMING,
743 video.width, video.height);
745 if (new_texture != NULL)
747 SDL_DestroyTexture(sdl_texture_stream);
749 sdl_texture_stream = new_texture;
752 new_texture = SDL_CreateTexture(sdl_renderer,
753 SDL_PIXELFORMAT_ARGB8888,
754 SDL_TEXTUREACCESS_TARGET,
755 video.width, video.height);
757 if (new_texture != NULL)
759 SDL_DestroyTexture(sdl_texture_target);
761 sdl_texture_target = new_texture;
767 if (sdl_texture == NULL)
770 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
772 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
773 SDL_PIXELFORMAT_ARGB8888,
774 SDL_TEXTUREACCESS_STREAMING,
775 video.width, video.height);
777 if (new_texture != NULL)
779 SDL_DestroyTexture(sdl_texture);
781 sdl_texture = new_texture;
787 video.window_scaling_quality = window_scaling_quality;
790 void SDLSetWindowFullscreen(boolean fullscreen)
792 if (sdl_window == NULL)
795 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
797 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
798 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
800 // if screen size was changed in fullscreen mode, correct desktop window size
801 if (!fullscreen && video.fullscreen_initial)
803 SDLSetWindowScaling(setup.window_scaling_percent);
804 SDL_SetWindowPosition(sdl_window,
805 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
807 video.fullscreen_initial = FALSE;
811 void SDLRedrawWindow()
817 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
820 SDL_Surface *surface =
821 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
824 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
826 SDLSetNativeSurface(&surface);
828 bitmap->surface = surface;
831 void SDLFreeBitmapPointers(Bitmap *bitmap)
834 SDL_FreeSurface(bitmap->surface);
835 if (bitmap->surface_masked)
836 SDL_FreeSurface(bitmap->surface_masked);
838 bitmap->surface = NULL;
839 bitmap->surface_masked = NULL;
841 #if defined(TARGET_SDL2)
843 SDL_DestroyTexture(bitmap->texture);
844 if (bitmap->texture_masked)
845 SDL_DestroyTexture(bitmap->texture_masked);
847 bitmap->texture = NULL;
848 bitmap->texture_masked = NULL;
852 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
853 int src_x, int src_y, int width, int height,
854 int dst_x, int dst_y, int mask_mode)
856 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
857 SDL_Rect src_rect, dst_rect;
869 // if (src_bitmap != backbuffer || dst_bitmap != window)
870 if (!(src_bitmap == backbuffer && dst_bitmap == window))
871 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
872 src_bitmap->surface_masked : src_bitmap->surface),
873 &src_rect, real_dst_bitmap->surface, &dst_rect);
875 if (dst_bitmap == window)
876 UpdateScreen(&dst_rect);
879 void SDLBlitTexture(Bitmap *bitmap,
880 int src_x, int src_y, int width, int height,
881 int dst_x, int dst_y, int mask_mode)
883 #if defined(TARGET_SDL2)
884 SDL_Texture *texture;
889 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
904 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
908 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
911 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
919 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
921 #if defined(TARGET_SDL2)
922 if (dst_bitmap == window)
924 // SDL_UpdateWindowSurface(sdl_window);
925 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
929 if (dst_bitmap == window)
931 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
937 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
938 int fade_mode, int fade_delay, int post_delay,
939 void (*draw_border_function)(void))
941 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
942 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
943 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
944 SDL_Surface *surface_screen = backbuffer->surface;
945 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
946 SDL_Rect src_rect, dst_rect;
948 int src_x = x, src_y = y;
949 int dst_x = x, dst_y = y;
950 unsigned int time_last, time_current;
952 // store function for drawing global masked border
953 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
955 // deactivate drawing of global border while fading, if needed
956 if (draw_border_function == NULL)
957 gfx.draw_global_border_function = NULL;
966 dst_rect.w = width; /* (ignored) */
967 dst_rect.h = height; /* (ignored) */
969 dst_rect2 = dst_rect;
971 /* copy source and target surfaces to temporary surfaces for fading */
972 if (fade_mode & FADE_TYPE_TRANSFORM)
974 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
975 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
977 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
978 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
980 else if (fade_mode & FADE_TYPE_FADE_IN)
982 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
983 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
985 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
987 else /* FADE_TYPE_FADE_OUT */
989 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
990 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
992 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
995 time_current = SDL_GetTicks();
997 if (fade_mode == FADE_MODE_MELT)
999 boolean done = FALSE;
1000 int melt_pixels = 2;
1001 int melt_columns = width / melt_pixels;
1002 int ypos[melt_columns];
1003 int max_steps = height / 8 + 32;
1008 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1009 #if defined(TARGET_SDL2)
1010 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1012 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1015 ypos[0] = -GetSimpleRandom(16);
1017 for (i = 1 ; i < melt_columns; i++)
1019 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1021 ypos[i] = ypos[i - 1] + r;
1034 time_last = time_current;
1035 time_current = SDL_GetTicks();
1036 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1037 steps_final = MIN(MAX(0, steps), max_steps);
1041 done = (steps_done >= steps_final);
1043 for (i = 0 ; i < melt_columns; i++)
1051 else if (ypos[i] < height)
1056 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1058 if (ypos[i] + dy >= height)
1059 dy = height - ypos[i];
1061 /* copy part of (appearing) target surface to upper area */
1062 src_rect.x = src_x + i * melt_pixels;
1063 // src_rect.y = src_y + ypos[i];
1065 src_rect.w = melt_pixels;
1067 src_rect.h = ypos[i] + dy;
1069 dst_rect.x = dst_x + i * melt_pixels;
1070 // dst_rect.y = dst_y + ypos[i];
1073 if (steps_done >= steps_final)
1074 SDL_BlitSurface(surface_target, &src_rect,
1075 surface_screen, &dst_rect);
1079 /* copy part of (disappearing) source surface to lower area */
1080 src_rect.x = src_x + i * melt_pixels;
1082 src_rect.w = melt_pixels;
1083 src_rect.h = height - ypos[i];
1085 dst_rect.x = dst_x + i * melt_pixels;
1086 dst_rect.y = dst_y + ypos[i];
1088 if (steps_done >= steps_final)
1089 SDL_BlitSurface(surface_source, &src_rect,
1090 surface_screen, &dst_rect);
1096 src_rect.x = src_x + i * melt_pixels;
1098 src_rect.w = melt_pixels;
1099 src_rect.h = height;
1101 dst_rect.x = dst_x + i * melt_pixels;
1104 if (steps_done >= steps_final)
1105 SDL_BlitSurface(surface_target, &src_rect,
1106 surface_screen, &dst_rect);
1110 if (steps_done >= steps_final)
1112 if (draw_border_function != NULL)
1113 draw_border_function();
1115 UpdateScreen(&dst_rect2);
1119 else if (fade_mode == FADE_MODE_CURTAIN)
1123 int xx_size = width / 2;
1125 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1126 #if defined(TARGET_SDL2)
1127 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1129 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1132 for (xx = 0; xx < xx_size;)
1134 time_last = time_current;
1135 time_current = SDL_GetTicks();
1136 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1137 xx_final = MIN(MAX(0, xx), xx_size);
1142 src_rect.h = height;
1147 /* draw new (target) image to screen buffer */
1148 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1150 if (xx_final < xx_size)
1152 src_rect.w = xx_size - xx_final;
1153 src_rect.h = height;
1155 /* draw old (source) image to screen buffer (left side) */
1157 src_rect.x = src_x + xx_final;
1160 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1162 /* draw old (source) image to screen buffer (right side) */
1164 src_rect.x = src_x + xx_size;
1165 dst_rect.x = dst_x + xx_size + xx_final;
1167 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1170 if (draw_border_function != NULL)
1171 draw_border_function();
1173 /* only update the region of the screen that is affected from fading */
1174 UpdateScreen(&dst_rect2);
1177 else /* fading in, fading out or cross-fading */
1182 for (alpha = 0.0; alpha < 255.0;)
1184 time_last = time_current;
1185 time_current = SDL_GetTicks();
1186 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1187 alpha_final = MIN(MAX(0, alpha), 255);
1189 /* draw existing (source) image to screen buffer */
1190 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1192 /* draw new (target) image to screen buffer using alpha blending */
1193 #if defined(TARGET_SDL2)
1194 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1195 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1197 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1199 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1201 if (draw_border_function != NULL)
1202 draw_border_function();
1204 /* only update the region of the screen that is affected from fading */
1205 UpdateScreen(&dst_rect);
1211 unsigned int time_post_delay;
1213 time_current = SDL_GetTicks();
1214 time_post_delay = time_current + post_delay;
1216 while (time_current < time_post_delay)
1218 // do not wait longer than 10 ms at a time to be able to ...
1219 Delay(MIN(10, time_post_delay - time_current));
1221 // ... continue drawing global animations during post delay
1224 time_current = SDL_GetTicks();
1228 // restore function for drawing global masked border
1229 gfx.draw_global_border_function = draw_global_border_function;
1232 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1233 int to_x, int to_y, Uint32 color)
1235 SDL_Surface *surface = dst_bitmap->surface;
1239 swap_numbers(&from_x, &to_x);
1242 swap_numbers(&from_y, &to_y);
1246 rect.w = (to_x - from_x + 1);
1247 rect.h = (to_y - from_y + 1);
1249 SDL_FillRect(surface, &rect, color);
1252 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1253 int to_x, int to_y, Uint32 color)
1255 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1258 #if ENABLE_UNUSED_CODE
1259 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1260 int num_points, Uint32 color)
1265 for (i = 0; i < num_points - 1; i++)
1267 for (x = 0; x < line_width; x++)
1269 for (y = 0; y < line_width; y++)
1271 int dx = x - line_width / 2;
1272 int dy = y - line_width / 2;
1274 if ((x == 0 && y == 0) ||
1275 (x == 0 && y == line_width - 1) ||
1276 (x == line_width - 1 && y == 0) ||
1277 (x == line_width - 1 && y == line_width - 1))
1280 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1281 points[i+1].x + dx, points[i+1].y + dy, color);
1288 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1290 SDL_Surface *surface = src_bitmap->surface;
1292 switch (surface->format->BytesPerPixel)
1294 case 1: /* assuming 8-bpp */
1296 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1300 case 2: /* probably 15-bpp or 16-bpp */
1302 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1306 case 3: /* slow 24-bpp mode; usually not used */
1308 /* does this work? */
1309 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1313 shift = surface->format->Rshift;
1314 color |= *(pix + shift / 8) >> shift;
1315 shift = surface->format->Gshift;
1316 color |= *(pix + shift / 8) >> shift;
1317 shift = surface->format->Bshift;
1318 color |= *(pix + shift / 8) >> shift;
1324 case 4: /* probably 32-bpp */
1326 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1335 /* ========================================================================= */
1336 /* The following functions were taken from the SGE library */
1337 /* (SDL Graphics Extension Library) by Anders Lindström */
1338 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1339 /* ========================================================================= */
1341 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1343 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1345 switch (surface->format->BytesPerPixel)
1349 /* Assuming 8-bpp */
1350 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1356 /* Probably 15-bpp or 16-bpp */
1357 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1363 /* Slow 24-bpp mode, usually not used */
1367 /* Gack - slow, but endian correct */
1368 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1369 shift = surface->format->Rshift;
1370 *(pix+shift/8) = color>>shift;
1371 shift = surface->format->Gshift;
1372 *(pix+shift/8) = color>>shift;
1373 shift = surface->format->Bshift;
1374 *(pix+shift/8) = color>>shift;
1380 /* Probably 32-bpp */
1381 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1388 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1389 Uint8 R, Uint8 G, Uint8 B)
1391 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1394 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1396 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1399 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1401 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1404 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1409 /* Gack - slow, but endian correct */
1410 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1411 shift = surface->format->Rshift;
1412 *(pix+shift/8) = color>>shift;
1413 shift = surface->format->Gshift;
1414 *(pix+shift/8) = color>>shift;
1415 shift = surface->format->Bshift;
1416 *(pix+shift/8) = color>>shift;
1419 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1421 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1424 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1426 switch (dest->format->BytesPerPixel)
1429 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1433 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1437 _PutPixel24(dest,x,y,color);
1441 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1446 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1448 if (SDL_MUSTLOCK(surface))
1450 if (SDL_LockSurface(surface) < 0)
1456 _PutPixel(surface, x, y, color);
1458 if (SDL_MUSTLOCK(surface))
1460 SDL_UnlockSurface(surface);
1464 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1465 Uint8 r, Uint8 g, Uint8 b)
1467 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1470 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1472 if (y >= 0 && y <= dest->h - 1)
1474 switch (dest->format->BytesPerPixel)
1477 return y*dest->pitch;
1481 return y*dest->pitch/2;
1485 return y*dest->pitch;
1489 return y*dest->pitch/4;
1497 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1499 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1501 switch (surface->format->BytesPerPixel)
1505 /* Assuming 8-bpp */
1506 *((Uint8 *)surface->pixels + ypitch + x) = color;
1512 /* Probably 15-bpp or 16-bpp */
1513 *((Uint16 *)surface->pixels + ypitch + x) = color;
1519 /* Slow 24-bpp mode, usually not used */
1523 /* Gack - slow, but endian correct */
1524 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1525 shift = surface->format->Rshift;
1526 *(pix+shift/8) = color>>shift;
1527 shift = surface->format->Gshift;
1528 *(pix+shift/8) = color>>shift;
1529 shift = surface->format->Bshift;
1530 *(pix+shift/8) = color>>shift;
1536 /* Probably 32-bpp */
1537 *((Uint32 *)surface->pixels + ypitch + x) = color;
1544 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1549 if (SDL_MUSTLOCK(Surface))
1551 if (SDL_LockSurface(Surface) < 0)
1564 /* Do the clipping */
1565 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1569 if (x2 > Surface->w - 1)
1570 x2 = Surface->w - 1;
1577 SDL_FillRect(Surface, &l, Color);
1579 if (SDL_MUSTLOCK(Surface))
1581 SDL_UnlockSurface(Surface);
1585 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1586 Uint8 R, Uint8 G, Uint8 B)
1588 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1591 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1602 /* Do the clipping */
1603 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1607 if (x2 > Surface->w - 1)
1608 x2 = Surface->w - 1;
1615 SDL_FillRect(Surface, &l, Color);
1618 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1623 if (SDL_MUSTLOCK(Surface))
1625 if (SDL_LockSurface(Surface) < 0)
1638 /* Do the clipping */
1639 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1643 if (y2 > Surface->h - 1)
1644 y2 = Surface->h - 1;
1651 SDL_FillRect(Surface, &l, Color);
1653 if (SDL_MUSTLOCK(Surface))
1655 SDL_UnlockSurface(Surface);
1659 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1660 Uint8 R, Uint8 G, Uint8 B)
1662 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1665 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1676 /* Do the clipping */
1677 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1681 if (y2 > Surface->h - 1)
1682 y2 = Surface->h - 1;
1689 SDL_FillRect(Surface, &l, Color);
1692 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1693 Sint16 x2, Sint16 y2, Uint32 Color,
1694 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1697 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1702 sdx = (dx < 0) ? -1 : 1;
1703 sdy = (dy < 0) ? -1 : 1;
1715 for (x = 0; x < dx; x++)
1717 Callback(Surface, px, py, Color);
1731 for (y = 0; y < dy; y++)
1733 Callback(Surface, px, py, Color);
1747 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1748 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1749 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1752 sge_DoLine(Surface, X1, Y1, X2, Y2,
1753 SDL_MapRGB(Surface->format, R, G, B), Callback);
1756 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1759 if (SDL_MUSTLOCK(Surface))
1761 if (SDL_LockSurface(Surface) < 0)
1766 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1768 /* unlock the display */
1769 if (SDL_MUSTLOCK(Surface))
1771 SDL_UnlockSurface(Surface);
1775 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1776 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1778 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1781 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1783 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1788 -----------------------------------------------------------------------------
1789 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1790 -----------------------------------------------------------------------------
1793 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1794 int width, int height, Uint32 color)
1798 for (y = src_y; y < src_y + height; y++)
1800 for (x = src_x; x < src_x + width; x++)
1802 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1804 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1809 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1810 int src_x, int src_y, int width, int height,
1811 int dst_x, int dst_y)
1815 for (y = 0; y < height; y++)
1817 for (x = 0; x < width; x++)
1819 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1821 if (pixel != BLACK_PIXEL)
1822 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1828 /* ========================================================================= */
1829 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1830 /* (Rotozoomer) by Andreas Schiffler */
1831 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1832 /* ========================================================================= */
1835 -----------------------------------------------------------------------------
1838 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1839 -----------------------------------------------------------------------------
1850 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1853 tColorRGBA *sp, *csp, *dp;
1857 sp = csp = (tColorRGBA *) src->pixels;
1858 dp = (tColorRGBA *) dst->pixels;
1859 dgap = dst->pitch - dst->w * 4;
1861 for (y = 0; y < dst->h; y++)
1865 for (x = 0; x < dst->w; x++)
1867 tColorRGBA *sp0 = sp;
1868 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1869 tColorRGBA *sp00 = &sp0[0];
1870 tColorRGBA *sp01 = &sp0[1];
1871 tColorRGBA *sp10 = &sp1[0];
1872 tColorRGBA *sp11 = &sp1[1];
1875 /* create new color pixel from all four source color pixels */
1876 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1877 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1878 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1879 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1884 /* advance source pointers */
1887 /* advance destination pointer */
1891 /* advance source pointer */
1892 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1894 /* advance destination pointers */
1895 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1901 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1903 int x, y, *sax, *say, *csax, *csay;
1905 tColorRGBA *sp, *csp, *csp0, *dp;
1908 /* use specialized zoom function when scaling down to exactly half size */
1909 if (src->w == 2 * dst->w &&
1910 src->h == 2 * dst->h)
1911 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1913 /* variable setup */
1914 sx = (float) src->w / (float) dst->w;
1915 sy = (float) src->h / (float) dst->h;
1917 /* allocate memory for row increments */
1918 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1919 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1921 /* precalculate row increments */
1922 for (x = 0; x <= dst->w; x++)
1923 *csax++ = (int)(sx * x);
1925 for (y = 0; y <= dst->h; y++)
1926 *csay++ = (int)(sy * y);
1929 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1930 dp = (tColorRGBA *) dst->pixels;
1931 dgap = dst->pitch - dst->w * 4;
1934 for (y = 0; y < dst->h; y++)
1939 for (x = 0; x < dst->w; x++)
1944 /* advance source pointers */
1948 /* advance destination pointer */
1952 /* advance source pointer */
1954 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1956 /* advance destination pointers */
1957 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1967 -----------------------------------------------------------------------------
1970 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1971 -----------------------------------------------------------------------------
1974 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1976 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1977 Uint8 *sp, *dp, *csp;
1980 /* variable setup */
1981 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1982 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1984 /* allocate memory for row increments */
1985 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1986 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1988 /* precalculate row increments */
1991 for (x = 0; x < dst->w; x++)
1994 *csax = (csx >> 16);
2001 for (y = 0; y < dst->h; y++)
2004 *csay = (csy >> 16);
2011 for (x = 0; x < dst->w; x++)
2019 for (y = 0; y < dst->h; y++)
2026 sp = csp = (Uint8 *) src->pixels;
2027 dp = (Uint8 *) dst->pixels;
2028 dgap = dst->pitch - dst->w;
2032 for (y = 0; y < dst->h; y++)
2036 for (x = 0; x < dst->w; x++)
2041 /* advance source pointers */
2045 /* advance destination pointer */
2049 /* advance source pointer (for row) */
2050 csp += ((*csay) * src->pitch);
2053 /* advance destination pointers */
2064 -----------------------------------------------------------------------------
2067 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2068 'zoomx' and 'zoomy' are scaling factors for width and height.
2069 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2070 into a 32bit RGBA format on the fly.
2071 -----------------------------------------------------------------------------
2074 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2076 SDL_Surface *zoom_src = NULL;
2077 SDL_Surface *zoom_dst = NULL;
2078 boolean is_converted = FALSE;
2085 /* determine if source surface is 32 bit or 8 bit */
2086 is_32bit = (src->format->BitsPerPixel == 32);
2088 if (is_32bit || src->format->BitsPerPixel == 8)
2090 /* use source surface 'as is' */
2095 /* new source surface is 32 bit with a defined RGB ordering */
2096 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2097 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2098 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2100 is_converted = TRUE;
2103 /* allocate surface to completely contain the zoomed surface */
2106 /* target surface is 32 bit with source RGBA/ABGR ordering */
2107 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2108 zoom_src->format->Rmask,
2109 zoom_src->format->Gmask,
2110 zoom_src->format->Bmask, 0);
2114 /* target surface is 8 bit */
2115 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2119 /* lock source surface */
2120 SDL_LockSurface(zoom_src);
2122 /* check which kind of surface we have */
2125 /* call the 32 bit transformation routine to do the zooming */
2126 zoomSurfaceRGBA(zoom_src, zoom_dst);
2131 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2132 zoom_dst->format->palette->colors[i] =
2133 zoom_src->format->palette->colors[i];
2134 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2136 /* call the 8 bit transformation routine to do the zooming */
2137 zoomSurfaceY(zoom_src, zoom_dst);
2140 /* unlock source surface */
2141 SDL_UnlockSurface(zoom_src);
2143 /* free temporary surface */
2145 SDL_FreeSurface(zoom_src);
2147 /* return destination surface */
2151 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2153 Bitmap *dst_bitmap = CreateBitmapStruct();
2154 SDL_Surface **dst_surface = &dst_bitmap->surface;
2156 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2157 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2159 dst_bitmap->width = dst_width;
2160 dst_bitmap->height = dst_height;
2162 /* create zoomed temporary surface from source surface */
2163 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2165 /* create native format destination surface from zoomed temporary surface */
2166 SDLSetNativeSurface(dst_surface);
2172 /* ========================================================================= */
2173 /* load image to bitmap */
2174 /* ========================================================================= */
2176 Bitmap *SDLLoadImage(char *filename)
2178 Bitmap *new_bitmap = CreateBitmapStruct();
2179 SDL_Surface *sdl_image_tmp;
2181 print_timestamp_init("SDLLoadImage");
2183 print_timestamp_time(getBaseNamePtr(filename));
2185 /* load image to temporary surface */
2186 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2188 SetError("IMG_Load(): %s", SDL_GetError());
2193 print_timestamp_time("IMG_Load");
2195 UPDATE_BUSY_STATE();
2197 /* create native non-transparent surface for current image */
2198 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2200 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2205 print_timestamp_time("SDL_DisplayFormat (opaque)");
2207 UPDATE_BUSY_STATE();
2209 /* create native transparent surface for current image */
2210 if (sdl_image_tmp->format->Amask == 0)
2211 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2212 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2214 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2216 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2221 print_timestamp_time("SDL_DisplayFormat (masked)");
2223 UPDATE_BUSY_STATE();
2225 /* free temporary surface */
2226 SDL_FreeSurface(sdl_image_tmp);
2228 new_bitmap->width = new_bitmap->surface->w;
2229 new_bitmap->height = new_bitmap->surface->h;
2231 print_timestamp_done("SDLLoadImage");
2237 /* ------------------------------------------------------------------------- */
2238 /* custom cursor fuctions */
2239 /* ------------------------------------------------------------------------- */
2241 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2243 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2244 cursor_info->width, cursor_info->height,
2245 cursor_info->hot_x, cursor_info->hot_y);
2248 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2250 static struct MouseCursorInfo *last_cursor_info = NULL;
2251 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2252 static SDL_Cursor *cursor_default = NULL;
2253 static SDL_Cursor *cursor_current = NULL;
2255 /* if invoked for the first time, store the SDL default cursor */
2256 if (cursor_default == NULL)
2257 cursor_default = SDL_GetCursor();
2259 /* only create new cursor if cursor info (custom only) has changed */
2260 if (cursor_info != NULL && cursor_info != last_cursor_info)
2262 cursor_current = create_cursor(cursor_info);
2263 last_cursor_info = cursor_info;
2266 /* only set new cursor if cursor info (custom or NULL) has changed */
2267 if (cursor_info != last_cursor_info2)
2268 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2270 last_cursor_info2 = cursor_info;
2274 /* ========================================================================= */
2275 /* audio functions */
2276 /* ========================================================================= */
2278 void SDLOpenAudio(void)
2280 #if !defined(TARGET_SDL2)
2281 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2282 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2285 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2287 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2291 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2292 AUDIO_NUM_CHANNELS_STEREO,
2293 setup.system.audio_fragment_size) < 0)
2295 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2299 audio.sound_available = TRUE;
2300 audio.music_available = TRUE;
2301 audio.loops_available = TRUE;
2302 audio.sound_enabled = TRUE;
2304 /* set number of available mixer channels */
2305 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2306 audio.music_channel = MUSIC_CHANNEL;
2307 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2309 Mixer_InitChannels();
2312 void SDLCloseAudio(void)
2315 Mix_HaltChannel(-1);
2318 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2322 /* ========================================================================= */
2323 /* event functions */
2324 /* ========================================================================= */
2326 void SDLNextEvent(Event *event)
2328 SDL_WaitEvent(event);
2331 void SDLHandleWindowManagerEvent(Event *event)
2334 #if defined(PLATFORM_WIN32)
2335 // experimental drag and drop code
2337 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2338 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2340 #if defined(TARGET_SDL2)
2341 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2343 if (syswmmsg->msg == WM_DROPFILES)
2346 #if defined(TARGET_SDL2)
2347 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2349 HDROP hdrop = (HDROP)syswmmsg->wParam;
2353 printf("::: SDL_SYSWMEVENT:\n");
2355 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2357 for (i = 0; i < num_files; i++)
2359 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2360 char buffer[buffer_len + 1];
2362 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2364 printf("::: - '%s'\n", buffer);
2367 #if defined(TARGET_SDL2)
2368 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2370 DragFinish((HDROP)syswmmsg->wParam);
2378 /* ========================================================================= */
2379 /* joystick functions */
2380 /* ========================================================================= */
2382 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2383 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2384 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2386 static boolean SDLOpenJoystick(int nr)
2388 if (nr < 0 || nr > MAX_PLAYERS)
2391 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2394 static void SDLCloseJoystick(int nr)
2396 if (nr < 0 || nr > MAX_PLAYERS)
2399 SDL_JoystickClose(sdl_joystick[nr]);
2401 sdl_joystick[nr] = NULL;
2404 static boolean SDLCheckJoystickOpened(int nr)
2406 if (nr < 0 || nr > MAX_PLAYERS)
2409 #if defined(TARGET_SDL2)
2410 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2412 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2416 void HandleJoystickEvent(Event *event)
2420 case SDL_JOYAXISMOTION:
2421 if (event->jaxis.axis < 2)
2422 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2425 case SDL_JOYBUTTONDOWN:
2426 if (event->jbutton.button < 2)
2427 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2430 case SDL_JOYBUTTONUP:
2431 if (event->jbutton.button < 2)
2432 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2440 void SDLInitJoysticks()
2442 static boolean sdl_joystick_subsystem_initialized = FALSE;
2443 boolean print_warning = !sdl_joystick_subsystem_initialized;
2446 if (!sdl_joystick_subsystem_initialized)
2448 sdl_joystick_subsystem_initialized = TRUE;
2450 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2452 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2457 for (i = 0; i < MAX_PLAYERS; i++)
2459 /* get configured joystick for this player */
2460 char *device_name = setup.input[i].joy.device_name;
2461 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2463 if (joystick_nr >= SDL_NumJoysticks())
2465 if (setup.input[i].use_joystick && print_warning)
2466 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2471 /* misuse joystick file descriptor variable to store joystick number */
2472 joystick.fd[i] = joystick_nr;
2474 if (joystick_nr == -1)
2477 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2478 if (SDLCheckJoystickOpened(joystick_nr))
2479 SDLCloseJoystick(joystick_nr);
2481 if (!setup.input[i].use_joystick)
2484 if (!SDLOpenJoystick(joystick_nr))
2487 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2492 joystick.status = JOYSTICK_ACTIVATED;
2496 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2498 if (nr < 0 || nr >= MAX_PLAYERS)
2502 *x = sdl_js_axis[nr][0];
2504 *y = sdl_js_axis[nr][1];
2507 *b1 = sdl_js_button[nr][0];
2509 *b2 = sdl_js_button[nr][1];