1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2001 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
19 #if defined(TARGET_SDL)
21 /* ========================================================================= */
23 /* ========================================================================= */
25 /* functions from SGE library */
26 inline void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
29 #define FULLSCREEN_BUG
32 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
33 static int fullscreen_width;
34 static int fullscreen_height;
35 static int fullscreen_xoffset;
36 static int fullscreen_yoffset;
37 static int video_xoffset;
38 static int video_yoffset;
40 inline void SDLInitVideoDisplay(void)
42 /* initialize SDL video */
43 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
44 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
46 /* set default SDL depth */
47 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
50 inline void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
55 static int screen_xy[][2] =
64 /* default: normal game window size */
65 fullscreen_width = video.width;
66 fullscreen_height = video.height;
67 fullscreen_xoffset = 0;
68 fullscreen_yoffset = 0;
71 for (i=0; screen_xy[i][0] != -1; i++)
73 if (video.width <= screen_xy[i][0] && video.height <= screen_xy[i][1])
75 fullscreen_width = screen_xy[i][0];
76 fullscreen_height = screen_xy[i][1];
81 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
82 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
85 /* open SDL video output device (window or fullscreen mode) */
86 if (!SDLSetVideoMode(backbuffer, fullscreen))
87 Error(ERR_EXIT, "setting video mode failed");
89 /* set window and icon title */
90 SDL_WM_SetCaption(program.window_title, program.window_title);
92 /* SDL cannot directly draw to the visible video framebuffer like X11,
93 but always uses a backbuffer, which is then blitted to the visible
94 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
95 visible video framebuffer with 'SDL_Flip', if the hardware supports
96 this). Therefore do not use an additional backbuffer for drawing, but
97 use a symbolic buffer (distinguishable from the SDL backbuffer) called
98 'window', which indicates that the SDL backbuffer should be updated to
99 the visible video framebuffer when attempting to blit to it.
101 For convenience, it seems to be a good idea to create this symbolic
102 buffer 'window' at the same size as the SDL backbuffer. Although it
103 should never be drawn to directly, it would do no harm nevertheless. */
105 /* create additional (symbolic) buffer for double-buffering */
106 *window = CreateBitmap(video.width, video.height, video.depth);
109 inline boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
111 boolean success = TRUE;
112 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
113 int surface_flags_window = SURFACE_FLAGS;
114 SDL_Surface *new_surface = NULL;
116 if (*backbuffer == NULL)
117 *backbuffer = CreateBitmapStruct();
119 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
121 video_xoffset = fullscreen_xoffset;
122 video_yoffset = fullscreen_yoffset;
124 /* switch display to fullscreen mode, if available */
125 if ((new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
126 video.depth, surface_flags_fullscreen))
129 /* switching display to fullscreen mode failed */
130 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
132 /* do not try it again */
133 video.fullscreen_available = FALSE;
138 (*backbuffer)->surface = new_surface;
140 video.fullscreen_enabled = TRUE;
145 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
150 /* switch display to window mode */
151 if ((new_surface = SDL_SetVideoMode(video.width, video.height,
152 video.depth, surface_flags_window))
155 /* switching display to window mode failed -- should not happen */
156 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
162 (*backbuffer)->surface = new_surface;
164 video.fullscreen_enabled = FALSE;
172 inline void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
173 int src_x, int src_y,
174 int width, int height,
175 int dst_x, int dst_y, int copy_mode)
177 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
178 SDL_Rect src_rect, dst_rect;
180 #ifdef FULLSCREEN_BUG
181 if (src_bitmap == backbuffer)
183 src_x += video_xoffset;
184 src_y += video_yoffset;
193 #ifdef FULLSCREEN_BUG
194 if (dst_bitmap == backbuffer || dst_bitmap == window)
196 dst_x += video_xoffset;
197 dst_y += video_yoffset;
206 if (src_bitmap != backbuffer || dst_bitmap != window)
207 SDL_BlitSurface((copy_mode == SDLCOPYAREA_MASKED ?
208 src_bitmap->surface_masked : src_bitmap->surface),
209 &src_rect, real_dst_bitmap->surface, &dst_rect);
211 if (dst_bitmap == window)
212 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
215 inline void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y,
216 int width, int height, unsigned int color)
218 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
220 unsigned int color_r = (color >> 16) && 0xff;
221 unsigned int color_g = (color >> 8) && 0xff;
222 unsigned int color_b = (color >> 0) && 0xff;
224 #ifdef FULLSCREEN_BUG
225 if (dst_bitmap == backbuffer || dst_bitmap == window)
237 SDL_FillRect(real_dst_bitmap->surface, &rect,
238 SDL_MapRGB(real_dst_bitmap->surface->format,
239 color_r, color_g, color_b));
241 if (dst_bitmap == window)
242 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
245 inline void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
246 int to_x, int to_y, unsigned int color)
248 SDL_Surface *surface = dst_bitmap->surface;
250 unsigned int color_r = (color >> 16) & 0xff;
251 unsigned int color_g = (color >> 8) & 0xff;
252 unsigned int color_b = (color >> 0) & 0xff;
255 swap_numbers(&from_x, &to_x);
258 swap_numbers(&from_y, &to_y);
262 rect.w = (to_x - from_x + 1);
263 rect.h = (to_y - from_y + 1);
265 #ifdef FULLSCREEN_BUG
266 if (dst_bitmap == backbuffer || dst_bitmap == window)
268 rect.x += video_xoffset;
269 rect.y += video_yoffset;
273 SDL_FillRect(surface, &rect,
274 SDL_MapRGB(surface->format, color_r, color_g, color_b));
277 inline void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
278 int to_x, int to_y, Uint32 color)
280 #ifdef FULLSCREEN_BUG
281 if (dst_bitmap == backbuffer || dst_bitmap == window)
283 from_x += video_xoffset;
284 from_y += video_yoffset;
285 to_x += video_xoffset;
286 to_y += video_yoffset;
290 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
294 inline void SDLDrawLines(SDL_Surface *surface, struct XY *points,
295 int num_points, Uint32 color)
300 for (i=0; i<num_points - 1; i++)
302 for (x=0; x<line_width; x++)
304 for (y=0; y<line_width; y++)
306 int dx = x - line_width / 2;
307 int dy = y - line_width / 2;
309 if ((x == 0 && y == 0) ||
310 (x == 0 && y == line_width - 1) ||
311 (x == line_width - 1 && y == 0) ||
312 (x == line_width - 1 && y == line_width - 1))
315 sge_Line(surface, points[i].x + dx, points[i].y + dy,
316 points[i+1].x + dx, points[i+1].y + dy, color);
324 /* ========================================================================= */
325 /* The following functions have been taken from the SGE library */
326 /* (SDL Graphics Extension Library) by Anders Lindström */
327 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
328 /* ========================================================================= */
330 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
332 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
334 switch (surface->format->BytesPerPixel)
339 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
345 /* Probably 15-bpp or 16-bpp */
346 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
352 /* Slow 24-bpp mode, usually not used */
356 /* Gack - slow, but endian correct */
357 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
358 shift = surface->format->Rshift;
359 *(pix+shift/8) = color>>shift;
360 shift = surface->format->Gshift;
361 *(pix+shift/8) = color>>shift;
362 shift = surface->format->Bshift;
363 *(pix+shift/8) = color>>shift;
369 /* Probably 32-bpp */
370 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
377 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
378 Uint8 R, Uint8 G, Uint8 B)
380 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
383 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
385 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
388 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
390 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
393 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
398 /* Gack - slow, but endian correct */
399 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
400 shift = surface->format->Rshift;
401 *(pix+shift/8) = color>>shift;
402 shift = surface->format->Gshift;
403 *(pix+shift/8) = color>>shift;
404 shift = surface->format->Bshift;
405 *(pix+shift/8) = color>>shift;
408 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
410 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
413 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
415 switch (dest->format->BytesPerPixel)
418 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
422 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
426 _PutPixel24(dest,x,y,color);
430 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
435 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
437 if (SDL_MUSTLOCK(surface))
439 if (SDL_LockSurface(surface) < 0)
445 _PutPixel(surface, x, y, color);
447 if (SDL_MUSTLOCK(surface))
449 SDL_UnlockSurface(surface);
453 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
454 Uint8 R, Uint8 G, Uint8 B)
456 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
459 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
461 if (y >= 0 && y <= dest->h - 1)
463 switch (dest->format->BytesPerPixel)
466 return y*dest->pitch;
470 return y*dest->pitch/2;
474 return y*dest->pitch;
478 return y*dest->pitch/4;
486 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
488 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
490 switch (surface->format->BytesPerPixel)
495 *((Uint8 *)surface->pixels + ypitch + x) = color;
501 /* Probably 15-bpp or 16-bpp */
502 *((Uint16 *)surface->pixels + ypitch + x) = color;
508 /* Slow 24-bpp mode, usually not used */
512 /* Gack - slow, but endian correct */
513 pix = (Uint8 *)surface->pixels + ypitch + x*3;
514 shift = surface->format->Rshift;
515 *(pix+shift/8) = color>>shift;
516 shift = surface->format->Gshift;
517 *(pix+shift/8) = color>>shift;
518 shift = surface->format->Bshift;
519 *(pix+shift/8) = color>>shift;
525 /* Probably 32-bpp */
526 *((Uint32 *)surface->pixels + ypitch + x) = color;
533 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
538 if (SDL_MUSTLOCK(Surface))
540 if (SDL_LockSurface(Surface) < 0)
553 /* Do the clipping */
554 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
558 if (x2 > Surface->w - 1)
566 SDL_FillRect(Surface, &l, Color);
568 if (SDL_MUSTLOCK(Surface))
570 SDL_UnlockSurface(Surface);
574 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
575 Uint8 R, Uint8 G, Uint8 B)
577 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
580 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
591 /* Do the clipping */
592 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
596 if (x2 > Surface->w - 1)
604 SDL_FillRect(Surface, &l, Color);
607 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
612 if (SDL_MUSTLOCK(Surface))
614 if (SDL_LockSurface(Surface) < 0)
627 /* Do the clipping */
628 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
632 if (y2 > Surface->h - 1)
640 SDL_FillRect(Surface, &l, Color);
642 if (SDL_MUSTLOCK(Surface))
644 SDL_UnlockSurface(Surface);
648 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
649 Uint8 R, Uint8 G, Uint8 B)
651 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
654 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
665 /* Do the clipping */
666 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
670 if (y2 > Surface->h - 1)
678 SDL_FillRect(Surface, &l, Color);
681 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
682 Sint16 x2, Sint16 y2, Uint32 Color,
683 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
686 Sint16 dx, dy, sdx, sdy, x, y, px, py;
691 sdx = (dx < 0) ? -1 : 1;
692 sdy = (dy < 0) ? -1 : 1;
704 for (x = 0; x < dx; x++)
706 Callback(Surface, px, py, Color);
720 for (y = 0; y < dy; y++)
722 Callback(Surface, px, py, Color);
736 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
737 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
738 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
741 sge_DoLine(Surface, X1, Y1, X2, Y2,
742 SDL_MapRGB(Surface->format, R, G, B), Callback);
745 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
748 if (SDL_MUSTLOCK(Surface))
750 if (SDL_LockSurface(Surface) < 0)
755 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
757 /* unlock the display */
758 if (SDL_MUSTLOCK(Surface))
760 SDL_UnlockSurface(Surface);
764 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
765 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
767 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
770 Bitmap *SDLLoadImage(char *filename)
772 Bitmap *new_bitmap = CreateBitmapStruct();
773 SDL_Surface *sdl_image_tmp;
775 /* load image to temporary surface */
776 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
777 Error(ERR_EXIT, "IMG_Load() failed: %s", SDL_GetError());
779 /* create native non-transparent surface for current image */
780 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
781 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
783 /* create native transparent surface for current image */
784 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
785 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
786 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
787 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
789 /* free temporary surface */
790 SDL_FreeSurface(sdl_image_tmp);
796 /* ========================================================================= */
797 /* audio functions */
798 /* ========================================================================= */
800 inline void SDLOpenAudio(void)
802 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
804 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
808 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, AUDIO_S16,
809 AUDIO_STEREO_CHANNELS,
810 DEFAULT_AUDIO_FRAGMENT_SIZE) < 0)
812 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
816 audio.sound_available = TRUE;
817 audio.music_available = TRUE;
818 audio.loops_available = TRUE;
819 audio.sound_enabled = TRUE;
821 /* determine number of available channels */
822 audio.channels = Mix_AllocateChannels(MIX_CHANNELS);
824 if (!audio.mods_available) /* reserve first channel for music loops */
826 if (Mix_ReserveChannels(1) == 1)
827 audio.music_channel = 0;
829 audio.music_available = FALSE;
832 Mix_Volume(-1, SOUND_MAX_VOLUME);
833 Mix_VolumeMusic(SOUND_MAX_VOLUME);
836 inline void SDLCloseAudio(void)
842 SDL_QuitSubSystem(SDL_INIT_AUDIO);
846 /* ========================================================================= */
847 /* event functions */
848 /* ========================================================================= */
850 inline void SDLNextEvent(Event *event)
852 SDL_WaitEvent(event);
854 #ifdef FULLSCREEN_BUG
855 if (event->type == EVENT_BUTTONPRESS ||
856 event->type == EVENT_BUTTONRELEASE)
858 if (((ButtonEvent *)event)->x > video_xoffset)
859 ((ButtonEvent *)event)->x -= video_xoffset;
861 ((ButtonEvent *)event)->x = 0;
862 if (((ButtonEvent *)event)->y > video_yoffset)
863 ((ButtonEvent *)event)->y -= video_yoffset;
865 ((ButtonEvent *)event)->y = 0;
867 else if (event->type == EVENT_MOTIONNOTIFY)
869 if (((ButtonEvent *)event)->x > video_xoffset)
870 ((ButtonEvent *)event)->x -= video_xoffset;
872 ((ButtonEvent *)event)->x = 0;
873 if (((ButtonEvent *)event)->y > video_yoffset)
874 ((ButtonEvent *)event)->y -= video_yoffset;
876 ((ButtonEvent *)event)->y = 0;
881 #endif /* TARGET_SDL */