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;
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_MODE_CROSSFADE)
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_MODE_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_MODE_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 for (alpha = 0.0; alpha < 255.0;)
495 time_last = time_current;
496 time_current = SDL_GetTicks();
497 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
498 alpha_final = MIN(MAX(0, alpha), 255);
500 /* draw existing (source) image to screen buffer */
501 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
503 /* draw new (target) image to screen buffer using alpha blending */
504 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
505 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
507 if (draw_border_function != NULL)
508 draw_border_function();
511 /* only update the region of the screen that is affected from fading */
512 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
514 SDL_Flip(surface_screen);
521 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
522 int to_x, int to_y, Uint32 color)
524 SDL_Surface *surface = dst_bitmap->surface;
528 swap_numbers(&from_x, &to_x);
531 swap_numbers(&from_y, &to_y);
535 rect.w = (to_x - from_x + 1);
536 rect.h = (to_y - from_y + 1);
538 if (dst_bitmap == backbuffer || dst_bitmap == window)
540 rect.x += video_xoffset;
541 rect.y += video_yoffset;
544 SDL_FillRect(surface, &rect, color);
547 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
548 int to_x, int to_y, Uint32 color)
550 if (dst_bitmap == backbuffer || dst_bitmap == window)
552 from_x += video_xoffset;
553 from_y += video_yoffset;
554 to_x += video_xoffset;
555 to_y += video_yoffset;
558 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
562 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
563 int num_points, Uint32 color)
568 for (i = 0; i < num_points - 1; i++)
570 for (x = 0; x < line_width; x++)
572 for (y = 0; y < line_width; y++)
574 int dx = x - line_width / 2;
575 int dy = y - line_width / 2;
577 if ((x == 0 && y == 0) ||
578 (x == 0 && y == line_width - 1) ||
579 (x == line_width - 1 && y == 0) ||
580 (x == line_width - 1 && y == line_width - 1))
583 sge_Line(surface, points[i].x + dx, points[i].y + dy,
584 points[i+1].x + dx, points[i+1].y + dy, color);
591 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
593 SDL_Surface *surface = src_bitmap->surface;
595 if (src_bitmap == backbuffer || src_bitmap == window)
601 switch (surface->format->BytesPerPixel)
603 case 1: /* assuming 8-bpp */
605 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
609 case 2: /* probably 15-bpp or 16-bpp */
611 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
615 case 3: /* slow 24-bpp mode; usually not used */
617 /* does this work? */
618 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
622 shift = surface->format->Rshift;
623 color |= *(pix + shift / 8) >> shift;
624 shift = surface->format->Gshift;
625 color |= *(pix + shift / 8) >> shift;
626 shift = surface->format->Bshift;
627 color |= *(pix + shift / 8) >> shift;
633 case 4: /* probably 32-bpp */
635 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
644 /* ========================================================================= */
645 /* The following functions were taken from the SGE library */
646 /* (SDL Graphics Extension Library) by Anders Lindström */
647 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
648 /* ========================================================================= */
650 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
652 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
654 switch (surface->format->BytesPerPixel)
659 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
665 /* Probably 15-bpp or 16-bpp */
666 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
672 /* Slow 24-bpp mode, usually not used */
676 /* Gack - slow, but endian correct */
677 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
678 shift = surface->format->Rshift;
679 *(pix+shift/8) = color>>shift;
680 shift = surface->format->Gshift;
681 *(pix+shift/8) = color>>shift;
682 shift = surface->format->Bshift;
683 *(pix+shift/8) = color>>shift;
689 /* Probably 32-bpp */
690 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
697 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
698 Uint8 R, Uint8 G, Uint8 B)
700 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
703 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
705 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
708 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
710 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
713 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
718 /* Gack - slow, but endian correct */
719 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
720 shift = surface->format->Rshift;
721 *(pix+shift/8) = color>>shift;
722 shift = surface->format->Gshift;
723 *(pix+shift/8) = color>>shift;
724 shift = surface->format->Bshift;
725 *(pix+shift/8) = color>>shift;
728 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
730 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
733 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
735 switch (dest->format->BytesPerPixel)
738 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
742 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
746 _PutPixel24(dest,x,y,color);
750 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
755 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
757 if (SDL_MUSTLOCK(surface))
759 if (SDL_LockSurface(surface) < 0)
765 _PutPixel(surface, x, y, color);
767 if (SDL_MUSTLOCK(surface))
769 SDL_UnlockSurface(surface);
773 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
774 Uint8 r, Uint8 g, Uint8 b)
776 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
779 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
781 if (y >= 0 && y <= dest->h - 1)
783 switch (dest->format->BytesPerPixel)
786 return y*dest->pitch;
790 return y*dest->pitch/2;
794 return y*dest->pitch;
798 return y*dest->pitch/4;
806 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
808 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
810 switch (surface->format->BytesPerPixel)
815 *((Uint8 *)surface->pixels + ypitch + x) = color;
821 /* Probably 15-bpp or 16-bpp */
822 *((Uint16 *)surface->pixels + ypitch + x) = color;
828 /* Slow 24-bpp mode, usually not used */
832 /* Gack - slow, but endian correct */
833 pix = (Uint8 *)surface->pixels + ypitch + x*3;
834 shift = surface->format->Rshift;
835 *(pix+shift/8) = color>>shift;
836 shift = surface->format->Gshift;
837 *(pix+shift/8) = color>>shift;
838 shift = surface->format->Bshift;
839 *(pix+shift/8) = color>>shift;
845 /* Probably 32-bpp */
846 *((Uint32 *)surface->pixels + ypitch + x) = color;
853 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
858 if (SDL_MUSTLOCK(Surface))
860 if (SDL_LockSurface(Surface) < 0)
873 /* Do the clipping */
874 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
878 if (x2 > Surface->w - 1)
886 SDL_FillRect(Surface, &l, Color);
888 if (SDL_MUSTLOCK(Surface))
890 SDL_UnlockSurface(Surface);
894 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
895 Uint8 R, Uint8 G, Uint8 B)
897 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
900 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
911 /* Do the clipping */
912 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
916 if (x2 > Surface->w - 1)
924 SDL_FillRect(Surface, &l, Color);
927 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
932 if (SDL_MUSTLOCK(Surface))
934 if (SDL_LockSurface(Surface) < 0)
947 /* Do the clipping */
948 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
952 if (y2 > Surface->h - 1)
960 SDL_FillRect(Surface, &l, Color);
962 if (SDL_MUSTLOCK(Surface))
964 SDL_UnlockSurface(Surface);
968 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
969 Uint8 R, Uint8 G, Uint8 B)
971 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
974 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
985 /* Do the clipping */
986 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
990 if (y2 > Surface->h - 1)
998 SDL_FillRect(Surface, &l, Color);
1001 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1002 Sint16 x2, Sint16 y2, Uint32 Color,
1003 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1006 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1011 sdx = (dx < 0) ? -1 : 1;
1012 sdy = (dy < 0) ? -1 : 1;
1024 for (x = 0; x < dx; x++)
1026 Callback(Surface, px, py, Color);
1040 for (y = 0; y < dy; y++)
1042 Callback(Surface, px, py, Color);
1056 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1057 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1058 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1061 sge_DoLine(Surface, X1, Y1, X2, Y2,
1062 SDL_MapRGB(Surface->format, R, G, B), Callback);
1065 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1068 if (SDL_MUSTLOCK(Surface))
1070 if (SDL_LockSurface(Surface) < 0)
1075 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1077 /* unlock the display */
1078 if (SDL_MUSTLOCK(Surface))
1080 SDL_UnlockSurface(Surface);
1084 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1085 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1087 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1090 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1092 if (dst_bitmap == backbuffer || dst_bitmap == window)
1098 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1103 -----------------------------------------------------------------------------
1104 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1105 -----------------------------------------------------------------------------
1108 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1109 int width, int height, Uint32 color)
1113 for (y = src_y; y < src_y + height; y++)
1115 for (x = src_x; x < src_x + width; x++)
1117 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1119 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1124 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1125 int src_x, int src_y, int width, int height,
1126 int dst_x, int dst_y)
1130 for (y = 0; y < height; y++)
1132 for (x = 0; x < width; x++)
1134 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1136 if (pixel != BLACK_PIXEL)
1137 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1143 /* ========================================================================= */
1144 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1145 /* (Rotozoomer) by Andreas Schiffler */
1146 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1147 /* ========================================================================= */
1150 -----------------------------------------------------------------------------
1153 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1154 -----------------------------------------------------------------------------
1165 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1168 tColorRGBA *sp, *csp, *dp;
1172 sp = csp = (tColorRGBA *) src->pixels;
1173 dp = (tColorRGBA *) dst->pixels;
1174 sgap = src->pitch - src->w * 4;
1175 dgap = dst->pitch - dst->w * 4;
1177 for (y = 0; y < dst->h; y++)
1181 for (x = 0; x < dst->w; x++)
1183 tColorRGBA *sp0 = sp;
1184 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1185 tColorRGBA *sp00 = &sp0[0];
1186 tColorRGBA *sp01 = &sp0[1];
1187 tColorRGBA *sp10 = &sp1[0];
1188 tColorRGBA *sp11 = &sp1[1];
1191 /* create new color pixel from all four source color pixels */
1192 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1193 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1194 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1195 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1200 /* advance source pointers */
1203 /* advance destination pointer */
1207 /* advance source pointer */
1208 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1210 /* advance destination pointers */
1211 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1217 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1219 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1220 tColorRGBA *sp, *csp, *dp;
1223 /* use specialized zoom function when scaling down to exactly half size */
1224 if (src->w == 2 * dst->w &&
1225 src->h == 2 * dst->h)
1226 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1228 /* variable setup */
1229 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1230 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1232 /* allocate memory for row increments */
1233 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1234 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1236 /* precalculate row increments */
1239 for (x = 0; x <= dst->w; x++)
1249 for (y = 0; y <= dst->h; y++)
1258 sp = csp = (tColorRGBA *) src->pixels;
1259 dp = (tColorRGBA *) dst->pixels;
1260 sgap = src->pitch - src->w * 4;
1261 dgap = dst->pitch - dst->w * 4;
1264 for (y = 0; y < dst->h; y++)
1269 for (x = 0; x < dst->w; x++)
1274 /* advance source pointers */
1276 sp += (*csax >> 16);
1278 /* advance destination pointer */
1282 /* advance source pointer */
1284 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1286 /* advance destination pointers */
1287 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1297 -----------------------------------------------------------------------------
1300 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1301 -----------------------------------------------------------------------------
1304 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1306 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1307 Uint8 *sp, *dp, *csp;
1310 /* variable setup */
1311 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1312 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1314 /* allocate memory for row increments */
1315 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1316 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1318 /* precalculate row increments */
1321 for (x = 0; x < dst->w; x++)
1324 *csax = (csx >> 16);
1331 for (y = 0; y < dst->h; y++)
1334 *csay = (csy >> 16);
1341 for (x = 0; x < dst->w; x++)
1349 for (y = 0; y < dst->h; y++)
1356 sp = csp = (Uint8 *) src->pixels;
1357 dp = (Uint8 *) dst->pixels;
1358 dgap = dst->pitch - dst->w;
1362 for (y = 0; y < dst->h; y++)
1366 for (x = 0; x < dst->w; x++)
1371 /* advance source pointers */
1375 /* advance destination pointer */
1379 /* advance source pointer (for row) */
1380 csp += ((*csay) * src->pitch);
1383 /* advance destination pointers */
1394 -----------------------------------------------------------------------------
1397 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1398 'zoomx' and 'zoomy' are scaling factors for width and height.
1399 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
1400 into a 32bit RGBA format on the fly.
1401 -----------------------------------------------------------------------------
1404 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
1406 SDL_Surface *zoom_src = NULL;
1407 SDL_Surface *zoom_dst = NULL;
1408 boolean is_converted = FALSE;
1415 /* determine if source surface is 32 bit or 8 bit */
1416 is_32bit = (src->format->BitsPerPixel == 32);
1418 if (is_32bit || src->format->BitsPerPixel == 8)
1420 /* use source surface 'as is' */
1425 /* new source surface is 32 bit with a defined RGB ordering */
1426 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1427 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
1428 SDL_BlitSurface(src, NULL, zoom_src, NULL);
1430 is_converted = TRUE;
1433 /* allocate surface to completely contain the zoomed surface */
1436 /* target surface is 32 bit with source RGBA/ABGR ordering */
1437 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
1438 zoom_src->format->Rmask,
1439 zoom_src->format->Gmask,
1440 zoom_src->format->Bmask, 0);
1444 /* target surface is 8 bit */
1445 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
1449 /* lock source surface */
1450 SDL_LockSurface(zoom_src);
1452 /* check which kind of surface we have */
1455 /* call the 32 bit transformation routine to do the zooming */
1456 zoomSurfaceRGBA(zoom_src, zoom_dst);
1461 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
1462 zoom_dst->format->palette->colors[i] =
1463 zoom_src->format->palette->colors[i];
1464 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
1466 /* call the 8 bit transformation routine to do the zooming */
1467 zoomSurfaceY(zoom_src, zoom_dst);
1470 /* unlock source surface */
1471 SDL_UnlockSurface(zoom_src);
1473 /* free temporary surface */
1475 SDL_FreeSurface(zoom_src);
1477 /* return destination surface */
1481 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
1483 SDL_Surface *sdl_surface_tmp;
1484 int dst_width = dst_bitmap->width;
1485 int dst_height = dst_bitmap->height;
1487 /* throw away old destination surface */
1488 SDL_FreeSurface(dst_bitmap->surface);
1490 /* create zoomed temporary surface from source surface */
1491 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
1493 /* create native format destination surface from zoomed temporary surface */
1494 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
1496 /* free temporary surface */
1497 SDL_FreeSurface(sdl_surface_tmp);
1501 /* ========================================================================= */
1502 /* load image to bitmap */
1503 /* ========================================================================= */
1505 Bitmap *SDLLoadImage(char *filename)
1507 Bitmap *new_bitmap = CreateBitmapStruct();
1508 SDL_Surface *sdl_image_tmp;
1510 /* load image to temporary surface */
1511 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
1513 SetError("IMG_Load(): %s", SDL_GetError());
1518 /* create native non-transparent surface for current image */
1519 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1521 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1526 /* create native transparent surface for current image */
1527 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
1528 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
1529 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1531 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1536 /* free temporary surface */
1537 SDL_FreeSurface(sdl_image_tmp);
1539 new_bitmap->width = new_bitmap->surface->w;
1540 new_bitmap->height = new_bitmap->surface->h;
1546 /* ------------------------------------------------------------------------- */
1547 /* custom cursor fuctions */
1548 /* ------------------------------------------------------------------------- */
1550 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
1552 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
1553 cursor_info->width, cursor_info->height,
1554 cursor_info->hot_x, cursor_info->hot_y);
1557 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
1559 static struct MouseCursorInfo *last_cursor_info = NULL;
1560 static struct MouseCursorInfo *last_cursor_info2 = NULL;
1561 static SDL_Cursor *cursor_default = NULL;
1562 static SDL_Cursor *cursor_current = NULL;
1564 /* if invoked for the first time, store the SDL default cursor */
1565 if (cursor_default == NULL)
1566 cursor_default = SDL_GetCursor();
1568 /* only create new cursor if cursor info (custom only) has changed */
1569 if (cursor_info != NULL && cursor_info != last_cursor_info)
1571 cursor_current = create_cursor(cursor_info);
1572 last_cursor_info = cursor_info;
1575 /* only set new cursor if cursor info (custom or NULL) has changed */
1576 if (cursor_info != last_cursor_info2)
1577 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
1579 last_cursor_info2 = cursor_info;
1583 /* ========================================================================= */
1584 /* audio functions */
1585 /* ========================================================================= */
1587 void SDLOpenAudio(void)
1589 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
1590 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
1592 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
1594 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
1598 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
1599 AUDIO_NUM_CHANNELS_STEREO,
1600 setup.system.audio_fragment_size) < 0)
1602 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
1606 audio.sound_available = TRUE;
1607 audio.music_available = TRUE;
1608 audio.loops_available = TRUE;
1609 audio.sound_enabled = TRUE;
1611 /* set number of available mixer channels */
1612 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
1613 audio.music_channel = MUSIC_CHANNEL;
1614 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
1616 Mixer_InitChannels();
1619 void SDLCloseAudio(void)
1622 Mix_HaltChannel(-1);
1625 SDL_QuitSubSystem(SDL_INIT_AUDIO);
1629 /* ========================================================================= */
1630 /* event functions */
1631 /* ========================================================================= */
1633 void SDLNextEvent(Event *event)
1635 SDL_WaitEvent(event);
1637 if (event->type == EVENT_BUTTONPRESS ||
1638 event->type == EVENT_BUTTONRELEASE)
1640 if (((ButtonEvent *)event)->x > video_xoffset)
1641 ((ButtonEvent *)event)->x -= video_xoffset;
1643 ((ButtonEvent *)event)->x = 0;
1644 if (((ButtonEvent *)event)->y > video_yoffset)
1645 ((ButtonEvent *)event)->y -= video_yoffset;
1647 ((ButtonEvent *)event)->y = 0;
1649 else if (event->type == EVENT_MOTIONNOTIFY)
1651 if (((MotionEvent *)event)->x > video_xoffset)
1652 ((MotionEvent *)event)->x -= video_xoffset;
1654 ((MotionEvent *)event)->x = 0;
1655 if (((MotionEvent *)event)->y > video_yoffset)
1656 ((MotionEvent *)event)->y -= video_yoffset;
1658 ((MotionEvent *)event)->y = 0;
1663 /* ========================================================================= */
1664 /* joystick functions */
1665 /* ========================================================================= */
1667 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
1668 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1669 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1671 static boolean SDLOpenJoystick(int nr)
1673 if (nr < 0 || nr > MAX_PLAYERS)
1676 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
1679 static void SDLCloseJoystick(int nr)
1681 if (nr < 0 || nr > MAX_PLAYERS)
1684 SDL_JoystickClose(sdl_joystick[nr]);
1687 static boolean SDLCheckJoystickOpened(int nr)
1689 if (nr < 0 || nr > MAX_PLAYERS)
1692 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
1695 void HandleJoystickEvent(Event *event)
1699 case SDL_JOYAXISMOTION:
1700 if (event->jaxis.axis < 2)
1701 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
1704 case SDL_JOYBUTTONDOWN:
1705 if (event->jbutton.button < 2)
1706 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
1709 case SDL_JOYBUTTONUP:
1710 if (event->jbutton.button < 2)
1711 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
1719 void SDLInitJoysticks()
1721 static boolean sdl_joystick_subsystem_initialized = FALSE;
1722 boolean print_warning = !sdl_joystick_subsystem_initialized;
1725 if (!sdl_joystick_subsystem_initialized)
1727 sdl_joystick_subsystem_initialized = TRUE;
1729 if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
1731 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
1736 for (i = 0; i < MAX_PLAYERS; i++)
1738 /* get configured joystick for this player */
1739 char *device_name = setup.input[i].joy.device_name;
1740 int joystick_nr = getJoystickNrFromDeviceName(device_name);
1742 if (joystick_nr >= SDL_NumJoysticks())
1744 if (setup.input[i].use_joystick && print_warning)
1745 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
1750 /* misuse joystick file descriptor variable to store joystick number */
1751 joystick.fd[i] = joystick_nr;
1753 if (joystick_nr == -1)
1756 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
1757 if (SDLCheckJoystickOpened(joystick_nr))
1758 SDLCloseJoystick(joystick_nr);
1760 if (!setup.input[i].use_joystick)
1763 if (!SDLOpenJoystick(joystick_nr))
1766 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
1771 joystick.status = JOYSTICK_ACTIVATED;
1775 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1777 if (nr < 0 || nr >= MAX_PLAYERS)
1781 *x = sdl_js_axis[nr][0];
1783 *y = sdl_js_axis[nr][1];
1786 *b1 = sdl_js_button[nr][0];
1788 *b2 = sdl_js_button[nr][1];
1793 #endif /* TARGET_SDL */