rnd-20001203-1-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;
69
70     if ((window_new = SDL_SetVideoMode(video.width, video.height, video.depth,
71                                        surface_flags)) == NULL)
72     {
73       /* switching display to fullscreen mode failed */
74       Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
75
76       /* do not try it again */
77       video.fullscreen_available = FALSE;
78       success = FALSE;
79     }
80     else
81     {
82       if (window_old)
83         SDL_FreeSurface(window_old);
84       *backbuffer = window_new;
85
86       video.fullscreen_enabled = TRUE;
87       success = TRUE;
88     }
89   }
90
91   if ((!fullscreen && video.fullscreen_enabled) || !*backbuffer)
92   {
93     /* switch display to window mode */
94     DrawWindow window_old = *backbuffer;
95     DrawWindow window_new;
96
97     if ((window_new = SDL_SetVideoMode(video.width, video.height, video.depth,
98                                        surface_flags)) == NULL)
99     {
100       /* switching display to window mode failed -- should not happen */
101       Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
102
103       success = FALSE;
104     }
105     else
106     {
107       if (window_old)
108         SDL_FreeSurface(window_old);
109       *backbuffer = window_new;
110
111       video.fullscreen_enabled = FALSE;
112       success = TRUE;
113     }
114   }
115
116   return success;
117 }
118
119 inline void SDLCopyArea(Bitmap src_bitmap, Bitmap dst_bitmap,
120                         int src_x, int src_y,
121                         int width, int height,
122                         int dst_x, int dst_y, int copy_mode)
123 {
124   Bitmap real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
125   SDL_Rect src_rect, dst_rect;
126
127   src_rect.x = src_x;
128   src_rect.y = src_y;
129   src_rect.w = width;
130   src_rect.h = height;
131
132   dst_rect.x = dst_x;
133   dst_rect.y = dst_y;
134   dst_rect.w = width;
135   dst_rect.h = height;
136
137   if (src_bitmap != backbuffer || dst_bitmap != window)
138     SDL_BlitSurface((copy_mode == SDLCOPYAREA_MASKED ?
139                      src_bitmap->surface_masked : src_bitmap->surface),
140                     &src_rect, real_dst_bitmap->surface, &dst_rect);
141
142   if (dst_bitmap == window)
143     SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
144 }
145
146 inline void SDLFillRectangle(Bitmap dst_bitmap, int x, int y,
147                              int width, int height, unsigned int color)
148 {
149   Bitmap real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
150   SDL_Rect rect;
151   unsigned int color_r = (color >> 16) && 0xff;
152   unsigned int color_g = (color >>  8) && 0xff;
153   unsigned int color_b = (color >>  0) && 0xff;
154
155   rect.x = x;
156   rect.y = y;
157   rect.w = width;
158   rect.h = height;
159
160   SDL_FillRect(real_dst_bitmap->surface, &rect,
161                SDL_MapRGB(real_dst_bitmap->surface->format,
162                           color_r, color_g, color_b));
163
164   if (dst_bitmap == window)
165     SDL_UpdateRect(backbuffer->surface, x, y, width, height);
166 }
167
168 inline void SDLDrawSimpleLine(SDL_Surface *surface, int from_x, int from_y,
169                               int to_x, int to_y, unsigned int color)
170 {
171   SDL_Rect rect;
172   unsigned int color_r = (color >> 16) & 0xff;
173   unsigned int color_g = (color >>  8) & 0xff;
174   unsigned int color_b = (color >>  0) & 0xff;
175
176   if (from_x > to_x)
177     swap_numbers(&from_x, &to_x);
178
179   if (from_y > to_y)
180     swap_numbers(&from_y, &to_y);
181
182   rect.x = from_x;
183   rect.y = from_y;
184   rect.w = (to_x - from_x + 1);
185   rect.h = (to_y - from_y + 1);
186
187   SDL_FillRect(surface, &rect,
188                SDL_MapRGB(surface->format, color_r, color_g, color_b));
189 }
190
191 inline boolean SDLOpenAudio(void)
192 {
193   if (SDL_Init(SDL_INIT_AUDIO) < 0)
194   {
195     Error(ERR_WARN, "SDL_Init() failed: %s", SDL_GetError());
196     return FALSE;
197   }
198
199   if (Mix_OpenAudio(22050, AUDIO_S16, 2, 512) < 0)
200   {
201     Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
202     return FALSE;
203   }
204
205   Mix_Volume(-1, SDL_MIX_MAXVOLUME / 4);
206   Mix_VolumeMusic(SDL_MIX_MAXVOLUME / 4);
207
208   return TRUE;
209 }
210
211 inline void SDLCloseAudio(void)
212 {
213   Mix_HaltMusic();
214   Mix_HaltChannel(-1);
215
216   Mix_CloseAudio();
217 }
218
219 #endif /* TARGET_SDL */