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 ***********************************************************/
19 #if defined(TARGET_SDL)
21 /* ========================================================================= */
23 /* ========================================================================= */
25 inline void SDLInitVideoDisplay(void)
27 /* initialize SDL video */
28 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
29 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
31 /* set default SDL depth */
32 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
35 inline void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
38 /* open SDL video output device (window or fullscreen mode) */
39 if (!SDLSetVideoMode(backbuffer, fullscreen))
40 Error(ERR_EXIT, "setting video mode failed");
42 /* set window and icon title */
43 SDL_WM_SetCaption(program.window_title, program.window_title);
45 /* SDL cannot directly draw to the visible video framebuffer like X11,
46 but always uses a backbuffer, which is then blitted to the visible
47 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
48 visible video framebuffer with 'SDL_Flip', if the hardware supports
49 this). Therefore do not use an additional backbuffer for drawing, but
50 use a symbolic buffer (distinguishable from the SDL backbuffer) called
51 'window', which indicates that the SDL backbuffer should be updated to
52 the visible video framebuffer when attempting to blit to it.
54 For convenience, it seems to be a good idea to create this symbolic
55 buffer 'window' at the same size as the SDL backbuffer. Although it
56 should never be drawn to directly, it would do no harm nevertheless. */
58 /* create additional (symbolic) buffer for double-buffering */
59 *window = CreateBitmap(video.width, video.height, video.depth);
62 inline boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
64 boolean success = TRUE;
65 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
66 int surface_flags_window = SURFACE_FLAGS;
67 SDL_Surface *new_surface = NULL;
69 if (*backbuffer == NULL)
70 *backbuffer = CreateBitmapStruct();
72 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
74 /* switch display to fullscreen mode, if available */
75 if ((new_surface = SDL_SetVideoMode(video.width, video.height,
76 video.depth, surface_flags_fullscreen))
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;
88 (*backbuffer)->surface = new_surface;
90 video.fullscreen_enabled = TRUE;
95 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
97 /* switch display to window mode */
98 if ((new_surface = SDL_SetVideoMode(video.width, video.height,
99 video.depth, surface_flags_window))
102 /* switching display to window mode failed -- should not happen */
103 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
109 (*backbuffer)->surface = new_surface;
111 video.fullscreen_enabled = FALSE;
119 inline void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
120 int src_x, int src_y,
121 int width, int height,
122 int dst_x, int dst_y, int copy_mode)
124 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
125 SDL_Rect src_rect, dst_rect;
137 if (src_bitmap != backbuffer || dst_bitmap != window)
138 SDL_BlitSurface((copy_mode == SDLCOPYAREA_MASKED ?
139 src_bitmap->surface_masked : src_bitmap->surface),
140 &src_rect, real_dst_bitmap->surface, &dst_rect);
142 if (dst_bitmap == window)
143 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
146 inline void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y,
147 int width, int height, unsigned int color)
149 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
151 unsigned int color_r = (color >> 16) && 0xff;
152 unsigned int color_g = (color >> 8) && 0xff;
153 unsigned int color_b = (color >> 0) && 0xff;
160 SDL_FillRect(real_dst_bitmap->surface, &rect,
161 SDL_MapRGB(real_dst_bitmap->surface->format,
162 color_r, color_g, color_b));
164 if (dst_bitmap == window)
165 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
168 inline void SDLDrawSimpleLine(SDL_Surface *surface, int from_x, int from_y,
169 int to_x, int to_y, unsigned int color)
172 unsigned int color_r = (color >> 16) & 0xff;
173 unsigned int color_g = (color >> 8) & 0xff;
174 unsigned int color_b = (color >> 0) & 0xff;
177 swap_numbers(&from_x, &to_x);
180 swap_numbers(&from_y, &to_y);
184 rect.w = (to_x - from_x + 1);
185 rect.h = (to_y - from_y + 1);
187 SDL_FillRect(surface, &rect,
188 SDL_MapRGB(surface->format, color_r, color_g, color_b));
191 inline void SDLDrawLine(SDL_Surface *surface, int from_x, int from_y,
192 int to_x, int to_y, Uint32 color)
194 sge_Line(surface, from_x, from_y, to_x, to_y, color);
198 inline void SDLDrawLines(SDL_Surface *surface, struct XY *points,
199 int num_points, Uint32 color)
204 for (i=0; i<num_points - 1; i++)
206 for (x=0; x<line_width; x++)
208 for (y=0; y<line_width; y++)
210 int dx = x - line_width / 2;
211 int dy = y - line_width / 2;
213 if ((x == 0 && y == 0) ||
214 (x == 0 && y == line_width - 1) ||
215 (x == line_width - 1 && y == 0) ||
216 (x == line_width - 1 && y == line_width - 1))
219 sge_Line(surface, points[i].x + dx, points[i].y + dy,
220 points[i+1].x + dx, points[i+1].y + dy, color);
228 /* ========================================================================= */
229 /* The following functions have been taken from the SGE library */
230 /* (SDL Graphics Extension Library) by Anders Lindström */
231 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
232 /* ========================================================================= */
234 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
236 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
238 switch (surface->format->BytesPerPixel)
243 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
249 /* Probably 15-bpp or 16-bpp */
250 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
256 /* Slow 24-bpp mode, usually not used */
260 /* Gack - slow, but endian correct */
261 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
262 shift = surface->format->Rshift;
263 *(pix+shift/8) = color>>shift;
264 shift = surface->format->Gshift;
265 *(pix+shift/8) = color>>shift;
266 shift = surface->format->Bshift;
267 *(pix+shift/8) = color>>shift;
273 /* Probably 32-bpp */
274 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
281 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
282 Uint8 R, Uint8 G, Uint8 B)
284 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
287 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
289 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
292 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
294 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
297 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
302 /* Gack - slow, but endian correct */
303 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
304 shift = surface->format->Rshift;
305 *(pix+shift/8) = color>>shift;
306 shift = surface->format->Gshift;
307 *(pix+shift/8) = color>>shift;
308 shift = surface->format->Bshift;
309 *(pix+shift/8) = color>>shift;
312 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
314 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
317 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
319 switch (dest->format->BytesPerPixel)
322 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
326 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
330 _PutPixel24(dest,x,y,color);
334 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
339 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
341 if (SDL_MUSTLOCK(surface))
343 if (SDL_LockSurface(surface) < 0)
349 _PutPixel(surface, x, y, color);
351 if (SDL_MUSTLOCK(surface))
353 SDL_UnlockSurface(surface);
357 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
358 Uint8 R, Uint8 G, Uint8 B)
360 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
363 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
365 if (y >= 0 && y <= dest->h - 1)
367 switch (dest->format->BytesPerPixel)
370 return y*dest->pitch;
374 return y*dest->pitch/2;
378 return y*dest->pitch;
382 return y*dest->pitch/4;
390 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
392 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
394 switch (surface->format->BytesPerPixel)
399 *((Uint8 *)surface->pixels + ypitch + x) = color;
405 /* Probably 15-bpp or 16-bpp */
406 *((Uint16 *)surface->pixels + ypitch + x) = color;
412 /* Slow 24-bpp mode, usually not used */
416 /* Gack - slow, but endian correct */
417 pix = (Uint8 *)surface->pixels + ypitch + x*3;
418 shift = surface->format->Rshift;
419 *(pix+shift/8) = color>>shift;
420 shift = surface->format->Gshift;
421 *(pix+shift/8) = color>>shift;
422 shift = surface->format->Bshift;
423 *(pix+shift/8) = color>>shift;
429 /* Probably 32-bpp */
430 *((Uint32 *)surface->pixels + ypitch + x) = color;
437 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
442 if (SDL_MUSTLOCK(Surface))
444 if (SDL_LockSurface(Surface) < 0)
457 /* Do the clipping */
458 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
462 if (x2 > Surface->w - 1)
470 SDL_FillRect(Surface, &l, Color);
472 if (SDL_MUSTLOCK(Surface))
474 SDL_UnlockSurface(Surface);
478 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
479 Uint8 R, Uint8 G, Uint8 B)
481 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
484 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
495 /* Do the clipping */
496 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
500 if (x2 > Surface->w - 1)
508 SDL_FillRect(Surface, &l, Color);
511 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
516 if (SDL_MUSTLOCK(Surface))
518 if (SDL_LockSurface(Surface) < 0)
531 /* Do the clipping */
532 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
536 if (y2 > Surface->h - 1)
544 SDL_FillRect(Surface, &l, Color);
546 if (SDL_MUSTLOCK(Surface))
548 SDL_UnlockSurface(Surface);
552 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
553 Uint8 R, Uint8 G, Uint8 B)
555 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
558 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
569 /* Do the clipping */
570 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
574 if (y2 > Surface->h - 1)
582 SDL_FillRect(Surface, &l, Color);
585 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
586 Sint16 x2, Sint16 y2, Uint32 Color,
587 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
590 Sint16 dx, dy, sdx, sdy, x, y, px, py;
595 sdx = (dx < 0) ? -1 : 1;
596 sdy = (dy < 0) ? -1 : 1;
608 for (x = 0; x < dx; x++)
610 Callback(Surface, px, py, Color);
624 for (y = 0; y < dy; y++)
626 Callback(Surface, px, py, Color);
640 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
641 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
642 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
645 sge_DoLine(Surface, X1, Y1, X2, Y2,
646 SDL_MapRGB(Surface->format, R, G, B), Callback);
649 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
652 if (SDL_MUSTLOCK(Surface))
654 if (SDL_LockSurface(Surface) < 0)
659 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
661 /* unlock the display */
662 if (SDL_MUSTLOCK(Surface))
664 SDL_UnlockSurface(Surface);
668 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
669 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
671 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
674 Bitmap *SDLLoadImage(char *filename)
676 Bitmap *new_bitmap = CreateBitmapStruct();
677 SDL_Surface *sdl_image_tmp;
679 /* load image to temporary surface */
680 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
681 Error(ERR_EXIT, "IMG_Load() failed: %s", SDL_GetError());
683 /* create native non-transparent surface for current image */
684 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
685 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
687 /* create native transparent surface for current image */
688 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
689 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
690 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
691 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
693 /* free temporary surface */
694 SDL_FreeSurface(sdl_image_tmp);
700 /* ========================================================================= */
701 /* audio functions */
702 /* ========================================================================= */
704 inline void SDLOpenAudio(void)
706 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
708 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
712 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, AUDIO_S16,
713 AUDIO_STEREO_CHANNELS,
714 DEFAULT_AUDIO_FRAGMENT_SIZE) < 0)
716 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
720 audio.sound_available = TRUE;
721 audio.music_available = TRUE;
722 audio.loops_available = TRUE;
723 audio.sound_enabled = TRUE;
725 /* determine number of available channels */
726 audio.channels = Mix_AllocateChannels(MIX_CHANNELS);
728 if (!audio.mods_available) /* reserve first channel for music loops */
730 if (Mix_ReserveChannels(1) == 1)
731 audio.music_channel = 0;
733 audio.music_available = FALSE;
736 Mix_Volume(-1, SOUND_MAX_VOLUME);
737 Mix_VolumeMusic(SOUND_MAX_VOLUME);
740 inline void SDLCloseAudio(void)
746 SDL_QuitSubSystem(SDL_INIT_AUDIO);
749 #endif /* TARGET_SDL */