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