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)
320 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
321 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
325 void SDLInitVideoDisplay(void)
327 #if !defined(TARGET_SDL2)
328 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
329 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
331 SDL_putenv("SDL_VIDEO_CENTERED=1");
334 /* initialize SDL video */
335 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
336 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
338 /* set default SDL depth */
339 #if !defined(TARGET_SDL2)
340 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
342 video.default_depth = 32; // (how to determine video depth in SDL2?)
346 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
349 #if !defined(TARGET_SDL2)
350 static int screen_xy[][2] =
358 SDL_Rect **modes = NULL;
359 boolean hardware_fullscreen_available = TRUE;
362 /* default: normal game window size */
363 fullscreen_width = video.width;
364 fullscreen_height = video.height;
365 fullscreen_xoffset = 0;
366 fullscreen_yoffset = 0;
368 #if !defined(TARGET_SDL2)
369 /* determine required standard fullscreen mode for game screen size */
370 for (i = 0; screen_xy[i][0] != -1; i++)
372 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
374 fullscreen_width = screen_xy[i][0];
375 fullscreen_height = screen_xy[i][1];
381 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
382 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
385 checked_free(video.fullscreen_modes);
387 video.fullscreen_modes = NULL;
388 video.fullscreen_mode_current = NULL;
390 video.window_scaling_percent = setup.window_scaling_percent;
391 video.window_scaling_quality = setup.window_scaling_quality;
393 #if defined(TARGET_SDL2)
394 int num_displays = SDL_GetNumVideoDisplays();
396 if (num_displays > 0)
398 // currently only display modes of first display supported
399 int num_modes = SDL_GetNumDisplayModes(0);
403 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
405 for (i = 0; i < num_modes; i++)
407 SDL_DisplayMode mode;
409 if (SDL_GetDisplayMode(0, i, &mode) < 0)
412 modes[i] = checked_calloc(sizeof(SDL_Rect));
414 modes[i]->w = mode.w;
415 modes[i]->h = mode.h;
420 /* get available hardware supported fullscreen modes */
421 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
426 /* no hardware screen modes available => no fullscreen mode support */
427 // video.fullscreen_available = FALSE;
428 hardware_fullscreen_available = FALSE;
430 else if (modes == (SDL_Rect **)-1)
432 /* fullscreen resolution is not restricted -- all resolutions available */
433 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
435 /* use native video buffer size for fullscreen mode */
436 video.fullscreen_modes[0].width = video.width;
437 video.fullscreen_modes[0].height = video.height;
439 video.fullscreen_modes[1].width = -1;
440 video.fullscreen_modes[1].height = -1;
444 /* in this case, a certain number of screen modes is available */
447 for (i = 0; modes[i] != NULL; i++)
449 boolean found_mode = FALSE;
451 /* screen mode is smaller than video buffer size -- skip it */
452 if (modes[i]->w < video.width || modes[i]->h < video.height)
455 if (video.fullscreen_modes != NULL)
456 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
457 if (modes[i]->w == video.fullscreen_modes[j].width &&
458 modes[i]->h == video.fullscreen_modes[j].height)
461 if (found_mode) /* screen mode already stored -- skip it */
464 /* new mode found; add it to list of available fullscreen modes */
468 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
470 sizeof(struct ScreenModeInfo));
472 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
473 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
475 video.fullscreen_modes[num_modes].width = -1;
476 video.fullscreen_modes[num_modes].height = -1;
481 /* no appropriate screen modes available => no fullscreen mode support */
482 // video.fullscreen_available = FALSE;
483 hardware_fullscreen_available = FALSE;
487 video.fullscreen_available = hardware_fullscreen_available;
489 #if USE_DESKTOP_FULLSCREEN
490 // in SDL 2.0, there is always support for desktop fullscreen mode
491 // (in SDL 1.2, there is only support for "real" fullscreen mode)
492 video.fullscreen_available = TRUE;
495 #if defined(TARGET_SDL2)
498 for (i = 0; modes[i] != NULL; i++)
499 checked_free(modes[i]);
505 /* open SDL video output device (window or fullscreen mode) */
506 if (!SDLSetVideoMode(backbuffer, fullscreen))
507 Error(ERR_EXIT, "setting video mode failed");
509 /* !!! SDL2 can only set the window icon if the window already exists !!! */
510 /* set window icon */
511 SDLSetWindowIcon(program.icon_filename);
513 /* set window and icon title */
514 #if defined(TARGET_SDL2)
515 SDL_SetWindowTitle(sdl_window, program.window_title);
517 SDL_WM_SetCaption(program.window_title, program.window_title);
520 /* SDL cannot directly draw to the visible video framebuffer like X11,
521 but always uses a backbuffer, which is then blitted to the visible
522 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
523 visible video framebuffer with 'SDL_Flip', if the hardware supports
524 this). Therefore do not use an additional backbuffer for drawing, but
525 use a symbolic buffer (distinguishable from the SDL backbuffer) called
526 'window', which indicates that the SDL backbuffer should be updated to
527 the visible video framebuffer when attempting to blit to it.
529 For convenience, it seems to be a good idea to create this symbolic
530 buffer 'window' at the same size as the SDL backbuffer. Although it
531 should never be drawn to directly, it would do no harm nevertheless. */
533 /* create additional (symbolic) buffer for double-buffering */
534 ReCreateBitmap(window, video.width, video.height, video.depth);
537 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
540 SDL_Surface *new_surface = NULL;
542 #if defined(TARGET_SDL2)
543 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
544 #if USE_DESKTOP_FULLSCREEN
545 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
547 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
551 int surface_flags_window = SURFACE_FLAGS;
552 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
555 int width = (fullscreen ? fullscreen_width : video.width);
556 int height = (fullscreen ? fullscreen_height : video.height);
557 int surface_flags = (fullscreen ? surface_flags_fullscreen :
558 surface_flags_window);
560 // default window size is unscaled
561 video.window_width = video.width;
562 video.window_height = video.height;
564 #if defined(TARGET_SDL2)
566 // store if initial screen mode is fullscreen mode when changing screen size
567 video.fullscreen_initial = fullscreen;
570 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
571 #if !USE_DESKTOP_FULLSCREEN
572 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
575 video.window_width = window_scaling_factor * width;
576 video.window_height = window_scaling_factor * height;
578 if ((*backbuffer)->surface)
580 SDL_FreeSurface((*backbuffer)->surface);
581 (*backbuffer)->surface = NULL;
586 SDL_DestroyTexture(sdl_texture);
590 if (!(fullscreen && fullscreen_enabled))
594 SDL_DestroyRenderer(sdl_renderer);
600 SDL_DestroyWindow(sdl_window);
605 if (sdl_window == NULL)
606 sdl_window = SDL_CreateWindow(program.window_title,
607 SDL_WINDOWPOS_CENTERED,
608 SDL_WINDOWPOS_CENTERED,
609 #if USE_DESKTOP_FULLSCREEN
613 (int)(screen_scaling_factor * width),
614 (int)(screen_scaling_factor * height),
618 if (sdl_window != NULL)
621 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
622 *without* enabling 2D/3D acceleration and/or guest additions installed,
623 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
624 it will try to use accelerated graphics and apparently fails miserably) */
625 if (sdl_renderer == NULL)
626 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
628 if (sdl_renderer == NULL)
629 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
632 if (sdl_renderer != NULL)
634 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
635 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
636 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
638 sdl_texture = SDL_CreateTexture(sdl_renderer,
639 SDL_PIXELFORMAT_ARGB8888,
640 SDL_TEXTUREACCESS_STREAMING,
643 if (sdl_texture != NULL)
645 // use SDL default values for RGB masks and no alpha channel
646 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
648 if (new_surface == NULL)
649 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
654 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
659 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
664 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
670 SDL_DestroyWindow(sdl_window);
672 sdl_window = SDL_CreateWindow(program.window_title,
673 SDL_WINDOWPOS_CENTERED,
674 SDL_WINDOWPOS_CENTERED,
678 if (sdl_window != NULL)
679 new_surface = SDL_GetWindowSurface(sdl_window);
683 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
686 #if defined(TARGET_SDL2)
687 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
688 if (new_surface != NULL)
689 fullscreen_enabled = fullscreen;
695 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
697 boolean success = TRUE;
698 SDL_Surface *new_surface = NULL;
702 if (*backbuffer == NULL)
703 *backbuffer = CreateBitmapStruct();
705 /* (real bitmap might be larger in fullscreen mode with video offsets) */
706 (*backbuffer)->width = video.width;
707 (*backbuffer)->height = video.height;
709 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
711 setFullscreenParameters(setup.fullscreen_mode);
713 video_xoffset = fullscreen_xoffset;
714 video_yoffset = fullscreen_yoffset;
716 /* switch display to fullscreen mode, if available */
717 new_surface = SDLCreateScreen(backbuffer, TRUE);
719 if (new_surface == NULL)
721 /* switching display to fullscreen mode failed */
722 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
724 /* do not try it again */
725 video.fullscreen_available = FALSE;
731 (*backbuffer)->surface = new_surface;
733 video.fullscreen_enabled = TRUE;
734 video.fullscreen_mode_current = setup.fullscreen_mode;
740 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
745 /* switch display to window mode */
746 new_surface = SDLCreateScreen(backbuffer, FALSE);
748 if (new_surface == NULL)
750 /* switching display to window mode failed -- should not happen */
751 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
757 (*backbuffer)->surface = new_surface;
759 video.fullscreen_enabled = FALSE;
760 video.window_scaling_percent = setup.window_scaling_percent;
761 video.window_scaling_quality = setup.window_scaling_quality;
767 #if defined(TARGET_SDL2)
768 SDLRedrawWindow(); // map window
772 #if defined(PLATFORM_WIN32)
773 // experimental drag and drop code
775 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
778 SDL_SysWMinfo wminfo;
780 boolean wminfo_success = FALSE;
782 SDL_VERSION(&wminfo.version);
783 #if defined(TARGET_SDL2)
785 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
787 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
792 #if defined(TARGET_SDL2)
793 hwnd = wminfo.info.win.window;
795 hwnd = wminfo.window;
798 DragAcceptFiles(hwnd, TRUE);
807 void SDLSetWindowTitle()
809 #if defined(TARGET_SDL2)
810 SDL_SetWindowTitle(sdl_window, program.window_title);
812 SDL_WM_SetCaption(program.window_title, program.window_title);
816 #if defined(TARGET_SDL2)
817 void SDLSetWindowScaling(int window_scaling_percent)
819 if (sdl_window == NULL)
822 float window_scaling_factor = (float)window_scaling_percent / 100;
823 int new_window_width = (int)(window_scaling_factor * video.width);
824 int new_window_height = (int)(window_scaling_factor * video.height);
826 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
828 video.window_scaling_percent = window_scaling_percent;
829 video.window_width = new_window_width;
830 video.window_height = new_window_height;
835 void SDLSetWindowScalingQuality(char *window_scaling_quality)
837 if (sdl_texture == NULL)
840 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
842 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
843 SDL_PIXELFORMAT_ARGB8888,
844 SDL_TEXTUREACCESS_STREAMING,
845 video.width, video.height);
847 if (new_texture != NULL)
849 SDL_DestroyTexture(sdl_texture);
851 sdl_texture = new_texture;
856 video.window_scaling_quality = window_scaling_quality;
859 void SDLSetWindowFullscreen(boolean fullscreen)
861 if (sdl_window == NULL)
864 #if USE_DESKTOP_FULLSCREEN
865 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
867 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
870 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
871 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
873 // if screen size was changed in fullscreen mode, correct desktop window size
874 if (!fullscreen && video.fullscreen_initial)
876 SDLSetWindowScaling(setup.window_scaling_percent);
877 SDL_SetWindowPosition(sdl_window,
878 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
880 video.fullscreen_initial = FALSE;
884 void SDLRedrawWindow()
890 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
893 SDL_Surface *surface =
894 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
897 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
899 SDLSetNativeSurface(&surface);
901 bitmap->surface = surface;
904 void SDLFreeBitmapPointers(Bitmap *bitmap)
907 SDL_FreeSurface(bitmap->surface);
908 if (bitmap->surface_masked)
909 SDL_FreeSurface(bitmap->surface_masked);
911 bitmap->surface = NULL;
912 bitmap->surface_masked = NULL;
914 #if defined(TARGET_SDL2)
916 SDL_DestroyTexture(bitmap->texture);
917 if (bitmap->texture_masked)
918 SDL_DestroyTexture(bitmap->texture_masked);
920 bitmap->texture = NULL;
921 bitmap->texture_masked = NULL;
925 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
926 int src_x, int src_y, int width, int height,
927 int dst_x, int dst_y, int mask_mode)
929 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
930 SDL_Rect src_rect, dst_rect;
932 if (src_bitmap == backbuffer)
934 src_x += video_xoffset;
935 src_y += video_yoffset;
943 if (dst_bitmap == backbuffer || dst_bitmap == window)
945 dst_x += video_xoffset;
946 dst_y += video_yoffset;
954 // if (src_bitmap != backbuffer || dst_bitmap != window)
955 if (!(src_bitmap == backbuffer && dst_bitmap == window))
956 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
957 src_bitmap->surface_masked : src_bitmap->surface),
958 &src_rect, real_dst_bitmap->surface, &dst_rect);
960 #if defined(TARGET_SDL2)
961 if (dst_bitmap == window)
963 // SDL_UpdateWindowSurface(sdl_window);
964 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
965 UpdateScreen(&dst_rect);
968 if (dst_bitmap == window)
970 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
971 UpdateScreen(&dst_rect);
976 void SDLBlitTexture(Bitmap *bitmap,
977 int src_x, int src_y, int width, int height,
978 int dst_x, int dst_y, int mask_mode)
980 #if defined(TARGET_SDL2)
982 SDL_Texture *texture;
987 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
1000 dst_rect.h = height;
1002 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
1007 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
1010 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1013 if (dst_bitmap == backbuffer || dst_bitmap == window)
1024 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
1026 #if defined(TARGET_SDL2)
1027 if (dst_bitmap == window)
1029 // SDL_UpdateWindowSurface(sdl_window);
1030 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
1031 UpdateScreen(&rect);
1034 if (dst_bitmap == window)
1036 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
1037 UpdateScreen(&rect);
1042 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
1043 int fade_mode, int fade_delay, int post_delay,
1044 void (*draw_border_function)(void))
1046 static boolean initialization_needed = TRUE;
1047 static SDL_Surface *surface_source = NULL;
1048 static SDL_Surface *surface_target = NULL;
1049 static SDL_Surface *surface_black = NULL;
1050 SDL_Surface *surface_screen = backbuffer->surface;
1051 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
1052 SDL_Rect src_rect, dst_rect;
1054 int src_x = x, src_y = y;
1055 int dst_x = x, dst_y = y;
1056 unsigned int time_last, time_current;
1058 /* check if screen size has changed */
1059 if (surface_source != NULL && (video.width != surface_source->w ||
1060 video.height != surface_source->h))
1062 SDL_FreeSurface(surface_source);
1063 SDL_FreeSurface(surface_target);
1064 SDL_FreeSurface(surface_black);
1066 initialization_needed = TRUE;
1072 src_rect.h = height;
1074 dst_x += video_xoffset;
1075 dst_y += video_yoffset;
1079 dst_rect.w = width; /* (ignored) */
1080 dst_rect.h = height; /* (ignored) */
1082 dst_rect2 = dst_rect;
1084 if (initialization_needed)
1086 #if defined(TARGET_SDL2)
1087 unsigned int flags = 0;
1089 unsigned int flags = SDL_SRCALPHA;
1091 /* use same surface type as screen surface */
1092 if ((surface_screen->flags & SDL_HWSURFACE))
1093 flags |= SDL_HWSURFACE;
1095 flags |= SDL_SWSURFACE;
1098 /* create surface for temporary copy of screen buffer (source) */
1099 if ((surface_source =
1100 SDL_CreateRGBSurface(flags,
1103 surface_screen->format->BitsPerPixel,
1104 surface_screen->format->Rmask,
1105 surface_screen->format->Gmask,
1106 surface_screen->format->Bmask,
1107 surface_screen->format->Amask)) == NULL)
1108 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1110 /* create surface for cross-fading screen buffer (target) */
1111 if ((surface_target =
1112 SDL_CreateRGBSurface(flags,
1115 surface_screen->format->BitsPerPixel,
1116 surface_screen->format->Rmask,
1117 surface_screen->format->Gmask,
1118 surface_screen->format->Bmask,
1119 surface_screen->format->Amask)) == NULL)
1120 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1122 /* create black surface for fading from/to black */
1123 if ((surface_black =
1124 SDL_CreateRGBSurface(flags,
1127 surface_screen->format->BitsPerPixel,
1128 surface_screen->format->Rmask,
1129 surface_screen->format->Gmask,
1130 surface_screen->format->Bmask,
1131 surface_screen->format->Amask)) == NULL)
1132 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1134 /* completely fill the surface with black color pixels */
1135 SDL_FillRect(surface_black, NULL,
1136 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1138 initialization_needed = FALSE;
1141 /* copy source and target surfaces to temporary surfaces for fading */
1142 if (fade_mode & FADE_TYPE_TRANSFORM)
1144 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1145 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1147 else if (fade_mode & FADE_TYPE_FADE_IN)
1149 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1150 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1152 else /* FADE_TYPE_FADE_OUT */
1154 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1155 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1158 time_current = SDL_GetTicks();
1160 if (fade_mode == FADE_MODE_MELT)
1162 boolean done = FALSE;
1163 int melt_pixels = 2;
1164 int melt_columns = width / melt_pixels;
1165 int ypos[melt_columns];
1166 int max_steps = height / 8 + 32;
1171 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1172 #if defined(TARGET_SDL2)
1173 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1175 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1178 ypos[0] = -GetSimpleRandom(16);
1180 for (i = 1 ; i < melt_columns; i++)
1182 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1184 ypos[i] = ypos[i - 1] + r;
1197 time_last = time_current;
1198 time_current = SDL_GetTicks();
1199 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1200 steps_final = MIN(MAX(0, steps), max_steps);
1204 done = (steps_done >= steps_final);
1206 for (i = 0 ; i < melt_columns; i++)
1214 else if (ypos[i] < height)
1219 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1221 if (ypos[i] + dy >= height)
1222 dy = height - ypos[i];
1224 /* copy part of (appearing) target surface to upper area */
1225 src_rect.x = src_x + i * melt_pixels;
1226 // src_rect.y = src_y + ypos[i];
1228 src_rect.w = melt_pixels;
1230 src_rect.h = ypos[i] + dy;
1232 dst_rect.x = dst_x + i * melt_pixels;
1233 // dst_rect.y = dst_y + ypos[i];
1236 if (steps_done >= steps_final)
1237 SDL_BlitSurface(surface_target, &src_rect,
1238 surface_screen, &dst_rect);
1242 /* copy part of (disappearing) source surface to lower area */
1243 src_rect.x = src_x + i * melt_pixels;
1245 src_rect.w = melt_pixels;
1246 src_rect.h = height - ypos[i];
1248 dst_rect.x = dst_x + i * melt_pixels;
1249 dst_rect.y = dst_y + ypos[i];
1251 if (steps_done >= steps_final)
1252 SDL_BlitSurface(surface_source, &src_rect,
1253 surface_screen, &dst_rect);
1259 src_rect.x = src_x + i * melt_pixels;
1261 src_rect.w = melt_pixels;
1262 src_rect.h = height;
1264 dst_rect.x = dst_x + i * melt_pixels;
1267 if (steps_done >= steps_final)
1268 SDL_BlitSurface(surface_target, &src_rect,
1269 surface_screen, &dst_rect);
1273 if (steps_done >= steps_final)
1275 if (draw_border_function != NULL)
1276 draw_border_function();
1278 UpdateScreen(&dst_rect2);
1282 else if (fade_mode == FADE_MODE_CURTAIN)
1286 int xx_size = width / 2;
1288 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1289 #if defined(TARGET_SDL2)
1290 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1292 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1295 for (xx = 0; xx < xx_size;)
1297 time_last = time_current;
1298 time_current = SDL_GetTicks();
1299 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1300 xx_final = MIN(MAX(0, xx), xx_size);
1305 src_rect.h = height;
1310 /* draw new (target) image to screen buffer */
1311 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1313 if (xx_final < xx_size)
1315 src_rect.w = xx_size - xx_final;
1316 src_rect.h = height;
1318 /* draw old (source) image to screen buffer (left side) */
1320 src_rect.x = src_x + xx_final;
1323 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1325 /* draw old (source) image to screen buffer (right side) */
1327 src_rect.x = src_x + xx_size;
1328 dst_rect.x = dst_x + xx_size + xx_final;
1330 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1333 if (draw_border_function != NULL)
1334 draw_border_function();
1336 /* only update the region of the screen that is affected from fading */
1337 UpdateScreen(&dst_rect2);
1340 else /* fading in, fading out or cross-fading */
1345 for (alpha = 0.0; alpha < 255.0;)
1347 time_last = time_current;
1348 time_current = SDL_GetTicks();
1349 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1350 alpha_final = MIN(MAX(0, alpha), 255);
1352 /* draw existing (source) image to screen buffer */
1353 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1355 /* draw new (target) image to screen buffer using alpha blending */
1356 #if defined(TARGET_SDL2)
1357 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1358 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1360 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1362 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1364 if (draw_border_function != NULL)
1365 draw_border_function();
1367 /* only update the region of the screen that is affected from fading */
1368 UpdateScreen(&dst_rect);
1375 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1376 int to_x, int to_y, Uint32 color)
1378 SDL_Surface *surface = dst_bitmap->surface;
1382 swap_numbers(&from_x, &to_x);
1385 swap_numbers(&from_y, &to_y);
1389 rect.w = (to_x - from_x + 1);
1390 rect.h = (to_y - from_y + 1);
1392 if (dst_bitmap == backbuffer || dst_bitmap == window)
1394 rect.x += video_xoffset;
1395 rect.y += video_yoffset;
1398 SDL_FillRect(surface, &rect, color);
1401 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1402 int to_x, int to_y, Uint32 color)
1404 if (dst_bitmap == backbuffer || dst_bitmap == window)
1406 from_x += video_xoffset;
1407 from_y += video_yoffset;
1408 to_x += video_xoffset;
1409 to_y += video_yoffset;
1412 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1415 #if ENABLE_UNUSED_CODE
1416 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1417 int num_points, Uint32 color)
1422 for (i = 0; i < num_points - 1; i++)
1424 for (x = 0; x < line_width; x++)
1426 for (y = 0; y < line_width; y++)
1428 int dx = x - line_width / 2;
1429 int dy = y - line_width / 2;
1431 if ((x == 0 && y == 0) ||
1432 (x == 0 && y == line_width - 1) ||
1433 (x == line_width - 1 && y == 0) ||
1434 (x == line_width - 1 && y == line_width - 1))
1437 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1438 points[i+1].x + dx, points[i+1].y + dy, color);
1445 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1447 SDL_Surface *surface = src_bitmap->surface;
1449 if (src_bitmap == backbuffer || src_bitmap == window)
1455 switch (surface->format->BytesPerPixel)
1457 case 1: /* assuming 8-bpp */
1459 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1463 case 2: /* probably 15-bpp or 16-bpp */
1465 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1469 case 3: /* slow 24-bpp mode; usually not used */
1471 /* does this work? */
1472 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1476 shift = surface->format->Rshift;
1477 color |= *(pix + shift / 8) >> shift;
1478 shift = surface->format->Gshift;
1479 color |= *(pix + shift / 8) >> shift;
1480 shift = surface->format->Bshift;
1481 color |= *(pix + shift / 8) >> shift;
1487 case 4: /* probably 32-bpp */
1489 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1498 /* ========================================================================= */
1499 /* The following functions were taken from the SGE library */
1500 /* (SDL Graphics Extension Library) by Anders Lindström */
1501 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1502 /* ========================================================================= */
1504 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1506 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1508 switch (surface->format->BytesPerPixel)
1512 /* Assuming 8-bpp */
1513 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1519 /* Probably 15-bpp or 16-bpp */
1520 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1526 /* Slow 24-bpp mode, usually not used */
1530 /* Gack - slow, but endian correct */
1531 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1532 shift = surface->format->Rshift;
1533 *(pix+shift/8) = color>>shift;
1534 shift = surface->format->Gshift;
1535 *(pix+shift/8) = color>>shift;
1536 shift = surface->format->Bshift;
1537 *(pix+shift/8) = color>>shift;
1543 /* Probably 32-bpp */
1544 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1551 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1552 Uint8 R, Uint8 G, Uint8 B)
1554 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1557 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1559 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1562 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1564 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1567 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1572 /* Gack - slow, but endian correct */
1573 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1574 shift = surface->format->Rshift;
1575 *(pix+shift/8) = color>>shift;
1576 shift = surface->format->Gshift;
1577 *(pix+shift/8) = color>>shift;
1578 shift = surface->format->Bshift;
1579 *(pix+shift/8) = color>>shift;
1582 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1584 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1587 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1589 switch (dest->format->BytesPerPixel)
1592 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1596 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1600 _PutPixel24(dest,x,y,color);
1604 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1609 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1611 if (SDL_MUSTLOCK(surface))
1613 if (SDL_LockSurface(surface) < 0)
1619 _PutPixel(surface, x, y, color);
1621 if (SDL_MUSTLOCK(surface))
1623 SDL_UnlockSurface(surface);
1627 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1628 Uint8 r, Uint8 g, Uint8 b)
1630 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1633 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1635 if (y >= 0 && y <= dest->h - 1)
1637 switch (dest->format->BytesPerPixel)
1640 return y*dest->pitch;
1644 return y*dest->pitch/2;
1648 return y*dest->pitch;
1652 return y*dest->pitch/4;
1660 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1662 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1664 switch (surface->format->BytesPerPixel)
1668 /* Assuming 8-bpp */
1669 *((Uint8 *)surface->pixels + ypitch + x) = color;
1675 /* Probably 15-bpp or 16-bpp */
1676 *((Uint16 *)surface->pixels + ypitch + x) = color;
1682 /* Slow 24-bpp mode, usually not used */
1686 /* Gack - slow, but endian correct */
1687 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1688 shift = surface->format->Rshift;
1689 *(pix+shift/8) = color>>shift;
1690 shift = surface->format->Gshift;
1691 *(pix+shift/8) = color>>shift;
1692 shift = surface->format->Bshift;
1693 *(pix+shift/8) = color>>shift;
1699 /* Probably 32-bpp */
1700 *((Uint32 *)surface->pixels + ypitch + x) = color;
1707 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1712 if (SDL_MUSTLOCK(Surface))
1714 if (SDL_LockSurface(Surface) < 0)
1727 /* Do the clipping */
1728 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1732 if (x2 > Surface->w - 1)
1733 x2 = Surface->w - 1;
1740 SDL_FillRect(Surface, &l, Color);
1742 if (SDL_MUSTLOCK(Surface))
1744 SDL_UnlockSurface(Surface);
1748 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1749 Uint8 R, Uint8 G, Uint8 B)
1751 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1754 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1765 /* Do the clipping */
1766 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1770 if (x2 > Surface->w - 1)
1771 x2 = Surface->w - 1;
1778 SDL_FillRect(Surface, &l, Color);
1781 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1786 if (SDL_MUSTLOCK(Surface))
1788 if (SDL_LockSurface(Surface) < 0)
1801 /* Do the clipping */
1802 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1806 if (y2 > Surface->h - 1)
1807 y2 = Surface->h - 1;
1814 SDL_FillRect(Surface, &l, Color);
1816 if (SDL_MUSTLOCK(Surface))
1818 SDL_UnlockSurface(Surface);
1822 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1823 Uint8 R, Uint8 G, Uint8 B)
1825 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1828 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1839 /* Do the clipping */
1840 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1844 if (y2 > Surface->h - 1)
1845 y2 = Surface->h - 1;
1852 SDL_FillRect(Surface, &l, Color);
1855 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1856 Sint16 x2, Sint16 y2, Uint32 Color,
1857 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1860 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1865 sdx = (dx < 0) ? -1 : 1;
1866 sdy = (dy < 0) ? -1 : 1;
1878 for (x = 0; x < dx; x++)
1880 Callback(Surface, px, py, Color);
1894 for (y = 0; y < dy; y++)
1896 Callback(Surface, px, py, Color);
1910 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1911 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1912 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1915 sge_DoLine(Surface, X1, Y1, X2, Y2,
1916 SDL_MapRGB(Surface->format, R, G, B), Callback);
1919 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1922 if (SDL_MUSTLOCK(Surface))
1924 if (SDL_LockSurface(Surface) < 0)
1929 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1931 /* unlock the display */
1932 if (SDL_MUSTLOCK(Surface))
1934 SDL_UnlockSurface(Surface);
1938 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1939 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1941 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1944 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1946 if (dst_bitmap == backbuffer || dst_bitmap == window)
1952 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1957 -----------------------------------------------------------------------------
1958 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1959 -----------------------------------------------------------------------------
1962 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1963 int width, int height, Uint32 color)
1967 for (y = src_y; y < src_y + height; y++)
1969 for (x = src_x; x < src_x + width; x++)
1971 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1973 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1978 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1979 int src_x, int src_y, int width, int height,
1980 int dst_x, int dst_y)
1984 for (y = 0; y < height; y++)
1986 for (x = 0; x < width; x++)
1988 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1990 if (pixel != BLACK_PIXEL)
1991 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1997 /* ========================================================================= */
1998 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1999 /* (Rotozoomer) by Andreas Schiffler */
2000 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
2001 /* ========================================================================= */
2004 -----------------------------------------------------------------------------
2007 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
2008 -----------------------------------------------------------------------------
2019 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
2022 tColorRGBA *sp, *csp, *dp;
2026 sp = csp = (tColorRGBA *) src->pixels;
2027 dp = (tColorRGBA *) dst->pixels;
2028 dgap = dst->pitch - dst->w * 4;
2030 for (y = 0; y < dst->h; y++)
2034 for (x = 0; x < dst->w; x++)
2036 tColorRGBA *sp0 = sp;
2037 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
2038 tColorRGBA *sp00 = &sp0[0];
2039 tColorRGBA *sp01 = &sp0[1];
2040 tColorRGBA *sp10 = &sp1[0];
2041 tColorRGBA *sp11 = &sp1[1];
2044 /* create new color pixel from all four source color pixels */
2045 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2046 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2047 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2048 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2053 /* advance source pointers */
2056 /* advance destination pointer */
2060 /* advance source pointer */
2061 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2063 /* advance destination pointers */
2064 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2070 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2072 int x, y, *sax, *say, *csax, *csay;
2074 tColorRGBA *sp, *csp, *csp0, *dp;
2077 /* use specialized zoom function when scaling down to exactly half size */
2078 if (src->w == 2 * dst->w &&
2079 src->h == 2 * dst->h)
2080 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2082 /* variable setup */
2083 sx = (float) src->w / (float) dst->w;
2084 sy = (float) src->h / (float) dst->h;
2086 /* allocate memory for row increments */
2087 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2088 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2090 /* precalculate row increments */
2091 for (x = 0; x <= dst->w; x++)
2092 *csax++ = (int)(sx * x);
2094 for (y = 0; y <= dst->h; y++)
2095 *csay++ = (int)(sy * y);
2098 sp = csp = csp0 = (tColorRGBA *) src->pixels;
2099 dp = (tColorRGBA *) dst->pixels;
2100 dgap = dst->pitch - dst->w * 4;
2103 for (y = 0; y < dst->h; y++)
2108 for (x = 0; x < dst->w; x++)
2113 /* advance source pointers */
2117 /* advance destination pointer */
2121 /* advance source pointer */
2123 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
2125 /* advance destination pointers */
2126 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2136 -----------------------------------------------------------------------------
2139 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2140 -----------------------------------------------------------------------------
2143 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2145 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2146 Uint8 *sp, *dp, *csp;
2149 /* variable setup */
2150 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2151 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2153 /* allocate memory for row increments */
2154 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2155 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2157 /* precalculate row increments */
2160 for (x = 0; x < dst->w; x++)
2163 *csax = (csx >> 16);
2170 for (y = 0; y < dst->h; y++)
2173 *csay = (csy >> 16);
2180 for (x = 0; x < dst->w; x++)
2188 for (y = 0; y < dst->h; y++)
2195 sp = csp = (Uint8 *) src->pixels;
2196 dp = (Uint8 *) dst->pixels;
2197 dgap = dst->pitch - dst->w;
2201 for (y = 0; y < dst->h; y++)
2205 for (x = 0; x < dst->w; x++)
2210 /* advance source pointers */
2214 /* advance destination pointer */
2218 /* advance source pointer (for row) */
2219 csp += ((*csay) * src->pitch);
2222 /* advance destination pointers */
2233 -----------------------------------------------------------------------------
2236 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2237 'zoomx' and 'zoomy' are scaling factors for width and height.
2238 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2239 into a 32bit RGBA format on the fly.
2240 -----------------------------------------------------------------------------
2243 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2245 SDL_Surface *zoom_src = NULL;
2246 SDL_Surface *zoom_dst = NULL;
2247 boolean is_converted = FALSE;
2254 /* determine if source surface is 32 bit or 8 bit */
2255 is_32bit = (src->format->BitsPerPixel == 32);
2257 if (is_32bit || src->format->BitsPerPixel == 8)
2259 /* use source surface 'as is' */
2264 /* new source surface is 32 bit with a defined RGB ordering */
2265 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2266 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2267 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2269 is_converted = TRUE;
2272 /* allocate surface to completely contain the zoomed surface */
2275 /* target surface is 32 bit with source RGBA/ABGR ordering */
2276 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2277 zoom_src->format->Rmask,
2278 zoom_src->format->Gmask,
2279 zoom_src->format->Bmask, 0);
2283 /* target surface is 8 bit */
2284 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2288 /* lock source surface */
2289 SDL_LockSurface(zoom_src);
2291 /* check which kind of surface we have */
2294 /* call the 32 bit transformation routine to do the zooming */
2295 zoomSurfaceRGBA(zoom_src, zoom_dst);
2300 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2301 zoom_dst->format->palette->colors[i] =
2302 zoom_src->format->palette->colors[i];
2303 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2305 /* call the 8 bit transformation routine to do the zooming */
2306 zoomSurfaceY(zoom_src, zoom_dst);
2309 /* unlock source surface */
2310 SDL_UnlockSurface(zoom_src);
2312 /* free temporary surface */
2314 SDL_FreeSurface(zoom_src);
2316 /* return destination surface */
2320 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2322 Bitmap *dst_bitmap = CreateBitmapStruct();
2323 SDL_Surface **dst_surface = &dst_bitmap->surface;
2325 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2326 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2328 dst_bitmap->width = dst_width;
2329 dst_bitmap->height = dst_height;
2331 /* create zoomed temporary surface from source surface */
2332 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2334 /* create native format destination surface from zoomed temporary surface */
2335 SDLSetNativeSurface(dst_surface);
2341 /* ========================================================================= */
2342 /* load image to bitmap */
2343 /* ========================================================================= */
2345 Bitmap *SDLLoadImage(char *filename)
2347 Bitmap *new_bitmap = CreateBitmapStruct();
2348 SDL_Surface *sdl_image_tmp;
2350 print_timestamp_init("SDLLoadImage");
2352 print_timestamp_time(getBaseNamePtr(filename));
2354 /* load image to temporary surface */
2355 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2357 SetError("IMG_Load(): %s", SDL_GetError());
2362 print_timestamp_time("IMG_Load");
2364 UPDATE_BUSY_STATE();
2366 /* create native non-transparent surface for current image */
2367 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2369 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2374 print_timestamp_time("SDL_DisplayFormat (opaque)");
2376 UPDATE_BUSY_STATE();
2378 /* create native transparent surface for current image */
2379 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2380 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2382 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2384 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2389 print_timestamp_time("SDL_DisplayFormat (masked)");
2391 UPDATE_BUSY_STATE();
2393 /* free temporary surface */
2394 SDL_FreeSurface(sdl_image_tmp);
2396 new_bitmap->width = new_bitmap->surface->w;
2397 new_bitmap->height = new_bitmap->surface->h;
2399 print_timestamp_done("SDLLoadImage");
2405 /* ------------------------------------------------------------------------- */
2406 /* custom cursor fuctions */
2407 /* ------------------------------------------------------------------------- */
2409 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2411 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2412 cursor_info->width, cursor_info->height,
2413 cursor_info->hot_x, cursor_info->hot_y);
2416 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2418 static struct MouseCursorInfo *last_cursor_info = NULL;
2419 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2420 static SDL_Cursor *cursor_default = NULL;
2421 static SDL_Cursor *cursor_current = NULL;
2423 /* if invoked for the first time, store the SDL default cursor */
2424 if (cursor_default == NULL)
2425 cursor_default = SDL_GetCursor();
2427 /* only create new cursor if cursor info (custom only) has changed */
2428 if (cursor_info != NULL && cursor_info != last_cursor_info)
2430 cursor_current = create_cursor(cursor_info);
2431 last_cursor_info = cursor_info;
2434 /* only set new cursor if cursor info (custom or NULL) has changed */
2435 if (cursor_info != last_cursor_info2)
2436 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2438 last_cursor_info2 = cursor_info;
2442 /* ========================================================================= */
2443 /* audio functions */
2444 /* ========================================================================= */
2446 void SDLOpenAudio(void)
2448 #if !defined(TARGET_SDL2)
2449 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2450 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2453 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2455 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2459 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2460 AUDIO_NUM_CHANNELS_STEREO,
2461 setup.system.audio_fragment_size) < 0)
2463 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2467 audio.sound_available = TRUE;
2468 audio.music_available = TRUE;
2469 audio.loops_available = TRUE;
2470 audio.sound_enabled = TRUE;
2472 /* set number of available mixer channels */
2473 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2474 audio.music_channel = MUSIC_CHANNEL;
2475 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2477 Mixer_InitChannels();
2480 void SDLCloseAudio(void)
2483 Mix_HaltChannel(-1);
2486 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2490 /* ========================================================================= */
2491 /* event functions */
2492 /* ========================================================================= */
2494 void SDLNextEvent(Event *event)
2496 SDL_WaitEvent(event);
2498 if (event->type == EVENT_BUTTONPRESS ||
2499 event->type == EVENT_BUTTONRELEASE)
2501 if (((ButtonEvent *)event)->x > video_xoffset)
2502 ((ButtonEvent *)event)->x -= video_xoffset;
2504 ((ButtonEvent *)event)->x = 0;
2505 if (((ButtonEvent *)event)->y > video_yoffset)
2506 ((ButtonEvent *)event)->y -= video_yoffset;
2508 ((ButtonEvent *)event)->y = 0;
2510 else if (event->type == EVENT_MOTIONNOTIFY)
2512 if (((MotionEvent *)event)->x > video_xoffset)
2513 ((MotionEvent *)event)->x -= video_xoffset;
2515 ((MotionEvent *)event)->x = 0;
2516 if (((MotionEvent *)event)->y > video_yoffset)
2517 ((MotionEvent *)event)->y -= video_yoffset;
2519 ((MotionEvent *)event)->y = 0;
2523 void SDLHandleWindowManagerEvent(Event *event)
2526 #if defined(PLATFORM_WIN32)
2527 // experimental drag and drop code
2529 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2530 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2532 #if defined(TARGET_SDL2)
2533 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2535 if (syswmmsg->msg == WM_DROPFILES)
2538 #if defined(TARGET_SDL2)
2539 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2541 HDROP hdrop = (HDROP)syswmmsg->wParam;
2545 printf("::: SDL_SYSWMEVENT:\n");
2547 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2549 for (i = 0; i < num_files; i++)
2551 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2552 char buffer[buffer_len + 1];
2554 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2556 printf("::: - '%s'\n", buffer);
2559 #if defined(TARGET_SDL2)
2560 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2562 DragFinish((HDROP)syswmmsg->wParam);
2570 /* ========================================================================= */
2571 /* joystick functions */
2572 /* ========================================================================= */
2574 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2575 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2576 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2578 static boolean SDLOpenJoystick(int nr)
2580 if (nr < 0 || nr > MAX_PLAYERS)
2583 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2586 static void SDLCloseJoystick(int nr)
2588 if (nr < 0 || nr > MAX_PLAYERS)
2591 SDL_JoystickClose(sdl_joystick[nr]);
2593 sdl_joystick[nr] = NULL;
2596 static boolean SDLCheckJoystickOpened(int nr)
2598 if (nr < 0 || nr > MAX_PLAYERS)
2601 #if defined(TARGET_SDL2)
2602 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2604 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2608 void HandleJoystickEvent(Event *event)
2612 case SDL_JOYAXISMOTION:
2613 if (event->jaxis.axis < 2)
2614 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2617 case SDL_JOYBUTTONDOWN:
2618 if (event->jbutton.button < 2)
2619 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2622 case SDL_JOYBUTTONUP:
2623 if (event->jbutton.button < 2)
2624 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2632 void SDLInitJoysticks()
2634 static boolean sdl_joystick_subsystem_initialized = FALSE;
2635 boolean print_warning = !sdl_joystick_subsystem_initialized;
2638 if (!sdl_joystick_subsystem_initialized)
2640 sdl_joystick_subsystem_initialized = TRUE;
2642 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2644 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2649 for (i = 0; i < MAX_PLAYERS; i++)
2651 /* get configured joystick for this player */
2652 char *device_name = setup.input[i].joy.device_name;
2653 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2655 if (joystick_nr >= SDL_NumJoysticks())
2657 if (setup.input[i].use_joystick && print_warning)
2658 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2663 /* misuse joystick file descriptor variable to store joystick number */
2664 joystick.fd[i] = joystick_nr;
2666 if (joystick_nr == -1)
2669 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2670 if (SDLCheckJoystickOpened(joystick_nr))
2671 SDLCloseJoystick(joystick_nr);
2673 if (!setup.input[i].use_joystick)
2676 if (!SDLOpenJoystick(joystick_nr))
2679 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2684 joystick.status = JOYSTICK_ACTIVATED;
2688 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2690 if (nr < 0 || nr >= MAX_PLAYERS)
2694 *x = sdl_js_axis[nr][0];
2696 *y = sdl_js_axis[nr][1];
2699 *b1 = sdl_js_button[nr][0];
2701 *b2 = sdl_js_button[nr][1];