1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
20 #if defined(TARGET_SDL)
22 /* ========================================================================= */
24 /* ========================================================================= */
26 /* functions from SGE library */
27 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
29 /* #ifdef PLATFORM_WIN32 */
30 #define FULLSCREEN_BUG
33 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
34 static int fullscreen_width;
35 static int fullscreen_height;
36 static int fullscreen_xoffset;
37 static int fullscreen_yoffset;
38 static int video_xoffset;
39 static int video_yoffset;
41 void SDLInitVideoDisplay(void)
43 putenv("SDL_VIDEO_CENTERED=1");
45 /* initialize SDL video */
46 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
47 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
49 /* set default SDL depth */
50 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
53 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
58 static int screen_xy[][2] =
67 /* default: normal game window size */
68 fullscreen_width = video.width;
69 fullscreen_height = video.height;
70 fullscreen_xoffset = 0;
71 fullscreen_yoffset = 0;
74 for (i = 0; screen_xy[i][0] != -1; i++)
76 if (video.width <= screen_xy[i][0] && video.height <= screen_xy[i][1])
78 fullscreen_width = screen_xy[i][0];
79 fullscreen_height = screen_xy[i][1];
84 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
85 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
88 /* open SDL video output device (window or fullscreen mode) */
89 if (!SDLSetVideoMode(backbuffer, fullscreen))
90 Error(ERR_EXIT, "setting video mode failed");
92 /* set window and icon title */
93 SDL_WM_SetCaption(program.window_title, program.window_title);
95 /* SDL cannot directly draw to the visible video framebuffer like X11,
96 but always uses a backbuffer, which is then blitted to the visible
97 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
98 visible video framebuffer with 'SDL_Flip', if the hardware supports
99 this). Therefore do not use an additional backbuffer for drawing, but
100 use a symbolic buffer (distinguishable from the SDL backbuffer) called
101 'window', which indicates that the SDL backbuffer should be updated to
102 the visible video framebuffer when attempting to blit to it.
104 For convenience, it seems to be a good idea to create this symbolic
105 buffer 'window' at the same size as the SDL backbuffer. Although it
106 should never be drawn to directly, it would do no harm nevertheless. */
108 /* create additional (symbolic) buffer for double-buffering */
109 *window = CreateBitmap(video.width, video.height, video.depth);
112 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
114 boolean success = TRUE;
115 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
116 int surface_flags_window = SURFACE_FLAGS;
117 SDL_Surface *new_surface = NULL;
119 if (*backbuffer == NULL)
120 *backbuffer = CreateBitmapStruct();
122 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
124 video_xoffset = fullscreen_xoffset;
125 video_yoffset = fullscreen_yoffset;
127 /* switch display to fullscreen mode, if available */
128 if ((new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
129 video.depth, surface_flags_fullscreen))
132 /* switching display to fullscreen mode failed */
133 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
135 /* do not try it again */
136 video.fullscreen_available = FALSE;
141 (*backbuffer)->surface = new_surface;
143 video.fullscreen_enabled = TRUE;
148 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
153 /* switch display to window mode */
154 if ((new_surface = SDL_SetVideoMode(video.width, video.height,
155 video.depth, surface_flags_window))
158 /* switching display to window mode failed -- should not happen */
159 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
165 (*backbuffer)->surface = new_surface;
167 video.fullscreen_enabled = FALSE;
175 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
178 SDL_Surface *surface_tmp, *surface_native;
180 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
183 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
185 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
186 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
188 SDL_FreeSurface(surface_tmp);
190 new_bitmap->surface = surface_native;
193 void SDLFreeBitmapPointers(Bitmap *bitmap)
196 SDL_FreeSurface(bitmap->surface);
197 if (bitmap->surface_masked)
198 SDL_FreeSurface(bitmap->surface_masked);
199 bitmap->surface = NULL;
200 bitmap->surface_masked = NULL;
203 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
204 int src_x, int src_y, int width, int height,
205 int dst_x, int dst_y, int mask_mode)
207 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
208 SDL_Rect src_rect, dst_rect;
210 #ifdef FULLSCREEN_BUG
211 if (src_bitmap == backbuffer)
213 src_x += video_xoffset;
214 src_y += video_yoffset;
223 #ifdef FULLSCREEN_BUG
224 if (dst_bitmap == backbuffer || dst_bitmap == window)
226 dst_x += video_xoffset;
227 dst_y += video_yoffset;
236 if (src_bitmap != backbuffer || dst_bitmap != window)
237 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
238 src_bitmap->surface_masked : src_bitmap->surface),
239 &src_rect, real_dst_bitmap->surface, &dst_rect);
241 if (dst_bitmap == window)
242 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
245 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y,
246 int width, int height, Uint32 color)
248 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
251 #ifdef FULLSCREEN_BUG
252 if (dst_bitmap == backbuffer || dst_bitmap == window)
264 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
266 if (dst_bitmap == window)
267 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
270 void SDLFadeScreen(Bitmap *bitmap_cross, int fade_mode, int fade_delay,
273 static boolean initialization_needed = TRUE;
274 static SDL_Surface *surface_screen_copy = NULL;
275 static SDL_Surface *surface_black = NULL;
276 SDL_Surface *surface_screen = backbuffer->surface;
277 SDL_Surface *surface_cross; /* initialized later */
278 SDL_Rect src_rect, dst_rect;
279 int src_x = 0, src_y = 0;
280 int dst_x = 0, dst_y = 0;
281 boolean fade_reverse = (fade_mode == FADE_MODE_FADE_IN ? TRUE : FALSE);
282 unsigned int time_last, time_current;
288 src_rect.w = video.width;
289 src_rect.h = video.height;
291 #ifdef FULLSCREEN_BUG
292 dst_x += video_xoffset;
293 dst_y += video_yoffset;
298 dst_rect.w = video.width;
299 dst_rect.h = video.height;
302 if (!initialization_needed)
304 /* check if screen size has changed (can happen when toggling fullscreen) */
305 if (surface_screen_copy->w != surface_screen->w ||
306 surface_screen_copy->h != surface_screen->h)
308 SDL_FreeSurface(surface_screen_copy);
309 SDL_FreeSurface(surface_black);
311 initialization_needed = TRUE;
316 if (initialization_needed)
318 unsigned int flags = SDL_SRCALPHA;
320 /* use same surface type as screen surface */
321 if ((surface_screen->flags & SDL_HWSURFACE))
322 flags |= SDL_HWSURFACE;
324 flags |= SDL_SWSURFACE;
326 /* create surface for temporary copy of screen buffer */
327 if ((surface_screen_copy =
328 SDL_CreateRGBSurface(flags,
336 surface_screen->format->BitsPerPixel,
337 surface_screen->format->Rmask,
338 surface_screen->format->Gmask,
339 surface_screen->format->Bmask,
340 surface_screen->format->Amask)) == NULL)
341 Error(ERR_EXIT, "SDL_CreateRGBSurface( ) failed: %s", SDL_GetError());
343 /* create black surface for fading from/to black */
345 SDL_CreateRGBSurface(flags,
353 surface_screen->format->BitsPerPixel,
354 surface_screen->format->Rmask,
355 surface_screen->format->Gmask,
356 surface_screen->format->Bmask,
357 surface_screen->format->Amask)) == NULL)
358 Error(ERR_EXIT, "SDL_CreateRGBSurface( ) failed: %s", SDL_GetError());
360 /* completely fill the surface with black color pixels */
361 SDL_FillRect(surface_black, NULL,
362 SDL_MapRGB(surface_screen->format, 0, 0, 0));
364 initialization_needed = FALSE;
367 /* copy the current screen backbuffer to the temporary screen copy buffer */
368 SDL_BlitSurface(surface_screen, &dst_rect, surface_screen_copy, &src_rect);
370 surface_cross = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_cross->surface :
373 time_current = SDL_GetTicks();
375 for (alpha = 0.0; alpha < 255.0;)
377 time_last = time_current;
378 time_current = SDL_GetTicks();
379 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
380 alpha_final = (int)(fade_reverse ? 255.0 - alpha : alpha);
381 alpha_final = MIN(MAX(0, alpha_final), 255);
383 /* draw existing image to screen buffer */
384 SDL_BlitSurface(surface_screen_copy, &src_rect, surface_screen, &dst_rect);
386 /* draw new image to screen buffer using alpha blending */
387 SDL_SetAlpha(surface_cross, SDL_SRCALPHA, alpha_final);
388 SDL_BlitSurface(surface_cross, &src_rect, surface_screen, &dst_rect);
390 /* draw screen buffer to visible display */
391 SDL_Flip(surface_screen);
397 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
398 int to_x, int to_y, Uint32 color)
400 SDL_Surface *surface = dst_bitmap->surface;
404 swap_numbers(&from_x, &to_x);
407 swap_numbers(&from_y, &to_y);
411 rect.w = (to_x - from_x + 1);
412 rect.h = (to_y - from_y + 1);
414 #ifdef FULLSCREEN_BUG
415 if (dst_bitmap == backbuffer || dst_bitmap == window)
417 rect.x += video_xoffset;
418 rect.y += video_yoffset;
422 SDL_FillRect(surface, &rect, color);
425 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
426 int to_x, int to_y, Uint32 color)
428 #ifdef FULLSCREEN_BUG
429 if (dst_bitmap == backbuffer || dst_bitmap == window)
431 from_x += video_xoffset;
432 from_y += video_yoffset;
433 to_x += video_xoffset;
434 to_y += video_yoffset;
438 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
442 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
443 int num_points, Uint32 color)
448 for (i = 0; i < num_points - 1; i++)
450 for (x = 0; x < line_width; x++)
452 for (y = 0; y < line_width; y++)
454 int dx = x - line_width / 2;
455 int dy = y - line_width / 2;
457 if ((x == 0 && y == 0) ||
458 (x == 0 && y == line_width - 1) ||
459 (x == line_width - 1 && y == 0) ||
460 (x == line_width - 1 && y == line_width - 1))
463 sge_Line(surface, points[i].x + dx, points[i].y + dy,
464 points[i+1].x + dx, points[i+1].y + dy, color);
471 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
473 SDL_Surface *surface = src_bitmap->surface;
475 #ifdef FULLSCREEN_BUG
476 if (src_bitmap == backbuffer || src_bitmap == window)
483 switch (surface->format->BytesPerPixel)
485 case 1: /* assuming 8-bpp */
487 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
491 case 2: /* probably 15-bpp or 16-bpp */
493 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
497 case 3: /* slow 24-bpp mode; usually not used */
499 /* does this work? */
500 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
504 shift = surface->format->Rshift;
505 color |= *(pix + shift / 8) >> shift;
506 shift = surface->format->Gshift;
507 color |= *(pix + shift / 8) >> shift;
508 shift = surface->format->Bshift;
509 color |= *(pix + shift / 8) >> shift;
515 case 4: /* probably 32-bpp */
517 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
526 /* ========================================================================= */
527 /* The following functions were taken from the SGE library */
528 /* (SDL Graphics Extension Library) by Anders Lindström */
529 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
530 /* ========================================================================= */
532 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
534 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
536 switch (surface->format->BytesPerPixel)
541 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
547 /* Probably 15-bpp or 16-bpp */
548 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
554 /* Slow 24-bpp mode, usually not used */
558 /* Gack - slow, but endian correct */
559 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
560 shift = surface->format->Rshift;
561 *(pix+shift/8) = color>>shift;
562 shift = surface->format->Gshift;
563 *(pix+shift/8) = color>>shift;
564 shift = surface->format->Bshift;
565 *(pix+shift/8) = color>>shift;
571 /* Probably 32-bpp */
572 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
579 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
580 Uint8 R, Uint8 G, Uint8 B)
582 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
585 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
587 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
590 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
592 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
595 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
600 /* Gack - slow, but endian correct */
601 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
602 shift = surface->format->Rshift;
603 *(pix+shift/8) = color>>shift;
604 shift = surface->format->Gshift;
605 *(pix+shift/8) = color>>shift;
606 shift = surface->format->Bshift;
607 *(pix+shift/8) = color>>shift;
610 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
612 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
615 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
617 switch (dest->format->BytesPerPixel)
620 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
624 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
628 _PutPixel24(dest,x,y,color);
632 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
637 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
639 if (SDL_MUSTLOCK(surface))
641 if (SDL_LockSurface(surface) < 0)
647 _PutPixel(surface, x, y, color);
649 if (SDL_MUSTLOCK(surface))
651 SDL_UnlockSurface(surface);
655 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
656 Uint8 r, Uint8 g, Uint8 b)
658 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
661 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
663 if (y >= 0 && y <= dest->h - 1)
665 switch (dest->format->BytesPerPixel)
668 return y*dest->pitch;
672 return y*dest->pitch/2;
676 return y*dest->pitch;
680 return y*dest->pitch/4;
688 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
690 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
692 switch (surface->format->BytesPerPixel)
697 *((Uint8 *)surface->pixels + ypitch + x) = color;
703 /* Probably 15-bpp or 16-bpp */
704 *((Uint16 *)surface->pixels + ypitch + x) = color;
710 /* Slow 24-bpp mode, usually not used */
714 /* Gack - slow, but endian correct */
715 pix = (Uint8 *)surface->pixels + ypitch + x*3;
716 shift = surface->format->Rshift;
717 *(pix+shift/8) = color>>shift;
718 shift = surface->format->Gshift;
719 *(pix+shift/8) = color>>shift;
720 shift = surface->format->Bshift;
721 *(pix+shift/8) = color>>shift;
727 /* Probably 32-bpp */
728 *((Uint32 *)surface->pixels + ypitch + x) = color;
735 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
740 if (SDL_MUSTLOCK(Surface))
742 if (SDL_LockSurface(Surface) < 0)
755 /* Do the clipping */
756 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
760 if (x2 > Surface->w - 1)
768 SDL_FillRect(Surface, &l, Color);
770 if (SDL_MUSTLOCK(Surface))
772 SDL_UnlockSurface(Surface);
776 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
777 Uint8 R, Uint8 G, Uint8 B)
779 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
782 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
793 /* Do the clipping */
794 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
798 if (x2 > Surface->w - 1)
806 SDL_FillRect(Surface, &l, Color);
809 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
814 if (SDL_MUSTLOCK(Surface))
816 if (SDL_LockSurface(Surface) < 0)
829 /* Do the clipping */
830 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
834 if (y2 > Surface->h - 1)
842 SDL_FillRect(Surface, &l, Color);
844 if (SDL_MUSTLOCK(Surface))
846 SDL_UnlockSurface(Surface);
850 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
851 Uint8 R, Uint8 G, Uint8 B)
853 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
856 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
867 /* Do the clipping */
868 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
872 if (y2 > Surface->h - 1)
880 SDL_FillRect(Surface, &l, Color);
883 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
884 Sint16 x2, Sint16 y2, Uint32 Color,
885 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
888 Sint16 dx, dy, sdx, sdy, x, y, px, py;
893 sdx = (dx < 0) ? -1 : 1;
894 sdy = (dy < 0) ? -1 : 1;
906 for (x = 0; x < dx; x++)
908 Callback(Surface, px, py, Color);
922 for (y = 0; y < dy; y++)
924 Callback(Surface, px, py, Color);
938 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
939 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
940 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
943 sge_DoLine(Surface, X1, Y1, X2, Y2,
944 SDL_MapRGB(Surface->format, R, G, B), Callback);
947 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
950 if (SDL_MUSTLOCK(Surface))
952 if (SDL_LockSurface(Surface) < 0)
957 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
959 /* unlock the display */
960 if (SDL_MUSTLOCK(Surface))
962 SDL_UnlockSurface(Surface);
966 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
967 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
969 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
972 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
974 #ifdef FULLSCREEN_BUG
975 if (dst_bitmap == backbuffer || dst_bitmap == window)
982 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
987 -----------------------------------------------------------------------------
988 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
989 -----------------------------------------------------------------------------
992 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
993 int width, int height, Uint32 color)
997 for (y = src_y; y < src_y + height; y++)
999 for (x = src_x; x < src_x + width; x++)
1001 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1003 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1008 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1009 int src_x, int src_y, int width, int height,
1010 int dst_x, int dst_y)
1014 for (y = 0; y < height; y++)
1016 for (x = 0; x < width; x++)
1018 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1020 if (pixel != BLACK_PIXEL)
1021 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1027 /* ========================================================================= */
1028 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1029 /* (Rotozoomer) by Andreas Schiffler */
1030 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1031 /* ========================================================================= */
1034 -----------------------------------------------------------------------------
1037 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1038 -----------------------------------------------------------------------------
1049 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1051 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1052 tColorRGBA *sp, *csp, *dp;
1055 /* variable setup */
1056 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1057 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1059 /* allocate memory for row increments */
1060 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1061 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1063 /* precalculate row increments */
1066 for (x = 0; x <= dst->w; x++)
1076 for (y = 0; y <= dst->h; y++)
1085 sp = csp = (tColorRGBA *) src->pixels;
1086 dp = (tColorRGBA *) dst->pixels;
1087 sgap = src->pitch - src->w * 4;
1088 dgap = dst->pitch - dst->w * 4;
1091 for (y = 0; y < dst->h; y++)
1096 for (x = 0; x < dst->w; x++)
1101 /* advance source pointers */
1103 sp += (*csax >> 16);
1105 /* advance destination pointer */
1109 /* advance source pointer */
1111 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1113 /* advance destination pointers */
1114 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1124 -----------------------------------------------------------------------------
1127 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1128 -----------------------------------------------------------------------------
1131 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1133 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1134 Uint8 *sp, *dp, *csp;
1137 /* variable setup */
1138 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1139 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1141 /* allocate memory for row increments */
1142 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1143 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1145 /* precalculate row increments */
1148 for (x = 0; x < dst->w; x++)
1151 *csax = (csx >> 16);
1158 for (y = 0; y < dst->h; y++)
1161 *csay = (csy >> 16);
1168 for (x = 0; x < dst->w; x++)
1176 for (y = 0; y < dst->h; y++)
1183 sp = csp = (Uint8 *) src->pixels;
1184 dp = (Uint8 *) dst->pixels;
1185 dgap = dst->pitch - dst->w;
1189 for (y = 0; y < dst->h; y++)
1193 for (x = 0; x < dst->w; x++)
1198 /* advance source pointers */
1202 /* advance destination pointer */
1206 /* advance source pointer (for row) */
1207 csp += ((*csay) * src->pitch);
1210 /* advance destination pointers */
1221 -----------------------------------------------------------------------------
1224 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1225 'zoomx' and 'zoomy' are scaling factors for width and height.
1226 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
1227 into a 32bit RGBA format on the fly.
1228 -----------------------------------------------------------------------------
1231 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
1233 SDL_Surface *zoom_src = NULL;
1234 SDL_Surface *zoom_dst = NULL;
1235 boolean is_converted = FALSE;
1242 /* determine if source surface is 32 bit or 8 bit */
1243 is_32bit = (src->format->BitsPerPixel == 32);
1245 if (is_32bit || src->format->BitsPerPixel == 8)
1247 /* use source surface 'as is' */
1252 /* new source surface is 32 bit with a defined RGB ordering */
1253 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1254 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
1255 SDL_BlitSurface(src, NULL, zoom_src, NULL);
1257 is_converted = TRUE;
1260 /* allocate surface to completely contain the zoomed surface */
1263 /* target surface is 32 bit with source RGBA/ABGR ordering */
1264 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
1265 zoom_src->format->Rmask,
1266 zoom_src->format->Gmask,
1267 zoom_src->format->Bmask, 0);
1271 /* target surface is 8 bit */
1272 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
1276 /* lock source surface */
1277 SDL_LockSurface(zoom_src);
1279 /* check which kind of surface we have */
1282 /* call the 32 bit transformation routine to do the zooming */
1283 zoomSurfaceRGBA(zoom_src, zoom_dst);
1288 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
1289 zoom_dst->format->palette->colors[i] =
1290 zoom_src->format->palette->colors[i];
1291 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
1293 /* call the 8 bit transformation routine to do the zooming */
1294 zoomSurfaceY(zoom_src, zoom_dst);
1297 /* unlock source surface */
1298 SDL_UnlockSurface(zoom_src);
1300 /* free temporary surface */
1302 SDL_FreeSurface(zoom_src);
1304 /* return destination surface */
1308 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
1310 SDL_Surface *sdl_surface_tmp;
1311 int dst_width = dst_bitmap->width;
1312 int dst_height = dst_bitmap->height;
1314 /* throw away old destination surface */
1315 SDL_FreeSurface(dst_bitmap->surface);
1317 /* create zoomed temporary surface from source surface */
1318 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
1320 /* create native format destination surface from zoomed temporary surface */
1321 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
1323 /* free temporary surface */
1324 SDL_FreeSurface(sdl_surface_tmp);
1328 /* ========================================================================= */
1329 /* load image to bitmap */
1330 /* ========================================================================= */
1332 Bitmap *SDLLoadImage(char *filename)
1334 Bitmap *new_bitmap = CreateBitmapStruct();
1335 SDL_Surface *sdl_image_tmp;
1337 /* load image to temporary surface */
1338 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
1340 SetError("IMG_Load(): %s", SDL_GetError());
1344 /* create native non-transparent surface for current image */
1345 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1347 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1351 /* create native transparent surface for current image */
1352 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
1353 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
1354 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1356 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1360 /* free temporary surface */
1361 SDL_FreeSurface(sdl_image_tmp);
1363 new_bitmap->width = new_bitmap->surface->w;
1364 new_bitmap->height = new_bitmap->surface->h;
1370 /* ------------------------------------------------------------------------- */
1371 /* custom cursor fuctions */
1372 /* ------------------------------------------------------------------------- */
1374 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
1376 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
1377 cursor_info->width, cursor_info->height,
1378 cursor_info->hot_x, cursor_info->hot_y);
1381 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
1383 static struct MouseCursorInfo *last_cursor_info = NULL;
1384 static struct MouseCursorInfo *last_cursor_info2 = NULL;
1385 static SDL_Cursor *cursor_default = NULL;
1386 static SDL_Cursor *cursor_current = NULL;
1388 /* if invoked for the first time, store the SDL default cursor */
1389 if (cursor_default == NULL)
1390 cursor_default = SDL_GetCursor();
1392 /* only create new cursor if cursor info (custom only) has changed */
1393 if (cursor_info != NULL && cursor_info != last_cursor_info)
1395 cursor_current = create_cursor(cursor_info);
1396 last_cursor_info = cursor_info;
1399 /* only set new cursor if cursor info (custom or NULL) has changed */
1400 if (cursor_info != last_cursor_info2)
1401 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
1403 last_cursor_info2 = cursor_info;
1407 /* ========================================================================= */
1408 /* audio functions */
1409 /* ========================================================================= */
1411 void SDLOpenAudio(void)
1413 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
1414 putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
1416 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
1418 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
1422 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
1423 AUDIO_NUM_CHANNELS_STEREO,
1424 setup.system.audio_fragment_size) < 0)
1426 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
1430 audio.sound_available = TRUE;
1431 audio.music_available = TRUE;
1432 audio.loops_available = TRUE;
1433 audio.sound_enabled = TRUE;
1435 /* set number of available mixer channels */
1436 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
1437 audio.music_channel = MUSIC_CHANNEL;
1438 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
1440 Mixer_InitChannels();
1443 void SDLCloseAudio(void)
1446 Mix_HaltChannel(-1);
1449 SDL_QuitSubSystem(SDL_INIT_AUDIO);
1453 /* ========================================================================= */
1454 /* event functions */
1455 /* ========================================================================= */
1457 void SDLNextEvent(Event *event)
1459 SDL_WaitEvent(event);
1461 #ifdef FULLSCREEN_BUG
1462 if (event->type == EVENT_BUTTONPRESS ||
1463 event->type == EVENT_BUTTONRELEASE)
1465 if (((ButtonEvent *)event)->x > video_xoffset)
1466 ((ButtonEvent *)event)->x -= video_xoffset;
1468 ((ButtonEvent *)event)->x = 0;
1469 if (((ButtonEvent *)event)->y > video_yoffset)
1470 ((ButtonEvent *)event)->y -= video_yoffset;
1472 ((ButtonEvent *)event)->y = 0;
1474 else if (event->type == EVENT_MOTIONNOTIFY)
1476 if (((MotionEvent *)event)->x > video_xoffset)
1477 ((MotionEvent *)event)->x -= video_xoffset;
1479 ((MotionEvent *)event)->x = 0;
1480 if (((MotionEvent *)event)->y > video_yoffset)
1481 ((MotionEvent *)event)->y -= video_yoffset;
1483 ((MotionEvent *)event)->y = 0;
1489 /* ========================================================================= */
1490 /* joystick functions */
1491 /* ========================================================================= */
1493 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
1494 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1495 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1497 static boolean SDLOpenJoystick(int nr)
1499 if (nr < 0 || nr > MAX_PLAYERS)
1502 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
1505 static void SDLCloseJoystick(int nr)
1507 if (nr < 0 || nr > MAX_PLAYERS)
1510 SDL_JoystickClose(sdl_joystick[nr]);
1513 static boolean SDLCheckJoystickOpened(int nr)
1515 if (nr < 0 || nr > MAX_PLAYERS)
1518 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
1521 void HandleJoystickEvent(Event *event)
1525 case SDL_JOYAXISMOTION:
1526 if (event->jaxis.axis < 2)
1527 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
1530 case SDL_JOYBUTTONDOWN:
1531 if (event->jbutton.button < 2)
1532 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
1535 case SDL_JOYBUTTONUP:
1536 if (event->jbutton.button < 2)
1537 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
1545 void SDLInitJoysticks()
1547 static boolean sdl_joystick_subsystem_initialized = FALSE;
1548 boolean print_warning = !sdl_joystick_subsystem_initialized;
1551 if (!sdl_joystick_subsystem_initialized)
1553 sdl_joystick_subsystem_initialized = TRUE;
1555 if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
1557 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
1562 for (i = 0; i < MAX_PLAYERS; i++)
1564 /* get configured joystick for this player */
1565 char *device_name = setup.input[i].joy.device_name;
1566 int joystick_nr = getJoystickNrFromDeviceName(device_name);
1568 if (joystick_nr >= SDL_NumJoysticks())
1570 if (setup.input[i].use_joystick && print_warning)
1571 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
1576 /* misuse joystick file descriptor variable to store joystick number */
1577 joystick.fd[i] = joystick_nr;
1579 if (joystick_nr == -1)
1582 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
1583 if (SDLCheckJoystickOpened(joystick_nr))
1584 SDLCloseJoystick(joystick_nr);
1586 if (!setup.input[i].use_joystick)
1589 if (!SDLOpenJoystick(joystick_nr))
1592 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
1597 joystick.status = JOYSTICK_ACTIVATED;
1601 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1603 if (nr < 0 || nr >= MAX_PLAYERS)
1607 *x = sdl_js_axis[nr][0];
1609 *y = sdl_js_axis[nr][1];
1612 *b1 = sdl_js_button[nr][0];
1614 *b2 = sdl_js_button[nr][1];
1619 #endif /* TARGET_SDL */