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_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1052 tColorRGBA *sp, *csp, *dp;
1056 sp = csp = (tColorRGBA *) src->pixels;
1057 dp = (tColorRGBA *) dst->pixels;
1058 sgap = src->pitch - src->w * 4;
1059 dgap = dst->pitch - dst->w * 4;
1061 for (y = 0; y < dst->h; y++)
1065 for (x = 0; x < dst->w; x++)
1067 tColorRGBA *sp0 = sp;
1068 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1069 tColorRGBA *sp00 = &sp0[0];
1070 tColorRGBA *sp01 = &sp0[1];
1071 tColorRGBA *sp10 = &sp1[0];
1072 tColorRGBA *sp11 = &sp1[1];
1075 /* create new color pixel from all four source color pixels */
1076 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1077 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1078 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1079 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1084 /* advance source pointers */
1087 /* advance destination pointer */
1091 /* advance source pointer */
1092 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1094 /* advance destination pointers */
1095 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1101 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1103 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1104 tColorRGBA *sp, *csp, *dp;
1107 /* use specialized zoom function when scaling down to exactly half size */
1108 if (src->w == 2 * dst->w &&
1109 src->h == 2 * dst->h)
1110 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1112 /* variable setup */
1113 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1114 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1116 /* allocate memory for row increments */
1117 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1118 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1120 /* precalculate row increments */
1123 for (x = 0; x <= dst->w; x++)
1133 for (y = 0; y <= dst->h; y++)
1142 sp = csp = (tColorRGBA *) src->pixels;
1143 dp = (tColorRGBA *) dst->pixels;
1144 sgap = src->pitch - src->w * 4;
1145 dgap = dst->pitch - dst->w * 4;
1148 for (y = 0; y < dst->h; y++)
1153 for (x = 0; x < dst->w; x++)
1158 /* advance source pointers */
1160 sp += (*csax >> 16);
1162 /* advance destination pointer */
1166 /* advance source pointer */
1168 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1170 /* advance destination pointers */
1171 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1181 -----------------------------------------------------------------------------
1184 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1185 -----------------------------------------------------------------------------
1188 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1190 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1191 Uint8 *sp, *dp, *csp;
1194 /* variable setup */
1195 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1196 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1198 /* allocate memory for row increments */
1199 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1200 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1202 /* precalculate row increments */
1205 for (x = 0; x < dst->w; x++)
1208 *csax = (csx >> 16);
1215 for (y = 0; y < dst->h; y++)
1218 *csay = (csy >> 16);
1225 for (x = 0; x < dst->w; x++)
1233 for (y = 0; y < dst->h; y++)
1240 sp = csp = (Uint8 *) src->pixels;
1241 dp = (Uint8 *) dst->pixels;
1242 dgap = dst->pitch - dst->w;
1246 for (y = 0; y < dst->h; y++)
1250 for (x = 0; x < dst->w; x++)
1255 /* advance source pointers */
1259 /* advance destination pointer */
1263 /* advance source pointer (for row) */
1264 csp += ((*csay) * src->pitch);
1267 /* advance destination pointers */
1278 -----------------------------------------------------------------------------
1281 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1282 'zoomx' and 'zoomy' are scaling factors for width and height.
1283 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
1284 into a 32bit RGBA format on the fly.
1285 -----------------------------------------------------------------------------
1288 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
1290 SDL_Surface *zoom_src = NULL;
1291 SDL_Surface *zoom_dst = NULL;
1292 boolean is_converted = FALSE;
1299 /* determine if source surface is 32 bit or 8 bit */
1300 is_32bit = (src->format->BitsPerPixel == 32);
1302 if (is_32bit || src->format->BitsPerPixel == 8)
1304 /* use source surface 'as is' */
1309 /* new source surface is 32 bit with a defined RGB ordering */
1310 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1311 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
1312 SDL_BlitSurface(src, NULL, zoom_src, NULL);
1314 is_converted = TRUE;
1317 /* allocate surface to completely contain the zoomed surface */
1320 /* target surface is 32 bit with source RGBA/ABGR ordering */
1321 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
1322 zoom_src->format->Rmask,
1323 zoom_src->format->Gmask,
1324 zoom_src->format->Bmask, 0);
1328 /* target surface is 8 bit */
1329 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
1333 /* lock source surface */
1334 SDL_LockSurface(zoom_src);
1336 /* check which kind of surface we have */
1339 /* call the 32 bit transformation routine to do the zooming */
1340 zoomSurfaceRGBA(zoom_src, zoom_dst);
1345 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
1346 zoom_dst->format->palette->colors[i] =
1347 zoom_src->format->palette->colors[i];
1348 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
1350 /* call the 8 bit transformation routine to do the zooming */
1351 zoomSurfaceY(zoom_src, zoom_dst);
1354 /* unlock source surface */
1355 SDL_UnlockSurface(zoom_src);
1357 /* free temporary surface */
1359 SDL_FreeSurface(zoom_src);
1361 /* return destination surface */
1365 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
1367 SDL_Surface *sdl_surface_tmp;
1368 int dst_width = dst_bitmap->width;
1369 int dst_height = dst_bitmap->height;
1371 /* throw away old destination surface */
1372 SDL_FreeSurface(dst_bitmap->surface);
1374 /* create zoomed temporary surface from source surface */
1375 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
1377 /* create native format destination surface from zoomed temporary surface */
1378 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
1380 /* free temporary surface */
1381 SDL_FreeSurface(sdl_surface_tmp);
1385 /* ========================================================================= */
1386 /* load image to bitmap */
1387 /* ========================================================================= */
1389 Bitmap *SDLLoadImage(char *filename)
1391 Bitmap *new_bitmap = CreateBitmapStruct();
1392 SDL_Surface *sdl_image_tmp;
1394 /* load image to temporary surface */
1395 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
1397 SetError("IMG_Load(): %s", SDL_GetError());
1401 /* create native non-transparent surface for current image */
1402 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1404 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1408 /* create native transparent surface for current image */
1409 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
1410 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
1411 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1413 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1417 /* free temporary surface */
1418 SDL_FreeSurface(sdl_image_tmp);
1420 new_bitmap->width = new_bitmap->surface->w;
1421 new_bitmap->height = new_bitmap->surface->h;
1427 /* ------------------------------------------------------------------------- */
1428 /* custom cursor fuctions */
1429 /* ------------------------------------------------------------------------- */
1431 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
1433 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
1434 cursor_info->width, cursor_info->height,
1435 cursor_info->hot_x, cursor_info->hot_y);
1438 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
1440 static struct MouseCursorInfo *last_cursor_info = NULL;
1441 static struct MouseCursorInfo *last_cursor_info2 = NULL;
1442 static SDL_Cursor *cursor_default = NULL;
1443 static SDL_Cursor *cursor_current = NULL;
1445 /* if invoked for the first time, store the SDL default cursor */
1446 if (cursor_default == NULL)
1447 cursor_default = SDL_GetCursor();
1449 /* only create new cursor if cursor info (custom only) has changed */
1450 if (cursor_info != NULL && cursor_info != last_cursor_info)
1452 cursor_current = create_cursor(cursor_info);
1453 last_cursor_info = cursor_info;
1456 /* only set new cursor if cursor info (custom or NULL) has changed */
1457 if (cursor_info != last_cursor_info2)
1458 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
1460 last_cursor_info2 = cursor_info;
1464 /* ========================================================================= */
1465 /* audio functions */
1466 /* ========================================================================= */
1468 void SDLOpenAudio(void)
1470 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
1471 putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
1473 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
1475 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
1479 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
1480 AUDIO_NUM_CHANNELS_STEREO,
1481 setup.system.audio_fragment_size) < 0)
1483 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
1487 audio.sound_available = TRUE;
1488 audio.music_available = TRUE;
1489 audio.loops_available = TRUE;
1490 audio.sound_enabled = TRUE;
1492 /* set number of available mixer channels */
1493 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
1494 audio.music_channel = MUSIC_CHANNEL;
1495 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
1497 Mixer_InitChannels();
1500 void SDLCloseAudio(void)
1503 Mix_HaltChannel(-1);
1506 SDL_QuitSubSystem(SDL_INIT_AUDIO);
1510 /* ========================================================================= */
1511 /* event functions */
1512 /* ========================================================================= */
1514 void SDLNextEvent(Event *event)
1516 SDL_WaitEvent(event);
1518 #ifdef FULLSCREEN_BUG
1519 if (event->type == EVENT_BUTTONPRESS ||
1520 event->type == EVENT_BUTTONRELEASE)
1522 if (((ButtonEvent *)event)->x > video_xoffset)
1523 ((ButtonEvent *)event)->x -= video_xoffset;
1525 ((ButtonEvent *)event)->x = 0;
1526 if (((ButtonEvent *)event)->y > video_yoffset)
1527 ((ButtonEvent *)event)->y -= video_yoffset;
1529 ((ButtonEvent *)event)->y = 0;
1531 else if (event->type == EVENT_MOTIONNOTIFY)
1533 if (((MotionEvent *)event)->x > video_xoffset)
1534 ((MotionEvent *)event)->x -= video_xoffset;
1536 ((MotionEvent *)event)->x = 0;
1537 if (((MotionEvent *)event)->y > video_yoffset)
1538 ((MotionEvent *)event)->y -= video_yoffset;
1540 ((MotionEvent *)event)->y = 0;
1546 /* ========================================================================= */
1547 /* joystick functions */
1548 /* ========================================================================= */
1550 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
1551 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1552 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1554 static boolean SDLOpenJoystick(int nr)
1556 if (nr < 0 || nr > MAX_PLAYERS)
1559 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
1562 static void SDLCloseJoystick(int nr)
1564 if (nr < 0 || nr > MAX_PLAYERS)
1567 SDL_JoystickClose(sdl_joystick[nr]);
1570 static boolean SDLCheckJoystickOpened(int nr)
1572 if (nr < 0 || nr > MAX_PLAYERS)
1575 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
1578 void HandleJoystickEvent(Event *event)
1582 case SDL_JOYAXISMOTION:
1583 if (event->jaxis.axis < 2)
1584 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
1587 case SDL_JOYBUTTONDOWN:
1588 if (event->jbutton.button < 2)
1589 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
1592 case SDL_JOYBUTTONUP:
1593 if (event->jbutton.button < 2)
1594 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
1602 void SDLInitJoysticks()
1604 static boolean sdl_joystick_subsystem_initialized = FALSE;
1605 boolean print_warning = !sdl_joystick_subsystem_initialized;
1608 if (!sdl_joystick_subsystem_initialized)
1610 sdl_joystick_subsystem_initialized = TRUE;
1612 if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
1614 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
1619 for (i = 0; i < MAX_PLAYERS; i++)
1621 /* get configured joystick for this player */
1622 char *device_name = setup.input[i].joy.device_name;
1623 int joystick_nr = getJoystickNrFromDeviceName(device_name);
1625 if (joystick_nr >= SDL_NumJoysticks())
1627 if (setup.input[i].use_joystick && print_warning)
1628 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
1633 /* misuse joystick file descriptor variable to store joystick number */
1634 joystick.fd[i] = joystick_nr;
1636 if (joystick_nr == -1)
1639 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
1640 if (SDLCheckJoystickOpened(joystick_nr))
1641 SDLCloseJoystick(joystick_nr);
1643 if (!setup.input[i].use_joystick)
1646 if (!SDLOpenJoystick(joystick_nr))
1649 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
1654 joystick.status = JOYSTICK_ACTIVATED;
1658 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1660 if (nr < 0 || nr >= MAX_PLAYERS)
1664 *x = sdl_js_axis[nr][0];
1666 *y = sdl_js_axis[nr][1];
1669 *b1 = sdl_js_button[nr][0];
1671 *b2 = sdl_js_button[nr][1];
1676 #endif /* TARGET_SDL */