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 ***********************************************************/
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()
40 struct ScreenModeInfo *fullscreen_mode;
43 fullscreen_mode = get_screen_mode_from_string(setup.fullscreen_mode);
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 char *filename = getCustomImageFilename(basename);
71 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
76 if ((surface = IMG_Load(filename)) == NULL)
78 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
83 /* set transparent color */
84 SDL_SetColorKey(surface, SDL_SRCCOLORKEY,
85 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
87 SDL_WM_SetIcon(surface, NULL);
90 void SDLInitVideoDisplay(void)
92 putenv("SDL_VIDEO_CENTERED=1");
94 /* initialize SDL video */
95 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
96 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
98 /* set default SDL depth */
99 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
102 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
105 static int screen_xy[][2] =
115 /* default: normal game window size */
116 fullscreen_width = video.width;
117 fullscreen_height = video.height;
118 fullscreen_xoffset = 0;
119 fullscreen_yoffset = 0;
121 for (i = 0; screen_xy[i][0] != -1; i++)
123 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
125 fullscreen_width = screen_xy[i][0];
126 fullscreen_height = screen_xy[i][1];
132 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
133 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
135 /* get available hardware supported fullscreen modes */
136 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
140 /* no screen modes available => no fullscreen mode support */
141 video.fullscreen_available = FALSE;
143 else if (modes == (SDL_Rect **)-1)
145 /* fullscreen resolution is not restricted -- all resolutions available */
146 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
148 /* use native video buffer size for fullscreen mode */
149 video.fullscreen_modes[0].width = video.width;
150 video.fullscreen_modes[0].height = video.height;
152 video.fullscreen_modes[1].width = -1;
153 video.fullscreen_modes[1].height = -1;
157 /* in this case, a certain number of screen modes is available */
160 for(i = 0; modes[i] != NULL; i++)
162 boolean found_mode = FALSE;
164 /* screen mode is smaller than video buffer size -- skip it */
165 if (modes[i]->w < video.width || modes[i]->h < video.height)
168 if (video.fullscreen_modes != NULL)
169 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
170 if (modes[i]->w == video.fullscreen_modes[j].width &&
171 modes[i]->h == video.fullscreen_modes[j].height)
174 if (found_mode) /* screen mode already stored -- skip it */
177 /* new mode found; add it to list of available fullscreen modes */
181 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
183 sizeof(struct ScreenModeInfo));
185 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
186 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
188 video.fullscreen_modes[num_modes].width = -1;
189 video.fullscreen_modes[num_modes].height = -1;
194 /* no appropriate screen modes available => no fullscreen mode support */
195 video.fullscreen_available = FALSE;
199 /* set window icon */
200 SDLSetWindowIcon(program.sdl_icon_filename);
202 /* open SDL video output device (window or fullscreen mode) */
203 if (!SDLSetVideoMode(backbuffer, fullscreen))
204 Error(ERR_EXIT, "setting video mode failed");
206 /* set window and icon title */
207 SDL_WM_SetCaption(program.window_title, program.window_title);
209 /* SDL cannot directly draw to the visible video framebuffer like X11,
210 but always uses a backbuffer, which is then blitted to the visible
211 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
212 visible video framebuffer with 'SDL_Flip', if the hardware supports
213 this). Therefore do not use an additional backbuffer for drawing, but
214 use a symbolic buffer (distinguishable from the SDL backbuffer) called
215 'window', which indicates that the SDL backbuffer should be updated to
216 the visible video framebuffer when attempting to blit to it.
218 For convenience, it seems to be a good idea to create this symbolic
219 buffer 'window' at the same size as the SDL backbuffer. Although it
220 should never be drawn to directly, it would do no harm nevertheless. */
222 /* create additional (symbolic) buffer for double-buffering */
223 *window = CreateBitmap(video.width, video.height, video.depth);
226 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
228 boolean success = TRUE;
229 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
230 int surface_flags_window = SURFACE_FLAGS;
231 SDL_Surface *new_surface = NULL;
233 if (*backbuffer == NULL)
234 *backbuffer = CreateBitmapStruct();
236 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
238 setFullscreenParameters();
240 video_xoffset = fullscreen_xoffset;
241 video_yoffset = fullscreen_yoffset;
243 /* switch display to fullscreen mode, if available */
244 if ((new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
245 video.depth, surface_flags_fullscreen))
248 /* switching display to fullscreen mode failed */
249 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
251 /* do not try it again */
252 video.fullscreen_available = FALSE;
257 (*backbuffer)->surface = new_surface;
259 video.fullscreen_enabled = TRUE;
264 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
269 /* switch display to window mode */
270 if ((new_surface = SDL_SetVideoMode(video.width, video.height,
271 video.depth, surface_flags_window))
274 /* switching display to window mode failed -- should not happen */
275 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
281 (*backbuffer)->surface = new_surface;
283 video.fullscreen_enabled = FALSE;
291 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
294 SDL_Surface *surface_tmp, *surface_native;
296 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
299 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
301 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
302 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
304 SDL_FreeSurface(surface_tmp);
306 new_bitmap->surface = surface_native;
309 void SDLFreeBitmapPointers(Bitmap *bitmap)
312 SDL_FreeSurface(bitmap->surface);
313 if (bitmap->surface_masked)
314 SDL_FreeSurface(bitmap->surface_masked);
315 bitmap->surface = NULL;
316 bitmap->surface_masked = NULL;
319 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
320 int src_x, int src_y, int width, int height,
321 int dst_x, int dst_y, int mask_mode)
323 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
324 SDL_Rect src_rect, dst_rect;
326 if (src_bitmap == backbuffer)
328 src_x += video_xoffset;
329 src_y += video_yoffset;
337 if (dst_bitmap == backbuffer || dst_bitmap == window)
339 dst_x += video_xoffset;
340 dst_y += video_yoffset;
348 if (src_bitmap != backbuffer || dst_bitmap != window)
349 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
350 src_bitmap->surface_masked : src_bitmap->surface),
351 &src_rect, real_dst_bitmap->surface, &dst_rect);
353 if (dst_bitmap == window)
354 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
357 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
360 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
363 if (dst_bitmap == backbuffer || dst_bitmap == window)
374 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
376 if (dst_bitmap == window)
377 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
380 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
381 int fade_mode, int fade_delay, int post_delay)
383 static boolean initialization_needed = TRUE;
384 static SDL_Surface *surface_source = NULL;
385 static SDL_Surface *surface_target = NULL;
386 static SDL_Surface *surface_black = NULL;
387 SDL_Surface *surface_screen = backbuffer->surface;
388 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
389 SDL_Rect src_rect, dst_rect;
390 int src_x = x, src_y = y;
391 int dst_x = x, dst_y = y;
392 boolean fade_reverse = (fade_mode == FADE_MODE_FADE_IN ? TRUE : FALSE);
393 unsigned int time_last, time_current;
402 dst_x += video_xoffset;
403 dst_y += video_yoffset;
410 if (initialization_needed)
412 unsigned int flags = SDL_SRCALPHA;
414 /* use same surface type as screen surface */
415 if ((surface_screen->flags & SDL_HWSURFACE))
416 flags |= SDL_HWSURFACE;
418 flags |= SDL_SWSURFACE;
420 /* create surface for temporary copy of screen buffer (source) */
421 if ((surface_source =
422 SDL_CreateRGBSurface(flags,
425 surface_screen->format->BitsPerPixel,
426 surface_screen->format->Rmask,
427 surface_screen->format->Gmask,
428 surface_screen->format->Bmask,
429 surface_screen->format->Amask)) == NULL)
430 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
432 /* create surface for cross-fading screen buffer (target) */
433 if ((surface_target =
434 SDL_CreateRGBSurface(flags,
437 surface_screen->format->BitsPerPixel,
438 surface_screen->format->Rmask,
439 surface_screen->format->Gmask,
440 surface_screen->format->Bmask,
441 surface_screen->format->Amask)) == NULL)
442 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
444 /* create black surface for fading from/to black */
446 SDL_CreateRGBSurface(flags,
449 surface_screen->format->BitsPerPixel,
450 surface_screen->format->Rmask,
451 surface_screen->format->Gmask,
452 surface_screen->format->Bmask,
453 surface_screen->format->Amask)) == NULL)
454 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
456 /* completely fill the surface with black color pixels */
457 SDL_FillRect(surface_black, NULL,
458 SDL_MapRGB(surface_screen->format, 0, 0, 0));
460 initialization_needed = FALSE;
463 /* copy source and target surfaces to temporary surfaces for fading */
464 if (fade_mode == FADE_MODE_CROSSFADE)
466 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
467 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
471 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
472 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
475 time_current = SDL_GetTicks();
477 for (alpha = 0.0; alpha < 255.0;)
479 time_last = time_current;
480 time_current = SDL_GetTicks();
481 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
482 alpha_final = (int)(fade_reverse ? 255.0 - alpha : alpha);
483 alpha_final = MIN(MAX(0, alpha_final), 255);
485 /* draw existing (source) image to screen buffer */
486 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
488 /* draw new (target) image to screen buffer using alpha blending */
489 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
490 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
493 /* only update the region of the screen that is affected from fading */
494 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
496 SDL_Flip(surface_screen);
503 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
504 int to_x, int to_y, Uint32 color)
506 SDL_Surface *surface = dst_bitmap->surface;
510 swap_numbers(&from_x, &to_x);
513 swap_numbers(&from_y, &to_y);
517 rect.w = (to_x - from_x + 1);
518 rect.h = (to_y - from_y + 1);
520 if (dst_bitmap == backbuffer || dst_bitmap == window)
522 rect.x += video_xoffset;
523 rect.y += video_yoffset;
526 SDL_FillRect(surface, &rect, color);
529 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
530 int to_x, int to_y, Uint32 color)
532 if (dst_bitmap == backbuffer || dst_bitmap == window)
534 from_x += video_xoffset;
535 from_y += video_yoffset;
536 to_x += video_xoffset;
537 to_y += video_yoffset;
540 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
544 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
545 int num_points, Uint32 color)
550 for (i = 0; i < num_points - 1; i++)
552 for (x = 0; x < line_width; x++)
554 for (y = 0; y < line_width; y++)
556 int dx = x - line_width / 2;
557 int dy = y - line_width / 2;
559 if ((x == 0 && y == 0) ||
560 (x == 0 && y == line_width - 1) ||
561 (x == line_width - 1 && y == 0) ||
562 (x == line_width - 1 && y == line_width - 1))
565 sge_Line(surface, points[i].x + dx, points[i].y + dy,
566 points[i+1].x + dx, points[i+1].y + dy, color);
573 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
575 SDL_Surface *surface = src_bitmap->surface;
577 if (src_bitmap == backbuffer || src_bitmap == window)
583 switch (surface->format->BytesPerPixel)
585 case 1: /* assuming 8-bpp */
587 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
591 case 2: /* probably 15-bpp or 16-bpp */
593 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
597 case 3: /* slow 24-bpp mode; usually not used */
599 /* does this work? */
600 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
604 shift = surface->format->Rshift;
605 color |= *(pix + shift / 8) >> shift;
606 shift = surface->format->Gshift;
607 color |= *(pix + shift / 8) >> shift;
608 shift = surface->format->Bshift;
609 color |= *(pix + shift / 8) >> shift;
615 case 4: /* probably 32-bpp */
617 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
626 /* ========================================================================= */
627 /* The following functions were taken from the SGE library */
628 /* (SDL Graphics Extension Library) by Anders Lindström */
629 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
630 /* ========================================================================= */
632 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
634 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
636 switch (surface->format->BytesPerPixel)
641 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
647 /* Probably 15-bpp or 16-bpp */
648 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
654 /* Slow 24-bpp mode, usually not used */
658 /* Gack - slow, but endian correct */
659 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
660 shift = surface->format->Rshift;
661 *(pix+shift/8) = color>>shift;
662 shift = surface->format->Gshift;
663 *(pix+shift/8) = color>>shift;
664 shift = surface->format->Bshift;
665 *(pix+shift/8) = color>>shift;
671 /* Probably 32-bpp */
672 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
679 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
680 Uint8 R, Uint8 G, Uint8 B)
682 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
685 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
687 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
690 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
692 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
695 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
700 /* Gack - slow, but endian correct */
701 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
702 shift = surface->format->Rshift;
703 *(pix+shift/8) = color>>shift;
704 shift = surface->format->Gshift;
705 *(pix+shift/8) = color>>shift;
706 shift = surface->format->Bshift;
707 *(pix+shift/8) = color>>shift;
710 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
712 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
715 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
717 switch (dest->format->BytesPerPixel)
720 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
724 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
728 _PutPixel24(dest,x,y,color);
732 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
737 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
739 if (SDL_MUSTLOCK(surface))
741 if (SDL_LockSurface(surface) < 0)
747 _PutPixel(surface, x, y, color);
749 if (SDL_MUSTLOCK(surface))
751 SDL_UnlockSurface(surface);
755 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
756 Uint8 r, Uint8 g, Uint8 b)
758 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
761 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
763 if (y >= 0 && y <= dest->h - 1)
765 switch (dest->format->BytesPerPixel)
768 return y*dest->pitch;
772 return y*dest->pitch/2;
776 return y*dest->pitch;
780 return y*dest->pitch/4;
788 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
790 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
792 switch (surface->format->BytesPerPixel)
797 *((Uint8 *)surface->pixels + ypitch + x) = color;
803 /* Probably 15-bpp or 16-bpp */
804 *((Uint16 *)surface->pixels + ypitch + x) = color;
810 /* Slow 24-bpp mode, usually not used */
814 /* Gack - slow, but endian correct */
815 pix = (Uint8 *)surface->pixels + ypitch + x*3;
816 shift = surface->format->Rshift;
817 *(pix+shift/8) = color>>shift;
818 shift = surface->format->Gshift;
819 *(pix+shift/8) = color>>shift;
820 shift = surface->format->Bshift;
821 *(pix+shift/8) = color>>shift;
827 /* Probably 32-bpp */
828 *((Uint32 *)surface->pixels + ypitch + x) = color;
835 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
840 if (SDL_MUSTLOCK(Surface))
842 if (SDL_LockSurface(Surface) < 0)
855 /* Do the clipping */
856 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
860 if (x2 > Surface->w - 1)
868 SDL_FillRect(Surface, &l, Color);
870 if (SDL_MUSTLOCK(Surface))
872 SDL_UnlockSurface(Surface);
876 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
877 Uint8 R, Uint8 G, Uint8 B)
879 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
882 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
893 /* Do the clipping */
894 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
898 if (x2 > Surface->w - 1)
906 SDL_FillRect(Surface, &l, Color);
909 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
914 if (SDL_MUSTLOCK(Surface))
916 if (SDL_LockSurface(Surface) < 0)
929 /* Do the clipping */
930 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
934 if (y2 > Surface->h - 1)
942 SDL_FillRect(Surface, &l, Color);
944 if (SDL_MUSTLOCK(Surface))
946 SDL_UnlockSurface(Surface);
950 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
951 Uint8 R, Uint8 G, Uint8 B)
953 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
956 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
967 /* Do the clipping */
968 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
972 if (y2 > Surface->h - 1)
980 SDL_FillRect(Surface, &l, Color);
983 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
984 Sint16 x2, Sint16 y2, Uint32 Color,
985 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
988 Sint16 dx, dy, sdx, sdy, x, y, px, py;
993 sdx = (dx < 0) ? -1 : 1;
994 sdy = (dy < 0) ? -1 : 1;
1006 for (x = 0; x < dx; x++)
1008 Callback(Surface, px, py, Color);
1022 for (y = 0; y < dy; y++)
1024 Callback(Surface, px, py, Color);
1038 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1039 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1040 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1043 sge_DoLine(Surface, X1, Y1, X2, Y2,
1044 SDL_MapRGB(Surface->format, R, G, B), Callback);
1047 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1050 if (SDL_MUSTLOCK(Surface))
1052 if (SDL_LockSurface(Surface) < 0)
1057 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1059 /* unlock the display */
1060 if (SDL_MUSTLOCK(Surface))
1062 SDL_UnlockSurface(Surface);
1066 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1067 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1069 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1072 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1074 if (dst_bitmap == backbuffer || dst_bitmap == window)
1080 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1085 -----------------------------------------------------------------------------
1086 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1087 -----------------------------------------------------------------------------
1090 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1091 int width, int height, Uint32 color)
1095 for (y = src_y; y < src_y + height; y++)
1097 for (x = src_x; x < src_x + width; x++)
1099 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1101 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1106 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1107 int src_x, int src_y, int width, int height,
1108 int dst_x, int dst_y)
1112 for (y = 0; y < height; y++)
1114 for (x = 0; x < width; x++)
1116 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1118 if (pixel != BLACK_PIXEL)
1119 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1125 /* ========================================================================= */
1126 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1127 /* (Rotozoomer) by Andreas Schiffler */
1128 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1129 /* ========================================================================= */
1132 -----------------------------------------------------------------------------
1135 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1136 -----------------------------------------------------------------------------
1147 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1150 tColorRGBA *sp, *csp, *dp;
1154 sp = csp = (tColorRGBA *) src->pixels;
1155 dp = (tColorRGBA *) dst->pixels;
1156 sgap = src->pitch - src->w * 4;
1157 dgap = dst->pitch - dst->w * 4;
1159 for (y = 0; y < dst->h; y++)
1163 for (x = 0; x < dst->w; x++)
1165 tColorRGBA *sp0 = sp;
1166 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1167 tColorRGBA *sp00 = &sp0[0];
1168 tColorRGBA *sp01 = &sp0[1];
1169 tColorRGBA *sp10 = &sp1[0];
1170 tColorRGBA *sp11 = &sp1[1];
1173 /* create new color pixel from all four source color pixels */
1174 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1175 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1176 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1177 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1182 /* advance source pointers */
1185 /* advance destination pointer */
1189 /* advance source pointer */
1190 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1192 /* advance destination pointers */
1193 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1199 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1201 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1202 tColorRGBA *sp, *csp, *dp;
1205 /* use specialized zoom function when scaling down to exactly half size */
1206 if (src->w == 2 * dst->w &&
1207 src->h == 2 * dst->h)
1208 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1210 /* variable setup */
1211 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1212 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1214 /* allocate memory for row increments */
1215 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1216 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1218 /* precalculate row increments */
1221 for (x = 0; x <= dst->w; x++)
1231 for (y = 0; y <= dst->h; y++)
1240 sp = csp = (tColorRGBA *) src->pixels;
1241 dp = (tColorRGBA *) dst->pixels;
1242 sgap = src->pitch - src->w * 4;
1243 dgap = dst->pitch - dst->w * 4;
1246 for (y = 0; y < dst->h; y++)
1251 for (x = 0; x < dst->w; x++)
1256 /* advance source pointers */
1258 sp += (*csax >> 16);
1260 /* advance destination pointer */
1264 /* advance source pointer */
1266 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1268 /* advance destination pointers */
1269 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1279 -----------------------------------------------------------------------------
1282 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1283 -----------------------------------------------------------------------------
1286 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1288 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1289 Uint8 *sp, *dp, *csp;
1292 /* variable setup */
1293 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1294 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1296 /* allocate memory for row increments */
1297 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1298 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1300 /* precalculate row increments */
1303 for (x = 0; x < dst->w; x++)
1306 *csax = (csx >> 16);
1313 for (y = 0; y < dst->h; y++)
1316 *csay = (csy >> 16);
1323 for (x = 0; x < dst->w; x++)
1331 for (y = 0; y < dst->h; y++)
1338 sp = csp = (Uint8 *) src->pixels;
1339 dp = (Uint8 *) dst->pixels;
1340 dgap = dst->pitch - dst->w;
1344 for (y = 0; y < dst->h; y++)
1348 for (x = 0; x < dst->w; x++)
1353 /* advance source pointers */
1357 /* advance destination pointer */
1361 /* advance source pointer (for row) */
1362 csp += ((*csay) * src->pitch);
1365 /* advance destination pointers */
1376 -----------------------------------------------------------------------------
1379 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1380 'zoomx' and 'zoomy' are scaling factors for width and height.
1381 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
1382 into a 32bit RGBA format on the fly.
1383 -----------------------------------------------------------------------------
1386 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
1388 SDL_Surface *zoom_src = NULL;
1389 SDL_Surface *zoom_dst = NULL;
1390 boolean is_converted = FALSE;
1397 /* determine if source surface is 32 bit or 8 bit */
1398 is_32bit = (src->format->BitsPerPixel == 32);
1400 if (is_32bit || src->format->BitsPerPixel == 8)
1402 /* use source surface 'as is' */
1407 /* new source surface is 32 bit with a defined RGB ordering */
1408 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1409 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
1410 SDL_BlitSurface(src, NULL, zoom_src, NULL);
1412 is_converted = TRUE;
1415 /* allocate surface to completely contain the zoomed surface */
1418 /* target surface is 32 bit with source RGBA/ABGR ordering */
1419 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
1420 zoom_src->format->Rmask,
1421 zoom_src->format->Gmask,
1422 zoom_src->format->Bmask, 0);
1426 /* target surface is 8 bit */
1427 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
1431 /* lock source surface */
1432 SDL_LockSurface(zoom_src);
1434 /* check which kind of surface we have */
1437 /* call the 32 bit transformation routine to do the zooming */
1438 zoomSurfaceRGBA(zoom_src, zoom_dst);
1443 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
1444 zoom_dst->format->palette->colors[i] =
1445 zoom_src->format->palette->colors[i];
1446 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
1448 /* call the 8 bit transformation routine to do the zooming */
1449 zoomSurfaceY(zoom_src, zoom_dst);
1452 /* unlock source surface */
1453 SDL_UnlockSurface(zoom_src);
1455 /* free temporary surface */
1457 SDL_FreeSurface(zoom_src);
1459 /* return destination surface */
1463 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
1465 SDL_Surface *sdl_surface_tmp;
1466 int dst_width = dst_bitmap->width;
1467 int dst_height = dst_bitmap->height;
1469 /* throw away old destination surface */
1470 SDL_FreeSurface(dst_bitmap->surface);
1472 /* create zoomed temporary surface from source surface */
1473 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
1475 /* create native format destination surface from zoomed temporary surface */
1476 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
1478 /* free temporary surface */
1479 SDL_FreeSurface(sdl_surface_tmp);
1483 /* ========================================================================= */
1484 /* load image to bitmap */
1485 /* ========================================================================= */
1487 Bitmap *SDLLoadImage(char *filename)
1489 Bitmap *new_bitmap = CreateBitmapStruct();
1490 SDL_Surface *sdl_image_tmp;
1492 /* load image to temporary surface */
1493 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
1495 SetError("IMG_Load(): %s", SDL_GetError());
1500 /* create native non-transparent surface for current image */
1501 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1503 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1508 /* create native transparent surface for current image */
1509 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
1510 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
1511 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1513 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1518 /* free temporary surface */
1519 SDL_FreeSurface(sdl_image_tmp);
1521 new_bitmap->width = new_bitmap->surface->w;
1522 new_bitmap->height = new_bitmap->surface->h;
1528 /* ------------------------------------------------------------------------- */
1529 /* custom cursor fuctions */
1530 /* ------------------------------------------------------------------------- */
1532 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
1534 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
1535 cursor_info->width, cursor_info->height,
1536 cursor_info->hot_x, cursor_info->hot_y);
1539 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
1541 static struct MouseCursorInfo *last_cursor_info = NULL;
1542 static struct MouseCursorInfo *last_cursor_info2 = NULL;
1543 static SDL_Cursor *cursor_default = NULL;
1544 static SDL_Cursor *cursor_current = NULL;
1546 /* if invoked for the first time, store the SDL default cursor */
1547 if (cursor_default == NULL)
1548 cursor_default = SDL_GetCursor();
1550 /* only create new cursor if cursor info (custom only) has changed */
1551 if (cursor_info != NULL && cursor_info != last_cursor_info)
1553 cursor_current = create_cursor(cursor_info);
1554 last_cursor_info = cursor_info;
1557 /* only set new cursor if cursor info (custom or NULL) has changed */
1558 if (cursor_info != last_cursor_info2)
1559 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
1561 last_cursor_info2 = cursor_info;
1565 /* ========================================================================= */
1566 /* audio functions */
1567 /* ========================================================================= */
1569 void SDLOpenAudio(void)
1571 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
1572 putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
1574 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
1576 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
1580 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
1581 AUDIO_NUM_CHANNELS_STEREO,
1582 setup.system.audio_fragment_size) < 0)
1584 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
1588 audio.sound_available = TRUE;
1589 audio.music_available = TRUE;
1590 audio.loops_available = TRUE;
1591 audio.sound_enabled = TRUE;
1593 /* set number of available mixer channels */
1594 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
1595 audio.music_channel = MUSIC_CHANNEL;
1596 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
1598 Mixer_InitChannels();
1601 void SDLCloseAudio(void)
1604 Mix_HaltChannel(-1);
1607 SDL_QuitSubSystem(SDL_INIT_AUDIO);
1611 /* ========================================================================= */
1612 /* event functions */
1613 /* ========================================================================= */
1615 void SDLNextEvent(Event *event)
1617 SDL_WaitEvent(event);
1619 if (event->type == EVENT_BUTTONPRESS ||
1620 event->type == EVENT_BUTTONRELEASE)
1622 if (((ButtonEvent *)event)->x > video_xoffset)
1623 ((ButtonEvent *)event)->x -= video_xoffset;
1625 ((ButtonEvent *)event)->x = 0;
1626 if (((ButtonEvent *)event)->y > video_yoffset)
1627 ((ButtonEvent *)event)->y -= video_yoffset;
1629 ((ButtonEvent *)event)->y = 0;
1631 else if (event->type == EVENT_MOTIONNOTIFY)
1633 if (((MotionEvent *)event)->x > video_xoffset)
1634 ((MotionEvent *)event)->x -= video_xoffset;
1636 ((MotionEvent *)event)->x = 0;
1637 if (((MotionEvent *)event)->y > video_yoffset)
1638 ((MotionEvent *)event)->y -= video_yoffset;
1640 ((MotionEvent *)event)->y = 0;
1645 /* ========================================================================= */
1646 /* joystick functions */
1647 /* ========================================================================= */
1649 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
1650 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1651 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1653 static boolean SDLOpenJoystick(int nr)
1655 if (nr < 0 || nr > MAX_PLAYERS)
1658 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
1661 static void SDLCloseJoystick(int nr)
1663 if (nr < 0 || nr > MAX_PLAYERS)
1666 SDL_JoystickClose(sdl_joystick[nr]);
1669 static boolean SDLCheckJoystickOpened(int nr)
1671 if (nr < 0 || nr > MAX_PLAYERS)
1674 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
1677 void HandleJoystickEvent(Event *event)
1681 case SDL_JOYAXISMOTION:
1682 if (event->jaxis.axis < 2)
1683 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
1686 case SDL_JOYBUTTONDOWN:
1687 if (event->jbutton.button < 2)
1688 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
1691 case SDL_JOYBUTTONUP:
1692 if (event->jbutton.button < 2)
1693 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
1701 void SDLInitJoysticks()
1703 static boolean sdl_joystick_subsystem_initialized = FALSE;
1704 boolean print_warning = !sdl_joystick_subsystem_initialized;
1707 if (!sdl_joystick_subsystem_initialized)
1709 sdl_joystick_subsystem_initialized = TRUE;
1711 if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
1713 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
1718 for (i = 0; i < MAX_PLAYERS; i++)
1720 /* get configured joystick for this player */
1721 char *device_name = setup.input[i].joy.device_name;
1722 int joystick_nr = getJoystickNrFromDeviceName(device_name);
1724 if (joystick_nr >= SDL_NumJoysticks())
1726 if (setup.input[i].use_joystick && print_warning)
1727 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
1732 /* misuse joystick file descriptor variable to store joystick number */
1733 joystick.fd[i] = joystick_nr;
1735 if (joystick_nr == -1)
1738 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
1739 if (SDLCheckJoystickOpened(joystick_nr))
1740 SDLCloseJoystick(joystick_nr);
1742 if (!setup.input[i].use_joystick)
1745 if (!SDLOpenJoystick(joystick_nr))
1748 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
1753 joystick.status = JOYSTICK_ACTIVATED;
1757 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1759 if (nr < 0 || nr >= MAX_PLAYERS)
1763 *x = sdl_js_axis[nr][0];
1765 *y = sdl_js_axis[nr][1];
1768 *b1 = sdl_js_button[nr][0];
1770 *b2 = sdl_js_button[nr][1];
1775 #endif /* TARGET_SDL */