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