rnd-20001204-1-src
[rocksndiamonds.git] / src / libgame / sdl.c
1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2000 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * sdl.c                                                    *
12 ***********************************************************/
13
14 #include "system.h"
15 #include "misc.h"
16
17
18 #if defined(TARGET_SDL)
19
20 inline void SDLInitVideoDisplay(void)
21 {
22   /* initialize SDL video */
23   if (SDL_Init(SDL_INIT_VIDEO) < 0)
24     Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
25
26   /* set default SDL depth */
27   video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
28
29   /* set exit function to automatically cleanup SDL stuff after exit() */
30   atexit(SDL_Quit);
31 }
32
33 inline void SDLInitVideoBuffer(DrawBuffer *backbuffer, DrawWindow *window,
34                                boolean fullscreen)
35 {
36   /* open SDL video output device (window or fullscreen mode) */
37   if (!SDLSetVideoMode(backbuffer, fullscreen))
38     Error(ERR_EXIT, "setting video mode failed");
39
40   /* set window and icon title */
41   SDL_WM_SetCaption(program.window_title, program.window_title);
42
43   /* SDL cannot directly draw to the visible video framebuffer like X11,
44      but always uses a backbuffer, which is then blitted to the visible
45      video framebuffer with 'SDL_UpdateRect' (or replaced with the current
46      visible video framebuffer with 'SDL_Flip', if the hardware supports
47      this). Therefore do not use an additional backbuffer for drawing, but
48      use a symbolic buffer (distinguishable from the SDL backbuffer) called
49      'window', which indicates that the SDL backbuffer should be updated to
50      the visible video framebuffer when attempting to blit to it.
51
52      For convenience, it seems to be a good idea to create this symbolic
53      buffer 'window' at the same size as the SDL backbuffer. Although it
54      should never be drawn to directly, it would do no harm nevertheless. */
55
56   /* create additional (symbolic) buffer for double-buffering */
57   *window = CreateBitmap(video.width, video.height, video.depth);
58 }
59
60 inline boolean SDLSetVideoMode(DrawBuffer *backbuffer, boolean fullscreen)
61 {
62   boolean success = TRUE;
63   int surface_flags = SDL_HWSURFACE | (fullscreen ? SDL_FULLSCREEN : 0);
64
65   if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
66   {
67     /* switch display to fullscreen mode, if available */
68     DrawWindow window_old = *backbuffer;
69     DrawWindow window_new = CreateBitmapStruct();
70
71     if ((window_new->surface = SDL_SetVideoMode(video.width, video.height,
72                                                 video.depth, surface_flags))
73         == NULL)
74     {
75       /* switching display to fullscreen mode failed */
76       Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
77
78       /* do not try it again */
79       video.fullscreen_available = FALSE;
80       success = FALSE;
81     }
82     else
83     {
84       if (window_old)
85         FreeBitmap(window_old);
86       *backbuffer = window_new;
87
88       video.fullscreen_enabled = TRUE;
89       success = TRUE;
90     }
91   }
92
93   if ((!fullscreen && video.fullscreen_enabled) || !*backbuffer)
94   {
95     /* switch display to window mode */
96     DrawWindow window_old = *backbuffer;
97     DrawWindow window_new = CreateBitmapStruct();
98
99     if ((window_new->surface = SDL_SetVideoMode(video.width, video.height,
100                                                 video.depth, surface_flags))
101         == NULL)
102     {
103       /* switching display to window mode failed -- should not happen */
104       Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
105
106       success = FALSE;
107     }
108     else
109     {
110       if (window_old)
111         FreeBitmap(window_old);
112       *backbuffer = window_new;
113
114       video.fullscreen_enabled = FALSE;
115       success = TRUE;
116     }
117   }
118
119   return success;
120 }
121
122 inline void SDLCopyArea(Bitmap src_bitmap, Bitmap dst_bitmap,
123                         int src_x, int src_y,
124                         int width, int height,
125                         int dst_x, int dst_y, int copy_mode)
126 {
127   Bitmap real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
128   SDL_Rect src_rect, dst_rect;
129
130   src_rect.x = src_x;
131   src_rect.y = src_y;
132   src_rect.w = width;
133   src_rect.h = height;
134
135   dst_rect.x = dst_x;
136   dst_rect.y = dst_y;
137   dst_rect.w = width;
138   dst_rect.h = height;
139
140   if (src_bitmap != backbuffer || dst_bitmap != window)
141     SDL_BlitSurface((copy_mode == SDLCOPYAREA_MASKED ?
142                      src_bitmap->surface_masked : src_bitmap->surface),
143                     &src_rect, real_dst_bitmap->surface, &dst_rect);
144
145   if (dst_bitmap == window)
146     SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
147 }
148
149 inline void SDLFillRectangle(Bitmap dst_bitmap, int x, int y,
150                              int width, int height, unsigned int color)
151 {
152   Bitmap real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
153   SDL_Rect rect;
154   unsigned int color_r = (color >> 16) && 0xff;
155   unsigned int color_g = (color >>  8) && 0xff;
156   unsigned int color_b = (color >>  0) && 0xff;
157
158   rect.x = x;
159   rect.y = y;
160   rect.w = width;
161   rect.h = height;
162
163   SDL_FillRect(real_dst_bitmap->surface, &rect,
164                SDL_MapRGB(real_dst_bitmap->surface->format,
165                           color_r, color_g, color_b));
166
167   if (dst_bitmap == window)
168     SDL_UpdateRect(backbuffer->surface, x, y, width, height);
169 }
170
171 inline void SDLDrawSimpleLine(SDL_Surface *surface, int from_x, int from_y,
172                               int to_x, int to_y, unsigned int color)
173 {
174   SDL_Rect rect;
175   unsigned int color_r = (color >> 16) & 0xff;
176   unsigned int color_g = (color >>  8) & 0xff;
177   unsigned int color_b = (color >>  0) & 0xff;
178
179   if (from_x > to_x)
180     swap_numbers(&from_x, &to_x);
181
182   if (from_y > to_y)
183     swap_numbers(&from_y, &to_y);
184
185   rect.x = from_x;
186   rect.y = from_y;
187   rect.w = (to_x - from_x + 1);
188   rect.h = (to_y - from_y + 1);
189
190   SDL_FillRect(surface, &rect,
191                SDL_MapRGB(surface->format, color_r, color_g, color_b));
192 }
193
194 inline boolean SDLOpenAudio(void)
195 {
196   if (SDL_Init(SDL_INIT_AUDIO) < 0)
197   {
198     Error(ERR_WARN, "SDL_Init() failed: %s", SDL_GetError());
199     return FALSE;
200   }
201
202   if (Mix_OpenAudio(22050, AUDIO_S16, 2, 512) < 0)
203   {
204     Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
205     return FALSE;
206   }
207
208   Mix_Volume(-1, SDL_MIX_MAXVOLUME / 4);
209   Mix_VolumeMusic(SDL_MIX_MAXVOLUME / 4);
210
211   return TRUE;
212 }
213
214 inline void SDLCloseAudio(void)
215 {
216   Mix_HaltMusic();
217   Mix_HaltChannel(-1);
218
219   Mix_CloseAudio();
220 }
221
222 #endif /* TARGET_SDL */