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_InitSubSystem(SDL_INIT_VIDEO) < 0)
28 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
30 /* set default SDL depth */
31 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
34 inline void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
37 /* open SDL video output device (window or fullscreen mode) */
38 if (!SDLSetVideoMode(backbuffer, fullscreen))
39 Error(ERR_EXIT, "setting video mode failed");
41 /* set window and icon title */
42 SDL_WM_SetCaption(program.window_title, program.window_title);
44 /* SDL cannot directly draw to the visible video framebuffer like X11,
45 but always uses a backbuffer, which is then blitted to the visible
46 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
47 visible video framebuffer with 'SDL_Flip', if the hardware supports
48 this). Therefore do not use an additional backbuffer for drawing, but
49 use a symbolic buffer (distinguishable from the SDL backbuffer) called
50 'window', which indicates that the SDL backbuffer should be updated to
51 the visible video framebuffer when attempting to blit to it.
53 For convenience, it seems to be a good idea to create this symbolic
54 buffer 'window' at the same size as the SDL backbuffer. Although it
55 should never be drawn to directly, it would do no harm nevertheless. */
57 /* create additional (symbolic) buffer for double-buffering */
58 *window = CreateBitmap(video.width, video.height, video.depth);
61 inline boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
63 boolean success = TRUE;
64 int surface_flags = SDL_HWSURFACE | (fullscreen ? SDL_FULLSCREEN : 0);
66 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
68 /* switch display to fullscreen mode, if available */
69 DrawWindow *window_old = *backbuffer;
70 DrawWindow *window_new = CreateBitmapStruct();
72 if ((window_new->surface = SDL_SetVideoMode(video.width, video.height,
73 video.depth, surface_flags))
76 /* switching display to fullscreen mode failed */
77 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
79 /* do not try it again */
80 video.fullscreen_available = FALSE;
86 FreeBitmap(window_old);
87 *backbuffer = window_new;
89 video.fullscreen_enabled = TRUE;
94 if ((!fullscreen && video.fullscreen_enabled) || !*backbuffer)
96 /* switch display to window mode */
97 DrawWindow *window_old = *backbuffer;
98 DrawWindow *window_new = CreateBitmapStruct();
100 if ((window_new->surface = SDL_SetVideoMode(video.width, video.height,
101 video.depth, surface_flags))
104 /* switching display to window mode failed -- should not happen */
105 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
112 FreeBitmap(window_old);
113 *backbuffer = window_new;
115 video.fullscreen_enabled = FALSE;
123 inline void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
124 int src_x, int src_y,
125 int width, int height,
126 int dst_x, int dst_y, int copy_mode)
128 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
129 SDL_Rect src_rect, dst_rect;
141 if (src_bitmap != backbuffer || dst_bitmap != window)
142 SDL_BlitSurface((copy_mode == SDLCOPYAREA_MASKED ?
143 src_bitmap->surface_masked : src_bitmap->surface),
144 &src_rect, real_dst_bitmap->surface, &dst_rect);
146 if (dst_bitmap == window)
147 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
150 inline void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y,
151 int width, int height, unsigned int color)
153 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
155 unsigned int color_r = (color >> 16) && 0xff;
156 unsigned int color_g = (color >> 8) && 0xff;
157 unsigned int color_b = (color >> 0) && 0xff;
164 SDL_FillRect(real_dst_bitmap->surface, &rect,
165 SDL_MapRGB(real_dst_bitmap->surface->format,
166 color_r, color_g, color_b));
168 if (dst_bitmap == window)
169 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
172 inline void SDLDrawSimpleLine(SDL_Surface *surface, int from_x, int from_y,
173 int to_x, int to_y, unsigned int color)
176 unsigned int color_r = (color >> 16) & 0xff;
177 unsigned int color_g = (color >> 8) & 0xff;
178 unsigned int color_b = (color >> 0) & 0xff;
181 swap_numbers(&from_x, &to_x);
184 swap_numbers(&from_y, &to_y);
188 rect.w = (to_x - from_x + 1);
189 rect.h = (to_y - from_y + 1);
191 SDL_FillRect(surface, &rect,
192 SDL_MapRGB(surface->format, color_r, color_g, color_b));
195 inline void SDLDrawLine(SDL_Surface *surface, int from_x, int from_y,
196 int to_x, int to_y, Uint32 color)
198 sge_Line(surface, from_x, from_y, to_x, to_y, color);
202 inline void SDLDrawLines(SDL_Surface *surface, struct XY *points,
203 int num_points, Uint32 color)
208 for (i=0; i<num_points - 1; i++)
210 for (x=0; x<line_width; x++)
212 for (y=0; y<line_width; y++)
214 int dx = x - line_width / 2;
215 int dy = y - line_width / 2;
217 if ((x == 0 && y == 0) ||
218 (x == 0 && y == line_width - 1) ||
219 (x == line_width - 1 && y == 0) ||
220 (x == line_width - 1 && y == line_width - 1))
223 sge_Line(surface, points[i].x + dx, points[i].y + dy,
224 points[i+1].x + dx, points[i+1].y + dy, color);
232 /* ========================================================================= */
233 /* The following functions have been taken from the SGE library */
234 /* (SDL Graphics Extension Library) by Anders Lindström */
235 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
236 /* ========================================================================= */
238 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
240 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
242 switch (surface->format->BytesPerPixel)
247 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
253 /* Probably 15-bpp or 16-bpp */
254 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
260 /* Slow 24-bpp mode, usually not used */
264 /* Gack - slow, but endian correct */
265 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
266 shift = surface->format->Rshift;
267 *(pix+shift/8) = color>>shift;
268 shift = surface->format->Gshift;
269 *(pix+shift/8) = color>>shift;
270 shift = surface->format->Bshift;
271 *(pix+shift/8) = color>>shift;
277 /* Probably 32-bpp */
278 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
285 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
286 Uint8 R, Uint8 G, Uint8 B)
288 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
291 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
293 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
296 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
298 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
301 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
306 /* Gack - slow, but endian correct */
307 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
308 shift = surface->format->Rshift;
309 *(pix+shift/8) = color>>shift;
310 shift = surface->format->Gshift;
311 *(pix+shift/8) = color>>shift;
312 shift = surface->format->Bshift;
313 *(pix+shift/8) = color>>shift;
316 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
318 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
321 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
323 switch (dest->format->BytesPerPixel)
326 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
330 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
334 _PutPixel24(dest,x,y,color);
338 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
343 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
345 if (SDL_MUSTLOCK(surface))
347 if (SDL_LockSurface(surface) < 0)
353 _PutPixel(surface, x, y, color);
355 if (SDL_MUSTLOCK(surface))
357 SDL_UnlockSurface(surface);
361 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
362 Uint8 R, Uint8 G, Uint8 B)
364 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
367 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
369 if (y >= 0 && y <= dest->h - 1)
371 switch (dest->format->BytesPerPixel)
374 return y*dest->pitch;
378 return y*dest->pitch/2;
382 return y*dest->pitch;
386 return y*dest->pitch/4;
394 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
396 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
398 switch (surface->format->BytesPerPixel)
403 *((Uint8 *)surface->pixels + ypitch + x) = color;
409 /* Probably 15-bpp or 16-bpp */
410 *((Uint16 *)surface->pixels + ypitch + x) = color;
416 /* Slow 24-bpp mode, usually not used */
420 /* Gack - slow, but endian correct */
421 pix = (Uint8 *)surface->pixels + ypitch + x*3;
422 shift = surface->format->Rshift;
423 *(pix+shift/8) = color>>shift;
424 shift = surface->format->Gshift;
425 *(pix+shift/8) = color>>shift;
426 shift = surface->format->Bshift;
427 *(pix+shift/8) = color>>shift;
433 /* Probably 32-bpp */
434 *((Uint32 *)surface->pixels + ypitch + x) = color;
441 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
446 if (SDL_MUSTLOCK(Surface))
448 if (SDL_LockSurface(Surface) < 0)
461 /* Do the clipping */
462 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
466 if (x2 > Surface->w - 1)
474 SDL_FillRect(Surface, &l, Color);
476 if (SDL_MUSTLOCK(Surface))
478 SDL_UnlockSurface(Surface);
482 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
483 Uint8 R, Uint8 G, Uint8 B)
485 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
488 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
499 /* Do the clipping */
500 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
504 if (x2 > Surface->w - 1)
512 SDL_FillRect(Surface, &l, Color);
515 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
520 if (SDL_MUSTLOCK(Surface))
522 if (SDL_LockSurface(Surface) < 0)
535 /* Do the clipping */
536 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
540 if (y2 > Surface->h - 1)
548 SDL_FillRect(Surface, &l, Color);
550 if (SDL_MUSTLOCK(Surface))
552 SDL_UnlockSurface(Surface);
556 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
557 Uint8 R, Uint8 G, Uint8 B)
559 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
562 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
573 /* Do the clipping */
574 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
578 if (y2 > Surface->h - 1)
586 SDL_FillRect(Surface, &l, Color);
589 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
590 Sint16 x2, Sint16 y2, Uint32 Color,
591 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
594 Sint16 dx, dy, sdx, sdy, x, y, px, py;
599 sdx = (dx < 0) ? -1 : 1;
600 sdy = (dy < 0) ? -1 : 1;
612 for (x = 0; x < dx; x++)
614 Callback(Surface, px, py, Color);
628 for (y = 0; y < dy; y++)
630 Callback(Surface, px, py, Color);
644 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
645 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
646 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
649 sge_DoLine(Surface, X1, Y1, X2, Y2,
650 SDL_MapRGB(Surface->format, R, G, B), Callback);
653 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
656 if (SDL_MUSTLOCK(Surface))
658 if (SDL_LockSurface(Surface) < 0)
663 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
665 /* unlock the display */
666 if (SDL_MUSTLOCK(Surface))
668 SDL_UnlockSurface(Surface);
672 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
673 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
675 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
678 Bitmap *SDLLoadImage(char *filename)
680 Bitmap *new_bitmap = CreateBitmapStruct();
681 SDL_Surface *sdl_image_tmp;
683 /* load image to temporary surface */
684 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
685 Error(ERR_EXIT, "IMG_Load() failed: %s", SDL_GetError());
687 /* create native non-transparent surface for current image */
688 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
689 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
691 /* create native transparent surface for current image */
692 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
693 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
694 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
695 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
697 /* free temporary surface */
698 SDL_FreeSurface(sdl_image_tmp);
704 /* ========================================================================= */
705 /* audio functions */
706 /* ========================================================================= */
708 inline boolean SDLOpenAudio(void)
710 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
712 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
716 if (Mix_OpenAudio(22050, AUDIO_S16, 2, 512) < 0)
718 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
722 Mix_Volume(-1, SDL_MIX_MAXVOLUME / 4);
723 Mix_VolumeMusic(SDL_MIX_MAXVOLUME / 4);
728 inline void SDLCloseAudio(void)
736 #endif /* TARGET_SDL */