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 SDL_Window *sdl_window = NULL;
31 // static SDL_Renderer *sdl_renderer = NULL;
34 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
35 static int fullscreen_width;
36 static int fullscreen_height;
37 static int fullscreen_xoffset;
38 static int fullscreen_yoffset;
39 static int video_xoffset;
40 static int video_yoffset;
42 /* functions from SGE library */
43 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
45 static void setFullscreenParameters(char *fullscreen_mode_string)
47 struct ScreenModeInfo *fullscreen_mode;
50 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
52 if (fullscreen_mode == NULL)
55 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
57 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
58 fullscreen_mode->height == video.fullscreen_modes[i].height)
60 fullscreen_width = fullscreen_mode->width;
61 fullscreen_height = fullscreen_mode->height;
63 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
64 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
71 static void SDLSetWindowIcon(char *basename)
73 /* (setting the window icon on Mac OS X would replace the high-quality
74 dock icon with the currently smaller (and uglier) icon from file) */
76 #if !defined(PLATFORM_MACOSX)
77 char *filename = getCustomImageFilename(basename);
82 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
87 if ((surface = IMG_Load(filename)) == NULL)
89 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
94 /* set transparent color */
95 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
96 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
98 #if defined(TARGET_SDL2)
99 SDL_SetWindowIcon(sdl_window, surface);
101 SDL_WM_SetIcon(surface, NULL);
106 #if defined(TARGET_SDL2)
107 SDL_Surface *SDL_DisplayFormat(SDL_Surface *surface)
109 if (backbuffer == NULL ||
110 backbuffer->surface == NULL)
113 return SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
117 void SDLInitVideoDisplay(void)
119 #if !defined(TARGET_SDL2)
120 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
121 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
123 SDL_putenv("SDL_VIDEO_CENTERED=1");
126 /* initialize SDL video */
127 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
128 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
130 /* set default SDL depth */
131 #if !defined(TARGET_SDL2)
132 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
134 video.default_depth = 32; // (how to determine video depth in SDL2?)
138 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
141 static int screen_xy[][2] =
151 /* default: normal game window size */
152 fullscreen_width = video.width;
153 fullscreen_height = video.height;
154 fullscreen_xoffset = 0;
155 fullscreen_yoffset = 0;
157 for (i = 0; screen_xy[i][0] != -1; i++)
159 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
161 fullscreen_width = screen_xy[i][0];
162 fullscreen_height = screen_xy[i][1];
168 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
169 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
172 checked_free(video.fullscreen_modes);
174 video.fullscreen_modes = NULL;
175 video.fullscreen_mode_current = NULL;
178 #if !defined(TARGET_SDL2)
179 /* get available hardware supported fullscreen modes */
180 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
182 // (for now, no display modes in SDL2 -- change this later)
188 /* no screen modes available => no fullscreen mode support */
189 video.fullscreen_available = FALSE;
191 else if (modes == (SDL_Rect **)-1)
193 /* fullscreen resolution is not restricted -- all resolutions available */
194 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
196 /* use native video buffer size for fullscreen mode */
197 video.fullscreen_modes[0].width = video.width;
198 video.fullscreen_modes[0].height = video.height;
200 video.fullscreen_modes[1].width = -1;
201 video.fullscreen_modes[1].height = -1;
205 /* in this case, a certain number of screen modes is available */
208 for(i = 0; modes[i] != NULL; i++)
210 boolean found_mode = FALSE;
212 /* screen mode is smaller than video buffer size -- skip it */
213 if (modes[i]->w < video.width || modes[i]->h < video.height)
216 if (video.fullscreen_modes != NULL)
217 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
218 if (modes[i]->w == video.fullscreen_modes[j].width &&
219 modes[i]->h == video.fullscreen_modes[j].height)
222 if (found_mode) /* screen mode already stored -- skip it */
225 /* new mode found; add it to list of available fullscreen modes */
229 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
231 sizeof(struct ScreenModeInfo));
233 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
234 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
236 video.fullscreen_modes[num_modes].width = -1;
237 video.fullscreen_modes[num_modes].height = -1;
242 /* no appropriate screen modes available => no fullscreen mode support */
243 video.fullscreen_available = FALSE;
247 /* set window icon */
248 SDLSetWindowIcon(program.sdl_icon_filename);
250 /* open SDL video output device (window or fullscreen mode) */
251 if (!SDLSetVideoMode(backbuffer, fullscreen))
252 Error(ERR_EXIT, "setting video mode failed");
254 /* set window and icon title */
255 #if defined(TARGET_SDL2)
256 SDL_SetWindowTitle(sdl_window, program.window_title);
258 SDL_WM_SetCaption(program.window_title, program.window_title);
261 /* SDL cannot directly draw to the visible video framebuffer like X11,
262 but always uses a backbuffer, which is then blitted to the visible
263 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
264 visible video framebuffer with 'SDL_Flip', if the hardware supports
265 this). Therefore do not use an additional backbuffer for drawing, but
266 use a symbolic buffer (distinguishable from the SDL backbuffer) called
267 'window', which indicates that the SDL backbuffer should be updated to
268 the visible video framebuffer when attempting to blit to it.
270 For convenience, it seems to be a good idea to create this symbolic
271 buffer 'window' at the same size as the SDL backbuffer. Although it
272 should never be drawn to directly, it would do no harm nevertheless. */
274 /* create additional (symbolic) buffer for double-buffering */
276 ReCreateBitmap(window, video.width, video.height, video.depth);
278 *window = CreateBitmap(video.width, video.height, video.depth);
282 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
284 boolean success = TRUE;
285 #if defined(TARGET_SDL2)
286 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
287 int surface_flags_window = SURFACE_FLAGS;
289 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
290 int surface_flags_window = SURFACE_FLAGS;
292 SDL_Surface *new_surface = NULL;
294 if (*backbuffer == NULL)
295 *backbuffer = CreateBitmapStruct();
297 /* (real bitmap might be larger in fullscreen mode with video offsets) */
298 (*backbuffer)->width = video.width;
299 (*backbuffer)->height = video.height;
301 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
303 setFullscreenParameters(setup.fullscreen_mode);
305 video_xoffset = fullscreen_xoffset;
306 video_yoffset = fullscreen_yoffset;
308 /* switch display to fullscreen mode, if available */
309 #if defined(TARGET_SDL2)
310 sdl_window = SDL_CreateWindow(program.window_title,
311 SDL_WINDOWPOS_CENTERED,
312 SDL_WINDOWPOS_CENTERED,
313 fullscreen_width, fullscreen_height,
314 surface_flags_fullscreen);
315 if (sdl_window != NULL)
317 new_surface = SDL_GetWindowSurface(sdl_window);
319 SDL_UpdateWindowSurface(sdl_window); // immediately map window
322 new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
323 video.depth, surface_flags_fullscreen);
326 if (new_surface == NULL)
328 /* switching display to fullscreen mode failed */
329 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
331 /* do not try it again */
332 video.fullscreen_available = FALSE;
338 (*backbuffer)->surface = new_surface;
340 video.fullscreen_enabled = TRUE;
341 video.fullscreen_mode_current = setup.fullscreen_mode;
347 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
352 /* switch display to window mode */
353 #if defined(TARGET_SDL2)
354 sdl_window = SDL_CreateWindow(program.window_title,
355 SDL_WINDOWPOS_CENTERED,
356 SDL_WINDOWPOS_CENTERED,
357 video.width, video.height,
358 surface_flags_window);
359 if (sdl_window != NULL)
361 new_surface = SDL_GetWindowSurface(sdl_window);
363 SDL_UpdateWindowSurface(sdl_window); // immediately map window
366 new_surface = SDL_SetVideoMode(video.width, video.height,
367 video.depth, surface_flags_window);
370 if (new_surface == NULL)
372 /* switching display to window mode failed -- should not happen */
373 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
379 (*backbuffer)->surface = new_surface;
381 video.fullscreen_enabled = FALSE;
388 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
390 #if defined(PLATFORM_WIN32)
392 SDL_SysWMinfo wminfo;
395 SDL_VERSION(&wminfo.version);
396 SDL_GetWMInfo(&wminfo);
398 hwnd = wminfo.window;
400 DragAcceptFiles(hwnd, TRUE);
409 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
412 SDL_Surface *surface_tmp, *surface_native;
414 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
417 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
419 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
420 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
422 SDL_FreeSurface(surface_tmp);
424 new_bitmap->surface = surface_native;
427 void SDLFreeBitmapPointers(Bitmap *bitmap)
430 SDL_FreeSurface(bitmap->surface);
431 if (bitmap->surface_masked)
432 SDL_FreeSurface(bitmap->surface_masked);
433 bitmap->surface = NULL;
434 bitmap->surface_masked = NULL;
437 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
438 int src_x, int src_y, int width, int height,
439 int dst_x, int dst_y, int mask_mode)
441 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
442 SDL_Rect src_rect, dst_rect;
444 if (src_bitmap == backbuffer)
446 src_x += video_xoffset;
447 src_y += video_yoffset;
455 if (dst_bitmap == backbuffer || dst_bitmap == window)
457 dst_x += video_xoffset;
458 dst_y += video_yoffset;
466 if (src_bitmap != backbuffer || dst_bitmap != window)
467 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
468 src_bitmap->surface_masked : src_bitmap->surface),
469 &src_rect, real_dst_bitmap->surface, &dst_rect);
471 #if defined(TARGET_SDL2)
472 if (dst_bitmap == window)
473 SDL_UpdateWindowSurface(sdl_window);
475 if (dst_bitmap == window)
476 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
480 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
483 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
486 if (dst_bitmap == backbuffer || dst_bitmap == window)
497 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
499 #if defined(TARGET_SDL2)
500 if (dst_bitmap == window)
501 SDL_UpdateWindowSurface(sdl_window);
503 if (dst_bitmap == window)
504 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
508 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
509 int fade_mode, int fade_delay, int post_delay,
510 void (*draw_border_function)(void))
512 static boolean initialization_needed = TRUE;
513 static SDL_Surface *surface_source = NULL;
514 static SDL_Surface *surface_target = NULL;
515 static SDL_Surface *surface_black = NULL;
516 SDL_Surface *surface_screen = backbuffer->surface;
517 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
518 SDL_Rect src_rect, dst_rect;
519 int src_x = x, src_y = y;
520 int dst_x = x, dst_y = y;
521 unsigned int time_last, time_current;
523 /* check if screen size has changed */
524 if (surface_source != NULL && (video.width != surface_source->w ||
525 video.height != surface_source->h))
527 SDL_FreeSurface(surface_source);
528 SDL_FreeSurface(surface_target);
529 SDL_FreeSurface(surface_black);
531 initialization_needed = TRUE;
539 dst_x += video_xoffset;
540 dst_y += video_yoffset;
544 dst_rect.w = width; /* (ignored) */
545 dst_rect.h = height; /* (ignored) */
547 if (initialization_needed)
549 #if defined(TARGET_SDL2)
550 unsigned int flags = 0;
552 unsigned int flags = SDL_SRCALPHA;
554 /* use same surface type as screen surface */
555 if ((surface_screen->flags & SDL_HWSURFACE))
556 flags |= SDL_HWSURFACE;
558 flags |= SDL_SWSURFACE;
561 /* create surface for temporary copy of screen buffer (source) */
562 if ((surface_source =
563 SDL_CreateRGBSurface(flags,
566 surface_screen->format->BitsPerPixel,
567 surface_screen->format->Rmask,
568 surface_screen->format->Gmask,
569 surface_screen->format->Bmask,
570 surface_screen->format->Amask)) == NULL)
571 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
573 /* create surface for cross-fading screen buffer (target) */
574 if ((surface_target =
575 SDL_CreateRGBSurface(flags,
578 surface_screen->format->BitsPerPixel,
579 surface_screen->format->Rmask,
580 surface_screen->format->Gmask,
581 surface_screen->format->Bmask,
582 surface_screen->format->Amask)) == NULL)
583 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
585 /* create black surface for fading from/to black */
587 SDL_CreateRGBSurface(flags,
590 surface_screen->format->BitsPerPixel,
591 surface_screen->format->Rmask,
592 surface_screen->format->Gmask,
593 surface_screen->format->Bmask,
594 surface_screen->format->Amask)) == NULL)
595 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
597 /* completely fill the surface with black color pixels */
598 SDL_FillRect(surface_black, NULL,
599 SDL_MapRGB(surface_screen->format, 0, 0, 0));
601 initialization_needed = FALSE;
604 /* copy source and target surfaces to temporary surfaces for fading */
605 if (fade_mode & FADE_TYPE_TRANSFORM)
607 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
608 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
610 else if (fade_mode & FADE_TYPE_FADE_IN)
612 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
613 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
615 else /* FADE_TYPE_FADE_OUT */
617 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
618 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
621 time_current = SDL_GetTicks();
623 if (fade_mode == FADE_MODE_MELT)
625 boolean done = FALSE;
627 int melt_columns = width / melt_pixels;
628 int ypos[melt_columns];
629 int max_steps = height / 8 + 32;
634 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
635 #if defined(TARGET_SDL2)
636 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
638 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
641 ypos[0] = -GetSimpleRandom(16);
643 for (i = 1 ; i < melt_columns; i++)
645 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
647 ypos[i] = ypos[i - 1] + r;
660 time_last = time_current;
661 time_current = SDL_GetTicks();
662 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
663 steps_final = MIN(MAX(0, steps), max_steps);
667 done = (steps_done >= steps_final);
669 for (i = 0 ; i < melt_columns; i++)
677 else if (ypos[i] < height)
682 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
684 if (ypos[i] + dy >= height)
685 dy = height - ypos[i];
687 /* copy part of (appearing) target surface to upper area */
688 src_rect.x = src_x + i * melt_pixels;
689 // src_rect.y = src_y + ypos[i];
691 src_rect.w = melt_pixels;
693 src_rect.h = ypos[i] + dy;
695 dst_rect.x = dst_x + i * melt_pixels;
696 // dst_rect.y = dst_y + ypos[i];
699 if (steps_done >= steps_final)
700 SDL_BlitSurface(surface_target, &src_rect,
701 surface_screen, &dst_rect);
705 /* copy part of (disappearing) source surface to lower area */
706 src_rect.x = src_x + i * melt_pixels;
708 src_rect.w = melt_pixels;
709 src_rect.h = height - ypos[i];
711 dst_rect.x = dst_x + i * melt_pixels;
712 dst_rect.y = dst_y + ypos[i];
714 if (steps_done >= steps_final)
715 SDL_BlitSurface(surface_source, &src_rect,
716 surface_screen, &dst_rect);
722 src_rect.x = src_x + i * melt_pixels;
724 src_rect.w = melt_pixels;
727 dst_rect.x = dst_x + i * melt_pixels;
730 if (steps_done >= steps_final)
731 SDL_BlitSurface(surface_target, &src_rect,
732 surface_screen, &dst_rect);
736 if (steps_done >= steps_final)
738 if (draw_border_function != NULL)
739 draw_border_function();
741 #if defined(TARGET_SDL2)
742 SDL_UpdateWindowSurface(sdl_window);
744 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
754 for (alpha = 0.0; alpha < 255.0;)
756 time_last = time_current;
757 time_current = SDL_GetTicks();
758 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
759 alpha_final = MIN(MAX(0, alpha), 255);
761 /* draw existing (source) image to screen buffer */
762 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
764 /* draw new (target) image to screen buffer using alpha blending */
765 #if defined(TARGET_SDL2)
766 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
767 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
769 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
771 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
773 if (draw_border_function != NULL)
774 draw_border_function();
777 /* only update the region of the screen that is affected from fading */
778 #if defined(TARGET_SDL2)
779 SDL_UpdateWindowSurface(sdl_window);
781 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
784 SDL_Flip(surface_screen);
792 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
793 int to_x, int to_y, Uint32 color)
795 SDL_Surface *surface = dst_bitmap->surface;
799 swap_numbers(&from_x, &to_x);
802 swap_numbers(&from_y, &to_y);
806 rect.w = (to_x - from_x + 1);
807 rect.h = (to_y - from_y + 1);
809 if (dst_bitmap == backbuffer || dst_bitmap == window)
811 rect.x += video_xoffset;
812 rect.y += video_yoffset;
815 SDL_FillRect(surface, &rect, color);
818 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
819 int to_x, int to_y, Uint32 color)
821 if (dst_bitmap == backbuffer || dst_bitmap == window)
823 from_x += video_xoffset;
824 from_y += video_yoffset;
825 to_x += video_xoffset;
826 to_y += video_yoffset;
829 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
833 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
834 int num_points, Uint32 color)
839 for (i = 0; i < num_points - 1; i++)
841 for (x = 0; x < line_width; x++)
843 for (y = 0; y < line_width; y++)
845 int dx = x - line_width / 2;
846 int dy = y - line_width / 2;
848 if ((x == 0 && y == 0) ||
849 (x == 0 && y == line_width - 1) ||
850 (x == line_width - 1 && y == 0) ||
851 (x == line_width - 1 && y == line_width - 1))
854 sge_Line(surface, points[i].x + dx, points[i].y + dy,
855 points[i+1].x + dx, points[i+1].y + dy, color);
862 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
864 SDL_Surface *surface = src_bitmap->surface;
866 if (src_bitmap == backbuffer || src_bitmap == window)
872 switch (surface->format->BytesPerPixel)
874 case 1: /* assuming 8-bpp */
876 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
880 case 2: /* probably 15-bpp or 16-bpp */
882 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
886 case 3: /* slow 24-bpp mode; usually not used */
888 /* does this work? */
889 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
893 shift = surface->format->Rshift;
894 color |= *(pix + shift / 8) >> shift;
895 shift = surface->format->Gshift;
896 color |= *(pix + shift / 8) >> shift;
897 shift = surface->format->Bshift;
898 color |= *(pix + shift / 8) >> shift;
904 case 4: /* probably 32-bpp */
906 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
915 /* ========================================================================= */
916 /* The following functions were taken from the SGE library */
917 /* (SDL Graphics Extension Library) by Anders Lindström */
918 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
919 /* ========================================================================= */
921 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
923 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
925 switch (surface->format->BytesPerPixel)
930 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
936 /* Probably 15-bpp or 16-bpp */
937 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
943 /* Slow 24-bpp mode, usually not used */
947 /* Gack - slow, but endian correct */
948 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
949 shift = surface->format->Rshift;
950 *(pix+shift/8) = color>>shift;
951 shift = surface->format->Gshift;
952 *(pix+shift/8) = color>>shift;
953 shift = surface->format->Bshift;
954 *(pix+shift/8) = color>>shift;
960 /* Probably 32-bpp */
961 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
968 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
969 Uint8 R, Uint8 G, Uint8 B)
971 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
974 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
976 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
979 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
981 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
984 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
989 /* Gack - slow, but endian correct */
990 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
991 shift = surface->format->Rshift;
992 *(pix+shift/8) = color>>shift;
993 shift = surface->format->Gshift;
994 *(pix+shift/8) = color>>shift;
995 shift = surface->format->Bshift;
996 *(pix+shift/8) = color>>shift;
999 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1001 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1004 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1006 switch (dest->format->BytesPerPixel)
1009 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1013 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1017 _PutPixel24(dest,x,y,color);
1021 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1026 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1028 if (SDL_MUSTLOCK(surface))
1030 if (SDL_LockSurface(surface) < 0)
1036 _PutPixel(surface, x, y, color);
1038 if (SDL_MUSTLOCK(surface))
1040 SDL_UnlockSurface(surface);
1044 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1045 Uint8 r, Uint8 g, Uint8 b)
1047 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1050 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1052 if (y >= 0 && y <= dest->h - 1)
1054 switch (dest->format->BytesPerPixel)
1057 return y*dest->pitch;
1061 return y*dest->pitch/2;
1065 return y*dest->pitch;
1069 return y*dest->pitch/4;
1077 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1079 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1081 switch (surface->format->BytesPerPixel)
1085 /* Assuming 8-bpp */
1086 *((Uint8 *)surface->pixels + ypitch + x) = color;
1092 /* Probably 15-bpp or 16-bpp */
1093 *((Uint16 *)surface->pixels + ypitch + x) = color;
1099 /* Slow 24-bpp mode, usually not used */
1103 /* Gack - slow, but endian correct */
1104 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1105 shift = surface->format->Rshift;
1106 *(pix+shift/8) = color>>shift;
1107 shift = surface->format->Gshift;
1108 *(pix+shift/8) = color>>shift;
1109 shift = surface->format->Bshift;
1110 *(pix+shift/8) = color>>shift;
1116 /* Probably 32-bpp */
1117 *((Uint32 *)surface->pixels + ypitch + x) = color;
1124 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1129 if (SDL_MUSTLOCK(Surface))
1131 if (SDL_LockSurface(Surface) < 0)
1144 /* Do the clipping */
1145 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1149 if (x2 > Surface->w - 1)
1150 x2 = Surface->w - 1;
1157 SDL_FillRect(Surface, &l, Color);
1159 if (SDL_MUSTLOCK(Surface))
1161 SDL_UnlockSurface(Surface);
1165 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1166 Uint8 R, Uint8 G, Uint8 B)
1168 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1171 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1182 /* Do the clipping */
1183 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1187 if (x2 > Surface->w - 1)
1188 x2 = Surface->w - 1;
1195 SDL_FillRect(Surface, &l, Color);
1198 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1203 if (SDL_MUSTLOCK(Surface))
1205 if (SDL_LockSurface(Surface) < 0)
1218 /* Do the clipping */
1219 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1223 if (y2 > Surface->h - 1)
1224 y2 = Surface->h - 1;
1231 SDL_FillRect(Surface, &l, Color);
1233 if (SDL_MUSTLOCK(Surface))
1235 SDL_UnlockSurface(Surface);
1239 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1240 Uint8 R, Uint8 G, Uint8 B)
1242 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1245 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1256 /* Do the clipping */
1257 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1261 if (y2 > Surface->h - 1)
1262 y2 = Surface->h - 1;
1269 SDL_FillRect(Surface, &l, Color);
1272 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1273 Sint16 x2, Sint16 y2, Uint32 Color,
1274 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1277 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1282 sdx = (dx < 0) ? -1 : 1;
1283 sdy = (dy < 0) ? -1 : 1;
1295 for (x = 0; x < dx; x++)
1297 Callback(Surface, px, py, Color);
1311 for (y = 0; y < dy; y++)
1313 Callback(Surface, px, py, Color);
1327 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1328 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1329 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1332 sge_DoLine(Surface, X1, Y1, X2, Y2,
1333 SDL_MapRGB(Surface->format, R, G, B), Callback);
1336 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1339 if (SDL_MUSTLOCK(Surface))
1341 if (SDL_LockSurface(Surface) < 0)
1346 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1348 /* unlock the display */
1349 if (SDL_MUSTLOCK(Surface))
1351 SDL_UnlockSurface(Surface);
1355 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1356 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1358 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1361 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1363 if (dst_bitmap == backbuffer || dst_bitmap == window)
1369 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1374 -----------------------------------------------------------------------------
1375 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1376 -----------------------------------------------------------------------------
1379 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1380 int width, int height, Uint32 color)
1384 for (y = src_y; y < src_y + height; y++)
1386 for (x = src_x; x < src_x + width; x++)
1388 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1390 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1395 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1396 int src_x, int src_y, int width, int height,
1397 int dst_x, int dst_y)
1401 for (y = 0; y < height; y++)
1403 for (x = 0; x < width; x++)
1405 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1407 if (pixel != BLACK_PIXEL)
1408 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1414 /* ========================================================================= */
1415 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1416 /* (Rotozoomer) by Andreas Schiffler */
1417 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1418 /* ========================================================================= */
1421 -----------------------------------------------------------------------------
1424 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1425 -----------------------------------------------------------------------------
1436 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1439 tColorRGBA *sp, *csp, *dp;
1446 sp = csp = (tColorRGBA *) src->pixels;
1447 dp = (tColorRGBA *) dst->pixels;
1449 sgap = src->pitch - src->w * 4;
1451 dgap = dst->pitch - dst->w * 4;
1453 for (y = 0; y < dst->h; y++)
1457 for (x = 0; x < dst->w; x++)
1459 tColorRGBA *sp0 = sp;
1460 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1461 tColorRGBA *sp00 = &sp0[0];
1462 tColorRGBA *sp01 = &sp0[1];
1463 tColorRGBA *sp10 = &sp1[0];
1464 tColorRGBA *sp11 = &sp1[1];
1467 /* create new color pixel from all four source color pixels */
1468 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1469 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1470 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1471 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1476 /* advance source pointers */
1479 /* advance destination pointer */
1483 /* advance source pointer */
1484 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1486 /* advance destination pointers */
1487 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1493 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1495 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1496 tColorRGBA *sp, *csp, *dp;
1502 /* use specialized zoom function when scaling down to exactly half size */
1503 if (src->w == 2 * dst->w &&
1504 src->h == 2 * dst->h)
1505 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1507 /* variable setup */
1508 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1509 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1511 /* allocate memory for row increments */
1512 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1513 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1515 /* precalculate row increments */
1518 for (x = 0; x <= dst->w; x++)
1528 for (y = 0; y <= dst->h; y++)
1537 sp = csp = (tColorRGBA *) src->pixels;
1538 dp = (tColorRGBA *) dst->pixels;
1540 sgap = src->pitch - src->w * 4;
1542 dgap = dst->pitch - dst->w * 4;
1545 for (y = 0; y < dst->h; y++)
1550 for (x = 0; x < dst->w; x++)
1555 /* advance source pointers */
1557 sp += (*csax >> 16);
1559 /* advance destination pointer */
1563 /* advance source pointer */
1565 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1567 /* advance destination pointers */
1568 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1578 -----------------------------------------------------------------------------
1581 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1582 -----------------------------------------------------------------------------
1585 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1587 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1588 Uint8 *sp, *dp, *csp;
1591 /* variable setup */
1592 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1593 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1595 /* allocate memory for row increments */
1596 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1597 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1599 /* precalculate row increments */
1602 for (x = 0; x < dst->w; x++)
1605 *csax = (csx >> 16);
1612 for (y = 0; y < dst->h; y++)
1615 *csay = (csy >> 16);
1622 for (x = 0; x < dst->w; x++)
1630 for (y = 0; y < dst->h; y++)
1637 sp = csp = (Uint8 *) src->pixels;
1638 dp = (Uint8 *) dst->pixels;
1639 dgap = dst->pitch - dst->w;
1643 for (y = 0; y < dst->h; y++)
1647 for (x = 0; x < dst->w; x++)
1652 /* advance source pointers */
1656 /* advance destination pointer */
1660 /* advance source pointer (for row) */
1661 csp += ((*csay) * src->pitch);
1664 /* advance destination pointers */
1675 -----------------------------------------------------------------------------
1678 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1679 'zoomx' and 'zoomy' are scaling factors for width and height.
1680 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
1681 into a 32bit RGBA format on the fly.
1682 -----------------------------------------------------------------------------
1685 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
1687 SDL_Surface *zoom_src = NULL;
1688 SDL_Surface *zoom_dst = NULL;
1689 boolean is_converted = FALSE;
1696 /* determine if source surface is 32 bit or 8 bit */
1697 is_32bit = (src->format->BitsPerPixel == 32);
1699 if (is_32bit || src->format->BitsPerPixel == 8)
1701 /* use source surface 'as is' */
1706 /* new source surface is 32 bit with a defined RGB ordering */
1707 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1708 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
1709 SDL_BlitSurface(src, NULL, zoom_src, NULL);
1711 is_converted = TRUE;
1714 /* allocate surface to completely contain the zoomed surface */
1717 /* target surface is 32 bit with source RGBA/ABGR ordering */
1718 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
1719 zoom_src->format->Rmask,
1720 zoom_src->format->Gmask,
1721 zoom_src->format->Bmask, 0);
1725 /* target surface is 8 bit */
1726 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
1730 /* lock source surface */
1731 SDL_LockSurface(zoom_src);
1733 /* check which kind of surface we have */
1736 /* call the 32 bit transformation routine to do the zooming */
1737 zoomSurfaceRGBA(zoom_src, zoom_dst);
1742 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
1743 zoom_dst->format->palette->colors[i] =
1744 zoom_src->format->palette->colors[i];
1745 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
1747 /* call the 8 bit transformation routine to do the zooming */
1748 zoomSurfaceY(zoom_src, zoom_dst);
1751 /* unlock source surface */
1752 SDL_UnlockSurface(zoom_src);
1754 /* free temporary surface */
1756 SDL_FreeSurface(zoom_src);
1758 /* return destination surface */
1762 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
1764 SDL_Surface *sdl_surface_tmp;
1765 int dst_width = dst_bitmap->width;
1766 int dst_height = dst_bitmap->height;
1768 /* throw away old destination surface */
1769 SDL_FreeSurface(dst_bitmap->surface);
1771 /* create zoomed temporary surface from source surface */
1772 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
1774 /* create native format destination surface from zoomed temporary surface */
1775 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
1777 /* free temporary surface */
1778 SDL_FreeSurface(sdl_surface_tmp);
1782 /* ========================================================================= */
1783 /* load image to bitmap */
1784 /* ========================================================================= */
1786 Bitmap *SDLLoadImage(char *filename)
1788 Bitmap *new_bitmap = CreateBitmapStruct();
1789 SDL_Surface *sdl_image_tmp;
1791 print_timestamp_init("SDLLoadImage");
1793 print_timestamp_time(getBaseNamePtr(filename));
1795 /* load image to temporary surface */
1796 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
1798 SetError("IMG_Load(): %s", SDL_GetError());
1803 print_timestamp_time("IMG_Load");
1805 UPDATE_BUSY_STATE();
1807 /* create native non-transparent surface for current image */
1808 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1810 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1815 print_timestamp_time("SDL_DisplayFormat (opaque)");
1817 UPDATE_BUSY_STATE();
1819 /* create native transparent surface for current image */
1820 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
1821 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
1822 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1824 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1829 print_timestamp_time("SDL_DisplayFormat (masked)");
1831 UPDATE_BUSY_STATE();
1833 /* free temporary surface */
1834 SDL_FreeSurface(sdl_image_tmp);
1836 new_bitmap->width = new_bitmap->surface->w;
1837 new_bitmap->height = new_bitmap->surface->h;
1839 print_timestamp_done("SDLLoadImage");
1845 /* ------------------------------------------------------------------------- */
1846 /* custom cursor fuctions */
1847 /* ------------------------------------------------------------------------- */
1849 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
1851 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
1852 cursor_info->width, cursor_info->height,
1853 cursor_info->hot_x, cursor_info->hot_y);
1856 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
1858 static struct MouseCursorInfo *last_cursor_info = NULL;
1859 static struct MouseCursorInfo *last_cursor_info2 = NULL;
1860 static SDL_Cursor *cursor_default = NULL;
1861 static SDL_Cursor *cursor_current = NULL;
1863 /* if invoked for the first time, store the SDL default cursor */
1864 if (cursor_default == NULL)
1865 cursor_default = SDL_GetCursor();
1867 /* only create new cursor if cursor info (custom only) has changed */
1868 if (cursor_info != NULL && cursor_info != last_cursor_info)
1870 cursor_current = create_cursor(cursor_info);
1871 last_cursor_info = cursor_info;
1874 /* only set new cursor if cursor info (custom or NULL) has changed */
1875 if (cursor_info != last_cursor_info2)
1876 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
1878 last_cursor_info2 = cursor_info;
1882 /* ========================================================================= */
1883 /* audio functions */
1884 /* ========================================================================= */
1886 void SDLOpenAudio(void)
1888 #if !defined(TARGET_SDL2)
1889 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
1890 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
1893 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
1895 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
1899 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
1900 AUDIO_NUM_CHANNELS_STEREO,
1901 setup.system.audio_fragment_size) < 0)
1903 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
1907 audio.sound_available = TRUE;
1908 audio.music_available = TRUE;
1909 audio.loops_available = TRUE;
1910 audio.sound_enabled = TRUE;
1912 /* set number of available mixer channels */
1913 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
1914 audio.music_channel = MUSIC_CHANNEL;
1915 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
1917 Mixer_InitChannels();
1920 void SDLCloseAudio(void)
1923 Mix_HaltChannel(-1);
1926 SDL_QuitSubSystem(SDL_INIT_AUDIO);
1930 /* ========================================================================= */
1931 /* event functions */
1932 /* ========================================================================= */
1934 void SDLNextEvent(Event *event)
1936 SDL_WaitEvent(event);
1938 if (event->type == EVENT_BUTTONPRESS ||
1939 event->type == EVENT_BUTTONRELEASE)
1941 if (((ButtonEvent *)event)->x > video_xoffset)
1942 ((ButtonEvent *)event)->x -= video_xoffset;
1944 ((ButtonEvent *)event)->x = 0;
1945 if (((ButtonEvent *)event)->y > video_yoffset)
1946 ((ButtonEvent *)event)->y -= video_yoffset;
1948 ((ButtonEvent *)event)->y = 0;
1950 else if (event->type == EVENT_MOTIONNOTIFY)
1952 if (((MotionEvent *)event)->x > video_xoffset)
1953 ((MotionEvent *)event)->x -= video_xoffset;
1955 ((MotionEvent *)event)->x = 0;
1956 if (((MotionEvent *)event)->y > video_yoffset)
1957 ((MotionEvent *)event)->y -= video_yoffset;
1959 ((MotionEvent *)event)->y = 0;
1963 void SDLHandleWindowManagerEvent(Event *event)
1965 #if defined(PLATFORM_WIN32)
1966 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
1967 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
1969 if (syswmmsg->msg == WM_DROPFILES)
1971 HDROP hdrop = (HDROP)syswmmsg->wParam;
1974 printf("::: SDL_SYSWMEVENT:\n");
1976 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
1978 for (i = 0; i < num_files; i++)
1980 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
1981 char buffer[buffer_len + 1];
1983 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
1985 printf("::: - '%s'\n", buffer);
1988 DragFinish((HDROP)syswmmsg->wParam);
1994 /* ========================================================================= */
1995 /* joystick functions */
1996 /* ========================================================================= */
1998 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
1999 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2000 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2002 static boolean SDLOpenJoystick(int nr)
2004 if (nr < 0 || nr > MAX_PLAYERS)
2007 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2010 static void SDLCloseJoystick(int nr)
2012 if (nr < 0 || nr > MAX_PLAYERS)
2015 SDL_JoystickClose(sdl_joystick[nr]);
2017 sdl_joystick[nr] = NULL;
2020 static boolean SDLCheckJoystickOpened(int nr)
2022 if (nr < 0 || nr > MAX_PLAYERS)
2025 #if defined(TARGET_SDL2)
2026 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2028 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2032 void HandleJoystickEvent(Event *event)
2036 case SDL_JOYAXISMOTION:
2037 if (event->jaxis.axis < 2)
2038 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2041 case SDL_JOYBUTTONDOWN:
2042 if (event->jbutton.button < 2)
2043 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2046 case SDL_JOYBUTTONUP:
2047 if (event->jbutton.button < 2)
2048 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2056 void SDLInitJoysticks()
2058 static boolean sdl_joystick_subsystem_initialized = FALSE;
2059 boolean print_warning = !sdl_joystick_subsystem_initialized;
2062 if (!sdl_joystick_subsystem_initialized)
2064 sdl_joystick_subsystem_initialized = TRUE;
2066 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2068 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2073 for (i = 0; i < MAX_PLAYERS; i++)
2075 /* get configured joystick for this player */
2076 char *device_name = setup.input[i].joy.device_name;
2077 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2079 if (joystick_nr >= SDL_NumJoysticks())
2081 if (setup.input[i].use_joystick && print_warning)
2082 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2087 /* misuse joystick file descriptor variable to store joystick number */
2088 joystick.fd[i] = joystick_nr;
2090 if (joystick_nr == -1)
2093 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2094 if (SDLCheckJoystickOpened(joystick_nr))
2095 SDLCloseJoystick(joystick_nr);
2097 if (!setup.input[i].use_joystick)
2100 if (!SDLOpenJoystick(joystick_nr))
2103 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2108 joystick.status = JOYSTICK_ACTIVATED;
2112 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2114 if (nr < 0 || nr >= MAX_PLAYERS)
2118 *x = sdl_js_axis[nr][0];
2120 *y = sdl_js_axis[nr][1];
2123 *b1 = sdl_js_button[nr][0];
2125 *b2 = sdl_js_button[nr][1];
2130 #endif /* TARGET_SDL */