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