1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2000 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
18 #if defined(TARGET_SDL)
20 /* ========================================================================= */
22 /* ========================================================================= */
24 inline void SDLInitVideoDisplay(void)
26 /* initialize SDL video */
27 if (SDL_Init(SDL_INIT_VIDEO) < 0)
28 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
30 /* set default SDL depth */
31 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
33 /* set exit function to automatically cleanup SDL stuff after exit() */
37 inline void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
40 /* open SDL video output device (window or fullscreen mode) */
41 if (!SDLSetVideoMode(backbuffer, fullscreen))
42 Error(ERR_EXIT, "setting video mode failed");
44 /* set window and icon title */
45 SDL_WM_SetCaption(program.window_title, program.window_title);
47 /* SDL cannot directly draw to the visible video framebuffer like X11,
48 but always uses a backbuffer, which is then blitted to the visible
49 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
50 visible video framebuffer with 'SDL_Flip', if the hardware supports
51 this). Therefore do not use an additional backbuffer for drawing, but
52 use a symbolic buffer (distinguishable from the SDL backbuffer) called
53 'window', which indicates that the SDL backbuffer should be updated to
54 the visible video framebuffer when attempting to blit to it.
56 For convenience, it seems to be a good idea to create this symbolic
57 buffer 'window' at the same size as the SDL backbuffer. Although it
58 should never be drawn to directly, it would do no harm nevertheless. */
60 /* create additional (symbolic) buffer for double-buffering */
61 *window = CreateBitmap(video.width, video.height, video.depth);
64 inline boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
66 boolean success = TRUE;
67 int surface_flags = SDL_HWSURFACE | (fullscreen ? SDL_FULLSCREEN : 0);
69 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
71 /* switch display to fullscreen mode, if available */
72 DrawWindow *window_old = *backbuffer;
73 DrawWindow *window_new = CreateBitmapStruct();
75 if ((window_new->surface = SDL_SetVideoMode(video.width, video.height,
76 video.depth, surface_flags))
79 /* switching display to fullscreen mode failed */
80 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
82 /* do not try it again */
83 video.fullscreen_available = FALSE;
89 FreeBitmap(window_old);
90 *backbuffer = window_new;
92 video.fullscreen_enabled = TRUE;
97 if ((!fullscreen && video.fullscreen_enabled) || !*backbuffer)
99 /* switch display to window mode */
100 DrawWindow *window_old = *backbuffer;
101 DrawWindow *window_new = CreateBitmapStruct();
103 if ((window_new->surface = SDL_SetVideoMode(video.width, video.height,
104 video.depth, surface_flags))
107 /* switching display to window mode failed -- should not happen */
108 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
115 FreeBitmap(window_old);
116 *backbuffer = window_new;
118 video.fullscreen_enabled = FALSE;
126 inline void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
127 int src_x, int src_y,
128 int width, int height,
129 int dst_x, int dst_y, int copy_mode)
131 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
132 SDL_Rect src_rect, dst_rect;
144 if (src_bitmap != backbuffer || dst_bitmap != window)
145 SDL_BlitSurface((copy_mode == SDLCOPYAREA_MASKED ?
146 src_bitmap->surface_masked : src_bitmap->surface),
147 &src_rect, real_dst_bitmap->surface, &dst_rect);
149 if (dst_bitmap == window)
150 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
153 inline void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y,
154 int width, int height, unsigned int color)
156 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
158 unsigned int color_r = (color >> 16) && 0xff;
159 unsigned int color_g = (color >> 8) && 0xff;
160 unsigned int color_b = (color >> 0) && 0xff;
167 SDL_FillRect(real_dst_bitmap->surface, &rect,
168 SDL_MapRGB(real_dst_bitmap->surface->format,
169 color_r, color_g, color_b));
171 if (dst_bitmap == window)
172 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
175 inline void SDLDrawSimpleLine(SDL_Surface *surface, int from_x, int from_y,
176 int to_x, int to_y, unsigned int color)
179 unsigned int color_r = (color >> 16) & 0xff;
180 unsigned int color_g = (color >> 8) & 0xff;
181 unsigned int color_b = (color >> 0) & 0xff;
184 swap_numbers(&from_x, &to_x);
187 swap_numbers(&from_y, &to_y);
191 rect.w = (to_x - from_x + 1);
192 rect.h = (to_y - from_y + 1);
194 SDL_FillRect(surface, &rect,
195 SDL_MapRGB(surface->format, color_r, color_g, color_b));
198 inline void SDLDrawLine(SDL_Surface *surface, int from_x, int from_y,
199 int to_x, int to_y, Uint32 color)
201 sge_Line(surface, from_x, from_y, to_x, to_y, color);
205 inline void SDLDrawLines(SDL_Surface *surface, struct XY *points,
206 int num_points, Uint32 color)
211 for (i=0; i<num_points - 1; i++)
213 for (x=0; x<line_width; x++)
215 for (y=0; y<line_width; y++)
217 int dx = x - line_width / 2;
218 int dy = y - line_width / 2;
220 if ((x == 0 && y == 0) ||
221 (x == 0 && y == line_width - 1) ||
222 (x == line_width - 1 && y == 0) ||
223 (x == line_width - 1 && y == line_width - 1))
226 sge_Line(surface, points[i].x + dx, points[i].y + dy,
227 points[i+1].x + dx, points[i+1].y + dy, color);
235 /* ========================================================================= */
236 /* The following functions have been taken from the SGE library */
237 /* (SDL Graphics Extension Library) by Anders Lindström */
238 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
239 /* ========================================================================= */
241 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
243 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
245 switch (surface->format->BytesPerPixel)
250 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
256 /* Probably 15-bpp or 16-bpp */
257 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
263 /* Slow 24-bpp mode, usually not used */
267 /* Gack - slow, but endian correct */
268 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
269 shift = surface->format->Rshift;
270 *(pix+shift/8) = color>>shift;
271 shift = surface->format->Gshift;
272 *(pix+shift/8) = color>>shift;
273 shift = surface->format->Bshift;
274 *(pix+shift/8) = color>>shift;
280 /* Probably 32-bpp */
281 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
288 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
289 Uint8 R, Uint8 G, Uint8 B)
291 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
294 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
296 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
299 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
301 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
304 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
309 /* Gack - slow, but endian correct */
310 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
311 shift = surface->format->Rshift;
312 *(pix+shift/8) = color>>shift;
313 shift = surface->format->Gshift;
314 *(pix+shift/8) = color>>shift;
315 shift = surface->format->Bshift;
316 *(pix+shift/8) = color>>shift;
319 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
321 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
324 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
326 switch (dest->format->BytesPerPixel)
329 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
333 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
337 _PutPixel24(dest,x,y,color);
341 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
346 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
348 if (SDL_MUSTLOCK(surface))
350 if (SDL_LockSurface(surface) < 0)
356 _PutPixel(surface, x, y, color);
358 if (SDL_MUSTLOCK(surface))
360 SDL_UnlockSurface(surface);
364 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
365 Uint8 R, Uint8 G, Uint8 B)
367 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
370 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
372 if (y >= 0 && y <= dest->h - 1)
374 switch (dest->format->BytesPerPixel)
377 return y*dest->pitch;
381 return y*dest->pitch/2;
385 return y*dest->pitch;
389 return y*dest->pitch/4;
397 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
399 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
401 switch (surface->format->BytesPerPixel)
406 *((Uint8 *)surface->pixels + ypitch + x) = color;
412 /* Probably 15-bpp or 16-bpp */
413 *((Uint16 *)surface->pixels + ypitch + x) = color;
419 /* Slow 24-bpp mode, usually not used */
423 /* Gack - slow, but endian correct */
424 pix = (Uint8 *)surface->pixels + ypitch + x*3;
425 shift = surface->format->Rshift;
426 *(pix+shift/8) = color>>shift;
427 shift = surface->format->Gshift;
428 *(pix+shift/8) = color>>shift;
429 shift = surface->format->Bshift;
430 *(pix+shift/8) = color>>shift;
436 /* Probably 32-bpp */
437 *((Uint32 *)surface->pixels + ypitch + x) = color;
444 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
449 if (SDL_MUSTLOCK(Surface))
451 if (SDL_LockSurface(Surface) < 0)
464 /* Do the clipping */
465 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
469 if (x2 > Surface->w - 1)
477 SDL_FillRect(Surface, &l, Color);
479 if (SDL_MUSTLOCK(Surface))
481 SDL_UnlockSurface(Surface);
485 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
486 Uint8 R, Uint8 G, Uint8 B)
488 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
491 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
502 /* Do the clipping */
503 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
507 if (x2 > Surface->w - 1)
515 SDL_FillRect(Surface, &l, Color);
518 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
523 if (SDL_MUSTLOCK(Surface))
525 if (SDL_LockSurface(Surface) < 0)
538 /* Do the clipping */
539 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
543 if (y2 > Surface->h - 1)
551 SDL_FillRect(Surface, &l, Color);
553 if (SDL_MUSTLOCK(Surface))
555 SDL_UnlockSurface(Surface);
559 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
560 Uint8 R, Uint8 G, Uint8 B)
562 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
565 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
576 /* Do the clipping */
577 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
581 if (y2 > Surface->h - 1)
589 SDL_FillRect(Surface, &l, Color);
592 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
593 Sint16 x2, Sint16 y2, Uint32 Color,
594 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
597 Sint16 dx, dy, sdx, sdy, x, y, px, py;
602 sdx = (dx < 0) ? -1 : 1;
603 sdy = (dy < 0) ? -1 : 1;
615 for (x = 0; x < dx; x++)
617 Callback(Surface, px, py, Color);
631 for (y = 0; y < dy; y++)
633 Callback(Surface, px, py, Color);
647 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
648 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
649 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
652 sge_DoLine(Surface, X1, Y1, X2, Y2,
653 SDL_MapRGB(Surface->format, R, G, B), Callback);
656 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
659 if (SDL_MUSTLOCK(Surface))
661 if (SDL_LockSurface(Surface) < 0)
666 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
668 /* unlock the display */
669 if (SDL_MUSTLOCK(Surface))
671 SDL_UnlockSurface(Surface);
675 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
676 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
678 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
681 Bitmap *SDLLoadImage(char *filename)
683 Bitmap *new_bitmap = CreateBitmapStruct();
684 SDL_Surface *sdl_image_tmp;
686 /* load image to temporary surface */
687 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
688 Error(ERR_EXIT, "IMG_Load() failed: %s", SDL_GetError());
690 /* create native non-transparent surface for current image */
691 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
692 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
694 /* create native transparent surface for current image */
695 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
696 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
697 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
698 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
700 /* free temporary surface */
701 SDL_FreeSurface(sdl_image_tmp);
707 /* ========================================================================= */
708 /* audio functions */
709 /* ========================================================================= */
711 inline boolean SDLOpenAudio(void)
713 if (SDL_Init(SDL_INIT_AUDIO) < 0)
715 Error(ERR_WARN, "SDL_Init() failed: %s", SDL_GetError());
719 if (Mix_OpenAudio(22050, AUDIO_S16, 2, 512) < 0)
721 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
725 Mix_Volume(-1, SDL_MIX_MAXVOLUME / 4);
726 Mix_VolumeMusic(SDL_MIX_MAXVOLUME / 4);
731 inline void SDLCloseAudio(void)
739 #endif /* TARGET_SDL */