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 printf("::: pitch == %d\n", new_surface->pitch);
449 if (new_surface == NULL)
450 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
455 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
460 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
465 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
468 sdl_window = SDL_CreateWindow(program.window_title,
469 SDL_WINDOWPOS_CENTERED,
470 SDL_WINDOWPOS_CENTERED,
471 video.width, video.height,
472 surface_flags_window);
474 if (sdl_window != NULL)
476 new_surface = SDL_GetWindowSurface(sdl_window);
478 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
479 // UpdateScreen(NULL); // immediately map window
484 new_surface = SDL_SetVideoMode(video.width, video.height,
485 video.depth, surface_flags_window);
488 if (new_surface == NULL)
490 /* switching display to window mode failed -- should not happen */
491 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
497 (*backbuffer)->surface = new_surface;
499 video.fullscreen_enabled = FALSE;
505 #if defined(TARGET_SDL2)
506 UpdateScreen(NULL); // map window
510 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
512 #if defined(PLATFORM_WIN32)
514 SDL_SysWMinfo wminfo;
517 SDL_VERSION(&wminfo.version);
518 SDL_GetWMInfo(&wminfo);
520 hwnd = wminfo.window;
522 DragAcceptFiles(hwnd, TRUE);
531 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
534 SDL_Surface *surface_tmp, *surface_native;
536 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
539 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
541 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
542 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
544 SDL_FreeSurface(surface_tmp);
546 new_bitmap->surface = surface_native;
549 void SDLFreeBitmapPointers(Bitmap *bitmap)
552 SDL_FreeSurface(bitmap->surface);
553 if (bitmap->surface_masked)
554 SDL_FreeSurface(bitmap->surface_masked);
555 bitmap->surface = NULL;
556 bitmap->surface_masked = NULL;
559 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
560 int src_x, int src_y, int width, int height,
561 int dst_x, int dst_y, int mask_mode)
563 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
564 SDL_Rect src_rect, dst_rect;
566 if (src_bitmap == backbuffer)
568 src_x += video_xoffset;
569 src_y += video_yoffset;
577 if (dst_bitmap == backbuffer || dst_bitmap == window)
579 dst_x += video_xoffset;
580 dst_y += video_yoffset;
588 // if (src_bitmap != backbuffer || dst_bitmap != window)
589 if (!(src_bitmap == backbuffer && dst_bitmap == window))
590 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
591 src_bitmap->surface_masked : src_bitmap->surface),
592 &src_rect, real_dst_bitmap->surface, &dst_rect);
594 #if defined(TARGET_SDL2)
595 if (dst_bitmap == window)
597 // SDL_UpdateWindowSurface(sdl_window);
598 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
599 UpdateScreen(&dst_rect);
602 if (dst_bitmap == window)
603 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
607 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
610 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
613 if (dst_bitmap == backbuffer || dst_bitmap == window)
624 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
626 #if defined(TARGET_SDL2)
627 if (dst_bitmap == window)
629 // SDL_UpdateWindowSurface(sdl_window);
630 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
634 if (dst_bitmap == window)
635 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
639 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
640 int fade_mode, int fade_delay, int post_delay,
641 void (*draw_border_function)(void))
643 static boolean initialization_needed = TRUE;
644 static SDL_Surface *surface_source = NULL;
645 static SDL_Surface *surface_target = NULL;
646 static SDL_Surface *surface_black = NULL;
647 SDL_Surface *surface_screen = backbuffer->surface;
648 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
649 SDL_Rect src_rect, dst_rect;
650 #if defined(TARGET_SDL2)
653 int src_x = x, src_y = y;
654 int dst_x = x, dst_y = y;
655 unsigned int time_last, time_current;
657 /* check if screen size has changed */
658 if (surface_source != NULL && (video.width != surface_source->w ||
659 video.height != surface_source->h))
661 SDL_FreeSurface(surface_source);
662 SDL_FreeSurface(surface_target);
663 SDL_FreeSurface(surface_black);
665 initialization_needed = TRUE;
673 dst_x += video_xoffset;
674 dst_y += video_yoffset;
678 dst_rect.w = width; /* (ignored) */
679 dst_rect.h = height; /* (ignored) */
681 #if defined(TARGET_SDL2)
682 dst_rect2 = dst_rect;
685 if (initialization_needed)
687 #if defined(TARGET_SDL2)
688 unsigned int flags = 0;
690 unsigned int flags = SDL_SRCALPHA;
692 /* use same surface type as screen surface */
693 if ((surface_screen->flags & SDL_HWSURFACE))
694 flags |= SDL_HWSURFACE;
696 flags |= SDL_SWSURFACE;
699 /* create surface for temporary copy of screen buffer (source) */
700 if ((surface_source =
701 SDL_CreateRGBSurface(flags,
704 surface_screen->format->BitsPerPixel,
705 surface_screen->format->Rmask,
706 surface_screen->format->Gmask,
707 surface_screen->format->Bmask,
708 surface_screen->format->Amask)) == NULL)
709 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
711 /* create surface for cross-fading screen buffer (target) */
712 if ((surface_target =
713 SDL_CreateRGBSurface(flags,
716 surface_screen->format->BitsPerPixel,
717 surface_screen->format->Rmask,
718 surface_screen->format->Gmask,
719 surface_screen->format->Bmask,
720 surface_screen->format->Amask)) == NULL)
721 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
723 /* create black surface for fading from/to black */
725 SDL_CreateRGBSurface(flags,
728 surface_screen->format->BitsPerPixel,
729 surface_screen->format->Rmask,
730 surface_screen->format->Gmask,
731 surface_screen->format->Bmask,
732 surface_screen->format->Amask)) == NULL)
733 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
735 /* completely fill the surface with black color pixels */
736 SDL_FillRect(surface_black, NULL,
737 SDL_MapRGB(surface_screen->format, 0, 0, 0));
739 initialization_needed = FALSE;
742 /* copy source and target surfaces to temporary surfaces for fading */
743 if (fade_mode & FADE_TYPE_TRANSFORM)
745 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
746 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
748 else if (fade_mode & FADE_TYPE_FADE_IN)
750 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
751 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
753 else /* FADE_TYPE_FADE_OUT */
755 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
756 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
759 time_current = SDL_GetTicks();
761 if (fade_mode == FADE_MODE_MELT)
763 boolean done = FALSE;
765 int melt_columns = width / melt_pixels;
766 int ypos[melt_columns];
767 int max_steps = height / 8 + 32;
772 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
773 #if defined(TARGET_SDL2)
774 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
776 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
779 ypos[0] = -GetSimpleRandom(16);
781 for (i = 1 ; i < melt_columns; i++)
783 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
785 ypos[i] = ypos[i - 1] + r;
798 time_last = time_current;
799 time_current = SDL_GetTicks();
800 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
801 steps_final = MIN(MAX(0, steps), max_steps);
805 done = (steps_done >= steps_final);
807 for (i = 0 ; i < melt_columns; i++)
815 else if (ypos[i] < height)
820 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
822 if (ypos[i] + dy >= height)
823 dy = height - ypos[i];
825 /* copy part of (appearing) target surface to upper area */
826 src_rect.x = src_x + i * melt_pixels;
827 // src_rect.y = src_y + ypos[i];
829 src_rect.w = melt_pixels;
831 src_rect.h = ypos[i] + dy;
833 dst_rect.x = dst_x + i * melt_pixels;
834 // dst_rect.y = dst_y + ypos[i];
837 if (steps_done >= steps_final)
838 SDL_BlitSurface(surface_target, &src_rect,
839 surface_screen, &dst_rect);
843 /* copy part of (disappearing) source surface to lower area */
844 src_rect.x = src_x + i * melt_pixels;
846 src_rect.w = melt_pixels;
847 src_rect.h = height - ypos[i];
849 dst_rect.x = dst_x + i * melt_pixels;
850 dst_rect.y = dst_y + ypos[i];
852 if (steps_done >= steps_final)
853 SDL_BlitSurface(surface_source, &src_rect,
854 surface_screen, &dst_rect);
860 src_rect.x = src_x + i * melt_pixels;
862 src_rect.w = melt_pixels;
865 dst_rect.x = dst_x + i * melt_pixels;
868 if (steps_done >= steps_final)
869 SDL_BlitSurface(surface_target, &src_rect,
870 surface_screen, &dst_rect);
874 if (steps_done >= steps_final)
876 if (draw_border_function != NULL)
877 draw_border_function();
879 #if defined(TARGET_SDL2)
880 // SDL_UpdateWindowSurface(sdl_window);
881 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
882 UpdateScreen(&dst_rect2);
884 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
894 for (alpha = 0.0; alpha < 255.0;)
896 time_last = time_current;
897 time_current = SDL_GetTicks();
898 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
899 alpha_final = MIN(MAX(0, alpha), 255);
901 /* draw existing (source) image to screen buffer */
902 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
904 /* draw new (target) image to screen buffer using alpha blending */
905 #if defined(TARGET_SDL2)
906 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
907 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
909 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
911 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
913 if (draw_border_function != NULL)
914 draw_border_function();
917 /* only update the region of the screen that is affected from fading */
918 #if defined(TARGET_SDL2)
919 // SDL_UpdateWindowSurface(sdl_window);
920 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
921 UpdateScreen(&dst_rect);
923 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
926 SDL_Flip(surface_screen);
934 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
935 int to_x, int to_y, Uint32 color)
937 SDL_Surface *surface = dst_bitmap->surface;
941 swap_numbers(&from_x, &to_x);
944 swap_numbers(&from_y, &to_y);
948 rect.w = (to_x - from_x + 1);
949 rect.h = (to_y - from_y + 1);
951 if (dst_bitmap == backbuffer || dst_bitmap == window)
953 rect.x += video_xoffset;
954 rect.y += video_yoffset;
957 SDL_FillRect(surface, &rect, color);
960 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
961 int to_x, int to_y, Uint32 color)
963 if (dst_bitmap == backbuffer || dst_bitmap == window)
965 from_x += video_xoffset;
966 from_y += video_yoffset;
967 to_x += video_xoffset;
968 to_y += video_yoffset;
971 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
975 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
976 int num_points, Uint32 color)
981 for (i = 0; i < num_points - 1; i++)
983 for (x = 0; x < line_width; x++)
985 for (y = 0; y < line_width; y++)
987 int dx = x - line_width / 2;
988 int dy = y - line_width / 2;
990 if ((x == 0 && y == 0) ||
991 (x == 0 && y == line_width - 1) ||
992 (x == line_width - 1 && y == 0) ||
993 (x == line_width - 1 && y == line_width - 1))
996 sge_Line(surface, points[i].x + dx, points[i].y + dy,
997 points[i+1].x + dx, points[i+1].y + dy, color);
1004 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1006 SDL_Surface *surface = src_bitmap->surface;
1008 if (src_bitmap == backbuffer || src_bitmap == window)
1014 switch (surface->format->BytesPerPixel)
1016 case 1: /* assuming 8-bpp */
1018 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1022 case 2: /* probably 15-bpp or 16-bpp */
1024 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1028 case 3: /* slow 24-bpp mode; usually not used */
1030 /* does this work? */
1031 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1035 shift = surface->format->Rshift;
1036 color |= *(pix + shift / 8) >> shift;
1037 shift = surface->format->Gshift;
1038 color |= *(pix + shift / 8) >> shift;
1039 shift = surface->format->Bshift;
1040 color |= *(pix + shift / 8) >> shift;
1046 case 4: /* probably 32-bpp */
1048 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1057 /* ========================================================================= */
1058 /* The following functions were taken from the SGE library */
1059 /* (SDL Graphics Extension Library) by Anders Lindström */
1060 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1061 /* ========================================================================= */
1063 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1065 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1067 switch (surface->format->BytesPerPixel)
1071 /* Assuming 8-bpp */
1072 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1078 /* Probably 15-bpp or 16-bpp */
1079 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1085 /* Slow 24-bpp mode, usually not used */
1089 /* Gack - slow, but endian correct */
1090 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1091 shift = surface->format->Rshift;
1092 *(pix+shift/8) = color>>shift;
1093 shift = surface->format->Gshift;
1094 *(pix+shift/8) = color>>shift;
1095 shift = surface->format->Bshift;
1096 *(pix+shift/8) = color>>shift;
1102 /* Probably 32-bpp */
1103 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1110 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1111 Uint8 R, Uint8 G, Uint8 B)
1113 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1116 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1118 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1121 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1123 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1126 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1131 /* Gack - slow, but endian correct */
1132 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1133 shift = surface->format->Rshift;
1134 *(pix+shift/8) = color>>shift;
1135 shift = surface->format->Gshift;
1136 *(pix+shift/8) = color>>shift;
1137 shift = surface->format->Bshift;
1138 *(pix+shift/8) = color>>shift;
1141 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1143 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1146 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1148 switch (dest->format->BytesPerPixel)
1151 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1155 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1159 _PutPixel24(dest,x,y,color);
1163 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1168 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1170 if (SDL_MUSTLOCK(surface))
1172 if (SDL_LockSurface(surface) < 0)
1178 _PutPixel(surface, x, y, color);
1180 if (SDL_MUSTLOCK(surface))
1182 SDL_UnlockSurface(surface);
1186 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1187 Uint8 r, Uint8 g, Uint8 b)
1189 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1192 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1194 if (y >= 0 && y <= dest->h - 1)
1196 switch (dest->format->BytesPerPixel)
1199 return y*dest->pitch;
1203 return y*dest->pitch/2;
1207 return y*dest->pitch;
1211 return y*dest->pitch/4;
1219 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1221 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1223 switch (surface->format->BytesPerPixel)
1227 /* Assuming 8-bpp */
1228 *((Uint8 *)surface->pixels + ypitch + x) = color;
1234 /* Probably 15-bpp or 16-bpp */
1235 *((Uint16 *)surface->pixels + ypitch + x) = color;
1241 /* Slow 24-bpp mode, usually not used */
1245 /* Gack - slow, but endian correct */
1246 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1247 shift = surface->format->Rshift;
1248 *(pix+shift/8) = color>>shift;
1249 shift = surface->format->Gshift;
1250 *(pix+shift/8) = color>>shift;
1251 shift = surface->format->Bshift;
1252 *(pix+shift/8) = color>>shift;
1258 /* Probably 32-bpp */
1259 *((Uint32 *)surface->pixels + ypitch + x) = color;
1266 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1271 if (SDL_MUSTLOCK(Surface))
1273 if (SDL_LockSurface(Surface) < 0)
1286 /* Do the clipping */
1287 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1291 if (x2 > Surface->w - 1)
1292 x2 = Surface->w - 1;
1299 SDL_FillRect(Surface, &l, Color);
1301 if (SDL_MUSTLOCK(Surface))
1303 SDL_UnlockSurface(Surface);
1307 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1308 Uint8 R, Uint8 G, Uint8 B)
1310 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1313 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1324 /* Do the clipping */
1325 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1329 if (x2 > Surface->w - 1)
1330 x2 = Surface->w - 1;
1337 SDL_FillRect(Surface, &l, Color);
1340 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1345 if (SDL_MUSTLOCK(Surface))
1347 if (SDL_LockSurface(Surface) < 0)
1360 /* Do the clipping */
1361 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1365 if (y2 > Surface->h - 1)
1366 y2 = Surface->h - 1;
1373 SDL_FillRect(Surface, &l, Color);
1375 if (SDL_MUSTLOCK(Surface))
1377 SDL_UnlockSurface(Surface);
1381 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1382 Uint8 R, Uint8 G, Uint8 B)
1384 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1387 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1398 /* Do the clipping */
1399 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1403 if (y2 > Surface->h - 1)
1404 y2 = Surface->h - 1;
1411 SDL_FillRect(Surface, &l, Color);
1414 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1415 Sint16 x2, Sint16 y2, Uint32 Color,
1416 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1419 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1424 sdx = (dx < 0) ? -1 : 1;
1425 sdy = (dy < 0) ? -1 : 1;
1437 for (x = 0; x < dx; x++)
1439 Callback(Surface, px, py, Color);
1453 for (y = 0; y < dy; y++)
1455 Callback(Surface, px, py, Color);
1469 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1470 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1471 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1474 sge_DoLine(Surface, X1, Y1, X2, Y2,
1475 SDL_MapRGB(Surface->format, R, G, B), Callback);
1478 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1481 if (SDL_MUSTLOCK(Surface))
1483 if (SDL_LockSurface(Surface) < 0)
1488 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1490 /* unlock the display */
1491 if (SDL_MUSTLOCK(Surface))
1493 SDL_UnlockSurface(Surface);
1497 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1498 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1500 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1503 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1505 if (dst_bitmap == backbuffer || dst_bitmap == window)
1511 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1516 -----------------------------------------------------------------------------
1517 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1518 -----------------------------------------------------------------------------
1521 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1522 int width, int height, Uint32 color)
1526 for (y = src_y; y < src_y + height; y++)
1528 for (x = src_x; x < src_x + width; x++)
1530 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1532 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1537 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1538 int src_x, int src_y, int width, int height,
1539 int dst_x, int dst_y)
1543 for (y = 0; y < height; y++)
1545 for (x = 0; x < width; x++)
1547 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1549 if (pixel != BLACK_PIXEL)
1550 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1556 /* ========================================================================= */
1557 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1558 /* (Rotozoomer) by Andreas Schiffler */
1559 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1560 /* ========================================================================= */
1563 -----------------------------------------------------------------------------
1566 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1567 -----------------------------------------------------------------------------
1578 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1581 tColorRGBA *sp, *csp, *dp;
1588 sp = csp = (tColorRGBA *) src->pixels;
1589 dp = (tColorRGBA *) dst->pixels;
1591 sgap = src->pitch - src->w * 4;
1593 dgap = dst->pitch - dst->w * 4;
1595 for (y = 0; y < dst->h; y++)
1599 for (x = 0; x < dst->w; x++)
1601 tColorRGBA *sp0 = sp;
1602 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1603 tColorRGBA *sp00 = &sp0[0];
1604 tColorRGBA *sp01 = &sp0[1];
1605 tColorRGBA *sp10 = &sp1[0];
1606 tColorRGBA *sp11 = &sp1[1];
1609 /* create new color pixel from all four source color pixels */
1610 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1611 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1612 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1613 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1618 /* advance source pointers */
1621 /* advance destination pointer */
1625 /* advance source pointer */
1626 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1628 /* advance destination pointers */
1629 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1635 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1637 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1638 tColorRGBA *sp, *csp, *dp;
1644 /* use specialized zoom function when scaling down to exactly half size */
1645 if (src->w == 2 * dst->w &&
1646 src->h == 2 * dst->h)
1647 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1649 /* variable setup */
1650 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1651 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1653 /* allocate memory for row increments */
1654 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1655 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1657 /* precalculate row increments */
1660 for (x = 0; x <= dst->w; x++)
1670 for (y = 0; y <= dst->h; y++)
1679 sp = csp = (tColorRGBA *) src->pixels;
1680 dp = (tColorRGBA *) dst->pixels;
1682 sgap = src->pitch - src->w * 4;
1684 dgap = dst->pitch - dst->w * 4;
1687 for (y = 0; y < dst->h; y++)
1692 for (x = 0; x < dst->w; x++)
1697 /* advance source pointers */
1699 sp += (*csax >> 16);
1701 /* advance destination pointer */
1705 /* advance source pointer */
1707 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1709 /* advance destination pointers */
1710 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1720 -----------------------------------------------------------------------------
1723 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1724 -----------------------------------------------------------------------------
1727 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1729 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1730 Uint8 *sp, *dp, *csp;
1733 /* variable setup */
1734 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1735 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1737 /* allocate memory for row increments */
1738 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1739 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1741 /* precalculate row increments */
1744 for (x = 0; x < dst->w; x++)
1747 *csax = (csx >> 16);
1754 for (y = 0; y < dst->h; y++)
1757 *csay = (csy >> 16);
1764 for (x = 0; x < dst->w; x++)
1772 for (y = 0; y < dst->h; y++)
1779 sp = csp = (Uint8 *) src->pixels;
1780 dp = (Uint8 *) dst->pixels;
1781 dgap = dst->pitch - dst->w;
1785 for (y = 0; y < dst->h; y++)
1789 for (x = 0; x < dst->w; x++)
1794 /* advance source pointers */
1798 /* advance destination pointer */
1802 /* advance source pointer (for row) */
1803 csp += ((*csay) * src->pitch);
1806 /* advance destination pointers */
1817 -----------------------------------------------------------------------------
1820 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1821 'zoomx' and 'zoomy' are scaling factors for width and height.
1822 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
1823 into a 32bit RGBA format on the fly.
1824 -----------------------------------------------------------------------------
1827 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
1829 SDL_Surface *zoom_src = NULL;
1830 SDL_Surface *zoom_dst = NULL;
1831 boolean is_converted = FALSE;
1838 /* determine if source surface is 32 bit or 8 bit */
1839 is_32bit = (src->format->BitsPerPixel == 32);
1841 if (is_32bit || src->format->BitsPerPixel == 8)
1843 /* use source surface 'as is' */
1848 /* new source surface is 32 bit with a defined RGB ordering */
1849 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1850 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
1851 SDL_BlitSurface(src, NULL, zoom_src, NULL);
1853 is_converted = TRUE;
1856 /* allocate surface to completely contain the zoomed surface */
1859 /* target surface is 32 bit with source RGBA/ABGR ordering */
1860 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
1861 zoom_src->format->Rmask,
1862 zoom_src->format->Gmask,
1863 zoom_src->format->Bmask, 0);
1867 /* target surface is 8 bit */
1868 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
1872 /* lock source surface */
1873 SDL_LockSurface(zoom_src);
1875 /* check which kind of surface we have */
1878 /* call the 32 bit transformation routine to do the zooming */
1879 zoomSurfaceRGBA(zoom_src, zoom_dst);
1884 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
1885 zoom_dst->format->palette->colors[i] =
1886 zoom_src->format->palette->colors[i];
1887 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
1889 /* call the 8 bit transformation routine to do the zooming */
1890 zoomSurfaceY(zoom_src, zoom_dst);
1893 /* unlock source surface */
1894 SDL_UnlockSurface(zoom_src);
1896 /* free temporary surface */
1898 SDL_FreeSurface(zoom_src);
1900 /* return destination surface */
1904 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
1906 SDL_Surface *sdl_surface_tmp;
1907 int dst_width = dst_bitmap->width;
1908 int dst_height = dst_bitmap->height;
1910 /* throw away old destination surface */
1911 SDL_FreeSurface(dst_bitmap->surface);
1913 /* create zoomed temporary surface from source surface */
1914 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
1916 /* create native format destination surface from zoomed temporary surface */
1917 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
1919 /* free temporary surface */
1920 SDL_FreeSurface(sdl_surface_tmp);
1924 /* ========================================================================= */
1925 /* load image to bitmap */
1926 /* ========================================================================= */
1928 Bitmap *SDLLoadImage(char *filename)
1930 Bitmap *new_bitmap = CreateBitmapStruct();
1931 SDL_Surface *sdl_image_tmp;
1933 print_timestamp_init("SDLLoadImage");
1935 print_timestamp_time(getBaseNamePtr(filename));
1937 /* load image to temporary surface */
1938 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
1940 SetError("IMG_Load(): %s", SDL_GetError());
1945 print_timestamp_time("IMG_Load");
1947 UPDATE_BUSY_STATE();
1949 /* create native non-transparent surface for current image */
1950 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1952 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1957 print_timestamp_time("SDL_DisplayFormat (opaque)");
1959 UPDATE_BUSY_STATE();
1961 /* create native transparent surface for current image */
1962 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
1963 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
1964 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1966 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1971 print_timestamp_time("SDL_DisplayFormat (masked)");
1973 UPDATE_BUSY_STATE();
1975 /* free temporary surface */
1976 SDL_FreeSurface(sdl_image_tmp);
1978 new_bitmap->width = new_bitmap->surface->w;
1979 new_bitmap->height = new_bitmap->surface->h;
1981 print_timestamp_done("SDLLoadImage");
1987 /* ------------------------------------------------------------------------- */
1988 /* custom cursor fuctions */
1989 /* ------------------------------------------------------------------------- */
1991 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
1993 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
1994 cursor_info->width, cursor_info->height,
1995 cursor_info->hot_x, cursor_info->hot_y);
1998 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2000 static struct MouseCursorInfo *last_cursor_info = NULL;
2001 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2002 static SDL_Cursor *cursor_default = NULL;
2003 static SDL_Cursor *cursor_current = NULL;
2005 /* if invoked for the first time, store the SDL default cursor */
2006 if (cursor_default == NULL)
2007 cursor_default = SDL_GetCursor();
2009 /* only create new cursor if cursor info (custom only) has changed */
2010 if (cursor_info != NULL && cursor_info != last_cursor_info)
2012 cursor_current = create_cursor(cursor_info);
2013 last_cursor_info = cursor_info;
2016 /* only set new cursor if cursor info (custom or NULL) has changed */
2017 if (cursor_info != last_cursor_info2)
2018 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2020 last_cursor_info2 = cursor_info;
2024 /* ========================================================================= */
2025 /* audio functions */
2026 /* ========================================================================= */
2028 void SDLOpenAudio(void)
2030 #if !defined(TARGET_SDL2)
2031 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2032 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2035 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2037 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2041 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2042 AUDIO_NUM_CHANNELS_STEREO,
2043 setup.system.audio_fragment_size) < 0)
2045 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2049 audio.sound_available = TRUE;
2050 audio.music_available = TRUE;
2051 audio.loops_available = TRUE;
2052 audio.sound_enabled = TRUE;
2054 /* set number of available mixer channels */
2055 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2056 audio.music_channel = MUSIC_CHANNEL;
2057 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2059 Mixer_InitChannels();
2062 void SDLCloseAudio(void)
2065 Mix_HaltChannel(-1);
2068 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2072 /* ========================================================================= */
2073 /* event functions */
2074 /* ========================================================================= */
2076 void SDLNextEvent(Event *event)
2078 SDL_WaitEvent(event);
2080 if (event->type == EVENT_BUTTONPRESS ||
2081 event->type == EVENT_BUTTONRELEASE)
2083 if (((ButtonEvent *)event)->x > video_xoffset)
2084 ((ButtonEvent *)event)->x -= video_xoffset;
2086 ((ButtonEvent *)event)->x = 0;
2087 if (((ButtonEvent *)event)->y > video_yoffset)
2088 ((ButtonEvent *)event)->y -= video_yoffset;
2090 ((ButtonEvent *)event)->y = 0;
2092 else if (event->type == EVENT_MOTIONNOTIFY)
2094 if (((MotionEvent *)event)->x > video_xoffset)
2095 ((MotionEvent *)event)->x -= video_xoffset;
2097 ((MotionEvent *)event)->x = 0;
2098 if (((MotionEvent *)event)->y > video_yoffset)
2099 ((MotionEvent *)event)->y -= video_yoffset;
2101 ((MotionEvent *)event)->y = 0;
2105 void SDLHandleWindowManagerEvent(Event *event)
2107 #if defined(PLATFORM_WIN32)
2108 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2109 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2111 if (syswmmsg->msg == WM_DROPFILES)
2113 HDROP hdrop = (HDROP)syswmmsg->wParam;
2116 printf("::: SDL_SYSWMEVENT:\n");
2118 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2120 for (i = 0; i < num_files; i++)
2122 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2123 char buffer[buffer_len + 1];
2125 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2127 printf("::: - '%s'\n", buffer);
2130 DragFinish((HDROP)syswmmsg->wParam);
2136 /* ========================================================================= */
2137 /* joystick functions */
2138 /* ========================================================================= */
2140 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2141 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2142 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2144 static boolean SDLOpenJoystick(int nr)
2146 if (nr < 0 || nr > MAX_PLAYERS)
2149 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2152 static void SDLCloseJoystick(int nr)
2154 if (nr < 0 || nr > MAX_PLAYERS)
2157 SDL_JoystickClose(sdl_joystick[nr]);
2159 sdl_joystick[nr] = NULL;
2162 static boolean SDLCheckJoystickOpened(int nr)
2164 if (nr < 0 || nr > MAX_PLAYERS)
2167 #if defined(TARGET_SDL2)
2168 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2170 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2174 void HandleJoystickEvent(Event *event)
2178 case SDL_JOYAXISMOTION:
2179 if (event->jaxis.axis < 2)
2180 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2183 case SDL_JOYBUTTONDOWN:
2184 if (event->jbutton.button < 2)
2185 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2188 case SDL_JOYBUTTONUP:
2189 if (event->jbutton.button < 2)
2190 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2198 void SDLInitJoysticks()
2200 static boolean sdl_joystick_subsystem_initialized = FALSE;
2201 boolean print_warning = !sdl_joystick_subsystem_initialized;
2204 if (!sdl_joystick_subsystem_initialized)
2206 sdl_joystick_subsystem_initialized = TRUE;
2208 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2210 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2215 for (i = 0; i < MAX_PLAYERS; i++)
2217 /* get configured joystick for this player */
2218 char *device_name = setup.input[i].joy.device_name;
2219 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2221 if (joystick_nr >= SDL_NumJoysticks())
2223 if (setup.input[i].use_joystick && print_warning)
2224 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2229 /* misuse joystick file descriptor variable to store joystick number */
2230 joystick.fd[i] = joystick_nr;
2232 if (joystick_nr == -1)
2235 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2236 if (SDLCheckJoystickOpened(joystick_nr))
2237 SDLCloseJoystick(joystick_nr);
2239 if (!setup.input[i].use_joystick)
2242 if (!SDLOpenJoystick(joystick_nr))
2245 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2250 joystick.status = JOYSTICK_ACTIVATED;
2254 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2256 if (nr < 0 || nr >= MAX_PLAYERS)
2260 *x = sdl_js_axis[nr][0];
2262 *y = sdl_js_axis[nr][1];
2265 *b1 = sdl_js_button[nr][0];
2267 *b2 = sdl_js_button[nr][1];
2272 #endif /* TARGET_SDL */