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 = NULL;
30 static boolean fullscreen_enabled = FALSE;
32 #define USE_RENDERER TRUE
35 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
36 static int fullscreen_width;
37 static int fullscreen_height;
38 static int fullscreen_xoffset;
39 static int fullscreen_yoffset;
40 static int video_xoffset;
41 static int video_yoffset;
42 static boolean limit_screen_updates = FALSE;
45 /* functions from SGE library */
46 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
48 void SDLLimitScreenUpdates(boolean enable)
50 limit_screen_updates = enable;
53 static void UpdateScreen(SDL_Rect *rect)
55 static unsigned int update_screen_delay = 0;
56 unsigned int update_screen_delay_value = 20; /* (milliseconds) */
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 defined(TARGET_SDL2)
83 SDL_Surface *screen = backbuffer->surface;
87 int bytes_x = screen->pitch / video.width;
88 int bytes_y = screen->pitch;
90 if (video.fullscreen_enabled)
91 bytes_x = screen->pitch / fullscreen_width;
93 SDL_UpdateTexture(sdl_texture, rect,
94 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
99 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
102 // clear render target buffer
103 SDL_RenderClear(sdl_renderer);
105 // copy backbuffer to render target buffer
106 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
108 // copy global animations to render target buffer, if defined
109 if (gfx.draw_global_anim_function != NULL)
110 gfx.draw_global_anim_function();
112 // show render target buffer on screen
113 SDL_RenderPresent(sdl_renderer);
118 SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
120 SDL_UpdateWindowSurface(sdl_window);
125 SDL_UpdateRects(backbuffer->surface, 1, rect);
127 SDL_UpdateRect(backbuffer->surface, 0, 0, 0, 0);
131 static void setFullscreenParameters(char *fullscreen_mode_string)
133 #if defined(TARGET_SDL2)
134 fullscreen_width = video.width;
135 fullscreen_height = video.height;
136 fullscreen_xoffset = 0;
137 fullscreen_yoffset = 0;
141 struct ScreenModeInfo *fullscreen_mode;
144 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
146 if (fullscreen_mode == NULL)
149 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
151 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
152 fullscreen_mode->height == video.fullscreen_modes[i].height)
154 fullscreen_width = fullscreen_mode->width;
155 fullscreen_height = fullscreen_mode->height;
157 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
158 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
166 static void SDLSetWindowIcon(char *basename)
168 /* (setting the window icon on Mac OS X would replace the high-quality
169 dock icon with the currently smaller (and uglier) icon from file) */
171 #if !defined(PLATFORM_MACOSX)
172 char *filename = getCustomImageFilename(basename);
173 SDL_Surface *surface;
175 if (filename == NULL)
177 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
182 if ((surface = IMG_Load(filename)) == NULL)
184 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
189 /* set transparent color */
190 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
191 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
193 #if defined(TARGET_SDL2)
194 SDL_SetWindowIcon(sdl_window, surface);
196 SDL_WM_SetIcon(surface, NULL);
201 #if defined(TARGET_SDL2)
203 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
204 SDL_PixelFormat *format2)
206 return (format1->format == format2->format &&
207 format1->BitsPerPixel == format2->BitsPerPixel &&
208 format1->BytesPerPixel == format2->BytesPerPixel &&
209 format1->Rmask == format2->Rmask &&
210 format1->Gmask == format2->Gmask &&
211 format1->Bmask == format2->Bmask &&
212 format1->Amask == format2->Amask);
215 boolean SDLSetNativeSurface(SDL_Surface **surface)
217 SDL_Surface *new_surface;
219 if (surface == NULL ||
221 backbuffer == NULL ||
222 backbuffer->surface == NULL)
225 // if pixel format already optimized for destination surface, do nothing
226 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
229 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
231 if (new_surface == NULL)
232 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
234 SDL_FreeSurface(*surface);
236 *surface = new_surface;
241 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
243 SDL_Surface *new_surface;
248 if (backbuffer && backbuffer->surface)
249 new_surface = SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
251 new_surface = SDL_ConvertSurface(surface, surface->format, 0);
253 if (new_surface == NULL)
254 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
261 boolean SDLSetNativeSurface(SDL_Surface **surface)
263 SDL_Surface *new_surface;
265 if (surface == NULL ||
270 new_surface = SDL_DisplayFormat(*surface);
272 if (new_surface == NULL)
273 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
275 SDL_FreeSurface(*surface);
277 *surface = new_surface;
282 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
284 SDL_Surface *new_surface;
286 if (video.initialized)
287 new_surface = SDL_DisplayFormat(surface);
289 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
291 if (new_surface == NULL)
292 Error(ERR_EXIT, "%s() failed: %s",
293 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
301 #if defined(TARGET_SDL2)
302 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
304 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
307 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
314 void SDLCreateBitmapTextures(Bitmap *bitmap)
316 #if defined(TARGET_SDL2)
321 SDL_DestroyTexture(bitmap->texture);
322 if (bitmap->texture_masked)
323 SDL_DestroyTexture(bitmap->texture_masked);
325 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
326 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
330 void SDLInitVideoDisplay(void)
332 #if !defined(TARGET_SDL2)
333 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
334 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
336 SDL_putenv("SDL_VIDEO_CENTERED=1");
339 /* initialize SDL video */
340 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
341 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
343 /* set default SDL depth */
344 #if !defined(TARGET_SDL2)
345 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
347 video.default_depth = 32; // (how to determine video depth in SDL2?)
351 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
354 #if !defined(TARGET_SDL2)
355 static int screen_xy[][2] =
363 SDL_Rect **modes = NULL;
364 boolean hardware_fullscreen_available = TRUE;
367 /* default: normal game window size */
368 fullscreen_width = video.width;
369 fullscreen_height = video.height;
370 fullscreen_xoffset = 0;
371 fullscreen_yoffset = 0;
373 #if !defined(TARGET_SDL2)
374 /* determine required standard fullscreen mode for game screen size */
375 for (i = 0; screen_xy[i][0] != -1; i++)
377 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
379 fullscreen_width = screen_xy[i][0];
380 fullscreen_height = screen_xy[i][1];
386 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
387 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
390 checked_free(video.fullscreen_modes);
392 video.fullscreen_modes = NULL;
393 video.fullscreen_mode_current = NULL;
395 video.window_scaling_percent = setup.window_scaling_percent;
396 video.window_scaling_quality = setup.window_scaling_quality;
398 #if defined(TARGET_SDL2)
399 int num_displays = SDL_GetNumVideoDisplays();
401 if (num_displays > 0)
403 // currently only display modes of first display supported
404 int num_modes = SDL_GetNumDisplayModes(0);
408 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
410 for (i = 0; i < num_modes; i++)
412 SDL_DisplayMode mode;
414 if (SDL_GetDisplayMode(0, i, &mode) < 0)
417 modes[i] = checked_calloc(sizeof(SDL_Rect));
419 modes[i]->w = mode.w;
420 modes[i]->h = mode.h;
425 /* get available hardware supported fullscreen modes */
426 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
431 /* no hardware screen modes available => no fullscreen mode support */
432 // video.fullscreen_available = FALSE;
433 hardware_fullscreen_available = FALSE;
435 else if (modes == (SDL_Rect **)-1)
437 /* fullscreen resolution is not restricted -- all resolutions available */
438 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
440 /* use native video buffer size for fullscreen mode */
441 video.fullscreen_modes[0].width = video.width;
442 video.fullscreen_modes[0].height = video.height;
444 video.fullscreen_modes[1].width = -1;
445 video.fullscreen_modes[1].height = -1;
449 /* in this case, a certain number of screen modes is available */
452 for (i = 0; modes[i] != NULL; i++)
454 boolean found_mode = FALSE;
456 /* screen mode is smaller than video buffer size -- skip it */
457 if (modes[i]->w < video.width || modes[i]->h < video.height)
460 if (video.fullscreen_modes != NULL)
461 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
462 if (modes[i]->w == video.fullscreen_modes[j].width &&
463 modes[i]->h == video.fullscreen_modes[j].height)
466 if (found_mode) /* screen mode already stored -- skip it */
469 /* new mode found; add it to list of available fullscreen modes */
473 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
475 sizeof(struct ScreenModeInfo));
477 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
478 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
480 video.fullscreen_modes[num_modes].width = -1;
481 video.fullscreen_modes[num_modes].height = -1;
486 /* no appropriate screen modes available => no fullscreen mode support */
487 // video.fullscreen_available = FALSE;
488 hardware_fullscreen_available = FALSE;
492 video.fullscreen_available = hardware_fullscreen_available;
494 #if USE_DESKTOP_FULLSCREEN
495 // in SDL 2.0, there is always support for desktop fullscreen mode
496 // (in SDL 1.2, there is only support for "real" fullscreen mode)
497 video.fullscreen_available = TRUE;
500 #if defined(TARGET_SDL2)
503 for (i = 0; modes[i] != NULL; i++)
504 checked_free(modes[i]);
510 /* open SDL video output device (window or fullscreen mode) */
511 if (!SDLSetVideoMode(backbuffer, fullscreen))
512 Error(ERR_EXIT, "setting video mode failed");
514 /* !!! SDL2 can only set the window icon if the window already exists !!! */
515 /* set window icon */
516 SDLSetWindowIcon(program.icon_filename);
518 /* set window and icon title */
519 #if defined(TARGET_SDL2)
520 SDL_SetWindowTitle(sdl_window, program.window_title);
522 SDL_WM_SetCaption(program.window_title, program.window_title);
525 /* SDL cannot directly draw to the visible video framebuffer like X11,
526 but always uses a backbuffer, which is then blitted to the visible
527 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
528 visible video framebuffer with 'SDL_Flip', if the hardware supports
529 this). Therefore do not use an additional backbuffer for drawing, but
530 use a symbolic buffer (distinguishable from the SDL backbuffer) called
531 'window', which indicates that the SDL backbuffer should be updated to
532 the visible video framebuffer when attempting to blit to it.
534 For convenience, it seems to be a good idea to create this symbolic
535 buffer 'window' at the same size as the SDL backbuffer. Although it
536 should never be drawn to directly, it would do no harm nevertheless. */
538 /* create additional (symbolic) buffer for double-buffering */
539 ReCreateBitmap(window, video.width, video.height, video.depth);
542 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
545 SDL_Surface *new_surface = NULL;
547 #if defined(TARGET_SDL2)
548 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
549 #if USE_DESKTOP_FULLSCREEN
550 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
552 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
556 int surface_flags_window = SURFACE_FLAGS;
557 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
560 int width = (fullscreen ? fullscreen_width : video.width);
561 int height = (fullscreen ? fullscreen_height : video.height);
562 int surface_flags = (fullscreen ? surface_flags_fullscreen :
563 surface_flags_window);
565 // default window size is unscaled
566 video.window_width = video.width;
567 video.window_height = video.height;
569 #if defined(TARGET_SDL2)
571 // store if initial screen mode is fullscreen mode when changing screen size
572 video.fullscreen_initial = fullscreen;
575 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
576 #if !USE_DESKTOP_FULLSCREEN
577 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
580 video.window_width = window_scaling_factor * width;
581 video.window_height = window_scaling_factor * height;
583 if ((*backbuffer)->surface)
585 SDL_FreeSurface((*backbuffer)->surface);
586 (*backbuffer)->surface = NULL;
591 SDL_DestroyTexture(sdl_texture);
595 if (!(fullscreen && fullscreen_enabled))
599 SDL_DestroyRenderer(sdl_renderer);
605 SDL_DestroyWindow(sdl_window);
610 if (sdl_window == NULL)
611 sdl_window = SDL_CreateWindow(program.window_title,
612 SDL_WINDOWPOS_CENTERED,
613 SDL_WINDOWPOS_CENTERED,
614 #if USE_DESKTOP_FULLSCREEN
618 (int)(screen_scaling_factor * width),
619 (int)(screen_scaling_factor * height),
623 if (sdl_window != NULL)
626 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
627 *without* enabling 2D/3D acceleration and/or guest additions installed,
628 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
629 it will try to use accelerated graphics and apparently fails miserably) */
630 if (sdl_renderer == NULL)
631 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
633 if (sdl_renderer == NULL)
634 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
637 if (sdl_renderer != NULL)
639 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
640 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
641 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
643 sdl_texture = SDL_CreateTexture(sdl_renderer,
644 SDL_PIXELFORMAT_ARGB8888,
645 SDL_TEXTUREACCESS_STREAMING,
648 if (sdl_texture != NULL)
650 // use SDL default values for RGB masks and no alpha channel
651 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
653 if (new_surface == NULL)
654 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
659 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
664 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
669 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
675 SDL_DestroyWindow(sdl_window);
677 sdl_window = SDL_CreateWindow(program.window_title,
678 SDL_WINDOWPOS_CENTERED,
679 SDL_WINDOWPOS_CENTERED,
683 if (sdl_window != NULL)
684 new_surface = SDL_GetWindowSurface(sdl_window);
688 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
691 #if defined(TARGET_SDL2)
692 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
693 if (new_surface != NULL)
694 fullscreen_enabled = fullscreen;
700 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
702 boolean success = TRUE;
703 SDL_Surface *new_surface = NULL;
707 if (*backbuffer == NULL)
708 *backbuffer = CreateBitmapStruct();
710 /* (real bitmap might be larger in fullscreen mode with video offsets) */
711 (*backbuffer)->width = video.width;
712 (*backbuffer)->height = video.height;
714 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
716 setFullscreenParameters(setup.fullscreen_mode);
718 video_xoffset = fullscreen_xoffset;
719 video_yoffset = fullscreen_yoffset;
721 /* switch display to fullscreen mode, if available */
722 new_surface = SDLCreateScreen(backbuffer, TRUE);
724 if (new_surface == NULL)
726 /* switching display to fullscreen mode failed */
727 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
729 /* do not try it again */
730 video.fullscreen_available = FALSE;
736 (*backbuffer)->surface = new_surface;
738 video.fullscreen_enabled = TRUE;
739 video.fullscreen_mode_current = setup.fullscreen_mode;
745 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
750 /* switch display to window mode */
751 new_surface = SDLCreateScreen(backbuffer, FALSE);
753 if (new_surface == NULL)
755 /* switching display to window mode failed -- should not happen */
756 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
762 (*backbuffer)->surface = new_surface;
764 video.fullscreen_enabled = FALSE;
765 video.window_scaling_percent = setup.window_scaling_percent;
766 video.window_scaling_quality = setup.window_scaling_quality;
772 #if defined(TARGET_SDL2)
773 SDLRedrawWindow(); // map window
777 #if defined(PLATFORM_WIN32)
778 // experimental drag and drop code
780 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
783 SDL_SysWMinfo wminfo;
785 boolean wminfo_success = FALSE;
787 SDL_VERSION(&wminfo.version);
788 #if defined(TARGET_SDL2)
790 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
792 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
797 #if defined(TARGET_SDL2)
798 hwnd = wminfo.info.win.window;
800 hwnd = wminfo.window;
803 DragAcceptFiles(hwnd, TRUE);
812 void SDLSetWindowTitle()
814 #if defined(TARGET_SDL2)
815 SDL_SetWindowTitle(sdl_window, program.window_title);
817 SDL_WM_SetCaption(program.window_title, program.window_title);
821 #if defined(TARGET_SDL2)
822 void SDLSetWindowScaling(int window_scaling_percent)
824 if (sdl_window == NULL)
827 float window_scaling_factor = (float)window_scaling_percent / 100;
828 int new_window_width = (int)(window_scaling_factor * video.width);
829 int new_window_height = (int)(window_scaling_factor * video.height);
831 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
833 video.window_scaling_percent = window_scaling_percent;
834 video.window_width = new_window_width;
835 video.window_height = new_window_height;
840 void SDLSetWindowScalingQuality(char *window_scaling_quality)
842 if (sdl_texture == NULL)
845 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
847 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
848 SDL_PIXELFORMAT_ARGB8888,
849 SDL_TEXTUREACCESS_STREAMING,
850 video.width, video.height);
852 if (new_texture != NULL)
854 SDL_DestroyTexture(sdl_texture);
856 sdl_texture = new_texture;
861 video.window_scaling_quality = window_scaling_quality;
864 void SDLSetWindowFullscreen(boolean fullscreen)
866 if (sdl_window == NULL)
869 #if USE_DESKTOP_FULLSCREEN
870 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
872 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
875 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
876 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
878 // if screen size was changed in fullscreen mode, correct desktop window size
879 if (!fullscreen && video.fullscreen_initial)
881 SDLSetWindowScaling(setup.window_scaling_percent);
882 SDL_SetWindowPosition(sdl_window,
883 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
885 video.fullscreen_initial = FALSE;
889 void SDLRedrawWindow()
895 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
898 SDL_Surface *surface =
899 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
902 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
904 SDLSetNativeSurface(&surface);
906 bitmap->surface = surface;
909 void SDLFreeBitmapPointers(Bitmap *bitmap)
912 SDL_FreeSurface(bitmap->surface);
913 if (bitmap->surface_masked)
914 SDL_FreeSurface(bitmap->surface_masked);
916 bitmap->surface = NULL;
917 bitmap->surface_masked = NULL;
919 #if defined(TARGET_SDL2)
921 SDL_DestroyTexture(bitmap->texture);
922 if (bitmap->texture_masked)
923 SDL_DestroyTexture(bitmap->texture_masked);
925 bitmap->texture = NULL;
926 bitmap->texture_masked = NULL;
930 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
931 int src_x, int src_y, int width, int height,
932 int dst_x, int dst_y, int mask_mode)
934 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
935 SDL_Rect src_rect, dst_rect;
937 if (src_bitmap == backbuffer)
939 src_x += video_xoffset;
940 src_y += video_yoffset;
948 if (dst_bitmap == backbuffer || dst_bitmap == window)
950 dst_x += video_xoffset;
951 dst_y += video_yoffset;
959 // if (src_bitmap != backbuffer || dst_bitmap != window)
960 if (!(src_bitmap == backbuffer && dst_bitmap == window))
961 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
962 src_bitmap->surface_masked : src_bitmap->surface),
963 &src_rect, real_dst_bitmap->surface, &dst_rect);
965 #if defined(TARGET_SDL2)
966 if (dst_bitmap == window)
968 // SDL_UpdateWindowSurface(sdl_window);
969 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
970 UpdateScreen(&dst_rect);
973 if (dst_bitmap == window)
975 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
976 UpdateScreen(&dst_rect);
981 void SDLBlitTexture(Bitmap *bitmap,
982 int src_x, int src_y, int width, int height,
983 int dst_x, int dst_y, int mask_mode)
985 #if defined(TARGET_SDL2)
987 SDL_Texture *texture;
992 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
1000 src_rect.h = height;
1005 dst_rect.h = height;
1007 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
1012 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
1015 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1018 if (dst_bitmap == backbuffer || dst_bitmap == window)
1029 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
1031 #if defined(TARGET_SDL2)
1032 if (dst_bitmap == window)
1034 // SDL_UpdateWindowSurface(sdl_window);
1035 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
1036 UpdateScreen(&rect);
1039 if (dst_bitmap == window)
1041 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
1042 UpdateScreen(&rect);
1047 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
1048 int fade_mode, int fade_delay, int post_delay,
1049 void (*draw_border_function)(void))
1051 static boolean initialization_needed = TRUE;
1052 static SDL_Surface *surface_source = NULL;
1053 static SDL_Surface *surface_target = NULL;
1054 static SDL_Surface *surface_black = NULL;
1055 SDL_Surface *surface_screen = backbuffer->surface;
1056 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
1057 SDL_Rect src_rect, dst_rect;
1059 int src_x = x, src_y = y;
1060 int dst_x = x, dst_y = y;
1061 unsigned int time_last, time_current;
1063 /* check if screen size has changed */
1064 if (surface_source != NULL && (video.width != surface_source->w ||
1065 video.height != surface_source->h))
1067 SDL_FreeSurface(surface_source);
1068 SDL_FreeSurface(surface_target);
1069 SDL_FreeSurface(surface_black);
1071 initialization_needed = TRUE;
1077 src_rect.h = height;
1079 dst_x += video_xoffset;
1080 dst_y += video_yoffset;
1084 dst_rect.w = width; /* (ignored) */
1085 dst_rect.h = height; /* (ignored) */
1087 dst_rect2 = dst_rect;
1089 if (initialization_needed)
1091 #if defined(TARGET_SDL2)
1092 unsigned int flags = 0;
1094 unsigned int flags = SDL_SRCALPHA;
1096 /* use same surface type as screen surface */
1097 if ((surface_screen->flags & SDL_HWSURFACE))
1098 flags |= SDL_HWSURFACE;
1100 flags |= SDL_SWSURFACE;
1103 /* create surface for temporary copy of screen buffer (source) */
1104 if ((surface_source =
1105 SDL_CreateRGBSurface(flags,
1108 surface_screen->format->BitsPerPixel,
1109 surface_screen->format->Rmask,
1110 surface_screen->format->Gmask,
1111 surface_screen->format->Bmask,
1112 surface_screen->format->Amask)) == NULL)
1113 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1115 /* create surface for cross-fading screen buffer (target) */
1116 if ((surface_target =
1117 SDL_CreateRGBSurface(flags,
1120 surface_screen->format->BitsPerPixel,
1121 surface_screen->format->Rmask,
1122 surface_screen->format->Gmask,
1123 surface_screen->format->Bmask,
1124 surface_screen->format->Amask)) == NULL)
1125 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1127 /* create black surface for fading from/to black */
1128 if ((surface_black =
1129 SDL_CreateRGBSurface(flags,
1132 surface_screen->format->BitsPerPixel,
1133 surface_screen->format->Rmask,
1134 surface_screen->format->Gmask,
1135 surface_screen->format->Bmask,
1136 surface_screen->format->Amask)) == NULL)
1137 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1139 /* completely fill the surface with black color pixels */
1140 SDL_FillRect(surface_black, NULL,
1141 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1143 initialization_needed = FALSE;
1146 /* copy source and target surfaces to temporary surfaces for fading */
1147 if (fade_mode & FADE_TYPE_TRANSFORM)
1149 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1150 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1152 else if (fade_mode & FADE_TYPE_FADE_IN)
1154 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1155 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1157 else /* FADE_TYPE_FADE_OUT */
1159 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1160 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1163 time_current = SDL_GetTicks();
1165 if (fade_mode == FADE_MODE_MELT)
1167 boolean done = FALSE;
1168 int melt_pixels = 2;
1169 int melt_columns = width / melt_pixels;
1170 int ypos[melt_columns];
1171 int max_steps = height / 8 + 32;
1176 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1177 #if defined(TARGET_SDL2)
1178 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1180 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1183 ypos[0] = -GetSimpleRandom(16);
1185 for (i = 1 ; i < melt_columns; i++)
1187 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1189 ypos[i] = ypos[i - 1] + r;
1202 time_last = time_current;
1203 time_current = SDL_GetTicks();
1204 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1205 steps_final = MIN(MAX(0, steps), max_steps);
1209 done = (steps_done >= steps_final);
1211 for (i = 0 ; i < melt_columns; i++)
1219 else if (ypos[i] < height)
1224 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1226 if (ypos[i] + dy >= height)
1227 dy = height - ypos[i];
1229 /* copy part of (appearing) target surface to upper area */
1230 src_rect.x = src_x + i * melt_pixels;
1231 // src_rect.y = src_y + ypos[i];
1233 src_rect.w = melt_pixels;
1235 src_rect.h = ypos[i] + dy;
1237 dst_rect.x = dst_x + i * melt_pixels;
1238 // dst_rect.y = dst_y + ypos[i];
1241 if (steps_done >= steps_final)
1242 SDL_BlitSurface(surface_target, &src_rect,
1243 surface_screen, &dst_rect);
1247 /* copy part of (disappearing) source surface to lower area */
1248 src_rect.x = src_x + i * melt_pixels;
1250 src_rect.w = melt_pixels;
1251 src_rect.h = height - ypos[i];
1253 dst_rect.x = dst_x + i * melt_pixels;
1254 dst_rect.y = dst_y + ypos[i];
1256 if (steps_done >= steps_final)
1257 SDL_BlitSurface(surface_source, &src_rect,
1258 surface_screen, &dst_rect);
1264 src_rect.x = src_x + i * melt_pixels;
1266 src_rect.w = melt_pixels;
1267 src_rect.h = height;
1269 dst_rect.x = dst_x + i * melt_pixels;
1272 if (steps_done >= steps_final)
1273 SDL_BlitSurface(surface_target, &src_rect,
1274 surface_screen, &dst_rect);
1278 if (steps_done >= steps_final)
1280 if (draw_border_function != NULL)
1281 draw_border_function();
1283 UpdateScreen(&dst_rect2);
1287 else if (fade_mode == FADE_MODE_CURTAIN)
1291 int xx_size = width / 2;
1293 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1294 #if defined(TARGET_SDL2)
1295 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1297 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1300 for (xx = 0; xx < xx_size;)
1302 time_last = time_current;
1303 time_current = SDL_GetTicks();
1304 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1305 xx_final = MIN(MAX(0, xx), xx_size);
1310 src_rect.h = height;
1315 /* draw new (target) image to screen buffer */
1316 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1318 if (xx_final < xx_size)
1320 src_rect.w = xx_size - xx_final;
1321 src_rect.h = height;
1323 /* draw old (source) image to screen buffer (left side) */
1325 src_rect.x = src_x + xx_final;
1328 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1330 /* draw old (source) image to screen buffer (right side) */
1332 src_rect.x = src_x + xx_size;
1333 dst_rect.x = dst_x + xx_size + xx_final;
1335 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1338 if (draw_border_function != NULL)
1339 draw_border_function();
1341 /* only update the region of the screen that is affected from fading */
1342 UpdateScreen(&dst_rect2);
1345 else /* fading in, fading out or cross-fading */
1350 for (alpha = 0.0; alpha < 255.0;)
1352 time_last = time_current;
1353 time_current = SDL_GetTicks();
1354 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1355 alpha_final = MIN(MAX(0, alpha), 255);
1357 /* draw existing (source) image to screen buffer */
1358 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1360 /* draw new (target) image to screen buffer using alpha blending */
1361 #if defined(TARGET_SDL2)
1362 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1363 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1365 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1367 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1369 if (draw_border_function != NULL)
1370 draw_border_function();
1372 /* only update the region of the screen that is affected from fading */
1373 UpdateScreen(&dst_rect);
1380 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1381 int to_x, int to_y, Uint32 color)
1383 SDL_Surface *surface = dst_bitmap->surface;
1387 swap_numbers(&from_x, &to_x);
1390 swap_numbers(&from_y, &to_y);
1394 rect.w = (to_x - from_x + 1);
1395 rect.h = (to_y - from_y + 1);
1397 if (dst_bitmap == backbuffer || dst_bitmap == window)
1399 rect.x += video_xoffset;
1400 rect.y += video_yoffset;
1403 SDL_FillRect(surface, &rect, color);
1406 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1407 int to_x, int to_y, Uint32 color)
1409 if (dst_bitmap == backbuffer || dst_bitmap == window)
1411 from_x += video_xoffset;
1412 from_y += video_yoffset;
1413 to_x += video_xoffset;
1414 to_y += video_yoffset;
1417 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1420 #if ENABLE_UNUSED_CODE
1421 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1422 int num_points, Uint32 color)
1427 for (i = 0; i < num_points - 1; i++)
1429 for (x = 0; x < line_width; x++)
1431 for (y = 0; y < line_width; y++)
1433 int dx = x - line_width / 2;
1434 int dy = y - line_width / 2;
1436 if ((x == 0 && y == 0) ||
1437 (x == 0 && y == line_width - 1) ||
1438 (x == line_width - 1 && y == 0) ||
1439 (x == line_width - 1 && y == line_width - 1))
1442 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1443 points[i+1].x + dx, points[i+1].y + dy, color);
1450 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1452 SDL_Surface *surface = src_bitmap->surface;
1454 if (src_bitmap == backbuffer || src_bitmap == window)
1460 switch (surface->format->BytesPerPixel)
1462 case 1: /* assuming 8-bpp */
1464 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1468 case 2: /* probably 15-bpp or 16-bpp */
1470 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1474 case 3: /* slow 24-bpp mode; usually not used */
1476 /* does this work? */
1477 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1481 shift = surface->format->Rshift;
1482 color |= *(pix + shift / 8) >> shift;
1483 shift = surface->format->Gshift;
1484 color |= *(pix + shift / 8) >> shift;
1485 shift = surface->format->Bshift;
1486 color |= *(pix + shift / 8) >> shift;
1492 case 4: /* probably 32-bpp */
1494 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1503 /* ========================================================================= */
1504 /* The following functions were taken from the SGE library */
1505 /* (SDL Graphics Extension Library) by Anders Lindström */
1506 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1507 /* ========================================================================= */
1509 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1511 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1513 switch (surface->format->BytesPerPixel)
1517 /* Assuming 8-bpp */
1518 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1524 /* Probably 15-bpp or 16-bpp */
1525 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1531 /* Slow 24-bpp mode, usually not used */
1535 /* Gack - slow, but endian correct */
1536 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1537 shift = surface->format->Rshift;
1538 *(pix+shift/8) = color>>shift;
1539 shift = surface->format->Gshift;
1540 *(pix+shift/8) = color>>shift;
1541 shift = surface->format->Bshift;
1542 *(pix+shift/8) = color>>shift;
1548 /* Probably 32-bpp */
1549 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1556 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1557 Uint8 R, Uint8 G, Uint8 B)
1559 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1562 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1564 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1567 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1569 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1572 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1577 /* Gack - slow, but endian correct */
1578 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1579 shift = surface->format->Rshift;
1580 *(pix+shift/8) = color>>shift;
1581 shift = surface->format->Gshift;
1582 *(pix+shift/8) = color>>shift;
1583 shift = surface->format->Bshift;
1584 *(pix+shift/8) = color>>shift;
1587 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1589 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1592 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1594 switch (dest->format->BytesPerPixel)
1597 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1601 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1605 _PutPixel24(dest,x,y,color);
1609 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1614 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1616 if (SDL_MUSTLOCK(surface))
1618 if (SDL_LockSurface(surface) < 0)
1624 _PutPixel(surface, x, y, color);
1626 if (SDL_MUSTLOCK(surface))
1628 SDL_UnlockSurface(surface);
1632 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1633 Uint8 r, Uint8 g, Uint8 b)
1635 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1638 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1640 if (y >= 0 && y <= dest->h - 1)
1642 switch (dest->format->BytesPerPixel)
1645 return y*dest->pitch;
1649 return y*dest->pitch/2;
1653 return y*dest->pitch;
1657 return y*dest->pitch/4;
1665 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1667 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1669 switch (surface->format->BytesPerPixel)
1673 /* Assuming 8-bpp */
1674 *((Uint8 *)surface->pixels + ypitch + x) = color;
1680 /* Probably 15-bpp or 16-bpp */
1681 *((Uint16 *)surface->pixels + ypitch + x) = color;
1687 /* Slow 24-bpp mode, usually not used */
1691 /* Gack - slow, but endian correct */
1692 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1693 shift = surface->format->Rshift;
1694 *(pix+shift/8) = color>>shift;
1695 shift = surface->format->Gshift;
1696 *(pix+shift/8) = color>>shift;
1697 shift = surface->format->Bshift;
1698 *(pix+shift/8) = color>>shift;
1704 /* Probably 32-bpp */
1705 *((Uint32 *)surface->pixels + ypitch + x) = color;
1712 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1717 if (SDL_MUSTLOCK(Surface))
1719 if (SDL_LockSurface(Surface) < 0)
1732 /* Do the clipping */
1733 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1737 if (x2 > Surface->w - 1)
1738 x2 = Surface->w - 1;
1745 SDL_FillRect(Surface, &l, Color);
1747 if (SDL_MUSTLOCK(Surface))
1749 SDL_UnlockSurface(Surface);
1753 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1754 Uint8 R, Uint8 G, Uint8 B)
1756 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1759 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1770 /* Do the clipping */
1771 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1775 if (x2 > Surface->w - 1)
1776 x2 = Surface->w - 1;
1783 SDL_FillRect(Surface, &l, Color);
1786 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1791 if (SDL_MUSTLOCK(Surface))
1793 if (SDL_LockSurface(Surface) < 0)
1806 /* Do the clipping */
1807 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1811 if (y2 > Surface->h - 1)
1812 y2 = Surface->h - 1;
1819 SDL_FillRect(Surface, &l, Color);
1821 if (SDL_MUSTLOCK(Surface))
1823 SDL_UnlockSurface(Surface);
1827 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1828 Uint8 R, Uint8 G, Uint8 B)
1830 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1833 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1844 /* Do the clipping */
1845 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1849 if (y2 > Surface->h - 1)
1850 y2 = Surface->h - 1;
1857 SDL_FillRect(Surface, &l, Color);
1860 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1861 Sint16 x2, Sint16 y2, Uint32 Color,
1862 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1865 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1870 sdx = (dx < 0) ? -1 : 1;
1871 sdy = (dy < 0) ? -1 : 1;
1883 for (x = 0; x < dx; x++)
1885 Callback(Surface, px, py, Color);
1899 for (y = 0; y < dy; y++)
1901 Callback(Surface, px, py, Color);
1915 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1916 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1917 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1920 sge_DoLine(Surface, X1, Y1, X2, Y2,
1921 SDL_MapRGB(Surface->format, R, G, B), Callback);
1924 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1927 if (SDL_MUSTLOCK(Surface))
1929 if (SDL_LockSurface(Surface) < 0)
1934 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1936 /* unlock the display */
1937 if (SDL_MUSTLOCK(Surface))
1939 SDL_UnlockSurface(Surface);
1943 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1944 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1946 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1949 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1951 if (dst_bitmap == backbuffer || dst_bitmap == window)
1957 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1962 -----------------------------------------------------------------------------
1963 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1964 -----------------------------------------------------------------------------
1967 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1968 int width, int height, Uint32 color)
1972 for (y = src_y; y < src_y + height; y++)
1974 for (x = src_x; x < src_x + width; x++)
1976 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1978 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1983 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1984 int src_x, int src_y, int width, int height,
1985 int dst_x, int dst_y)
1989 for (y = 0; y < height; y++)
1991 for (x = 0; x < width; x++)
1993 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1995 if (pixel != BLACK_PIXEL)
1996 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
2002 /* ========================================================================= */
2003 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
2004 /* (Rotozoomer) by Andreas Schiffler */
2005 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
2006 /* ========================================================================= */
2009 -----------------------------------------------------------------------------
2012 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
2013 -----------------------------------------------------------------------------
2024 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
2027 tColorRGBA *sp, *csp, *dp;
2031 sp = csp = (tColorRGBA *) src->pixels;
2032 dp = (tColorRGBA *) dst->pixels;
2033 dgap = dst->pitch - dst->w * 4;
2035 for (y = 0; y < dst->h; y++)
2039 for (x = 0; x < dst->w; x++)
2041 tColorRGBA *sp0 = sp;
2042 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
2043 tColorRGBA *sp00 = &sp0[0];
2044 tColorRGBA *sp01 = &sp0[1];
2045 tColorRGBA *sp10 = &sp1[0];
2046 tColorRGBA *sp11 = &sp1[1];
2049 /* create new color pixel from all four source color pixels */
2050 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2051 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2052 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2053 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2058 /* advance source pointers */
2061 /* advance destination pointer */
2065 /* advance source pointer */
2066 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2068 /* advance destination pointers */
2069 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2075 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2077 int x, y, *sax, *say, *csax, *csay;
2079 tColorRGBA *sp, *csp, *csp0, *dp;
2082 /* use specialized zoom function when scaling down to exactly half size */
2083 if (src->w == 2 * dst->w &&
2084 src->h == 2 * dst->h)
2085 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2087 /* variable setup */
2088 sx = (float) src->w / (float) dst->w;
2089 sy = (float) src->h / (float) dst->h;
2091 /* allocate memory for row increments */
2092 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2093 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2095 /* precalculate row increments */
2096 for (x = 0; x <= dst->w; x++)
2097 *csax++ = (int)(sx * x);
2099 for (y = 0; y <= dst->h; y++)
2100 *csay++ = (int)(sy * y);
2103 sp = csp = csp0 = (tColorRGBA *) src->pixels;
2104 dp = (tColorRGBA *) dst->pixels;
2105 dgap = dst->pitch - dst->w * 4;
2108 for (y = 0; y < dst->h; y++)
2113 for (x = 0; x < dst->w; x++)
2118 /* advance source pointers */
2122 /* advance destination pointer */
2126 /* advance source pointer */
2128 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
2130 /* advance destination pointers */
2131 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2141 -----------------------------------------------------------------------------
2144 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2145 -----------------------------------------------------------------------------
2148 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2150 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2151 Uint8 *sp, *dp, *csp;
2154 /* variable setup */
2155 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2156 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2158 /* allocate memory for row increments */
2159 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2160 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2162 /* precalculate row increments */
2165 for (x = 0; x < dst->w; x++)
2168 *csax = (csx >> 16);
2175 for (y = 0; y < dst->h; y++)
2178 *csay = (csy >> 16);
2185 for (x = 0; x < dst->w; x++)
2193 for (y = 0; y < dst->h; y++)
2200 sp = csp = (Uint8 *) src->pixels;
2201 dp = (Uint8 *) dst->pixels;
2202 dgap = dst->pitch - dst->w;
2206 for (y = 0; y < dst->h; y++)
2210 for (x = 0; x < dst->w; x++)
2215 /* advance source pointers */
2219 /* advance destination pointer */
2223 /* advance source pointer (for row) */
2224 csp += ((*csay) * src->pitch);
2227 /* advance destination pointers */
2238 -----------------------------------------------------------------------------
2241 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2242 'zoomx' and 'zoomy' are scaling factors for width and height.
2243 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2244 into a 32bit RGBA format on the fly.
2245 -----------------------------------------------------------------------------
2248 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2250 SDL_Surface *zoom_src = NULL;
2251 SDL_Surface *zoom_dst = NULL;
2252 boolean is_converted = FALSE;
2259 /* determine if source surface is 32 bit or 8 bit */
2260 is_32bit = (src->format->BitsPerPixel == 32);
2262 if (is_32bit || src->format->BitsPerPixel == 8)
2264 /* use source surface 'as is' */
2269 /* new source surface is 32 bit with a defined RGB ordering */
2270 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2271 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2272 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2274 is_converted = TRUE;
2277 /* allocate surface to completely contain the zoomed surface */
2280 /* target surface is 32 bit with source RGBA/ABGR ordering */
2281 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2282 zoom_src->format->Rmask,
2283 zoom_src->format->Gmask,
2284 zoom_src->format->Bmask, 0);
2288 /* target surface is 8 bit */
2289 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2293 /* lock source surface */
2294 SDL_LockSurface(zoom_src);
2296 /* check which kind of surface we have */
2299 /* call the 32 bit transformation routine to do the zooming */
2300 zoomSurfaceRGBA(zoom_src, zoom_dst);
2305 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2306 zoom_dst->format->palette->colors[i] =
2307 zoom_src->format->palette->colors[i];
2308 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2310 /* call the 8 bit transformation routine to do the zooming */
2311 zoomSurfaceY(zoom_src, zoom_dst);
2314 /* unlock source surface */
2315 SDL_UnlockSurface(zoom_src);
2317 /* free temporary surface */
2319 SDL_FreeSurface(zoom_src);
2321 /* return destination surface */
2325 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2327 Bitmap *dst_bitmap = CreateBitmapStruct();
2328 SDL_Surface **dst_surface = &dst_bitmap->surface;
2330 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2331 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2333 dst_bitmap->width = dst_width;
2334 dst_bitmap->height = dst_height;
2336 /* create zoomed temporary surface from source surface */
2337 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2339 /* create native format destination surface from zoomed temporary surface */
2340 SDLSetNativeSurface(dst_surface);
2346 /* ========================================================================= */
2347 /* load image to bitmap */
2348 /* ========================================================================= */
2350 Bitmap *SDLLoadImage(char *filename)
2352 Bitmap *new_bitmap = CreateBitmapStruct();
2353 SDL_Surface *sdl_image_tmp;
2355 print_timestamp_init("SDLLoadImage");
2357 print_timestamp_time(getBaseNamePtr(filename));
2359 /* load image to temporary surface */
2360 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2362 SetError("IMG_Load(): %s", SDL_GetError());
2367 print_timestamp_time("IMG_Load");
2369 UPDATE_BUSY_STATE();
2371 /* create native non-transparent surface for current image */
2372 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2374 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2379 print_timestamp_time("SDL_DisplayFormat (opaque)");
2381 UPDATE_BUSY_STATE();
2383 /* create native transparent surface for current image */
2384 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2385 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2387 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2389 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2394 print_timestamp_time("SDL_DisplayFormat (masked)");
2396 UPDATE_BUSY_STATE();
2398 /* free temporary surface */
2399 SDL_FreeSurface(sdl_image_tmp);
2401 new_bitmap->width = new_bitmap->surface->w;
2402 new_bitmap->height = new_bitmap->surface->h;
2404 print_timestamp_done("SDLLoadImage");
2410 /* ------------------------------------------------------------------------- */
2411 /* custom cursor fuctions */
2412 /* ------------------------------------------------------------------------- */
2414 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2416 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2417 cursor_info->width, cursor_info->height,
2418 cursor_info->hot_x, cursor_info->hot_y);
2421 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2423 static struct MouseCursorInfo *last_cursor_info = NULL;
2424 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2425 static SDL_Cursor *cursor_default = NULL;
2426 static SDL_Cursor *cursor_current = NULL;
2428 /* if invoked for the first time, store the SDL default cursor */
2429 if (cursor_default == NULL)
2430 cursor_default = SDL_GetCursor();
2432 /* only create new cursor if cursor info (custom only) has changed */
2433 if (cursor_info != NULL && cursor_info != last_cursor_info)
2435 cursor_current = create_cursor(cursor_info);
2436 last_cursor_info = cursor_info;
2439 /* only set new cursor if cursor info (custom or NULL) has changed */
2440 if (cursor_info != last_cursor_info2)
2441 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2443 last_cursor_info2 = cursor_info;
2447 /* ========================================================================= */
2448 /* audio functions */
2449 /* ========================================================================= */
2451 void SDLOpenAudio(void)
2453 #if !defined(TARGET_SDL2)
2454 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2455 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2458 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2460 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2464 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2465 AUDIO_NUM_CHANNELS_STEREO,
2466 setup.system.audio_fragment_size) < 0)
2468 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2472 audio.sound_available = TRUE;
2473 audio.music_available = TRUE;
2474 audio.loops_available = TRUE;
2475 audio.sound_enabled = TRUE;
2477 /* set number of available mixer channels */
2478 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2479 audio.music_channel = MUSIC_CHANNEL;
2480 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2482 Mixer_InitChannels();
2485 void SDLCloseAudio(void)
2488 Mix_HaltChannel(-1);
2491 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2495 /* ========================================================================= */
2496 /* event functions */
2497 /* ========================================================================= */
2499 void SDLNextEvent(Event *event)
2501 SDL_WaitEvent(event);
2503 if (event->type == EVENT_BUTTONPRESS ||
2504 event->type == EVENT_BUTTONRELEASE)
2506 if (((ButtonEvent *)event)->x > video_xoffset)
2507 ((ButtonEvent *)event)->x -= video_xoffset;
2509 ((ButtonEvent *)event)->x = 0;
2510 if (((ButtonEvent *)event)->y > video_yoffset)
2511 ((ButtonEvent *)event)->y -= video_yoffset;
2513 ((ButtonEvent *)event)->y = 0;
2515 else if (event->type == EVENT_MOTIONNOTIFY)
2517 if (((MotionEvent *)event)->x > video_xoffset)
2518 ((MotionEvent *)event)->x -= video_xoffset;
2520 ((MotionEvent *)event)->x = 0;
2521 if (((MotionEvent *)event)->y > video_yoffset)
2522 ((MotionEvent *)event)->y -= video_yoffset;
2524 ((MotionEvent *)event)->y = 0;
2528 void SDLHandleWindowManagerEvent(Event *event)
2531 #if defined(PLATFORM_WIN32)
2532 // experimental drag and drop code
2534 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2535 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2537 #if defined(TARGET_SDL2)
2538 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2540 if (syswmmsg->msg == WM_DROPFILES)
2543 #if defined(TARGET_SDL2)
2544 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2546 HDROP hdrop = (HDROP)syswmmsg->wParam;
2550 printf("::: SDL_SYSWMEVENT:\n");
2552 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2554 for (i = 0; i < num_files; i++)
2556 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2557 char buffer[buffer_len + 1];
2559 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2561 printf("::: - '%s'\n", buffer);
2564 #if defined(TARGET_SDL2)
2565 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2567 DragFinish((HDROP)syswmmsg->wParam);
2575 /* ========================================================================= */
2576 /* joystick functions */
2577 /* ========================================================================= */
2579 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2580 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2581 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2583 static boolean SDLOpenJoystick(int nr)
2585 if (nr < 0 || nr > MAX_PLAYERS)
2588 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2591 static void SDLCloseJoystick(int nr)
2593 if (nr < 0 || nr > MAX_PLAYERS)
2596 SDL_JoystickClose(sdl_joystick[nr]);
2598 sdl_joystick[nr] = NULL;
2601 static boolean SDLCheckJoystickOpened(int nr)
2603 if (nr < 0 || nr > MAX_PLAYERS)
2606 #if defined(TARGET_SDL2)
2607 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2609 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2613 void HandleJoystickEvent(Event *event)
2617 case SDL_JOYAXISMOTION:
2618 if (event->jaxis.axis < 2)
2619 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2622 case SDL_JOYBUTTONDOWN:
2623 if (event->jbutton.button < 2)
2624 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2627 case SDL_JOYBUTTONUP:
2628 if (event->jbutton.button < 2)
2629 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2637 void SDLInitJoysticks()
2639 static boolean sdl_joystick_subsystem_initialized = FALSE;
2640 boolean print_warning = !sdl_joystick_subsystem_initialized;
2643 if (!sdl_joystick_subsystem_initialized)
2645 sdl_joystick_subsystem_initialized = TRUE;
2647 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2649 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2654 for (i = 0; i < MAX_PLAYERS; i++)
2656 /* get configured joystick for this player */
2657 char *device_name = setup.input[i].joy.device_name;
2658 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2660 if (joystick_nr >= SDL_NumJoysticks())
2662 if (setup.input[i].use_joystick && print_warning)
2663 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2668 /* misuse joystick file descriptor variable to store joystick number */
2669 joystick.fd[i] = joystick_nr;
2671 if (joystick_nr == -1)
2674 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2675 if (SDLCheckJoystickOpened(joystick_nr))
2676 SDLCloseJoystick(joystick_nr);
2678 if (!setup.input[i].use_joystick)
2681 if (!SDLOpenJoystick(joystick_nr))
2684 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2689 joystick.status = JOYSTICK_ACTIVATED;
2693 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2695 if (nr < 0 || nr >= MAX_PLAYERS)
2699 *x = sdl_js_axis[nr][0];
2701 *y = sdl_js_axis[nr][1];
2704 *b1 = sdl_js_button[nr][0];
2706 *b2 = sdl_js_button[nr][1];