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 /* functions from SGE library */
28 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
30 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
31 static int fullscreen_width;
32 static int fullscreen_height;
33 static int fullscreen_xoffset;
34 static int fullscreen_yoffset;
35 static int video_xoffset;
36 static int video_yoffset;
38 static void setFullscreenParameters(char *fullscreen_mode_string)
40 struct ScreenModeInfo *fullscreen_mode;
43 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
45 if (fullscreen_mode == NULL)
48 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
50 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
51 fullscreen_mode->height == video.fullscreen_modes[i].height)
53 fullscreen_width = fullscreen_mode->width;
54 fullscreen_height = fullscreen_mode->height;
56 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
57 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
64 static void SDLSetWindowIcon(char *basename)
66 /* (setting the window icon on Mac OS X would replace the high-quality
67 dock icon with the currently smaller (and uglier) icon from file) */
69 #if !defined(PLATFORM_MACOSX)
70 char *filename = getCustomImageFilename(basename);
75 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
80 if ((surface = IMG_Load(filename)) == NULL)
82 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
87 /* set transparent color */
88 SDL_SetColorKey(surface, SDL_SRCCOLORKEY,
89 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
91 SDL_WM_SetIcon(surface, NULL);
95 void SDLInitVideoDisplay(void)
97 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
98 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
100 SDL_putenv("SDL_VIDEO_CENTERED=1");
102 /* initialize SDL video */
103 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
104 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
106 /* set default SDL depth */
107 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
110 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
113 static int screen_xy[][2] =
123 /* default: normal game window size */
124 fullscreen_width = video.width;
125 fullscreen_height = video.height;
126 fullscreen_xoffset = 0;
127 fullscreen_yoffset = 0;
129 for (i = 0; screen_xy[i][0] != -1; i++)
131 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
133 fullscreen_width = screen_xy[i][0];
134 fullscreen_height = screen_xy[i][1];
140 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
141 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
143 /* get available hardware supported fullscreen modes */
144 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
148 /* no screen modes available => no fullscreen mode support */
149 video.fullscreen_available = FALSE;
151 else if (modes == (SDL_Rect **)-1)
153 /* fullscreen resolution is not restricted -- all resolutions available */
154 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
156 /* use native video buffer size for fullscreen mode */
157 video.fullscreen_modes[0].width = video.width;
158 video.fullscreen_modes[0].height = video.height;
160 video.fullscreen_modes[1].width = -1;
161 video.fullscreen_modes[1].height = -1;
165 /* in this case, a certain number of screen modes is available */
168 for(i = 0; modes[i] != NULL; i++)
170 boolean found_mode = FALSE;
172 /* screen mode is smaller than video buffer size -- skip it */
173 if (modes[i]->w < video.width || modes[i]->h < video.height)
176 if (video.fullscreen_modes != NULL)
177 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
178 if (modes[i]->w == video.fullscreen_modes[j].width &&
179 modes[i]->h == video.fullscreen_modes[j].height)
182 if (found_mode) /* screen mode already stored -- skip it */
185 /* new mode found; add it to list of available fullscreen modes */
189 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
191 sizeof(struct ScreenModeInfo));
193 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
194 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
196 video.fullscreen_modes[num_modes].width = -1;
197 video.fullscreen_modes[num_modes].height = -1;
202 /* no appropriate screen modes available => no fullscreen mode support */
203 video.fullscreen_available = FALSE;
207 /* set window icon */
208 SDLSetWindowIcon(program.sdl_icon_filename);
210 /* open SDL video output device (window or fullscreen mode) */
211 if (!SDLSetVideoMode(backbuffer, fullscreen))
212 Error(ERR_EXIT, "setting video mode failed");
214 /* set window and icon title */
215 SDL_WM_SetCaption(program.window_title, program.window_title);
217 /* SDL cannot directly draw to the visible video framebuffer like X11,
218 but always uses a backbuffer, which is then blitted to the visible
219 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
220 visible video framebuffer with 'SDL_Flip', if the hardware supports
221 this). Therefore do not use an additional backbuffer for drawing, but
222 use a symbolic buffer (distinguishable from the SDL backbuffer) called
223 'window', which indicates that the SDL backbuffer should be updated to
224 the visible video framebuffer when attempting to blit to it.
226 For convenience, it seems to be a good idea to create this symbolic
227 buffer 'window' at the same size as the SDL backbuffer. Although it
228 should never be drawn to directly, it would do no harm nevertheless. */
230 /* create additional (symbolic) buffer for double-buffering */
231 *window = CreateBitmap(video.width, video.height, video.depth);
234 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
236 boolean success = TRUE;
237 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
238 int surface_flags_window = SURFACE_FLAGS;
239 SDL_Surface *new_surface = NULL;
241 if (*backbuffer == NULL)
242 *backbuffer = CreateBitmapStruct();
244 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
246 setFullscreenParameters(setup.fullscreen_mode);
248 video_xoffset = fullscreen_xoffset;
249 video_yoffset = fullscreen_yoffset;
251 /* switch display to fullscreen mode, if available */
252 if ((new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
253 video.depth, surface_flags_fullscreen))
256 /* switching display to fullscreen mode failed */
257 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
259 /* do not try it again */
260 video.fullscreen_available = FALSE;
266 (*backbuffer)->surface = new_surface;
268 video.fullscreen_enabled = TRUE;
269 video.fullscreen_mode_current = setup.fullscreen_mode;
275 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
280 /* switch display to window mode */
281 if ((new_surface = SDL_SetVideoMode(video.width, video.height,
282 video.depth, surface_flags_window))
285 /* switching display to window mode failed -- should not happen */
286 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
292 (*backbuffer)->surface = new_surface;
294 video.fullscreen_enabled = FALSE;
302 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
305 SDL_Surface *surface_tmp, *surface_native;
307 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
310 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
312 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
313 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
315 SDL_FreeSurface(surface_tmp);
317 new_bitmap->surface = surface_native;
320 void SDLFreeBitmapPointers(Bitmap *bitmap)
323 SDL_FreeSurface(bitmap->surface);
324 if (bitmap->surface_masked)
325 SDL_FreeSurface(bitmap->surface_masked);
326 bitmap->surface = NULL;
327 bitmap->surface_masked = NULL;
330 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
331 int src_x, int src_y, int width, int height,
332 int dst_x, int dst_y, int mask_mode)
334 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
335 SDL_Rect src_rect, dst_rect;
337 if (src_bitmap == backbuffer)
339 src_x += video_xoffset;
340 src_y += video_yoffset;
348 if (dst_bitmap == backbuffer || dst_bitmap == window)
350 dst_x += video_xoffset;
351 dst_y += video_yoffset;
359 if (src_bitmap != backbuffer || dst_bitmap != window)
360 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
361 src_bitmap->surface_masked : src_bitmap->surface),
362 &src_rect, real_dst_bitmap->surface, &dst_rect);
364 if (dst_bitmap == window)
365 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
368 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
371 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
374 if (dst_bitmap == backbuffer || dst_bitmap == window)
385 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
387 if (dst_bitmap == window)
388 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
391 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
392 int fade_mode, int fade_delay, int post_delay,
393 void (*draw_border_function)(void))
395 static boolean initialization_needed = TRUE;
396 static SDL_Surface *surface_source = NULL;
397 static SDL_Surface *surface_target = NULL;
398 static SDL_Surface *surface_black = NULL;
399 SDL_Surface *surface_screen = backbuffer->surface;
400 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
401 SDL_Rect src_rect, dst_rect;
402 int src_x = x, src_y = y;
403 int dst_x = x, dst_y = y;
404 unsigned int time_last, time_current;
413 dst_x += video_xoffset;
414 dst_y += video_yoffset;
418 dst_rect.w = width; /* (ignored) */
419 dst_rect.h = height; /* (ignored) */
421 if (initialization_needed)
423 unsigned int flags = SDL_SRCALPHA;
425 /* use same surface type as screen surface */
426 if ((surface_screen->flags & SDL_HWSURFACE))
427 flags |= SDL_HWSURFACE;
429 flags |= SDL_SWSURFACE;
431 /* create surface for temporary copy of screen buffer (source) */
432 if ((surface_source =
433 SDL_CreateRGBSurface(flags,
436 surface_screen->format->BitsPerPixel,
437 surface_screen->format->Rmask,
438 surface_screen->format->Gmask,
439 surface_screen->format->Bmask,
440 surface_screen->format->Amask)) == NULL)
441 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
443 /* create surface for cross-fading screen buffer (target) */
444 if ((surface_target =
445 SDL_CreateRGBSurface(flags,
448 surface_screen->format->BitsPerPixel,
449 surface_screen->format->Rmask,
450 surface_screen->format->Gmask,
451 surface_screen->format->Bmask,
452 surface_screen->format->Amask)) == NULL)
453 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
455 /* create black surface for fading from/to black */
457 SDL_CreateRGBSurface(flags,
460 surface_screen->format->BitsPerPixel,
461 surface_screen->format->Rmask,
462 surface_screen->format->Gmask,
463 surface_screen->format->Bmask,
464 surface_screen->format->Amask)) == NULL)
465 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
467 /* completely fill the surface with black color pixels */
468 SDL_FillRect(surface_black, NULL,
469 SDL_MapRGB(surface_screen->format, 0, 0, 0));
471 initialization_needed = FALSE;
474 /* copy source and target surfaces to temporary surfaces for fading */
475 if (fade_mode & FADE_TYPE_TRANSFORM)
477 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
478 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
480 else if (fade_mode & FADE_TYPE_FADE_IN)
482 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
483 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
485 else /* FADE_TYPE_FADE_OUT */
487 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
488 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
491 time_current = SDL_GetTicks();
493 if (fade_mode == FADE_MODE_MELT)
495 boolean done = FALSE;
497 int melt_columns = width / melt_pixels;
498 int ypos[melt_columns];
499 int max_steps = height / 8 + 32;
503 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
504 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
506 ypos[0] = -GetSimpleRandom(16);
508 for (i = 1 ; i < melt_columns; i++)
510 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
512 ypos[i] = ypos[i - 1] + r;
526 time_last = time_current;
527 time_current = SDL_GetTicks();
528 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
529 steps_final = MIN(MAX(0, steps), max_steps);
533 done = (steps_done >= steps_final);
535 for (i = 0 ; i < melt_columns; i++)
543 else if (ypos[i] < height)
548 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
550 if (ypos[i] + dy >= height)
551 dy = height - ypos[i];
553 /* copy part of (appearing) target surface to upper area */
554 src_rect.x = src_x + i * melt_pixels;
555 // src_rect.y = src_y + ypos[i];
557 src_rect.w = melt_pixels;
559 src_rect.h = ypos[i] + dy;
561 dst_rect.x = dst_x + i * melt_pixels;
562 // dst_rect.y = dst_y + ypos[i];
565 if (steps_done >= steps_final)
566 SDL_BlitSurface(surface_target, &src_rect,
567 surface_screen, &dst_rect);
571 /* copy part of (disappearing) source surface to lower area */
572 src_rect.x = src_x + i * melt_pixels;
574 src_rect.w = melt_pixels;
575 src_rect.h = height - ypos[i];
577 dst_rect.x = dst_x + i * melt_pixels;
578 dst_rect.y = dst_y + ypos[i];
580 if (steps_done >= steps_final)
581 SDL_BlitSurface(surface_source, &src_rect,
582 surface_screen, &dst_rect);
588 src_rect.x = src_x + i * melt_pixels;
590 src_rect.w = melt_pixels;
593 dst_rect.x = dst_x + i * melt_pixels;
596 if (steps_done >= steps_final)
597 SDL_BlitSurface(surface_target, &src_rect,
598 surface_screen, &dst_rect);
602 if (steps_done >= steps_final)
603 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
608 for (alpha = 0.0; alpha < 255.0;)
610 time_last = time_current;
611 time_current = SDL_GetTicks();
612 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
613 alpha_final = MIN(MAX(0, alpha), 255);
615 /* draw existing (source) image to screen buffer */
616 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
618 /* draw new (target) image to screen buffer using alpha blending */
619 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
620 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
622 if (draw_border_function != NULL)
623 draw_border_function();
626 /* only update the region of the screen that is affected from fading */
627 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
629 SDL_Flip(surface_screen);
637 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
638 int to_x, int to_y, Uint32 color)
640 SDL_Surface *surface = dst_bitmap->surface;
644 swap_numbers(&from_x, &to_x);
647 swap_numbers(&from_y, &to_y);
651 rect.w = (to_x - from_x + 1);
652 rect.h = (to_y - from_y + 1);
654 if (dst_bitmap == backbuffer || dst_bitmap == window)
656 rect.x += video_xoffset;
657 rect.y += video_yoffset;
660 SDL_FillRect(surface, &rect, color);
663 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
664 int to_x, int to_y, Uint32 color)
666 if (dst_bitmap == backbuffer || dst_bitmap == window)
668 from_x += video_xoffset;
669 from_y += video_yoffset;
670 to_x += video_xoffset;
671 to_y += video_yoffset;
674 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
678 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
679 int num_points, Uint32 color)
684 for (i = 0; i < num_points - 1; i++)
686 for (x = 0; x < line_width; x++)
688 for (y = 0; y < line_width; y++)
690 int dx = x - line_width / 2;
691 int dy = y - line_width / 2;
693 if ((x == 0 && y == 0) ||
694 (x == 0 && y == line_width - 1) ||
695 (x == line_width - 1 && y == 0) ||
696 (x == line_width - 1 && y == line_width - 1))
699 sge_Line(surface, points[i].x + dx, points[i].y + dy,
700 points[i+1].x + dx, points[i+1].y + dy, color);
707 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
709 SDL_Surface *surface = src_bitmap->surface;
711 if (src_bitmap == backbuffer || src_bitmap == window)
717 switch (surface->format->BytesPerPixel)
719 case 1: /* assuming 8-bpp */
721 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
725 case 2: /* probably 15-bpp or 16-bpp */
727 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
731 case 3: /* slow 24-bpp mode; usually not used */
733 /* does this work? */
734 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
738 shift = surface->format->Rshift;
739 color |= *(pix + shift / 8) >> shift;
740 shift = surface->format->Gshift;
741 color |= *(pix + shift / 8) >> shift;
742 shift = surface->format->Bshift;
743 color |= *(pix + shift / 8) >> shift;
749 case 4: /* probably 32-bpp */
751 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
760 /* ========================================================================= */
761 /* The following functions were taken from the SGE library */
762 /* (SDL Graphics Extension Library) by Anders Lindström */
763 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
764 /* ========================================================================= */
766 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
768 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
770 switch (surface->format->BytesPerPixel)
775 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
781 /* Probably 15-bpp or 16-bpp */
782 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
788 /* Slow 24-bpp mode, usually not used */
792 /* Gack - slow, but endian correct */
793 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
794 shift = surface->format->Rshift;
795 *(pix+shift/8) = color>>shift;
796 shift = surface->format->Gshift;
797 *(pix+shift/8) = color>>shift;
798 shift = surface->format->Bshift;
799 *(pix+shift/8) = color>>shift;
805 /* Probably 32-bpp */
806 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
813 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
814 Uint8 R, Uint8 G, Uint8 B)
816 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
819 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
821 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
824 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
826 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
829 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
834 /* Gack - slow, but endian correct */
835 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
836 shift = surface->format->Rshift;
837 *(pix+shift/8) = color>>shift;
838 shift = surface->format->Gshift;
839 *(pix+shift/8) = color>>shift;
840 shift = surface->format->Bshift;
841 *(pix+shift/8) = color>>shift;
844 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
846 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
849 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
851 switch (dest->format->BytesPerPixel)
854 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
858 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
862 _PutPixel24(dest,x,y,color);
866 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
871 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
873 if (SDL_MUSTLOCK(surface))
875 if (SDL_LockSurface(surface) < 0)
881 _PutPixel(surface, x, y, color);
883 if (SDL_MUSTLOCK(surface))
885 SDL_UnlockSurface(surface);
889 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
890 Uint8 r, Uint8 g, Uint8 b)
892 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
895 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
897 if (y >= 0 && y <= dest->h - 1)
899 switch (dest->format->BytesPerPixel)
902 return y*dest->pitch;
906 return y*dest->pitch/2;
910 return y*dest->pitch;
914 return y*dest->pitch/4;
922 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
924 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
926 switch (surface->format->BytesPerPixel)
931 *((Uint8 *)surface->pixels + ypitch + x) = color;
937 /* Probably 15-bpp or 16-bpp */
938 *((Uint16 *)surface->pixels + ypitch + x) = color;
944 /* Slow 24-bpp mode, usually not used */
948 /* Gack - slow, but endian correct */
949 pix = (Uint8 *)surface->pixels + ypitch + x*3;
950 shift = surface->format->Rshift;
951 *(pix+shift/8) = color>>shift;
952 shift = surface->format->Gshift;
953 *(pix+shift/8) = color>>shift;
954 shift = surface->format->Bshift;
955 *(pix+shift/8) = color>>shift;
961 /* Probably 32-bpp */
962 *((Uint32 *)surface->pixels + ypitch + x) = color;
969 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
974 if (SDL_MUSTLOCK(Surface))
976 if (SDL_LockSurface(Surface) < 0)
989 /* Do the clipping */
990 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
994 if (x2 > Surface->w - 1)
1002 SDL_FillRect(Surface, &l, Color);
1004 if (SDL_MUSTLOCK(Surface))
1006 SDL_UnlockSurface(Surface);
1010 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1011 Uint8 R, Uint8 G, Uint8 B)
1013 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1016 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1027 /* Do the clipping */
1028 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1032 if (x2 > Surface->w - 1)
1033 x2 = Surface->w - 1;
1040 SDL_FillRect(Surface, &l, Color);
1043 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1048 if (SDL_MUSTLOCK(Surface))
1050 if (SDL_LockSurface(Surface) < 0)
1063 /* Do the clipping */
1064 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1068 if (y2 > Surface->h - 1)
1069 y2 = Surface->h - 1;
1076 SDL_FillRect(Surface, &l, Color);
1078 if (SDL_MUSTLOCK(Surface))
1080 SDL_UnlockSurface(Surface);
1084 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1085 Uint8 R, Uint8 G, Uint8 B)
1087 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1090 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1101 /* Do the clipping */
1102 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1106 if (y2 > Surface->h - 1)
1107 y2 = Surface->h - 1;
1114 SDL_FillRect(Surface, &l, Color);
1117 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1118 Sint16 x2, Sint16 y2, Uint32 Color,
1119 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1122 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1127 sdx = (dx < 0) ? -1 : 1;
1128 sdy = (dy < 0) ? -1 : 1;
1140 for (x = 0; x < dx; x++)
1142 Callback(Surface, px, py, Color);
1156 for (y = 0; y < dy; y++)
1158 Callback(Surface, px, py, Color);
1172 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1173 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1174 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1177 sge_DoLine(Surface, X1, Y1, X2, Y2,
1178 SDL_MapRGB(Surface->format, R, G, B), Callback);
1181 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1184 if (SDL_MUSTLOCK(Surface))
1186 if (SDL_LockSurface(Surface) < 0)
1191 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1193 /* unlock the display */
1194 if (SDL_MUSTLOCK(Surface))
1196 SDL_UnlockSurface(Surface);
1200 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1201 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1203 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1206 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1208 if (dst_bitmap == backbuffer || dst_bitmap == window)
1214 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1219 -----------------------------------------------------------------------------
1220 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1221 -----------------------------------------------------------------------------
1224 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1225 int width, int height, Uint32 color)
1229 for (y = src_y; y < src_y + height; y++)
1231 for (x = src_x; x < src_x + width; x++)
1233 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1235 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1240 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1241 int src_x, int src_y, int width, int height,
1242 int dst_x, int dst_y)
1246 for (y = 0; y < height; y++)
1248 for (x = 0; x < width; x++)
1250 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1252 if (pixel != BLACK_PIXEL)
1253 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1259 /* ========================================================================= */
1260 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1261 /* (Rotozoomer) by Andreas Schiffler */
1262 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1263 /* ========================================================================= */
1266 -----------------------------------------------------------------------------
1269 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1270 -----------------------------------------------------------------------------
1281 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1284 tColorRGBA *sp, *csp, *dp;
1288 sp = csp = (tColorRGBA *) src->pixels;
1289 dp = (tColorRGBA *) dst->pixels;
1290 sgap = src->pitch - src->w * 4;
1291 dgap = dst->pitch - dst->w * 4;
1293 for (y = 0; y < dst->h; y++)
1297 for (x = 0; x < dst->w; x++)
1299 tColorRGBA *sp0 = sp;
1300 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1301 tColorRGBA *sp00 = &sp0[0];
1302 tColorRGBA *sp01 = &sp0[1];
1303 tColorRGBA *sp10 = &sp1[0];
1304 tColorRGBA *sp11 = &sp1[1];
1307 /* create new color pixel from all four source color pixels */
1308 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1309 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1310 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1311 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1316 /* advance source pointers */
1319 /* advance destination pointer */
1323 /* advance source pointer */
1324 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1326 /* advance destination pointers */
1327 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1333 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1335 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1336 tColorRGBA *sp, *csp, *dp;
1339 /* use specialized zoom function when scaling down to exactly half size */
1340 if (src->w == 2 * dst->w &&
1341 src->h == 2 * dst->h)
1342 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1344 /* variable setup */
1345 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1346 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1348 /* allocate memory for row increments */
1349 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1350 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1352 /* precalculate row increments */
1355 for (x = 0; x <= dst->w; x++)
1365 for (y = 0; y <= dst->h; y++)
1374 sp = csp = (tColorRGBA *) src->pixels;
1375 dp = (tColorRGBA *) dst->pixels;
1376 sgap = src->pitch - src->w * 4;
1377 dgap = dst->pitch - dst->w * 4;
1380 for (y = 0; y < dst->h; y++)
1385 for (x = 0; x < dst->w; x++)
1390 /* advance source pointers */
1392 sp += (*csax >> 16);
1394 /* advance destination pointer */
1398 /* advance source pointer */
1400 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1402 /* advance destination pointers */
1403 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1413 -----------------------------------------------------------------------------
1416 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1417 -----------------------------------------------------------------------------
1420 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1422 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1423 Uint8 *sp, *dp, *csp;
1426 /* variable setup */
1427 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1428 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1430 /* allocate memory for row increments */
1431 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1432 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1434 /* precalculate row increments */
1437 for (x = 0; x < dst->w; x++)
1440 *csax = (csx >> 16);
1447 for (y = 0; y < dst->h; y++)
1450 *csay = (csy >> 16);
1457 for (x = 0; x < dst->w; x++)
1465 for (y = 0; y < dst->h; y++)
1472 sp = csp = (Uint8 *) src->pixels;
1473 dp = (Uint8 *) dst->pixels;
1474 dgap = dst->pitch - dst->w;
1478 for (y = 0; y < dst->h; y++)
1482 for (x = 0; x < dst->w; x++)
1487 /* advance source pointers */
1491 /* advance destination pointer */
1495 /* advance source pointer (for row) */
1496 csp += ((*csay) * src->pitch);
1499 /* advance destination pointers */
1510 -----------------------------------------------------------------------------
1513 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1514 'zoomx' and 'zoomy' are scaling factors for width and height.
1515 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
1516 into a 32bit RGBA format on the fly.
1517 -----------------------------------------------------------------------------
1520 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
1522 SDL_Surface *zoom_src = NULL;
1523 SDL_Surface *zoom_dst = NULL;
1524 boolean is_converted = FALSE;
1531 /* determine if source surface is 32 bit or 8 bit */
1532 is_32bit = (src->format->BitsPerPixel == 32);
1534 if (is_32bit || src->format->BitsPerPixel == 8)
1536 /* use source surface 'as is' */
1541 /* new source surface is 32 bit with a defined RGB ordering */
1542 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1543 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
1544 SDL_BlitSurface(src, NULL, zoom_src, NULL);
1546 is_converted = TRUE;
1549 /* allocate surface to completely contain the zoomed surface */
1552 /* target surface is 32 bit with source RGBA/ABGR ordering */
1553 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
1554 zoom_src->format->Rmask,
1555 zoom_src->format->Gmask,
1556 zoom_src->format->Bmask, 0);
1560 /* target surface is 8 bit */
1561 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
1565 /* lock source surface */
1566 SDL_LockSurface(zoom_src);
1568 /* check which kind of surface we have */
1571 /* call the 32 bit transformation routine to do the zooming */
1572 zoomSurfaceRGBA(zoom_src, zoom_dst);
1577 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
1578 zoom_dst->format->palette->colors[i] =
1579 zoom_src->format->palette->colors[i];
1580 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
1582 /* call the 8 bit transformation routine to do the zooming */
1583 zoomSurfaceY(zoom_src, zoom_dst);
1586 /* unlock source surface */
1587 SDL_UnlockSurface(zoom_src);
1589 /* free temporary surface */
1591 SDL_FreeSurface(zoom_src);
1593 /* return destination surface */
1597 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
1599 SDL_Surface *sdl_surface_tmp;
1600 int dst_width = dst_bitmap->width;
1601 int dst_height = dst_bitmap->height;
1603 /* throw away old destination surface */
1604 SDL_FreeSurface(dst_bitmap->surface);
1606 /* create zoomed temporary surface from source surface */
1607 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
1609 /* create native format destination surface from zoomed temporary surface */
1610 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
1612 /* free temporary surface */
1613 SDL_FreeSurface(sdl_surface_tmp);
1617 /* ========================================================================= */
1618 /* load image to bitmap */
1619 /* ========================================================================= */
1621 Bitmap *SDLLoadImage(char *filename)
1623 Bitmap *new_bitmap = CreateBitmapStruct();
1624 SDL_Surface *sdl_image_tmp;
1626 /* load image to temporary surface */
1627 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
1629 SetError("IMG_Load(): %s", SDL_GetError());
1634 /* create native non-transparent surface for current image */
1635 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1637 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1642 /* create native transparent surface for current image */
1643 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
1644 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
1645 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1647 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1652 /* free temporary surface */
1653 SDL_FreeSurface(sdl_image_tmp);
1655 new_bitmap->width = new_bitmap->surface->w;
1656 new_bitmap->height = new_bitmap->surface->h;
1662 /* ------------------------------------------------------------------------- */
1663 /* custom cursor fuctions */
1664 /* ------------------------------------------------------------------------- */
1666 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
1668 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
1669 cursor_info->width, cursor_info->height,
1670 cursor_info->hot_x, cursor_info->hot_y);
1673 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
1675 static struct MouseCursorInfo *last_cursor_info = NULL;
1676 static struct MouseCursorInfo *last_cursor_info2 = NULL;
1677 static SDL_Cursor *cursor_default = NULL;
1678 static SDL_Cursor *cursor_current = NULL;
1680 /* if invoked for the first time, store the SDL default cursor */
1681 if (cursor_default == NULL)
1682 cursor_default = SDL_GetCursor();
1684 /* only create new cursor if cursor info (custom only) has changed */
1685 if (cursor_info != NULL && cursor_info != last_cursor_info)
1687 cursor_current = create_cursor(cursor_info);
1688 last_cursor_info = cursor_info;
1691 /* only set new cursor if cursor info (custom or NULL) has changed */
1692 if (cursor_info != last_cursor_info2)
1693 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
1695 last_cursor_info2 = cursor_info;
1699 /* ========================================================================= */
1700 /* audio functions */
1701 /* ========================================================================= */
1703 void SDLOpenAudio(void)
1705 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
1706 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
1708 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
1710 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
1714 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
1715 AUDIO_NUM_CHANNELS_STEREO,
1716 setup.system.audio_fragment_size) < 0)
1718 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
1722 audio.sound_available = TRUE;
1723 audio.music_available = TRUE;
1724 audio.loops_available = TRUE;
1725 audio.sound_enabled = TRUE;
1727 /* set number of available mixer channels */
1728 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
1729 audio.music_channel = MUSIC_CHANNEL;
1730 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
1732 Mixer_InitChannels();
1735 void SDLCloseAudio(void)
1738 Mix_HaltChannel(-1);
1741 SDL_QuitSubSystem(SDL_INIT_AUDIO);
1745 /* ========================================================================= */
1746 /* event functions */
1747 /* ========================================================================= */
1749 void SDLNextEvent(Event *event)
1751 SDL_WaitEvent(event);
1753 if (event->type == EVENT_BUTTONPRESS ||
1754 event->type == EVENT_BUTTONRELEASE)
1756 if (((ButtonEvent *)event)->x > video_xoffset)
1757 ((ButtonEvent *)event)->x -= video_xoffset;
1759 ((ButtonEvent *)event)->x = 0;
1760 if (((ButtonEvent *)event)->y > video_yoffset)
1761 ((ButtonEvent *)event)->y -= video_yoffset;
1763 ((ButtonEvent *)event)->y = 0;
1765 else if (event->type == EVENT_MOTIONNOTIFY)
1767 if (((MotionEvent *)event)->x > video_xoffset)
1768 ((MotionEvent *)event)->x -= video_xoffset;
1770 ((MotionEvent *)event)->x = 0;
1771 if (((MotionEvent *)event)->y > video_yoffset)
1772 ((MotionEvent *)event)->y -= video_yoffset;
1774 ((MotionEvent *)event)->y = 0;
1779 /* ========================================================================= */
1780 /* joystick functions */
1781 /* ========================================================================= */
1783 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
1784 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1785 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1787 static boolean SDLOpenJoystick(int nr)
1789 if (nr < 0 || nr > MAX_PLAYERS)
1792 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
1795 static void SDLCloseJoystick(int nr)
1797 if (nr < 0 || nr > MAX_PLAYERS)
1800 SDL_JoystickClose(sdl_joystick[nr]);
1803 static boolean SDLCheckJoystickOpened(int nr)
1805 if (nr < 0 || nr > MAX_PLAYERS)
1808 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
1811 void HandleJoystickEvent(Event *event)
1815 case SDL_JOYAXISMOTION:
1816 if (event->jaxis.axis < 2)
1817 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
1820 case SDL_JOYBUTTONDOWN:
1821 if (event->jbutton.button < 2)
1822 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
1825 case SDL_JOYBUTTONUP:
1826 if (event->jbutton.button < 2)
1827 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
1835 void SDLInitJoysticks()
1837 static boolean sdl_joystick_subsystem_initialized = FALSE;
1838 boolean print_warning = !sdl_joystick_subsystem_initialized;
1841 if (!sdl_joystick_subsystem_initialized)
1843 sdl_joystick_subsystem_initialized = TRUE;
1845 if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
1847 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
1852 for (i = 0; i < MAX_PLAYERS; i++)
1854 /* get configured joystick for this player */
1855 char *device_name = setup.input[i].joy.device_name;
1856 int joystick_nr = getJoystickNrFromDeviceName(device_name);
1858 if (joystick_nr >= SDL_NumJoysticks())
1860 if (setup.input[i].use_joystick && print_warning)
1861 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
1866 /* misuse joystick file descriptor variable to store joystick number */
1867 joystick.fd[i] = joystick_nr;
1869 if (joystick_nr == -1)
1872 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
1873 if (SDLCheckJoystickOpened(joystick_nr))
1874 SDLCloseJoystick(joystick_nr);
1876 if (!setup.input[i].use_joystick)
1879 if (!SDLOpenJoystick(joystick_nr))
1882 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
1887 joystick.status = JOYSTICK_ACTIVATED;
1891 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1893 if (nr < 0 || nr >= MAX_PLAYERS)
1897 *x = sdl_js_axis[nr][0];
1899 *y = sdl_js_axis[nr][1];
1902 *b1 = sdl_js_button[nr][0];
1904 *b2 = sdl_js_button[nr][1];
1909 #endif /* TARGET_SDL */