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);
323 inline Pixel SDLGetPixel(Bitmap *dst_bitmap, int x, int y)
325 SDL_Surface *surface = dst_bitmap->surface;
327 #ifdef FULLSCREEN_BUG
328 if (dst_bitmap == backbuffer || dst_bitmap == window)
335 switch (surface->format->BytesPerPixel)
337 case 1: /* assuming 8-bpp */
339 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
343 case 2: /* probably 15-bpp or 16-bpp */
345 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
349 case 3: /* slow 24-bpp mode; usually not used */
351 /* does this work? */
352 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
356 shift = surface->format->Rshift;
357 color |= *(pix + shift / 8) >> shift;
358 shift = surface->format->Gshift;
359 color |= *(pix + shift / 8) >> shift;
360 shift = surface->format->Bshift;
361 color |= *(pix + shift / 8) >> shift;
367 case 4: /* probably 32-bpp */
369 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
378 /* ========================================================================= */
379 /* The following functions have been taken from the SGE library */
380 /* (SDL Graphics Extension Library) by Anders Lindström */
381 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
382 /* ========================================================================= */
384 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
386 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
388 switch (surface->format->BytesPerPixel)
393 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
399 /* Probably 15-bpp or 16-bpp */
400 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
406 /* Slow 24-bpp mode, usually not used */
410 /* Gack - slow, but endian correct */
411 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
412 shift = surface->format->Rshift;
413 *(pix+shift/8) = color>>shift;
414 shift = surface->format->Gshift;
415 *(pix+shift/8) = color>>shift;
416 shift = surface->format->Bshift;
417 *(pix+shift/8) = color>>shift;
423 /* Probably 32-bpp */
424 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
431 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
432 Uint8 R, Uint8 G, Uint8 B)
434 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
437 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
439 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
442 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
444 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
447 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
452 /* Gack - slow, but endian correct */
453 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
454 shift = surface->format->Rshift;
455 *(pix+shift/8) = color>>shift;
456 shift = surface->format->Gshift;
457 *(pix+shift/8) = color>>shift;
458 shift = surface->format->Bshift;
459 *(pix+shift/8) = color>>shift;
462 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
464 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
467 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
469 switch (dest->format->BytesPerPixel)
472 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
476 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
480 _PutPixel24(dest,x,y,color);
484 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
489 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
491 if (SDL_MUSTLOCK(surface))
493 if (SDL_LockSurface(surface) < 0)
499 _PutPixel(surface, x, y, color);
501 if (SDL_MUSTLOCK(surface))
503 SDL_UnlockSurface(surface);
507 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
508 Uint8 R, Uint8 G, Uint8 B)
510 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
513 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
515 if (y >= 0 && y <= dest->h - 1)
517 switch (dest->format->BytesPerPixel)
520 return y*dest->pitch;
524 return y*dest->pitch/2;
528 return y*dest->pitch;
532 return y*dest->pitch/4;
540 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
542 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
544 switch (surface->format->BytesPerPixel)
549 *((Uint8 *)surface->pixels + ypitch + x) = color;
555 /* Probably 15-bpp or 16-bpp */
556 *((Uint16 *)surface->pixels + ypitch + x) = color;
562 /* Slow 24-bpp mode, usually not used */
566 /* Gack - slow, but endian correct */
567 pix = (Uint8 *)surface->pixels + ypitch + x*3;
568 shift = surface->format->Rshift;
569 *(pix+shift/8) = color>>shift;
570 shift = surface->format->Gshift;
571 *(pix+shift/8) = color>>shift;
572 shift = surface->format->Bshift;
573 *(pix+shift/8) = color>>shift;
579 /* Probably 32-bpp */
580 *((Uint32 *)surface->pixels + ypitch + x) = color;
587 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
592 if (SDL_MUSTLOCK(Surface))
594 if (SDL_LockSurface(Surface) < 0)
607 /* Do the clipping */
608 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
612 if (x2 > Surface->w - 1)
620 SDL_FillRect(Surface, &l, Color);
622 if (SDL_MUSTLOCK(Surface))
624 SDL_UnlockSurface(Surface);
628 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
629 Uint8 R, Uint8 G, Uint8 B)
631 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
634 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
645 /* Do the clipping */
646 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
650 if (x2 > Surface->w - 1)
658 SDL_FillRect(Surface, &l, Color);
661 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
666 if (SDL_MUSTLOCK(Surface))
668 if (SDL_LockSurface(Surface) < 0)
681 /* Do the clipping */
682 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
686 if (y2 > Surface->h - 1)
694 SDL_FillRect(Surface, &l, Color);
696 if (SDL_MUSTLOCK(Surface))
698 SDL_UnlockSurface(Surface);
702 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
703 Uint8 R, Uint8 G, Uint8 B)
705 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
708 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
719 /* Do the clipping */
720 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
724 if (y2 > Surface->h - 1)
732 SDL_FillRect(Surface, &l, Color);
735 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
736 Sint16 x2, Sint16 y2, Uint32 Color,
737 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
740 Sint16 dx, dy, sdx, sdy, x, y, px, py;
745 sdx = (dx < 0) ? -1 : 1;
746 sdy = (dy < 0) ? -1 : 1;
758 for (x = 0; x < dx; x++)
760 Callback(Surface, px, py, Color);
774 for (y = 0; y < dy; y++)
776 Callback(Surface, px, py, Color);
790 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
791 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
792 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
795 sge_DoLine(Surface, X1, Y1, X2, Y2,
796 SDL_MapRGB(Surface->format, R, G, B), Callback);
799 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
802 if (SDL_MUSTLOCK(Surface))
804 if (SDL_LockSurface(Surface) < 0)
809 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
811 /* unlock the display */
812 if (SDL_MUSTLOCK(Surface))
814 SDL_UnlockSurface(Surface);
818 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
819 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
821 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
824 Bitmap *SDLLoadImage(char *filename)
826 Bitmap *new_bitmap = CreateBitmapStruct();
827 SDL_Surface *sdl_image_tmp;
829 /* load image to temporary surface */
830 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
831 Error(ERR_EXIT, "IMG_Load() failed: %s", SDL_GetError());
833 /* create native non-transparent surface for current image */
834 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
835 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
837 /* create native transparent surface for current image */
838 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
839 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
840 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
841 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
843 /* free temporary surface */
844 SDL_FreeSurface(sdl_image_tmp);
850 /* ========================================================================= */
851 /* audio functions */
852 /* ========================================================================= */
854 inline void SDLOpenAudio(void)
856 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
858 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
862 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, AUDIO_S16,
863 AUDIO_STEREO_CHANNELS,
864 DEFAULT_AUDIO_FRAGMENT_SIZE) < 0)
866 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
870 audio.sound_available = TRUE;
871 audio.music_available = TRUE;
872 audio.loops_available = TRUE;
873 audio.sound_enabled = TRUE;
875 /* determine number of available channels */
876 audio.channels = Mix_AllocateChannels(MIX_CHANNELS);
878 if (!audio.mods_available) /* reserve first channel for music loops */
880 if (Mix_ReserveChannels(1) == 1)
881 audio.music_channel = 0;
883 audio.music_available = FALSE;
886 Mix_Volume(-1, SOUND_MAX_VOLUME);
887 Mix_VolumeMusic(SOUND_MAX_VOLUME);
890 inline void SDLCloseAudio(void)
896 SDL_QuitSubSystem(SDL_INIT_AUDIO);
900 /* ========================================================================= */
901 /* event functions */
902 /* ========================================================================= */
904 inline void SDLNextEvent(Event *event)
906 SDL_WaitEvent(event);
908 #ifdef FULLSCREEN_BUG
909 if (event->type == EVENT_BUTTONPRESS ||
910 event->type == EVENT_BUTTONRELEASE)
912 if (((ButtonEvent *)event)->x > video_xoffset)
913 ((ButtonEvent *)event)->x -= video_xoffset;
915 ((ButtonEvent *)event)->x = 0;
916 if (((ButtonEvent *)event)->y > video_yoffset)
917 ((ButtonEvent *)event)->y -= video_yoffset;
919 ((ButtonEvent *)event)->y = 0;
921 else if (event->type == EVENT_MOTIONNOTIFY)
923 if (((ButtonEvent *)event)->x > video_xoffset)
924 ((ButtonEvent *)event)->x -= video_xoffset;
926 ((ButtonEvent *)event)->x = 0;
927 if (((ButtonEvent *)event)->y > video_yoffset)
928 ((ButtonEvent *)event)->y -= video_yoffset;
930 ((ButtonEvent *)event)->y = 0;
935 #endif /* TARGET_SDL */