1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
21 #if defined(TARGET_SDL)
23 /* ========================================================================= */
25 /* ========================================================================= */
27 /* SDL internal variables */
28 #if defined(TARGET_SDL2)
29 static SDL_Window *sdl_window = NULL;
30 static SDL_Renderer *sdl_renderer = NULL;
31 static SDL_Texture *sdl_texture = NULL;
33 #define USE_RENDERER 1
36 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
37 static int fullscreen_width;
38 static int fullscreen_height;
39 static int fullscreen_xoffset;
40 static int fullscreen_yoffset;
41 static int video_xoffset;
42 static int video_yoffset;
44 /* functions from SGE library */
45 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
47 #if defined(TARGET_SDL2)
48 static void UpdateScreen(SDL_Rect *rect)
51 SDL_Surface *screen = backbuffer->surface;
56 int bytes_x = screen->pitch / video.width;
57 int bytes_y = screen->pitch;
59 SDL_UpdateTexture(sdl_texture, rect,
60 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
65 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
68 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
70 SDL_RenderClear(sdl_renderer);
71 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
72 SDL_RenderPresent(sdl_renderer);
75 SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
77 SDL_UpdateWindowSurface(sdl_window);
82 static void setFullscreenParameters(char *fullscreen_mode_string)
84 struct ScreenModeInfo *fullscreen_mode;
87 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
89 if (fullscreen_mode == NULL)
92 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
94 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
95 fullscreen_mode->height == video.fullscreen_modes[i].height)
97 fullscreen_width = fullscreen_mode->width;
98 fullscreen_height = fullscreen_mode->height;
100 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
101 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
108 static void SDLSetWindowIcon(char *basename)
110 /* (setting the window icon on Mac OS X would replace the high-quality
111 dock icon with the currently smaller (and uglier) icon from file) */
113 #if !defined(PLATFORM_MACOSX)
114 char *filename = getCustomImageFilename(basename);
115 SDL_Surface *surface;
117 if (filename == NULL)
119 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
124 if ((surface = IMG_Load(filename)) == NULL)
126 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
131 /* set transparent color */
132 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
133 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
135 #if defined(TARGET_SDL2)
136 SDL_SetWindowIcon(sdl_window, surface);
138 SDL_WM_SetIcon(surface, NULL);
143 #if defined(TARGET_SDL2)
144 SDL_Surface *SDL_DisplayFormat(SDL_Surface *surface)
146 if (backbuffer == NULL ||
147 backbuffer->surface == NULL)
150 return SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
154 void SDLInitVideoDisplay(void)
156 #if !defined(TARGET_SDL2)
157 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
158 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
160 SDL_putenv("SDL_VIDEO_CENTERED=1");
163 /* initialize SDL video */
164 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
165 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
167 /* set default SDL depth */
168 #if !defined(TARGET_SDL2)
169 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
171 video.default_depth = 32; // (how to determine video depth in SDL2?)
175 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
178 static int screen_xy[][2] =
188 /* default: normal game window size */
189 fullscreen_width = video.width;
190 fullscreen_height = video.height;
191 fullscreen_xoffset = 0;
192 fullscreen_yoffset = 0;
194 for (i = 0; screen_xy[i][0] != -1; i++)
196 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
198 fullscreen_width = screen_xy[i][0];
199 fullscreen_height = screen_xy[i][1];
205 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
206 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
209 checked_free(video.fullscreen_modes);
211 video.fullscreen_modes = NULL;
212 video.fullscreen_mode_current = NULL;
215 #if !defined(TARGET_SDL2)
216 /* get available hardware supported fullscreen modes */
217 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
219 // (for now, no display modes in SDL2 -- change this later)
225 /* no screen modes available => no fullscreen mode support */
226 video.fullscreen_available = FALSE;
228 else if (modes == (SDL_Rect **)-1)
230 /* fullscreen resolution is not restricted -- all resolutions available */
231 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
233 /* use native video buffer size for fullscreen mode */
234 video.fullscreen_modes[0].width = video.width;
235 video.fullscreen_modes[0].height = video.height;
237 video.fullscreen_modes[1].width = -1;
238 video.fullscreen_modes[1].height = -1;
242 /* in this case, a certain number of screen modes is available */
245 for(i = 0; modes[i] != NULL; i++)
247 boolean found_mode = FALSE;
249 /* screen mode is smaller than video buffer size -- skip it */
250 if (modes[i]->w < video.width || modes[i]->h < video.height)
253 if (video.fullscreen_modes != NULL)
254 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
255 if (modes[i]->w == video.fullscreen_modes[j].width &&
256 modes[i]->h == video.fullscreen_modes[j].height)
259 if (found_mode) /* screen mode already stored -- skip it */
262 /* new mode found; add it to list of available fullscreen modes */
266 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
268 sizeof(struct ScreenModeInfo));
270 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
271 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
273 video.fullscreen_modes[num_modes].width = -1;
274 video.fullscreen_modes[num_modes].height = -1;
279 /* no appropriate screen modes available => no fullscreen mode support */
280 video.fullscreen_available = FALSE;
285 /* set window icon */
286 SDLSetWindowIcon(program.sdl_icon_filename);
289 /* open SDL video output device (window or fullscreen mode) */
290 if (!SDLSetVideoMode(backbuffer, fullscreen))
291 Error(ERR_EXIT, "setting video mode failed");
294 /* !!! SDL2 can only set the window icon if the window already exists !!! */
295 /* set window icon */
296 SDLSetWindowIcon(program.sdl_icon_filename);
299 /* set window and icon title */
300 #if defined(TARGET_SDL2)
301 SDL_SetWindowTitle(sdl_window, program.window_title);
303 SDL_WM_SetCaption(program.window_title, program.window_title);
306 /* SDL cannot directly draw to the visible video framebuffer like X11,
307 but always uses a backbuffer, which is then blitted to the visible
308 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
309 visible video framebuffer with 'SDL_Flip', if the hardware supports
310 this). Therefore do not use an additional backbuffer for drawing, but
311 use a symbolic buffer (distinguishable from the SDL backbuffer) called
312 'window', which indicates that the SDL backbuffer should be updated to
313 the visible video framebuffer when attempting to blit to it.
315 For convenience, it seems to be a good idea to create this symbolic
316 buffer 'window' at the same size as the SDL backbuffer. Although it
317 should never be drawn to directly, it would do no harm nevertheless. */
319 /* create additional (symbolic) buffer for double-buffering */
321 ReCreateBitmap(window, video.width, video.height, video.depth);
323 *window = CreateBitmap(video.width, video.height, video.depth);
327 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
329 boolean success = TRUE;
330 #if defined(TARGET_SDL2)
331 // int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
332 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
333 int surface_flags_window = SURFACE_FLAGS;
335 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
336 int surface_flags_window = SURFACE_FLAGS;
338 SDL_Surface *new_surface = NULL;
340 if (*backbuffer == NULL)
341 *backbuffer = CreateBitmapStruct();
343 /* (real bitmap might be larger in fullscreen mode with video offsets) */
344 (*backbuffer)->width = video.width;
345 (*backbuffer)->height = video.height;
347 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
349 setFullscreenParameters(setup.fullscreen_mode);
351 video_xoffset = fullscreen_xoffset;
352 video_yoffset = fullscreen_yoffset;
354 /* switch display to fullscreen mode, if available */
355 #if defined(TARGET_SDL2)
356 sdl_window = SDL_CreateWindow(program.window_title,
357 SDL_WINDOWPOS_CENTERED,
358 SDL_WINDOWPOS_CENTERED,
359 fullscreen_width, fullscreen_height,
360 surface_flags_fullscreen);
361 if (sdl_window != NULL)
363 new_surface = SDL_GetWindowSurface(sdl_window);
365 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
366 // UpdateScreen(NULL); // immediately map window
369 new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
370 video.depth, surface_flags_fullscreen);
373 if (new_surface == NULL)
375 /* switching display to fullscreen mode failed */
376 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
378 /* do not try it again */
379 video.fullscreen_available = FALSE;
385 (*backbuffer)->surface = new_surface;
387 video.fullscreen_enabled = TRUE;
388 video.fullscreen_mode_current = setup.fullscreen_mode;
394 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
399 /* switch display to window mode */
400 #if defined(TARGET_SDL2)
403 float scale_factor = 1.2;
404 int test_fullscreen = 0;
405 int surface_flags = (test_fullscreen ? surface_flags_fullscreen :
406 surface_flags_window);
408 sdl_window = SDL_CreateWindow(program.window_title,
409 SDL_WINDOWPOS_CENTERED,
410 SDL_WINDOWPOS_CENTERED,
411 (int)(scale_factor * video.width),
412 (int)(scale_factor * video.height),
415 if (sdl_window != NULL)
417 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
419 if (sdl_renderer != NULL)
421 SDL_RenderSetLogicalSize(sdl_renderer, video.width, video.height);
422 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
424 sdl_texture = SDL_CreateTexture(sdl_renderer,
425 SDL_PIXELFORMAT_ARGB8888,
426 SDL_TEXTUREACCESS_STREAMING,
427 video.width, video.height);
429 if (sdl_texture != NULL)
432 // (do not use alpha channel)
433 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
439 // (this uses an alpha channel, which we don't want here)
440 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
447 if (new_surface == NULL)
448 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
453 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
458 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
463 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
466 sdl_window = SDL_CreateWindow(program.window_title,
467 SDL_WINDOWPOS_CENTERED,
468 SDL_WINDOWPOS_CENTERED,
469 video.width, video.height,
470 surface_flags_window);
472 if (sdl_window != NULL)
474 new_surface = SDL_GetWindowSurface(sdl_window);
476 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
477 // UpdateScreen(NULL); // immediately map window
482 new_surface = SDL_SetVideoMode(video.width, video.height,
483 video.depth, surface_flags_window);
486 if (new_surface == NULL)
488 /* switching display to window mode failed -- should not happen */
489 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
495 (*backbuffer)->surface = new_surface;
497 video.fullscreen_enabled = FALSE;
503 #if defined(TARGET_SDL2)
504 UpdateScreen(NULL); // map window
508 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
510 #if defined(PLATFORM_WIN32)
512 SDL_SysWMinfo wminfo;
515 SDL_VERSION(&wminfo.version);
516 SDL_GetWMInfo(&wminfo);
518 hwnd = wminfo.window;
520 DragAcceptFiles(hwnd, TRUE);
529 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
532 SDL_Surface *surface_tmp, *surface_native;
534 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
537 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
539 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
540 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
542 SDL_FreeSurface(surface_tmp);
544 new_bitmap->surface = surface_native;
547 void SDLFreeBitmapPointers(Bitmap *bitmap)
550 SDL_FreeSurface(bitmap->surface);
551 if (bitmap->surface_masked)
552 SDL_FreeSurface(bitmap->surface_masked);
553 bitmap->surface = NULL;
554 bitmap->surface_masked = NULL;
557 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
558 int src_x, int src_y, int width, int height,
559 int dst_x, int dst_y, int mask_mode)
561 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
562 SDL_Rect src_rect, dst_rect;
564 if (src_bitmap == backbuffer)
566 src_x += video_xoffset;
567 src_y += video_yoffset;
575 if (dst_bitmap == backbuffer || dst_bitmap == window)
577 dst_x += video_xoffset;
578 dst_y += video_yoffset;
586 // if (src_bitmap != backbuffer || dst_bitmap != window)
587 if (!(src_bitmap == backbuffer && dst_bitmap == window))
588 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
589 src_bitmap->surface_masked : src_bitmap->surface),
590 &src_rect, real_dst_bitmap->surface, &dst_rect);
592 #if defined(TARGET_SDL2)
593 if (dst_bitmap == window)
595 // SDL_UpdateWindowSurface(sdl_window);
596 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
597 UpdateScreen(&dst_rect);
600 if (dst_bitmap == window)
601 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
605 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
608 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
611 if (dst_bitmap == backbuffer || dst_bitmap == window)
622 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
624 #if defined(TARGET_SDL2)
625 if (dst_bitmap == window)
627 // SDL_UpdateWindowSurface(sdl_window);
628 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
632 if (dst_bitmap == window)
633 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
637 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
638 int fade_mode, int fade_delay, int post_delay,
639 void (*draw_border_function)(void))
641 static boolean initialization_needed = TRUE;
642 static SDL_Surface *surface_source = NULL;
643 static SDL_Surface *surface_target = NULL;
644 static SDL_Surface *surface_black = NULL;
645 SDL_Surface *surface_screen = backbuffer->surface;
646 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
647 SDL_Rect src_rect, dst_rect;
648 #if defined(TARGET_SDL2)
651 int src_x = x, src_y = y;
652 int dst_x = x, dst_y = y;
653 unsigned int time_last, time_current;
655 /* check if screen size has changed */
656 if (surface_source != NULL && (video.width != surface_source->w ||
657 video.height != surface_source->h))
659 SDL_FreeSurface(surface_source);
660 SDL_FreeSurface(surface_target);
661 SDL_FreeSurface(surface_black);
663 initialization_needed = TRUE;
671 dst_x += video_xoffset;
672 dst_y += video_yoffset;
676 dst_rect.w = width; /* (ignored) */
677 dst_rect.h = height; /* (ignored) */
679 #if defined(TARGET_SDL2)
680 dst_rect2 = dst_rect;
683 if (initialization_needed)
685 #if defined(TARGET_SDL2)
686 unsigned int flags = 0;
688 unsigned int flags = SDL_SRCALPHA;
690 /* use same surface type as screen surface */
691 if ((surface_screen->flags & SDL_HWSURFACE))
692 flags |= SDL_HWSURFACE;
694 flags |= SDL_SWSURFACE;
697 /* create surface for temporary copy of screen buffer (source) */
698 if ((surface_source =
699 SDL_CreateRGBSurface(flags,
702 surface_screen->format->BitsPerPixel,
703 surface_screen->format->Rmask,
704 surface_screen->format->Gmask,
705 surface_screen->format->Bmask,
706 surface_screen->format->Amask)) == NULL)
707 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
709 /* create surface for cross-fading screen buffer (target) */
710 if ((surface_target =
711 SDL_CreateRGBSurface(flags,
714 surface_screen->format->BitsPerPixel,
715 surface_screen->format->Rmask,
716 surface_screen->format->Gmask,
717 surface_screen->format->Bmask,
718 surface_screen->format->Amask)) == NULL)
719 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
721 /* create black surface for fading from/to black */
723 SDL_CreateRGBSurface(flags,
726 surface_screen->format->BitsPerPixel,
727 surface_screen->format->Rmask,
728 surface_screen->format->Gmask,
729 surface_screen->format->Bmask,
730 surface_screen->format->Amask)) == NULL)
731 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
733 /* completely fill the surface with black color pixels */
734 SDL_FillRect(surface_black, NULL,
735 SDL_MapRGB(surface_screen->format, 0, 0, 0));
737 initialization_needed = FALSE;
740 /* copy source and target surfaces to temporary surfaces for fading */
741 if (fade_mode & FADE_TYPE_TRANSFORM)
743 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
744 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
746 else if (fade_mode & FADE_TYPE_FADE_IN)
748 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
749 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
751 else /* FADE_TYPE_FADE_OUT */
753 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
754 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
757 time_current = SDL_GetTicks();
759 if (fade_mode == FADE_MODE_MELT)
761 boolean done = FALSE;
763 int melt_columns = width / melt_pixels;
764 int ypos[melt_columns];
765 int max_steps = height / 8 + 32;
770 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
771 #if defined(TARGET_SDL2)
772 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
774 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
777 ypos[0] = -GetSimpleRandom(16);
779 for (i = 1 ; i < melt_columns; i++)
781 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
783 ypos[i] = ypos[i - 1] + r;
796 time_last = time_current;
797 time_current = SDL_GetTicks();
798 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
799 steps_final = MIN(MAX(0, steps), max_steps);
803 done = (steps_done >= steps_final);
805 for (i = 0 ; i < melt_columns; i++)
813 else if (ypos[i] < height)
818 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
820 if (ypos[i] + dy >= height)
821 dy = height - ypos[i];
823 /* copy part of (appearing) target surface to upper area */
824 src_rect.x = src_x + i * melt_pixels;
825 // src_rect.y = src_y + ypos[i];
827 src_rect.w = melt_pixels;
829 src_rect.h = ypos[i] + dy;
831 dst_rect.x = dst_x + i * melt_pixels;
832 // dst_rect.y = dst_y + ypos[i];
835 if (steps_done >= steps_final)
836 SDL_BlitSurface(surface_target, &src_rect,
837 surface_screen, &dst_rect);
841 /* copy part of (disappearing) source surface to lower area */
842 src_rect.x = src_x + i * melt_pixels;
844 src_rect.w = melt_pixels;
845 src_rect.h = height - ypos[i];
847 dst_rect.x = dst_x + i * melt_pixels;
848 dst_rect.y = dst_y + ypos[i];
850 if (steps_done >= steps_final)
851 SDL_BlitSurface(surface_source, &src_rect,
852 surface_screen, &dst_rect);
858 src_rect.x = src_x + i * melt_pixels;
860 src_rect.w = melt_pixels;
863 dst_rect.x = dst_x + i * melt_pixels;
866 if (steps_done >= steps_final)
867 SDL_BlitSurface(surface_target, &src_rect,
868 surface_screen, &dst_rect);
872 if (steps_done >= steps_final)
874 if (draw_border_function != NULL)
875 draw_border_function();
877 #if defined(TARGET_SDL2)
878 // SDL_UpdateWindowSurface(sdl_window);
879 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
880 UpdateScreen(&dst_rect2);
882 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
892 for (alpha = 0.0; alpha < 255.0;)
894 time_last = time_current;
895 time_current = SDL_GetTicks();
896 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
897 alpha_final = MIN(MAX(0, alpha), 255);
899 /* draw existing (source) image to screen buffer */
900 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
902 /* draw new (target) image to screen buffer using alpha blending */
903 #if defined(TARGET_SDL2)
904 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
905 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
907 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
909 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
911 if (draw_border_function != NULL)
912 draw_border_function();
915 /* only update the region of the screen that is affected from fading */
916 #if defined(TARGET_SDL2)
917 // SDL_UpdateWindowSurface(sdl_window);
918 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
919 UpdateScreen(&dst_rect);
921 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
924 SDL_Flip(surface_screen);
932 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
933 int to_x, int to_y, Uint32 color)
935 SDL_Surface *surface = dst_bitmap->surface;
939 swap_numbers(&from_x, &to_x);
942 swap_numbers(&from_y, &to_y);
946 rect.w = (to_x - from_x + 1);
947 rect.h = (to_y - from_y + 1);
949 if (dst_bitmap == backbuffer || dst_bitmap == window)
951 rect.x += video_xoffset;
952 rect.y += video_yoffset;
955 SDL_FillRect(surface, &rect, color);
958 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
959 int to_x, int to_y, Uint32 color)
961 if (dst_bitmap == backbuffer || dst_bitmap == window)
963 from_x += video_xoffset;
964 from_y += video_yoffset;
965 to_x += video_xoffset;
966 to_y += video_yoffset;
969 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
973 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
974 int num_points, Uint32 color)
979 for (i = 0; i < num_points - 1; i++)
981 for (x = 0; x < line_width; x++)
983 for (y = 0; y < line_width; y++)
985 int dx = x - line_width / 2;
986 int dy = y - line_width / 2;
988 if ((x == 0 && y == 0) ||
989 (x == 0 && y == line_width - 1) ||
990 (x == line_width - 1 && y == 0) ||
991 (x == line_width - 1 && y == line_width - 1))
994 sge_Line(surface, points[i].x + dx, points[i].y + dy,
995 points[i+1].x + dx, points[i+1].y + dy, color);
1002 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1004 SDL_Surface *surface = src_bitmap->surface;
1006 if (src_bitmap == backbuffer || src_bitmap == window)
1012 switch (surface->format->BytesPerPixel)
1014 case 1: /* assuming 8-bpp */
1016 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1020 case 2: /* probably 15-bpp or 16-bpp */
1022 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1026 case 3: /* slow 24-bpp mode; usually not used */
1028 /* does this work? */
1029 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1033 shift = surface->format->Rshift;
1034 color |= *(pix + shift / 8) >> shift;
1035 shift = surface->format->Gshift;
1036 color |= *(pix + shift / 8) >> shift;
1037 shift = surface->format->Bshift;
1038 color |= *(pix + shift / 8) >> shift;
1044 case 4: /* probably 32-bpp */
1046 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1055 /* ========================================================================= */
1056 /* The following functions were taken from the SGE library */
1057 /* (SDL Graphics Extension Library) by Anders Lindström */
1058 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1059 /* ========================================================================= */
1061 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1063 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1065 switch (surface->format->BytesPerPixel)
1069 /* Assuming 8-bpp */
1070 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1076 /* Probably 15-bpp or 16-bpp */
1077 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1083 /* Slow 24-bpp mode, usually not used */
1087 /* Gack - slow, but endian correct */
1088 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1089 shift = surface->format->Rshift;
1090 *(pix+shift/8) = color>>shift;
1091 shift = surface->format->Gshift;
1092 *(pix+shift/8) = color>>shift;
1093 shift = surface->format->Bshift;
1094 *(pix+shift/8) = color>>shift;
1100 /* Probably 32-bpp */
1101 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1108 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1109 Uint8 R, Uint8 G, Uint8 B)
1111 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1114 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1116 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1119 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1121 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1124 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1129 /* Gack - slow, but endian correct */
1130 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1131 shift = surface->format->Rshift;
1132 *(pix+shift/8) = color>>shift;
1133 shift = surface->format->Gshift;
1134 *(pix+shift/8) = color>>shift;
1135 shift = surface->format->Bshift;
1136 *(pix+shift/8) = color>>shift;
1139 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1141 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1144 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1146 switch (dest->format->BytesPerPixel)
1149 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1153 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1157 _PutPixel24(dest,x,y,color);
1161 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1166 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1168 if (SDL_MUSTLOCK(surface))
1170 if (SDL_LockSurface(surface) < 0)
1176 _PutPixel(surface, x, y, color);
1178 if (SDL_MUSTLOCK(surface))
1180 SDL_UnlockSurface(surface);
1184 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1185 Uint8 r, Uint8 g, Uint8 b)
1187 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1190 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1192 if (y >= 0 && y <= dest->h - 1)
1194 switch (dest->format->BytesPerPixel)
1197 return y*dest->pitch;
1201 return y*dest->pitch/2;
1205 return y*dest->pitch;
1209 return y*dest->pitch/4;
1217 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1219 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1221 switch (surface->format->BytesPerPixel)
1225 /* Assuming 8-bpp */
1226 *((Uint8 *)surface->pixels + ypitch + x) = color;
1232 /* Probably 15-bpp or 16-bpp */
1233 *((Uint16 *)surface->pixels + ypitch + x) = color;
1239 /* Slow 24-bpp mode, usually not used */
1243 /* Gack - slow, but endian correct */
1244 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1245 shift = surface->format->Rshift;
1246 *(pix+shift/8) = color>>shift;
1247 shift = surface->format->Gshift;
1248 *(pix+shift/8) = color>>shift;
1249 shift = surface->format->Bshift;
1250 *(pix+shift/8) = color>>shift;
1256 /* Probably 32-bpp */
1257 *((Uint32 *)surface->pixels + ypitch + x) = color;
1264 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1269 if (SDL_MUSTLOCK(Surface))
1271 if (SDL_LockSurface(Surface) < 0)
1284 /* Do the clipping */
1285 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1289 if (x2 > Surface->w - 1)
1290 x2 = Surface->w - 1;
1297 SDL_FillRect(Surface, &l, Color);
1299 if (SDL_MUSTLOCK(Surface))
1301 SDL_UnlockSurface(Surface);
1305 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1306 Uint8 R, Uint8 G, Uint8 B)
1308 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1311 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1322 /* Do the clipping */
1323 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1327 if (x2 > Surface->w - 1)
1328 x2 = Surface->w - 1;
1335 SDL_FillRect(Surface, &l, Color);
1338 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1343 if (SDL_MUSTLOCK(Surface))
1345 if (SDL_LockSurface(Surface) < 0)
1358 /* Do the clipping */
1359 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1363 if (y2 > Surface->h - 1)
1364 y2 = Surface->h - 1;
1371 SDL_FillRect(Surface, &l, Color);
1373 if (SDL_MUSTLOCK(Surface))
1375 SDL_UnlockSurface(Surface);
1379 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1380 Uint8 R, Uint8 G, Uint8 B)
1382 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1385 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1396 /* Do the clipping */
1397 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1401 if (y2 > Surface->h - 1)
1402 y2 = Surface->h - 1;
1409 SDL_FillRect(Surface, &l, Color);
1412 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1413 Sint16 x2, Sint16 y2, Uint32 Color,
1414 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1417 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1422 sdx = (dx < 0) ? -1 : 1;
1423 sdy = (dy < 0) ? -1 : 1;
1435 for (x = 0; x < dx; x++)
1437 Callback(Surface, px, py, Color);
1451 for (y = 0; y < dy; y++)
1453 Callback(Surface, px, py, Color);
1467 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1468 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1469 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1472 sge_DoLine(Surface, X1, Y1, X2, Y2,
1473 SDL_MapRGB(Surface->format, R, G, B), Callback);
1476 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1479 if (SDL_MUSTLOCK(Surface))
1481 if (SDL_LockSurface(Surface) < 0)
1486 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1488 /* unlock the display */
1489 if (SDL_MUSTLOCK(Surface))
1491 SDL_UnlockSurface(Surface);
1495 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1496 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1498 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1501 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1503 if (dst_bitmap == backbuffer || dst_bitmap == window)
1509 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1514 -----------------------------------------------------------------------------
1515 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1516 -----------------------------------------------------------------------------
1519 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1520 int width, int height, Uint32 color)
1524 for (y = src_y; y < src_y + height; y++)
1526 for (x = src_x; x < src_x + width; x++)
1528 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1530 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1535 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1536 int src_x, int src_y, int width, int height,
1537 int dst_x, int dst_y)
1541 for (y = 0; y < height; y++)
1543 for (x = 0; x < width; x++)
1545 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1547 if (pixel != BLACK_PIXEL)
1548 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1554 /* ========================================================================= */
1555 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1556 /* (Rotozoomer) by Andreas Schiffler */
1557 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1558 /* ========================================================================= */
1561 -----------------------------------------------------------------------------
1564 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1565 -----------------------------------------------------------------------------
1576 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1579 tColorRGBA *sp, *csp, *dp;
1586 sp = csp = (tColorRGBA *) src->pixels;
1587 dp = (tColorRGBA *) dst->pixels;
1589 sgap = src->pitch - src->w * 4;
1591 dgap = dst->pitch - dst->w * 4;
1593 for (y = 0; y < dst->h; y++)
1597 for (x = 0; x < dst->w; x++)
1599 tColorRGBA *sp0 = sp;
1600 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1601 tColorRGBA *sp00 = &sp0[0];
1602 tColorRGBA *sp01 = &sp0[1];
1603 tColorRGBA *sp10 = &sp1[0];
1604 tColorRGBA *sp11 = &sp1[1];
1607 /* create new color pixel from all four source color pixels */
1608 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1609 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1610 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1611 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1616 /* advance source pointers */
1619 /* advance destination pointer */
1623 /* advance source pointer */
1624 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1626 /* advance destination pointers */
1627 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1633 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1635 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1636 tColorRGBA *sp, *csp, *dp;
1642 /* use specialized zoom function when scaling down to exactly half size */
1643 if (src->w == 2 * dst->w &&
1644 src->h == 2 * dst->h)
1645 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1647 /* variable setup */
1648 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1649 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1651 /* allocate memory for row increments */
1652 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1653 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1655 /* precalculate row increments */
1658 for (x = 0; x <= dst->w; x++)
1668 for (y = 0; y <= dst->h; y++)
1677 sp = csp = (tColorRGBA *) src->pixels;
1678 dp = (tColorRGBA *) dst->pixels;
1680 sgap = src->pitch - src->w * 4;
1682 dgap = dst->pitch - dst->w * 4;
1685 for (y = 0; y < dst->h; y++)
1690 for (x = 0; x < dst->w; x++)
1695 /* advance source pointers */
1697 sp += (*csax >> 16);
1699 /* advance destination pointer */
1703 /* advance source pointer */
1705 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1707 /* advance destination pointers */
1708 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1718 -----------------------------------------------------------------------------
1721 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1722 -----------------------------------------------------------------------------
1725 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1727 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1728 Uint8 *sp, *dp, *csp;
1731 /* variable setup */
1732 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1733 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1735 /* allocate memory for row increments */
1736 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1737 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1739 /* precalculate row increments */
1742 for (x = 0; x < dst->w; x++)
1745 *csax = (csx >> 16);
1752 for (y = 0; y < dst->h; y++)
1755 *csay = (csy >> 16);
1762 for (x = 0; x < dst->w; x++)
1770 for (y = 0; y < dst->h; y++)
1777 sp = csp = (Uint8 *) src->pixels;
1778 dp = (Uint8 *) dst->pixels;
1779 dgap = dst->pitch - dst->w;
1783 for (y = 0; y < dst->h; y++)
1787 for (x = 0; x < dst->w; x++)
1792 /* advance source pointers */
1796 /* advance destination pointer */
1800 /* advance source pointer (for row) */
1801 csp += ((*csay) * src->pitch);
1804 /* advance destination pointers */
1815 -----------------------------------------------------------------------------
1818 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1819 'zoomx' and 'zoomy' are scaling factors for width and height.
1820 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
1821 into a 32bit RGBA format on the fly.
1822 -----------------------------------------------------------------------------
1825 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
1827 SDL_Surface *zoom_src = NULL;
1828 SDL_Surface *zoom_dst = NULL;
1829 boolean is_converted = FALSE;
1836 /* determine if source surface is 32 bit or 8 bit */
1837 is_32bit = (src->format->BitsPerPixel == 32);
1839 if (is_32bit || src->format->BitsPerPixel == 8)
1841 /* use source surface 'as is' */
1846 /* new source surface is 32 bit with a defined RGB ordering */
1847 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1848 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
1849 SDL_BlitSurface(src, NULL, zoom_src, NULL);
1851 is_converted = TRUE;
1854 /* allocate surface to completely contain the zoomed surface */
1857 /* target surface is 32 bit with source RGBA/ABGR ordering */
1858 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
1859 zoom_src->format->Rmask,
1860 zoom_src->format->Gmask,
1861 zoom_src->format->Bmask, 0);
1865 /* target surface is 8 bit */
1866 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
1870 /* lock source surface */
1871 SDL_LockSurface(zoom_src);
1873 /* check which kind of surface we have */
1876 /* call the 32 bit transformation routine to do the zooming */
1877 zoomSurfaceRGBA(zoom_src, zoom_dst);
1882 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
1883 zoom_dst->format->palette->colors[i] =
1884 zoom_src->format->palette->colors[i];
1885 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
1887 /* call the 8 bit transformation routine to do the zooming */
1888 zoomSurfaceY(zoom_src, zoom_dst);
1891 /* unlock source surface */
1892 SDL_UnlockSurface(zoom_src);
1894 /* free temporary surface */
1896 SDL_FreeSurface(zoom_src);
1898 /* return destination surface */
1902 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
1904 SDL_Surface *sdl_surface_tmp;
1905 int dst_width = dst_bitmap->width;
1906 int dst_height = dst_bitmap->height;
1908 /* throw away old destination surface */
1909 SDL_FreeSurface(dst_bitmap->surface);
1911 /* create zoomed temporary surface from source surface */
1912 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
1914 /* create native format destination surface from zoomed temporary surface */
1915 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
1917 /* free temporary surface */
1918 SDL_FreeSurface(sdl_surface_tmp);
1922 /* ========================================================================= */
1923 /* load image to bitmap */
1924 /* ========================================================================= */
1926 Bitmap *SDLLoadImage(char *filename)
1928 Bitmap *new_bitmap = CreateBitmapStruct();
1929 SDL_Surface *sdl_image_tmp;
1931 print_timestamp_init("SDLLoadImage");
1933 print_timestamp_time(getBaseNamePtr(filename));
1935 /* load image to temporary surface */
1936 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
1938 SetError("IMG_Load(): %s", SDL_GetError());
1943 print_timestamp_time("IMG_Load");
1945 UPDATE_BUSY_STATE();
1947 /* create native non-transparent surface for current image */
1948 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1950 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1955 print_timestamp_time("SDL_DisplayFormat (opaque)");
1957 UPDATE_BUSY_STATE();
1959 /* create native transparent surface for current image */
1960 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
1961 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
1962 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1964 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1969 print_timestamp_time("SDL_DisplayFormat (masked)");
1971 UPDATE_BUSY_STATE();
1973 /* free temporary surface */
1974 SDL_FreeSurface(sdl_image_tmp);
1976 new_bitmap->width = new_bitmap->surface->w;
1977 new_bitmap->height = new_bitmap->surface->h;
1979 print_timestamp_done("SDLLoadImage");
1985 /* ------------------------------------------------------------------------- */
1986 /* custom cursor fuctions */
1987 /* ------------------------------------------------------------------------- */
1989 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
1991 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
1992 cursor_info->width, cursor_info->height,
1993 cursor_info->hot_x, cursor_info->hot_y);
1996 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
1998 static struct MouseCursorInfo *last_cursor_info = NULL;
1999 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2000 static SDL_Cursor *cursor_default = NULL;
2001 static SDL_Cursor *cursor_current = NULL;
2003 /* if invoked for the first time, store the SDL default cursor */
2004 if (cursor_default == NULL)
2005 cursor_default = SDL_GetCursor();
2007 /* only create new cursor if cursor info (custom only) has changed */
2008 if (cursor_info != NULL && cursor_info != last_cursor_info)
2010 cursor_current = create_cursor(cursor_info);
2011 last_cursor_info = cursor_info;
2014 /* only set new cursor if cursor info (custom or NULL) has changed */
2015 if (cursor_info != last_cursor_info2)
2016 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2018 last_cursor_info2 = cursor_info;
2022 /* ========================================================================= */
2023 /* audio functions */
2024 /* ========================================================================= */
2026 void SDLOpenAudio(void)
2028 #if !defined(TARGET_SDL2)
2029 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2030 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2033 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2035 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2039 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2040 AUDIO_NUM_CHANNELS_STEREO,
2041 setup.system.audio_fragment_size) < 0)
2043 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2047 audio.sound_available = TRUE;
2048 audio.music_available = TRUE;
2049 audio.loops_available = TRUE;
2050 audio.sound_enabled = TRUE;
2052 /* set number of available mixer channels */
2053 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2054 audio.music_channel = MUSIC_CHANNEL;
2055 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2057 Mixer_InitChannels();
2060 void SDLCloseAudio(void)
2063 Mix_HaltChannel(-1);
2066 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2070 /* ========================================================================= */
2071 /* event functions */
2072 /* ========================================================================= */
2074 void SDLNextEvent(Event *event)
2076 SDL_WaitEvent(event);
2078 if (event->type == EVENT_BUTTONPRESS ||
2079 event->type == EVENT_BUTTONRELEASE)
2081 if (((ButtonEvent *)event)->x > video_xoffset)
2082 ((ButtonEvent *)event)->x -= video_xoffset;
2084 ((ButtonEvent *)event)->x = 0;
2085 if (((ButtonEvent *)event)->y > video_yoffset)
2086 ((ButtonEvent *)event)->y -= video_yoffset;
2088 ((ButtonEvent *)event)->y = 0;
2090 else if (event->type == EVENT_MOTIONNOTIFY)
2092 if (((MotionEvent *)event)->x > video_xoffset)
2093 ((MotionEvent *)event)->x -= video_xoffset;
2095 ((MotionEvent *)event)->x = 0;
2096 if (((MotionEvent *)event)->y > video_yoffset)
2097 ((MotionEvent *)event)->y -= video_yoffset;
2099 ((MotionEvent *)event)->y = 0;
2103 void SDLHandleWindowManagerEvent(Event *event)
2105 #if defined(PLATFORM_WIN32)
2106 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2107 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2109 if (syswmmsg->msg == WM_DROPFILES)
2111 HDROP hdrop = (HDROP)syswmmsg->wParam;
2114 printf("::: SDL_SYSWMEVENT:\n");
2116 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2118 for (i = 0; i < num_files; i++)
2120 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2121 char buffer[buffer_len + 1];
2123 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2125 printf("::: - '%s'\n", buffer);
2128 DragFinish((HDROP)syswmmsg->wParam);
2134 /* ========================================================================= */
2135 /* joystick functions */
2136 /* ========================================================================= */
2138 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2139 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2140 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2142 static boolean SDLOpenJoystick(int nr)
2144 if (nr < 0 || nr > MAX_PLAYERS)
2147 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2150 static void SDLCloseJoystick(int nr)
2152 if (nr < 0 || nr > MAX_PLAYERS)
2155 SDL_JoystickClose(sdl_joystick[nr]);
2157 sdl_joystick[nr] = NULL;
2160 static boolean SDLCheckJoystickOpened(int nr)
2162 if (nr < 0 || nr > MAX_PLAYERS)
2165 #if defined(TARGET_SDL2)
2166 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2168 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2172 void HandleJoystickEvent(Event *event)
2176 case SDL_JOYAXISMOTION:
2177 if (event->jaxis.axis < 2)
2178 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2181 case SDL_JOYBUTTONDOWN:
2182 if (event->jbutton.button < 2)
2183 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2186 case SDL_JOYBUTTONUP:
2187 if (event->jbutton.button < 2)
2188 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2196 void SDLInitJoysticks()
2198 static boolean sdl_joystick_subsystem_initialized = FALSE;
2199 boolean print_warning = !sdl_joystick_subsystem_initialized;
2202 if (!sdl_joystick_subsystem_initialized)
2204 sdl_joystick_subsystem_initialized = TRUE;
2206 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2208 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2213 for (i = 0; i < MAX_PLAYERS; i++)
2215 /* get configured joystick for this player */
2216 char *device_name = setup.input[i].joy.device_name;
2217 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2219 if (joystick_nr >= SDL_NumJoysticks())
2221 if (setup.input[i].use_joystick && print_warning)
2222 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2227 /* misuse joystick file descriptor variable to store joystick number */
2228 joystick.fd[i] = joystick_nr;
2230 if (joystick_nr == -1)
2233 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2234 if (SDLCheckJoystickOpened(joystick_nr))
2235 SDLCloseJoystick(joystick_nr);
2237 if (!setup.input[i].use_joystick)
2240 if (!SDLOpenJoystick(joystick_nr))
2243 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2248 joystick.status = JOYSTICK_ACTIVATED;
2252 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2254 if (nr < 0 || nr >= MAX_PLAYERS)
2258 *x = sdl_js_axis[nr][0];
2260 *y = sdl_js_axis[nr][1];
2263 *b1 = sdl_js_button[nr][0];
2265 *b2 = sdl_js_button[nr][1];
2270 #endif /* TARGET_SDL */