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