rnd-20001202-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(WIN_XSIZE, WIN_YSIZE, DEFAULT_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(SDL_Surface *src_surface, SDL_Surface *dst_surface,
120                         int src_x, int src_y,
121                         int width, int height,
122                         int dst_x, int dst_y)
123 {
124   SDL_Surface *surface = (dst_surface == window ? backbuffer : dst_surface);
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_surface != backbuffer || dst_surface != window)
138     SDL_BlitSurface(src_surface, &src_rect, surface, &dst_rect);
139
140   if (dst_surface == window)
141     SDL_UpdateRect(backbuffer, dst_x, dst_y, width, height);
142 }
143
144 inline void SDLFillRectangle(SDL_Surface *dst_surface, int x, int y,
145                              int width, int height, unsigned int color)
146 {
147   SDL_Surface *surface = (dst_surface == window ? backbuffer : dst_surface);
148   SDL_Rect rect;
149   unsigned int color_r = (color >> 16) && 0xff;
150   unsigned int color_g = (color >>  8) && 0xff;
151   unsigned int color_b = (color >>  0) && 0xff;
152
153   rect.x = x;
154   rect.y = y;
155   rect.w = width;
156   rect.h = height;
157
158   SDL_FillRect(surface, &rect,
159                SDL_MapRGB(surface->format, color_r, color_g, color_b));
160
161   if (dst_surface == window)
162     SDL_UpdateRect(backbuffer, x, y, width, height);
163 }
164
165 inline void SDLDrawSimpleLine(SDL_Surface *surface, int from_x, int from_y,
166                               int to_x, int to_y, unsigned int color)
167 {
168   SDL_Rect rect;
169   unsigned int color_r = (color >> 16) & 0xff;
170   unsigned int color_g = (color >>  8) & 0xff;
171   unsigned int color_b = (color >>  0) & 0xff;
172
173   if (from_x > to_x)
174     swap_numbers(&from_x, &to_x);
175
176   if (from_y > to_y)
177     swap_numbers(&from_y, &to_y);
178
179   rect.x = from_x;
180   rect.y = from_y;
181   rect.w = (to_x - from_x + 1);
182   rect.h = (to_y - from_y + 1);
183
184   SDL_FillRect(surface, &rect,
185                SDL_MapRGB(surface->format, color_r, color_g, color_b));
186 }
187
188 inline boolean SDLOpenAudio(void)
189 {
190   if (SDL_Init(SDL_INIT_AUDIO) < 0)
191   {
192     Error(ERR_WARN, "SDL_Init() failed: %s", SDL_GetError());
193     return FALSE;
194   }
195
196   if (Mix_OpenAudio(22050, AUDIO_S16, 2, 512) < 0)
197   {
198     Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
199     return FALSE;
200   }
201
202   Mix_Volume(-1, SDL_MIX_MAXVOLUME / 4);
203   Mix_VolumeMusic(SDL_MIX_MAXVOLUME / 4);
204
205   return TRUE;
206 }
207
208 inline void SDLCloseAudio(void)
209 {
210   Mix_HaltMusic();
211   Mix_HaltChannel(-1);
212
213   Mix_CloseAudio();
214 }
215
216 #endif /* TARGET_SDL */