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 = SDL_HWSURFACE | (fullscreen ? SDL_FULLSCREEN : 0);
67 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
69 /* switch display to fullscreen mode, if available */
70 DrawWindow *window_old = *backbuffer;
71 DrawWindow *window_new = CreateBitmapStruct();
73 if ((window_new->surface = SDL_SetVideoMode(video.width, video.height,
74 video.depth, surface_flags))
77 /* switching display to fullscreen mode failed */
78 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
80 /* do not try it again */
81 video.fullscreen_available = FALSE;
87 FreeBitmap(window_old);
88 *backbuffer = window_new;
90 video.fullscreen_enabled = TRUE;
95 if ((!fullscreen && video.fullscreen_enabled) || !*backbuffer)
97 /* switch display to window mode */
98 DrawWindow *window_old = *backbuffer;
99 DrawWindow *window_new = CreateBitmapStruct();
101 if ((window_new->surface = SDL_SetVideoMode(video.width, video.height,
102 video.depth, surface_flags))
105 /* switching display to window mode failed -- should not happen */
106 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
113 FreeBitmap(window_old);
114 *backbuffer = window_new;
116 video.fullscreen_enabled = FALSE;
124 inline void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
125 int src_x, int src_y,
126 int width, int height,
127 int dst_x, int dst_y, int copy_mode)
129 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
130 SDL_Rect src_rect, dst_rect;
142 if (src_bitmap != backbuffer || dst_bitmap != window)
143 SDL_BlitSurface((copy_mode == SDLCOPYAREA_MASKED ?
144 src_bitmap->surface_masked : src_bitmap->surface),
145 &src_rect, real_dst_bitmap->surface, &dst_rect);
147 if (dst_bitmap == window)
148 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
151 inline void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y,
152 int width, int height, unsigned int color)
154 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
156 unsigned int color_r = (color >> 16) && 0xff;
157 unsigned int color_g = (color >> 8) && 0xff;
158 unsigned int color_b = (color >> 0) && 0xff;
165 SDL_FillRect(real_dst_bitmap->surface, &rect,
166 SDL_MapRGB(real_dst_bitmap->surface->format,
167 color_r, color_g, color_b));
169 if (dst_bitmap == window)
170 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
173 inline void SDLDrawSimpleLine(SDL_Surface *surface, int from_x, int from_y,
174 int to_x, int to_y, unsigned int color)
177 unsigned int color_r = (color >> 16) & 0xff;
178 unsigned int color_g = (color >> 8) & 0xff;
179 unsigned int color_b = (color >> 0) & 0xff;
182 swap_numbers(&from_x, &to_x);
185 swap_numbers(&from_y, &to_y);
189 rect.w = (to_x - from_x + 1);
190 rect.h = (to_y - from_y + 1);
192 SDL_FillRect(surface, &rect,
193 SDL_MapRGB(surface->format, color_r, color_g, color_b));
196 inline void SDLDrawLine(SDL_Surface *surface, int from_x, int from_y,
197 int to_x, int to_y, Uint32 color)
199 sge_Line(surface, from_x, from_y, to_x, to_y, color);
203 inline void SDLDrawLines(SDL_Surface *surface, struct XY *points,
204 int num_points, Uint32 color)
209 for (i=0; i<num_points - 1; i++)
211 for (x=0; x<line_width; x++)
213 for (y=0; y<line_width; y++)
215 int dx = x - line_width / 2;
216 int dy = y - line_width / 2;
218 if ((x == 0 && y == 0) ||
219 (x == 0 && y == line_width - 1) ||
220 (x == line_width - 1 && y == 0) ||
221 (x == line_width - 1 && y == line_width - 1))
224 sge_Line(surface, points[i].x + dx, points[i].y + dy,
225 points[i+1].x + dx, points[i+1].y + dy, color);
233 /* ========================================================================= */
234 /* The following functions have been taken from the SGE library */
235 /* (SDL Graphics Extension Library) by Anders Lindström */
236 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
237 /* ========================================================================= */
239 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
241 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
243 switch (surface->format->BytesPerPixel)
248 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
254 /* Probably 15-bpp or 16-bpp */
255 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
261 /* Slow 24-bpp mode, usually not used */
265 /* Gack - slow, but endian correct */
266 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
267 shift = surface->format->Rshift;
268 *(pix+shift/8) = color>>shift;
269 shift = surface->format->Gshift;
270 *(pix+shift/8) = color>>shift;
271 shift = surface->format->Bshift;
272 *(pix+shift/8) = color>>shift;
278 /* Probably 32-bpp */
279 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
286 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
287 Uint8 R, Uint8 G, Uint8 B)
289 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
292 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
294 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
297 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
299 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
302 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
307 /* Gack - slow, but endian correct */
308 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
309 shift = surface->format->Rshift;
310 *(pix+shift/8) = color>>shift;
311 shift = surface->format->Gshift;
312 *(pix+shift/8) = color>>shift;
313 shift = surface->format->Bshift;
314 *(pix+shift/8) = color>>shift;
317 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
319 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
322 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
324 switch (dest->format->BytesPerPixel)
327 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
331 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
335 _PutPixel24(dest,x,y,color);
339 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
344 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
346 if (SDL_MUSTLOCK(surface))
348 if (SDL_LockSurface(surface) < 0)
354 _PutPixel(surface, x, y, color);
356 if (SDL_MUSTLOCK(surface))
358 SDL_UnlockSurface(surface);
362 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
363 Uint8 R, Uint8 G, Uint8 B)
365 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
368 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
370 if (y >= 0 && y <= dest->h - 1)
372 switch (dest->format->BytesPerPixel)
375 return y*dest->pitch;
379 return y*dest->pitch/2;
383 return y*dest->pitch;
387 return y*dest->pitch/4;
395 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
397 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
399 switch (surface->format->BytesPerPixel)
404 *((Uint8 *)surface->pixels + ypitch + x) = color;
410 /* Probably 15-bpp or 16-bpp */
411 *((Uint16 *)surface->pixels + ypitch + x) = color;
417 /* Slow 24-bpp mode, usually not used */
421 /* Gack - slow, but endian correct */
422 pix = (Uint8 *)surface->pixels + ypitch + x*3;
423 shift = surface->format->Rshift;
424 *(pix+shift/8) = color>>shift;
425 shift = surface->format->Gshift;
426 *(pix+shift/8) = color>>shift;
427 shift = surface->format->Bshift;
428 *(pix+shift/8) = color>>shift;
434 /* Probably 32-bpp */
435 *((Uint32 *)surface->pixels + ypitch + x) = color;
442 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
447 if (SDL_MUSTLOCK(Surface))
449 if (SDL_LockSurface(Surface) < 0)
462 /* Do the clipping */
463 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
467 if (x2 > Surface->w - 1)
475 SDL_FillRect(Surface, &l, Color);
477 if (SDL_MUSTLOCK(Surface))
479 SDL_UnlockSurface(Surface);
483 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
484 Uint8 R, Uint8 G, Uint8 B)
486 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
489 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
500 /* Do the clipping */
501 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
505 if (x2 > Surface->w - 1)
513 SDL_FillRect(Surface, &l, Color);
516 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
521 if (SDL_MUSTLOCK(Surface))
523 if (SDL_LockSurface(Surface) < 0)
536 /* Do the clipping */
537 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
541 if (y2 > Surface->h - 1)
549 SDL_FillRect(Surface, &l, Color);
551 if (SDL_MUSTLOCK(Surface))
553 SDL_UnlockSurface(Surface);
557 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
558 Uint8 R, Uint8 G, Uint8 B)
560 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
563 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
574 /* Do the clipping */
575 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
579 if (y2 > Surface->h - 1)
587 SDL_FillRect(Surface, &l, Color);
590 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
591 Sint16 x2, Sint16 y2, Uint32 Color,
592 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
595 Sint16 dx, dy, sdx, sdy, x, y, px, py;
600 sdx = (dx < 0) ? -1 : 1;
601 sdy = (dy < 0) ? -1 : 1;
613 for (x = 0; x < dx; x++)
615 Callback(Surface, px, py, Color);
629 for (y = 0; y < dy; y++)
631 Callback(Surface, px, py, Color);
645 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
646 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
647 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
650 sge_DoLine(Surface, X1, Y1, X2, Y2,
651 SDL_MapRGB(Surface->format, R, G, B), Callback);
654 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
657 if (SDL_MUSTLOCK(Surface))
659 if (SDL_LockSurface(Surface) < 0)
664 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
666 /* unlock the display */
667 if (SDL_MUSTLOCK(Surface))
669 SDL_UnlockSurface(Surface);
673 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
674 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
676 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
679 Bitmap *SDLLoadImage(char *filename)
681 Bitmap *new_bitmap = CreateBitmapStruct();
682 SDL_Surface *sdl_image_tmp;
684 /* load image to temporary surface */
685 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
686 Error(ERR_EXIT, "IMG_Load() failed: %s", SDL_GetError());
688 /* create native non-transparent surface for current image */
689 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
690 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
692 /* create native transparent surface for current image */
693 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
694 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
695 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
696 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
698 /* free temporary surface */
699 SDL_FreeSurface(sdl_image_tmp);
705 /* ========================================================================= */
706 /* audio functions */
707 /* ========================================================================= */
709 inline void SDLOpenAudio(void)
711 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
713 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
717 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, AUDIO_S16,
718 AUDIO_STEREO_CHANNELS,
719 DEFAULT_AUDIO_FRAGMENT_SIZE) < 0)
721 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
725 audio.sound_available = TRUE;
726 audio.music_available = TRUE;
727 audio.loops_available = TRUE;
728 audio.sound_enabled = TRUE;
730 /* determine number of available channels */
731 audio.channels = Mix_AllocateChannels(MIX_CHANNELS);
733 if (!audio.mods_available) /* reserve first channel for music loops */
735 if (Mix_ReserveChannels(1) == 1)
736 audio.music_channel = 0;
738 audio.music_available = FALSE;
741 Mix_Volume(-1, SOUND_MAX_VOLUME);
742 Mix_VolumeMusic(SOUND_MAX_VOLUME);
745 inline void SDLCloseAudio(void)
753 #endif /* TARGET_SDL */