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