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);
101 SDL_RenderClear(sdl_renderer);
102 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
103 SDL_RenderPresent(sdl_renderer);
106 SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
108 SDL_UpdateWindowSurface(sdl_window);
113 SDL_UpdateRects(backbuffer->surface, 1, rect);
115 SDL_UpdateRect(backbuffer->surface, 0, 0, 0, 0);
119 static void setFullscreenParameters(char *fullscreen_mode_string)
121 #if defined(TARGET_SDL2)
122 fullscreen_width = video.width;
123 fullscreen_height = video.height;
124 fullscreen_xoffset = 0;
125 fullscreen_yoffset = 0;
129 struct ScreenModeInfo *fullscreen_mode;
132 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
134 if (fullscreen_mode == NULL)
137 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
139 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
140 fullscreen_mode->height == video.fullscreen_modes[i].height)
142 fullscreen_width = fullscreen_mode->width;
143 fullscreen_height = fullscreen_mode->height;
145 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
146 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
154 static void SDLSetWindowIcon(char *basename)
156 /* (setting the window icon on Mac OS X would replace the high-quality
157 dock icon with the currently smaller (and uglier) icon from file) */
159 #if !defined(PLATFORM_MACOSX)
160 char *filename = getCustomImageFilename(basename);
161 SDL_Surface *surface;
163 if (filename == NULL)
165 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
170 if ((surface = IMG_Load(filename)) == NULL)
172 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
177 /* set transparent color */
178 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
179 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
181 #if defined(TARGET_SDL2)
182 SDL_SetWindowIcon(sdl_window, surface);
184 SDL_WM_SetIcon(surface, NULL);
189 #if defined(TARGET_SDL2)
191 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
192 SDL_PixelFormat *format2)
194 return (format1->format == format2->format &&
195 format1->BitsPerPixel == format2->BitsPerPixel &&
196 format1->BytesPerPixel == format2->BytesPerPixel &&
197 format1->Rmask == format2->Rmask &&
198 format1->Gmask == format2->Gmask &&
199 format1->Bmask == format2->Bmask &&
200 format1->Amask == format2->Amask);
203 boolean SDLSetNativeSurface(SDL_Surface **surface)
205 SDL_Surface *new_surface;
207 if (surface == NULL ||
209 backbuffer == NULL ||
210 backbuffer->surface == NULL)
213 // if pixel format already optimized for destination surface, do nothing
214 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
217 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
219 if (new_surface == NULL)
220 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
222 SDL_FreeSurface(*surface);
224 *surface = new_surface;
229 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
231 SDL_Surface *new_surface;
236 if (backbuffer && backbuffer->surface)
237 new_surface = SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
239 new_surface = SDL_ConvertSurface(surface, surface->format, 0);
241 if (new_surface == NULL)
242 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
249 boolean SDLSetNativeSurface(SDL_Surface **surface)
251 SDL_Surface *new_surface;
253 if (surface == NULL ||
258 new_surface = SDL_DisplayFormat(*surface);
260 if (new_surface == NULL)
261 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
263 SDL_FreeSurface(*surface);
265 *surface = new_surface;
270 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
272 SDL_Surface *new_surface;
274 if (video.initialized)
275 new_surface = SDL_DisplayFormat(surface);
277 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
279 if (new_surface == NULL)
280 Error(ERR_EXIT, "%s() failed: %s",
281 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
289 #if defined(TARGET_SDL2)
290 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
292 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
295 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
302 void SDLCreateBitmapTextures(Bitmap *bitmap)
304 #if defined(TARGET_SDL2)
308 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
309 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
313 void SDLInitVideoDisplay(void)
315 #if !defined(TARGET_SDL2)
316 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
317 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
319 SDL_putenv("SDL_VIDEO_CENTERED=1");
322 /* initialize SDL video */
323 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
324 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
326 /* set default SDL depth */
327 #if !defined(TARGET_SDL2)
328 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
330 video.default_depth = 32; // (how to determine video depth in SDL2?)
334 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
337 #if !defined(TARGET_SDL2)
338 static int screen_xy[][2] =
346 SDL_Rect **modes = NULL;
347 boolean hardware_fullscreen_available = TRUE;
350 /* default: normal game window size */
351 fullscreen_width = video.width;
352 fullscreen_height = video.height;
353 fullscreen_xoffset = 0;
354 fullscreen_yoffset = 0;
356 #if !defined(TARGET_SDL2)
357 /* determine required standard fullscreen mode for game screen size */
358 for (i = 0; screen_xy[i][0] != -1; i++)
360 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
362 fullscreen_width = screen_xy[i][0];
363 fullscreen_height = screen_xy[i][1];
369 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
370 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
373 checked_free(video.fullscreen_modes);
375 video.fullscreen_modes = NULL;
376 video.fullscreen_mode_current = NULL;
378 video.window_scaling_percent = setup.window_scaling_percent;
379 video.window_scaling_quality = setup.window_scaling_quality;
381 #if defined(TARGET_SDL2)
382 int num_displays = SDL_GetNumVideoDisplays();
384 if (num_displays > 0)
386 // currently only display modes of first display supported
387 int num_modes = SDL_GetNumDisplayModes(0);
391 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
393 for (i = 0; i < num_modes; i++)
395 SDL_DisplayMode mode;
397 if (SDL_GetDisplayMode(0, i, &mode) < 0)
400 modes[i] = checked_calloc(sizeof(SDL_Rect));
402 modes[i]->w = mode.w;
403 modes[i]->h = mode.h;
408 /* get available hardware supported fullscreen modes */
409 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
414 /* no hardware screen modes available => no fullscreen mode support */
415 // video.fullscreen_available = FALSE;
416 hardware_fullscreen_available = FALSE;
418 else if (modes == (SDL_Rect **)-1)
420 /* fullscreen resolution is not restricted -- all resolutions available */
421 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
423 /* use native video buffer size for fullscreen mode */
424 video.fullscreen_modes[0].width = video.width;
425 video.fullscreen_modes[0].height = video.height;
427 video.fullscreen_modes[1].width = -1;
428 video.fullscreen_modes[1].height = -1;
432 /* in this case, a certain number of screen modes is available */
435 for (i = 0; modes[i] != NULL; i++)
437 boolean found_mode = FALSE;
439 /* screen mode is smaller than video buffer size -- skip it */
440 if (modes[i]->w < video.width || modes[i]->h < video.height)
443 if (video.fullscreen_modes != NULL)
444 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
445 if (modes[i]->w == video.fullscreen_modes[j].width &&
446 modes[i]->h == video.fullscreen_modes[j].height)
449 if (found_mode) /* screen mode already stored -- skip it */
452 /* new mode found; add it to list of available fullscreen modes */
456 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
458 sizeof(struct ScreenModeInfo));
460 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
461 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
463 video.fullscreen_modes[num_modes].width = -1;
464 video.fullscreen_modes[num_modes].height = -1;
469 /* no appropriate screen modes available => no fullscreen mode support */
470 // video.fullscreen_available = FALSE;
471 hardware_fullscreen_available = FALSE;
475 video.fullscreen_available = hardware_fullscreen_available;
477 #if USE_DESKTOP_FULLSCREEN
478 // in SDL 2.0, there is always support for desktop fullscreen mode
479 // (in SDL 1.2, there is only support for "real" fullscreen mode)
480 video.fullscreen_available = TRUE;
483 #if defined(TARGET_SDL2)
486 for (i = 0; modes[i] != NULL; i++)
487 checked_free(modes[i]);
493 /* open SDL video output device (window or fullscreen mode) */
494 if (!SDLSetVideoMode(backbuffer, fullscreen))
495 Error(ERR_EXIT, "setting video mode failed");
497 /* !!! SDL2 can only set the window icon if the window already exists !!! */
498 /* set window icon */
499 SDLSetWindowIcon(program.icon_filename);
501 /* set window and icon title */
502 #if defined(TARGET_SDL2)
503 SDL_SetWindowTitle(sdl_window, program.window_title);
505 SDL_WM_SetCaption(program.window_title, program.window_title);
508 /* SDL cannot directly draw to the visible video framebuffer like X11,
509 but always uses a backbuffer, which is then blitted to the visible
510 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
511 visible video framebuffer with 'SDL_Flip', if the hardware supports
512 this). Therefore do not use an additional backbuffer for drawing, but
513 use a symbolic buffer (distinguishable from the SDL backbuffer) called
514 'window', which indicates that the SDL backbuffer should be updated to
515 the visible video framebuffer when attempting to blit to it.
517 For convenience, it seems to be a good idea to create this symbolic
518 buffer 'window' at the same size as the SDL backbuffer. Although it
519 should never be drawn to directly, it would do no harm nevertheless. */
521 /* create additional (symbolic) buffer for double-buffering */
522 ReCreateBitmap(window, video.width, video.height, video.depth);
525 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
528 SDL_Surface *new_surface = NULL;
530 #if defined(TARGET_SDL2)
531 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
532 #if USE_DESKTOP_FULLSCREEN
533 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
535 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
539 int surface_flags_window = SURFACE_FLAGS;
540 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
543 int width = (fullscreen ? fullscreen_width : video.width);
544 int height = (fullscreen ? fullscreen_height : video.height);
545 int surface_flags = (fullscreen ? surface_flags_fullscreen :
546 surface_flags_window);
548 // default window size is unscaled
549 video.window_width = video.width;
550 video.window_height = video.height;
552 #if defined(TARGET_SDL2)
554 // store if initial screen mode is fullscreen mode when changing screen size
555 video.fullscreen_initial = fullscreen;
558 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
559 #if !USE_DESKTOP_FULLSCREEN
560 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
563 video.window_width = window_scaling_factor * width;
564 video.window_height = window_scaling_factor * height;
566 if ((*backbuffer)->surface)
568 SDL_FreeSurface((*backbuffer)->surface);
569 (*backbuffer)->surface = NULL;
574 SDL_DestroyTexture(sdl_texture);
578 if (!(fullscreen && fullscreen_enabled))
582 SDL_DestroyRenderer(sdl_renderer);
588 SDL_DestroyWindow(sdl_window);
593 if (sdl_window == NULL)
594 sdl_window = SDL_CreateWindow(program.window_title,
595 SDL_WINDOWPOS_CENTERED,
596 SDL_WINDOWPOS_CENTERED,
597 #if USE_DESKTOP_FULLSCREEN
601 (int)(screen_scaling_factor * width),
602 (int)(screen_scaling_factor * height),
606 if (sdl_window != NULL)
609 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
610 *without* enabling 2D/3D acceleration and/or guest additions installed,
611 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
612 it will try to use accelerated graphics and apparently fails miserably) */
613 if (sdl_renderer == NULL)
614 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
616 if (sdl_renderer == NULL)
617 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
620 if (sdl_renderer != NULL)
622 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
623 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
624 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
626 sdl_texture = SDL_CreateTexture(sdl_renderer,
627 SDL_PIXELFORMAT_ARGB8888,
628 SDL_TEXTUREACCESS_STREAMING,
631 if (sdl_texture != NULL)
633 // use SDL default values for RGB masks and no alpha channel
634 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
636 if (new_surface == NULL)
637 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
642 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
647 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
652 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
658 SDL_DestroyWindow(sdl_window);
660 sdl_window = SDL_CreateWindow(program.window_title,
661 SDL_WINDOWPOS_CENTERED,
662 SDL_WINDOWPOS_CENTERED,
666 if (sdl_window != NULL)
667 new_surface = SDL_GetWindowSurface(sdl_window);
671 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
674 #if defined(TARGET_SDL2)
675 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
676 if (new_surface != NULL)
677 fullscreen_enabled = fullscreen;
683 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
685 boolean success = TRUE;
686 SDL_Surface *new_surface = NULL;
690 if (*backbuffer == NULL)
691 *backbuffer = CreateBitmapStruct();
693 /* (real bitmap might be larger in fullscreen mode with video offsets) */
694 (*backbuffer)->width = video.width;
695 (*backbuffer)->height = video.height;
697 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
699 setFullscreenParameters(setup.fullscreen_mode);
701 video_xoffset = fullscreen_xoffset;
702 video_yoffset = fullscreen_yoffset;
704 /* switch display to fullscreen mode, if available */
705 new_surface = SDLCreateScreen(backbuffer, TRUE);
707 if (new_surface == NULL)
709 /* switching display to fullscreen mode failed */
710 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
712 /* do not try it again */
713 video.fullscreen_available = FALSE;
719 (*backbuffer)->surface = new_surface;
721 video.fullscreen_enabled = TRUE;
722 video.fullscreen_mode_current = setup.fullscreen_mode;
728 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
733 /* switch display to window mode */
734 new_surface = SDLCreateScreen(backbuffer, FALSE);
736 if (new_surface == NULL)
738 /* switching display to window mode failed -- should not happen */
739 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
745 (*backbuffer)->surface = new_surface;
747 video.fullscreen_enabled = FALSE;
748 video.window_scaling_percent = setup.window_scaling_percent;
749 video.window_scaling_quality = setup.window_scaling_quality;
755 #if defined(TARGET_SDL2)
756 SDLRedrawWindow(); // map window
760 #if defined(PLATFORM_WIN32)
761 // experimental drag and drop code
763 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
766 SDL_SysWMinfo wminfo;
768 boolean wminfo_success = FALSE;
770 SDL_VERSION(&wminfo.version);
771 #if defined(TARGET_SDL2)
773 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
775 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
780 #if defined(TARGET_SDL2)
781 hwnd = wminfo.info.win.window;
783 hwnd = wminfo.window;
786 DragAcceptFiles(hwnd, TRUE);
795 void SDLSetWindowTitle()
797 #if defined(TARGET_SDL2)
798 SDL_SetWindowTitle(sdl_window, program.window_title);
800 SDL_WM_SetCaption(program.window_title, program.window_title);
804 #if defined(TARGET_SDL2)
805 void SDLSetWindowScaling(int window_scaling_percent)
807 if (sdl_window == NULL)
810 float window_scaling_factor = (float)window_scaling_percent / 100;
811 int new_window_width = (int)(window_scaling_factor * video.width);
812 int new_window_height = (int)(window_scaling_factor * video.height);
814 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
816 video.window_scaling_percent = window_scaling_percent;
817 video.window_width = new_window_width;
818 video.window_height = new_window_height;
823 void SDLSetWindowScalingQuality(char *window_scaling_quality)
825 if (sdl_texture == NULL)
828 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
830 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
831 SDL_PIXELFORMAT_ARGB8888,
832 SDL_TEXTUREACCESS_STREAMING,
833 video.width, video.height);
835 if (new_texture != NULL)
837 SDL_DestroyTexture(sdl_texture);
839 sdl_texture = new_texture;
844 video.window_scaling_quality = window_scaling_quality;
847 void SDLSetWindowFullscreen(boolean fullscreen)
849 if (sdl_window == NULL)
852 #if USE_DESKTOP_FULLSCREEN
853 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
855 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
858 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
859 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
861 // if screen size was changed in fullscreen mode, correct desktop window size
862 if (!fullscreen && video.fullscreen_initial)
864 SDLSetWindowScaling(setup.window_scaling_percent);
865 SDL_SetWindowPosition(sdl_window,
866 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
868 video.fullscreen_initial = FALSE;
872 void SDLRedrawWindow()
878 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
881 SDL_Surface *surface =
882 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
885 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
887 SDLSetNativeSurface(&surface);
889 bitmap->surface = surface;
892 void SDLFreeBitmapPointers(Bitmap *bitmap)
895 SDL_FreeSurface(bitmap->surface);
896 if (bitmap->surface_masked)
897 SDL_FreeSurface(bitmap->surface_masked);
899 bitmap->surface = NULL;
900 bitmap->surface_masked = NULL;
902 #if defined(TARGET_SDL2)
904 SDL_DestroyTexture(bitmap->texture);
905 if (bitmap->texture_masked)
906 SDL_DestroyTexture(bitmap->texture_masked);
908 bitmap->texture = NULL;
909 bitmap->texture_masked = NULL;
913 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
914 int src_x, int src_y, int width, int height,
915 int dst_x, int dst_y, int mask_mode)
917 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
918 SDL_Rect src_rect, dst_rect;
920 if (src_bitmap == backbuffer)
922 src_x += video_xoffset;
923 src_y += video_yoffset;
931 if (dst_bitmap == backbuffer || dst_bitmap == window)
933 dst_x += video_xoffset;
934 dst_y += video_yoffset;
942 // if (src_bitmap != backbuffer || dst_bitmap != window)
943 if (!(src_bitmap == backbuffer && dst_bitmap == window))
944 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
945 src_bitmap->surface_masked : src_bitmap->surface),
946 &src_rect, real_dst_bitmap->surface, &dst_rect);
948 #if defined(TARGET_SDL2)
949 if (dst_bitmap == window)
951 // SDL_UpdateWindowSurface(sdl_window);
952 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
953 UpdateScreen(&dst_rect);
956 if (dst_bitmap == window)
958 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
959 UpdateScreen(&dst_rect);
964 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
967 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
970 if (dst_bitmap == backbuffer || dst_bitmap == window)
981 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
983 #if defined(TARGET_SDL2)
984 if (dst_bitmap == window)
986 // SDL_UpdateWindowSurface(sdl_window);
987 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
991 if (dst_bitmap == window)
993 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
999 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
1000 int fade_mode, int fade_delay, int post_delay,
1001 void (*draw_border_function)(void))
1003 static boolean initialization_needed = TRUE;
1004 static SDL_Surface *surface_source = NULL;
1005 static SDL_Surface *surface_target = NULL;
1006 static SDL_Surface *surface_black = NULL;
1007 SDL_Surface *surface_screen = backbuffer->surface;
1008 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
1009 SDL_Rect src_rect, dst_rect;
1011 int src_x = x, src_y = y;
1012 int dst_x = x, dst_y = y;
1013 unsigned int time_last, time_current;
1015 /* check if screen size has changed */
1016 if (surface_source != NULL && (video.width != surface_source->w ||
1017 video.height != surface_source->h))
1019 SDL_FreeSurface(surface_source);
1020 SDL_FreeSurface(surface_target);
1021 SDL_FreeSurface(surface_black);
1023 initialization_needed = TRUE;
1029 src_rect.h = height;
1031 dst_x += video_xoffset;
1032 dst_y += video_yoffset;
1036 dst_rect.w = width; /* (ignored) */
1037 dst_rect.h = height; /* (ignored) */
1039 dst_rect2 = dst_rect;
1041 if (initialization_needed)
1043 #if defined(TARGET_SDL2)
1044 unsigned int flags = 0;
1046 unsigned int flags = SDL_SRCALPHA;
1048 /* use same surface type as screen surface */
1049 if ((surface_screen->flags & SDL_HWSURFACE))
1050 flags |= SDL_HWSURFACE;
1052 flags |= SDL_SWSURFACE;
1055 /* create surface for temporary copy of screen buffer (source) */
1056 if ((surface_source =
1057 SDL_CreateRGBSurface(flags,
1060 surface_screen->format->BitsPerPixel,
1061 surface_screen->format->Rmask,
1062 surface_screen->format->Gmask,
1063 surface_screen->format->Bmask,
1064 surface_screen->format->Amask)) == NULL)
1065 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1067 /* create surface for cross-fading screen buffer (target) */
1068 if ((surface_target =
1069 SDL_CreateRGBSurface(flags,
1072 surface_screen->format->BitsPerPixel,
1073 surface_screen->format->Rmask,
1074 surface_screen->format->Gmask,
1075 surface_screen->format->Bmask,
1076 surface_screen->format->Amask)) == NULL)
1077 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1079 /* create black surface for fading from/to black */
1080 if ((surface_black =
1081 SDL_CreateRGBSurface(flags,
1084 surface_screen->format->BitsPerPixel,
1085 surface_screen->format->Rmask,
1086 surface_screen->format->Gmask,
1087 surface_screen->format->Bmask,
1088 surface_screen->format->Amask)) == NULL)
1089 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1091 /* completely fill the surface with black color pixels */
1092 SDL_FillRect(surface_black, NULL,
1093 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1095 initialization_needed = FALSE;
1098 /* copy source and target surfaces to temporary surfaces for fading */
1099 if (fade_mode & FADE_TYPE_TRANSFORM)
1101 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1102 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1104 else if (fade_mode & FADE_TYPE_FADE_IN)
1106 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1107 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1109 else /* FADE_TYPE_FADE_OUT */
1111 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1112 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1115 time_current = SDL_GetTicks();
1117 if (fade_mode == FADE_MODE_MELT)
1119 boolean done = FALSE;
1120 int melt_pixels = 2;
1121 int melt_columns = width / melt_pixels;
1122 int ypos[melt_columns];
1123 int max_steps = height / 8 + 32;
1128 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1129 #if defined(TARGET_SDL2)
1130 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1132 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1135 ypos[0] = -GetSimpleRandom(16);
1137 for (i = 1 ; i < melt_columns; i++)
1139 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1141 ypos[i] = ypos[i - 1] + r;
1154 time_last = time_current;
1155 time_current = SDL_GetTicks();
1156 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1157 steps_final = MIN(MAX(0, steps), max_steps);
1161 done = (steps_done >= steps_final);
1163 for (i = 0 ; i < melt_columns; i++)
1171 else if (ypos[i] < height)
1176 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1178 if (ypos[i] + dy >= height)
1179 dy = height - ypos[i];
1181 /* copy part of (appearing) target surface to upper area */
1182 src_rect.x = src_x + i * melt_pixels;
1183 // src_rect.y = src_y + ypos[i];
1185 src_rect.w = melt_pixels;
1187 src_rect.h = ypos[i] + dy;
1189 dst_rect.x = dst_x + i * melt_pixels;
1190 // dst_rect.y = dst_y + ypos[i];
1193 if (steps_done >= steps_final)
1194 SDL_BlitSurface(surface_target, &src_rect,
1195 surface_screen, &dst_rect);
1199 /* copy part of (disappearing) source surface to lower area */
1200 src_rect.x = src_x + i * melt_pixels;
1202 src_rect.w = melt_pixels;
1203 src_rect.h = height - ypos[i];
1205 dst_rect.x = dst_x + i * melt_pixels;
1206 dst_rect.y = dst_y + ypos[i];
1208 if (steps_done >= steps_final)
1209 SDL_BlitSurface(surface_source, &src_rect,
1210 surface_screen, &dst_rect);
1216 src_rect.x = src_x + i * melt_pixels;
1218 src_rect.w = melt_pixels;
1219 src_rect.h = height;
1221 dst_rect.x = dst_x + i * melt_pixels;
1224 if (steps_done >= steps_final)
1225 SDL_BlitSurface(surface_target, &src_rect,
1226 surface_screen, &dst_rect);
1230 if (steps_done >= steps_final)
1232 if (draw_border_function != NULL)
1233 draw_border_function();
1235 UpdateScreen(&dst_rect2);
1239 else if (fade_mode == FADE_MODE_CURTAIN)
1243 int xx_size = width / 2;
1245 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1246 #if defined(TARGET_SDL2)
1247 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1249 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1252 for (xx = 0; xx < xx_size;)
1254 time_last = time_current;
1255 time_current = SDL_GetTicks();
1256 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1257 xx_final = MIN(MAX(0, xx), xx_size);
1262 src_rect.h = height;
1267 /* draw new (target) image to screen buffer */
1268 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1270 if (xx_final < xx_size)
1272 src_rect.w = xx_size - xx_final;
1273 src_rect.h = height;
1275 /* draw old (source) image to screen buffer (left side) */
1277 src_rect.x = src_x + xx_final;
1280 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1282 /* draw old (source) image to screen buffer (right side) */
1284 src_rect.x = src_x + xx_size;
1285 dst_rect.x = dst_x + xx_size + xx_final;
1287 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1290 if (draw_border_function != NULL)
1291 draw_border_function();
1293 /* only update the region of the screen that is affected from fading */
1294 UpdateScreen(&dst_rect2);
1297 else /* fading in, fading out or cross-fading */
1302 for (alpha = 0.0; alpha < 255.0;)
1304 time_last = time_current;
1305 time_current = SDL_GetTicks();
1306 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1307 alpha_final = MIN(MAX(0, alpha), 255);
1309 /* draw existing (source) image to screen buffer */
1310 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1312 /* draw new (target) image to screen buffer using alpha blending */
1313 #if defined(TARGET_SDL2)
1314 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1315 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1317 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1319 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1321 if (draw_border_function != NULL)
1322 draw_border_function();
1324 /* only update the region of the screen that is affected from fading */
1325 UpdateScreen(&dst_rect);
1332 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1333 int to_x, int to_y, Uint32 color)
1335 SDL_Surface *surface = dst_bitmap->surface;
1339 swap_numbers(&from_x, &to_x);
1342 swap_numbers(&from_y, &to_y);
1346 rect.w = (to_x - from_x + 1);
1347 rect.h = (to_y - from_y + 1);
1349 if (dst_bitmap == backbuffer || dst_bitmap == window)
1351 rect.x += video_xoffset;
1352 rect.y += video_yoffset;
1355 SDL_FillRect(surface, &rect, color);
1358 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1359 int to_x, int to_y, Uint32 color)
1361 if (dst_bitmap == backbuffer || dst_bitmap == window)
1363 from_x += video_xoffset;
1364 from_y += video_yoffset;
1365 to_x += video_xoffset;
1366 to_y += video_yoffset;
1369 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1372 #if ENABLE_UNUSED_CODE
1373 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1374 int num_points, Uint32 color)
1379 for (i = 0; i < num_points - 1; i++)
1381 for (x = 0; x < line_width; x++)
1383 for (y = 0; y < line_width; y++)
1385 int dx = x - line_width / 2;
1386 int dy = y - line_width / 2;
1388 if ((x == 0 && y == 0) ||
1389 (x == 0 && y == line_width - 1) ||
1390 (x == line_width - 1 && y == 0) ||
1391 (x == line_width - 1 && y == line_width - 1))
1394 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1395 points[i+1].x + dx, points[i+1].y + dy, color);
1402 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1404 SDL_Surface *surface = src_bitmap->surface;
1406 if (src_bitmap == backbuffer || src_bitmap == window)
1412 switch (surface->format->BytesPerPixel)
1414 case 1: /* assuming 8-bpp */
1416 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1420 case 2: /* probably 15-bpp or 16-bpp */
1422 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1426 case 3: /* slow 24-bpp mode; usually not used */
1428 /* does this work? */
1429 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1433 shift = surface->format->Rshift;
1434 color |= *(pix + shift / 8) >> shift;
1435 shift = surface->format->Gshift;
1436 color |= *(pix + shift / 8) >> shift;
1437 shift = surface->format->Bshift;
1438 color |= *(pix + shift / 8) >> shift;
1444 case 4: /* probably 32-bpp */
1446 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1455 /* ========================================================================= */
1456 /* The following functions were taken from the SGE library */
1457 /* (SDL Graphics Extension Library) by Anders Lindström */
1458 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1459 /* ========================================================================= */
1461 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1463 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1465 switch (surface->format->BytesPerPixel)
1469 /* Assuming 8-bpp */
1470 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1476 /* Probably 15-bpp or 16-bpp */
1477 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1483 /* Slow 24-bpp mode, usually not used */
1487 /* Gack - slow, but endian correct */
1488 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1489 shift = surface->format->Rshift;
1490 *(pix+shift/8) = color>>shift;
1491 shift = surface->format->Gshift;
1492 *(pix+shift/8) = color>>shift;
1493 shift = surface->format->Bshift;
1494 *(pix+shift/8) = color>>shift;
1500 /* Probably 32-bpp */
1501 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1508 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1509 Uint8 R, Uint8 G, Uint8 B)
1511 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1514 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1516 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1519 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1521 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1524 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1529 /* Gack - slow, but endian correct */
1530 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1531 shift = surface->format->Rshift;
1532 *(pix+shift/8) = color>>shift;
1533 shift = surface->format->Gshift;
1534 *(pix+shift/8) = color>>shift;
1535 shift = surface->format->Bshift;
1536 *(pix+shift/8) = color>>shift;
1539 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1541 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1544 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1546 switch (dest->format->BytesPerPixel)
1549 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1553 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1557 _PutPixel24(dest,x,y,color);
1561 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1566 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1568 if (SDL_MUSTLOCK(surface))
1570 if (SDL_LockSurface(surface) < 0)
1576 _PutPixel(surface, x, y, color);
1578 if (SDL_MUSTLOCK(surface))
1580 SDL_UnlockSurface(surface);
1584 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1585 Uint8 r, Uint8 g, Uint8 b)
1587 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1590 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1592 if (y >= 0 && y <= dest->h - 1)
1594 switch (dest->format->BytesPerPixel)
1597 return y*dest->pitch;
1601 return y*dest->pitch/2;
1605 return y*dest->pitch;
1609 return y*dest->pitch/4;
1617 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1619 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1621 switch (surface->format->BytesPerPixel)
1625 /* Assuming 8-bpp */
1626 *((Uint8 *)surface->pixels + ypitch + x) = color;
1632 /* Probably 15-bpp or 16-bpp */
1633 *((Uint16 *)surface->pixels + ypitch + x) = color;
1639 /* Slow 24-bpp mode, usually not used */
1643 /* Gack - slow, but endian correct */
1644 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1645 shift = surface->format->Rshift;
1646 *(pix+shift/8) = color>>shift;
1647 shift = surface->format->Gshift;
1648 *(pix+shift/8) = color>>shift;
1649 shift = surface->format->Bshift;
1650 *(pix+shift/8) = color>>shift;
1656 /* Probably 32-bpp */
1657 *((Uint32 *)surface->pixels + ypitch + x) = color;
1664 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1669 if (SDL_MUSTLOCK(Surface))
1671 if (SDL_LockSurface(Surface) < 0)
1684 /* Do the clipping */
1685 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1689 if (x2 > Surface->w - 1)
1690 x2 = Surface->w - 1;
1697 SDL_FillRect(Surface, &l, Color);
1699 if (SDL_MUSTLOCK(Surface))
1701 SDL_UnlockSurface(Surface);
1705 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1706 Uint8 R, Uint8 G, Uint8 B)
1708 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1711 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1722 /* Do the clipping */
1723 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1727 if (x2 > Surface->w - 1)
1728 x2 = Surface->w - 1;
1735 SDL_FillRect(Surface, &l, Color);
1738 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1743 if (SDL_MUSTLOCK(Surface))
1745 if (SDL_LockSurface(Surface) < 0)
1758 /* Do the clipping */
1759 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1763 if (y2 > Surface->h - 1)
1764 y2 = Surface->h - 1;
1771 SDL_FillRect(Surface, &l, Color);
1773 if (SDL_MUSTLOCK(Surface))
1775 SDL_UnlockSurface(Surface);
1779 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1780 Uint8 R, Uint8 G, Uint8 B)
1782 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1785 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1796 /* Do the clipping */
1797 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1801 if (y2 > Surface->h - 1)
1802 y2 = Surface->h - 1;
1809 SDL_FillRect(Surface, &l, Color);
1812 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1813 Sint16 x2, Sint16 y2, Uint32 Color,
1814 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1817 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1822 sdx = (dx < 0) ? -1 : 1;
1823 sdy = (dy < 0) ? -1 : 1;
1835 for (x = 0; x < dx; x++)
1837 Callback(Surface, px, py, Color);
1851 for (y = 0; y < dy; y++)
1853 Callback(Surface, px, py, Color);
1867 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1868 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1869 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1872 sge_DoLine(Surface, X1, Y1, X2, Y2,
1873 SDL_MapRGB(Surface->format, R, G, B), Callback);
1876 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1879 if (SDL_MUSTLOCK(Surface))
1881 if (SDL_LockSurface(Surface) < 0)
1886 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1888 /* unlock the display */
1889 if (SDL_MUSTLOCK(Surface))
1891 SDL_UnlockSurface(Surface);
1895 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1896 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1898 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1901 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1903 if (dst_bitmap == backbuffer || dst_bitmap == window)
1909 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1914 -----------------------------------------------------------------------------
1915 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1916 -----------------------------------------------------------------------------
1919 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1920 int width, int height, Uint32 color)
1924 for (y = src_y; y < src_y + height; y++)
1926 for (x = src_x; x < src_x + width; x++)
1928 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1930 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1935 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1936 int src_x, int src_y, int width, int height,
1937 int dst_x, int dst_y)
1941 for (y = 0; y < height; y++)
1943 for (x = 0; x < width; x++)
1945 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1947 if (pixel != BLACK_PIXEL)
1948 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1954 /* ========================================================================= */
1955 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1956 /* (Rotozoomer) by Andreas Schiffler */
1957 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1958 /* ========================================================================= */
1961 -----------------------------------------------------------------------------
1964 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1965 -----------------------------------------------------------------------------
1976 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1979 tColorRGBA *sp, *csp, *dp;
1983 sp = csp = (tColorRGBA *) src->pixels;
1984 dp = (tColorRGBA *) dst->pixels;
1985 dgap = dst->pitch - dst->w * 4;
1987 for (y = 0; y < dst->h; y++)
1991 for (x = 0; x < dst->w; x++)
1993 tColorRGBA *sp0 = sp;
1994 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1995 tColorRGBA *sp00 = &sp0[0];
1996 tColorRGBA *sp01 = &sp0[1];
1997 tColorRGBA *sp10 = &sp1[0];
1998 tColorRGBA *sp11 = &sp1[1];
2001 /* create new color pixel from all four source color pixels */
2002 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2003 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2004 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2005 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2010 /* advance source pointers */
2013 /* advance destination pointer */
2017 /* advance source pointer */
2018 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2020 /* advance destination pointers */
2021 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2027 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2029 int x, y, *sax, *say, *csax, *csay;
2031 tColorRGBA *sp, *csp, *csp0, *dp;
2034 /* use specialized zoom function when scaling down to exactly half size */
2035 if (src->w == 2 * dst->w &&
2036 src->h == 2 * dst->h)
2037 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2039 /* variable setup */
2040 sx = (float) src->w / (float) dst->w;
2041 sy = (float) src->h / (float) dst->h;
2043 /* allocate memory for row increments */
2044 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2045 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2047 /* precalculate row increments */
2048 for (x = 0; x <= dst->w; x++)
2049 *csax++ = (int)(sx * x);
2051 for (y = 0; y <= dst->h; y++)
2052 *csay++ = (int)(sy * y);
2055 sp = csp = csp0 = (tColorRGBA *) src->pixels;
2056 dp = (tColorRGBA *) dst->pixels;
2057 dgap = dst->pitch - dst->w * 4;
2060 for (y = 0; y < dst->h; y++)
2065 for (x = 0; x < dst->w; x++)
2070 /* advance source pointers */
2074 /* advance destination pointer */
2078 /* advance source pointer */
2080 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
2082 /* advance destination pointers */
2083 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2093 -----------------------------------------------------------------------------
2096 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2097 -----------------------------------------------------------------------------
2100 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2102 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2103 Uint8 *sp, *dp, *csp;
2106 /* variable setup */
2107 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2108 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2110 /* allocate memory for row increments */
2111 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2112 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2114 /* precalculate row increments */
2117 for (x = 0; x < dst->w; x++)
2120 *csax = (csx >> 16);
2127 for (y = 0; y < dst->h; y++)
2130 *csay = (csy >> 16);
2137 for (x = 0; x < dst->w; x++)
2145 for (y = 0; y < dst->h; y++)
2152 sp = csp = (Uint8 *) src->pixels;
2153 dp = (Uint8 *) dst->pixels;
2154 dgap = dst->pitch - dst->w;
2158 for (y = 0; y < dst->h; y++)
2162 for (x = 0; x < dst->w; x++)
2167 /* advance source pointers */
2171 /* advance destination pointer */
2175 /* advance source pointer (for row) */
2176 csp += ((*csay) * src->pitch);
2179 /* advance destination pointers */
2190 -----------------------------------------------------------------------------
2193 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2194 'zoomx' and 'zoomy' are scaling factors for width and height.
2195 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2196 into a 32bit RGBA format on the fly.
2197 -----------------------------------------------------------------------------
2200 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2202 SDL_Surface *zoom_src = NULL;
2203 SDL_Surface *zoom_dst = NULL;
2204 boolean is_converted = FALSE;
2211 /* determine if source surface is 32 bit or 8 bit */
2212 is_32bit = (src->format->BitsPerPixel == 32);
2214 if (is_32bit || src->format->BitsPerPixel == 8)
2216 /* use source surface 'as is' */
2221 /* new source surface is 32 bit with a defined RGB ordering */
2222 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2223 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2224 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2226 is_converted = TRUE;
2229 /* allocate surface to completely contain the zoomed surface */
2232 /* target surface is 32 bit with source RGBA/ABGR ordering */
2233 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2234 zoom_src->format->Rmask,
2235 zoom_src->format->Gmask,
2236 zoom_src->format->Bmask, 0);
2240 /* target surface is 8 bit */
2241 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2245 /* lock source surface */
2246 SDL_LockSurface(zoom_src);
2248 /* check which kind of surface we have */
2251 /* call the 32 bit transformation routine to do the zooming */
2252 zoomSurfaceRGBA(zoom_src, zoom_dst);
2257 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2258 zoom_dst->format->palette->colors[i] =
2259 zoom_src->format->palette->colors[i];
2260 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2262 /* call the 8 bit transformation routine to do the zooming */
2263 zoomSurfaceY(zoom_src, zoom_dst);
2266 /* unlock source surface */
2267 SDL_UnlockSurface(zoom_src);
2269 /* free temporary surface */
2271 SDL_FreeSurface(zoom_src);
2273 /* return destination surface */
2277 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2279 Bitmap *dst_bitmap = CreateBitmapStruct();
2280 SDL_Surface **dst_surface = &dst_bitmap->surface;
2282 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2283 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2285 dst_bitmap->width = dst_width;
2286 dst_bitmap->height = dst_height;
2288 /* create zoomed temporary surface from source surface */
2289 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2291 /* create native format destination surface from zoomed temporary surface */
2292 SDLSetNativeSurface(dst_surface);
2298 /* ========================================================================= */
2299 /* load image to bitmap */
2300 /* ========================================================================= */
2302 Bitmap *SDLLoadImage(char *filename)
2304 Bitmap *new_bitmap = CreateBitmapStruct();
2305 SDL_Surface *sdl_image_tmp;
2307 print_timestamp_init("SDLLoadImage");
2309 print_timestamp_time(getBaseNamePtr(filename));
2311 /* load image to temporary surface */
2312 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2314 SetError("IMG_Load(): %s", SDL_GetError());
2319 print_timestamp_time("IMG_Load");
2321 UPDATE_BUSY_STATE();
2323 /* create native non-transparent surface for current image */
2324 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2326 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2331 print_timestamp_time("SDL_DisplayFormat (opaque)");
2333 UPDATE_BUSY_STATE();
2335 /* create native transparent surface for current image */
2336 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2337 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2339 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2341 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2346 print_timestamp_time("SDL_DisplayFormat (masked)");
2348 UPDATE_BUSY_STATE();
2350 /* free temporary surface */
2351 SDL_FreeSurface(sdl_image_tmp);
2353 new_bitmap->width = new_bitmap->surface->w;
2354 new_bitmap->height = new_bitmap->surface->h;
2356 print_timestamp_done("SDLLoadImage");
2362 /* ------------------------------------------------------------------------- */
2363 /* custom cursor fuctions */
2364 /* ------------------------------------------------------------------------- */
2366 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2368 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2369 cursor_info->width, cursor_info->height,
2370 cursor_info->hot_x, cursor_info->hot_y);
2373 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2375 static struct MouseCursorInfo *last_cursor_info = NULL;
2376 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2377 static SDL_Cursor *cursor_default = NULL;
2378 static SDL_Cursor *cursor_current = NULL;
2380 /* if invoked for the first time, store the SDL default cursor */
2381 if (cursor_default == NULL)
2382 cursor_default = SDL_GetCursor();
2384 /* only create new cursor if cursor info (custom only) has changed */
2385 if (cursor_info != NULL && cursor_info != last_cursor_info)
2387 cursor_current = create_cursor(cursor_info);
2388 last_cursor_info = cursor_info;
2391 /* only set new cursor if cursor info (custom or NULL) has changed */
2392 if (cursor_info != last_cursor_info2)
2393 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2395 last_cursor_info2 = cursor_info;
2399 /* ========================================================================= */
2400 /* audio functions */
2401 /* ========================================================================= */
2403 void SDLOpenAudio(void)
2405 #if !defined(TARGET_SDL2)
2406 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2407 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2410 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2412 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2416 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2417 AUDIO_NUM_CHANNELS_STEREO,
2418 setup.system.audio_fragment_size) < 0)
2420 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2424 audio.sound_available = TRUE;
2425 audio.music_available = TRUE;
2426 audio.loops_available = TRUE;
2427 audio.sound_enabled = TRUE;
2429 /* set number of available mixer channels */
2430 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2431 audio.music_channel = MUSIC_CHANNEL;
2432 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2434 Mixer_InitChannels();
2437 void SDLCloseAudio(void)
2440 Mix_HaltChannel(-1);
2443 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2447 /* ========================================================================= */
2448 /* event functions */
2449 /* ========================================================================= */
2451 void SDLNextEvent(Event *event)
2453 SDL_WaitEvent(event);
2455 if (event->type == EVENT_BUTTONPRESS ||
2456 event->type == EVENT_BUTTONRELEASE)
2458 if (((ButtonEvent *)event)->x > video_xoffset)
2459 ((ButtonEvent *)event)->x -= video_xoffset;
2461 ((ButtonEvent *)event)->x = 0;
2462 if (((ButtonEvent *)event)->y > video_yoffset)
2463 ((ButtonEvent *)event)->y -= video_yoffset;
2465 ((ButtonEvent *)event)->y = 0;
2467 else if (event->type == EVENT_MOTIONNOTIFY)
2469 if (((MotionEvent *)event)->x > video_xoffset)
2470 ((MotionEvent *)event)->x -= video_xoffset;
2472 ((MotionEvent *)event)->x = 0;
2473 if (((MotionEvent *)event)->y > video_yoffset)
2474 ((MotionEvent *)event)->y -= video_yoffset;
2476 ((MotionEvent *)event)->y = 0;
2480 void SDLHandleWindowManagerEvent(Event *event)
2483 #if defined(PLATFORM_WIN32)
2484 // experimental drag and drop code
2486 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2487 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2489 #if defined(TARGET_SDL2)
2490 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2492 if (syswmmsg->msg == WM_DROPFILES)
2495 #if defined(TARGET_SDL2)
2496 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2498 HDROP hdrop = (HDROP)syswmmsg->wParam;
2502 printf("::: SDL_SYSWMEVENT:\n");
2504 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2506 for (i = 0; i < num_files; i++)
2508 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2509 char buffer[buffer_len + 1];
2511 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2513 printf("::: - '%s'\n", buffer);
2516 #if defined(TARGET_SDL2)
2517 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2519 DragFinish((HDROP)syswmmsg->wParam);
2527 /* ========================================================================= */
2528 /* joystick functions */
2529 /* ========================================================================= */
2531 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2532 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2533 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2535 static boolean SDLOpenJoystick(int nr)
2537 if (nr < 0 || nr > MAX_PLAYERS)
2540 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2543 static void SDLCloseJoystick(int nr)
2545 if (nr < 0 || nr > MAX_PLAYERS)
2548 SDL_JoystickClose(sdl_joystick[nr]);
2550 sdl_joystick[nr] = NULL;
2553 static boolean SDLCheckJoystickOpened(int nr)
2555 if (nr < 0 || nr > MAX_PLAYERS)
2558 #if defined(TARGET_SDL2)
2559 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2561 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2565 void HandleJoystickEvent(Event *event)
2569 case SDL_JOYAXISMOTION:
2570 if (event->jaxis.axis < 2)
2571 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2574 case SDL_JOYBUTTONDOWN:
2575 if (event->jbutton.button < 2)
2576 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2579 case SDL_JOYBUTTONUP:
2580 if (event->jbutton.button < 2)
2581 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2589 void SDLInitJoysticks()
2591 static boolean sdl_joystick_subsystem_initialized = FALSE;
2592 boolean print_warning = !sdl_joystick_subsystem_initialized;
2595 if (!sdl_joystick_subsystem_initialized)
2597 sdl_joystick_subsystem_initialized = TRUE;
2599 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2601 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2606 for (i = 0; i < MAX_PLAYERS; i++)
2608 /* get configured joystick for this player */
2609 char *device_name = setup.input[i].joy.device_name;
2610 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2612 if (joystick_nr >= SDL_NumJoysticks())
2614 if (setup.input[i].use_joystick && print_warning)
2615 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2620 /* misuse joystick file descriptor variable to store joystick number */
2621 joystick.fd[i] = joystick_nr;
2623 if (joystick_nr == -1)
2626 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2627 if (SDLCheckJoystickOpened(joystick_nr))
2628 SDLCloseJoystick(joystick_nr);
2630 if (!setup.input[i].use_joystick)
2633 if (!SDLOpenJoystick(joystick_nr))
2636 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2641 joystick.status = JOYSTICK_ACTIVATED;
2645 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2647 if (nr < 0 || nr >= MAX_PLAYERS)
2651 *x = sdl_js_axis[nr][0];
2653 *y = sdl_js_axis[nr][1];
2656 *b1 = sdl_js_button[nr][0];
2658 *b2 = sdl_js_button[nr][1];