1 /*
2 vid_sdl.c
3
4 Video driver for Sam Lantinga's Simple DirectMedia Layer
5
6 Copyright (C) 1996-1997 Id Software, Inc.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17 See the GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to:
21
22 Free Software Foundation, Inc.
23 59 Temple Place - Suite 330
24 Boston, MA 02111-1307, USA
25
26 */
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_STRING_H
32 # include <string.h>
33 #endif
34 #ifdef HAVE_STRINGS_H
35 # include <strings.h>
36 #endif
37
38 #include <stdlib.h>
39 #include <SDL.h>
40
41 #include "QF/console.h"
42 #include "QF/cvar.h"
43 #include "QF/qendian.h"
44 #include "QF/sys.h"
45 #include "QF/vid.h"
46
47 #include "context_sdl.h"
48 #include "d_iface.h"
49 #include "vid_internal.h"
50
51 #ifdef _WIN32 // FIXME: evil hack to get full DirectSound support with SDL
52 #include <windows.h>
53 #include <SDL_syswm.h>
54 HWND mainwindow;
55 #endif
56
57 // The original defaults
58 #define BASEWIDTH 320
59 #define BASEHEIGHT 200
60
61 byte *VGA_pagebase;
62 int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes = 0;
63
64 SDL_Surface *screen = NULL;
65
66 // Define GLAPIENTRY to a useful value
67 #ifndef GLAPIENTRY
68 # ifdef _WIN32
69 # include <windows.h>
70 # define GLAPIENTRY WINAPI
71 # undef LoadImage
72 # else
73 # ifdef APIENTRY
74 # define GLAPIENTRY APIENTRY
75 # else
76 # define GLAPIENTRY
77 # endif
78 # endif
79 #endif
80
81 static void (*set_vid_mode) (Uint32 flags);
82
83 static void (GLAPIENTRY *qfglFinish) (void);
84 static int use_gl_procaddress = 0;
85 static cvar_t *gl_driver;
86
87 static byte cached_palette[256 * 3];
88 static int update_palette;
89
90 static void *
QFGL_ProcAddress(const char * name,qboolean crit)91 QFGL_ProcAddress (const char *name, qboolean crit)
92 {
93 void *glfunc = NULL;
94
95 Sys_MaskPrintf (SYS_VID, "DEBUG: Finding symbol %s ... ", name);
96
97 glfunc = SDL_GL_GetProcAddress (name);
98 if (glfunc) {
99 Sys_MaskPrintf (SYS_VID, "found [%p]\n", glfunc);
100 return glfunc;
101 }
102 Sys_MaskPrintf (SYS_VID, "not found\n");
103
104 if (crit) {
105 if (strncmp ("fxMesa", name, 6) == 0) {
106 Sys_Printf ("This target requires a special version of Mesa with "
107 "support for Glide and SVGAlib.\n");
108 Sys_Printf ("If you are in X, try using a GLX or SGL target.\n");
109 }
110 Sys_Error ("Couldn't load critical OpenGL function %s, exiting...",
111 name);
112 }
113 return NULL;
114 }
115
116 static void
sdlgl_set_vid_mode(Uint32 flags)117 sdlgl_set_vid_mode (Uint32 flags)
118 {
119 int i, j;
120
121 flags |= SDL_OPENGL;
122
123 // Setup GL Attributes
124 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
125 // SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 0); // Try for 0, 8
126 // SDL_GL_SetAttribute (SDL_GL_STEREO, 1); // Someday...
127
128 for (i = 0; i < 5; i++) {
129 int k;
130 int color[5] = {32, 24, 16, 15, 0};
131 int rgba[5][4] = {
132 {8, 8, 8, 0},
133 {8, 8, 8, 8},
134 {5, 6, 5, 0},
135 {5, 5, 5, 0},
136 {5, 5, 5, 1},
137 };
138
139 SDL_GL_SetAttribute (SDL_GL_RED_SIZE, rgba[i][0]);
140 SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, rgba[i][1]);
141 SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, rgba[i][2]);
142 SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, rgba[i][3]);
143
144 for (j = 0; j < 5; j++) {
145 for (k = 32; k >= 16; k -= 8) {
146 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, k);
147 if ((screen = SDL_SetVideoMode (viddef.width, viddef.height,
148 color[j], flags)))
149 goto success;
150 }
151 }
152 }
153
154 Sys_Error ("Couldn't set video mode: %s", SDL_GetError ());
155 SDL_Quit ();
156
157 success:
158 viddef.numpages = 2;
159
160 viddef.init_gl ();
161 }
162
163 static void
sdlgl_end_rendering(void)164 sdlgl_end_rendering (void)
165 {
166 qfglFinish ();
167 SDL_GL_SwapBuffers ();
168 }
169
170 static void
sdl_load_gl(void)171 sdl_load_gl (void)
172 {
173 viddef.get_proc_address = QFGL_ProcAddress;
174 viddef.end_rendering = sdlgl_end_rendering;
175 set_vid_mode = sdlgl_set_vid_mode;
176
177 if (SDL_GL_LoadLibrary (gl_driver->string) != 0)
178 Sys_Error ("Couldn't load OpenGL library %s!", gl_driver->string);
179
180 use_gl_procaddress = 1;
181
182 qfglFinish = QFGL_ProcAddress ("glFinish", true);
183 }
184
185 static void
sdl_update_palette(const byte * palette)186 sdl_update_palette (const byte *palette)
187 {
188 SDL_Color colors[256];
189 int i;
190
191 for (i = 0; i < 256; ++i) {
192 colors[i].r = *palette++;
193 colors[i].g = *palette++;
194 colors[i].b = *palette++;
195 }
196 SDL_SetColors (screen, colors, 0, 256);
197 }
198
199 static void
VID_SetPalette(const byte * palette)200 VID_SetPalette (const byte *palette)
201 {
202 if (memcmp (cached_palette, palette, sizeof (cached_palette))) {
203 memcpy (cached_palette, palette, sizeof (cached_palette));
204 update_palette = 1;
205 }
206 }
207
208 static void
do_screen_buffer(void)209 do_screen_buffer (void)
210 {
211 }
212
213 static void
sdl_set_vid_mode(Uint32 flags)214 sdl_set_vid_mode (Uint32 flags)
215 {
216 // Initialize display
217 if (!(screen = SDL_SetVideoMode (viddef.width, viddef.height, 8, flags)))
218 Sys_Error ("VID: Couldn't set video mode: %s", SDL_GetError ());
219
220 // now know everything we need to know about the buffer
221 VGA_width = viddef.width;
222 VGA_height = viddef.height;
223 viddef.do_screen_buffer = do_screen_buffer;
224 VGA_pagebase = viddef.buffer = screen->pixels;
225 VGA_rowbytes = viddef.rowbytes = screen->pitch;
226 viddef.conbuffer = viddef.buffer;
227 viddef.conrowbytes = viddef.rowbytes;
228 viddef.direct = 0;
229
230 VID_InitBuffers (); // allocate z buffer and surface cache
231 }
232
233 void
VID_Init(byte * palette,byte * colormap)234 VID_Init (byte *palette, byte *colormap)
235 {
236 Uint32 flags;
237
238 set_vid_mode = sdl_set_vid_mode;
239
240 // Load the SDL library
241 if (SDL_Init (SDL_INIT_VIDEO) < 0)
242 Sys_Error ("VID: Couldn't load SDL: %s", SDL_GetError ());
243
244 R_LoadModule (sdl_load_gl, VID_SetPalette);
245
246 viddef.numpages = 1;
247 viddef.colormap8 = colormap;
248 viddef.fullbright = 256 - viddef.colormap8[256 * VID_GRADES];
249
250 // Set up display mode (width and height)
251 VID_GetWindowSize (BASEWIDTH, BASEHEIGHT);
252
253 // Set video width, height and flags
254 flags = (SDL_SWSURFACE | SDL_HWPALETTE);
255 if (vid_fullscreen->int_val) {
256 flags |= SDL_FULLSCREEN;
257 #ifndef _WIN32 // Don't annoy Mesa/3dfx folks
258 // doesn't hurt if not using a gl renderer
259 // FIXME: Maybe this could be put in a different spot, but I don't
260 // know where. Anyway, it's to work around a 3Dfx Glide bug.
261 // Cvar_SetValue (in_grab, 1); // Needs #include "QF/input.h"
262 putenv ((char *)"MESA_GLX_FX=fullscreen");
263 } else {
264 putenv ((char *)"MESA_GLX_FX=window");
265 #endif
266 }
267
268 set_vid_mode (flags);
269
270 VID_SDL_GammaCheck ();
271 VID_InitGamma (palette);
272 viddef.set_palette (viddef.palette);
273
274 viddef.initialized = true;
275
276 SDL_ShowCursor (0); // hide the mouse pointer
277
278 #ifdef _WIN32
279 // FIXME: EVIL thing - but needed for win32 until
280 // SDL_sound works better - without this DirectSound fails.
281
282 // SDL_GetWMInfo(&info);
283 // mainwindow=info.window;
284 mainwindow=GetActiveWindow();
285 #endif
286
287 viddef.recalc_refdef = 1; // force a surface cache flush
288 }
289
290 void
VID_Init_Cvars()291 VID_Init_Cvars ()
292 {
293 SDL_Init_Cvars ();
294 gl_driver = Cvar_Get ("gl_driver", GL_DRIVER, CVAR_ROM, NULL,
295 "The OpenGL library to use. (path optional)");
296 }
297
298 void
VID_Update(vrect_t * rects)299 VID_Update (vrect_t *rects)
300 {
301 static SDL_Rect *sdlrects;
302 static int num_sdlrects;
303 int i, n;
304 vrect_t *rect;
305
306 if (update_palette) {
307 update_palette = 0;
308 sdl_update_palette (cached_palette);
309 }
310 // Two-pass system, since Quake doesn't do it the SDL way...
311
312 // First, count the number of rectangles
313 n = 0;
314 for (rect = rects; rect; rect = rect->next)
315 ++n;
316
317 if (n > num_sdlrects) {
318 num_sdlrects = n;
319 sdlrects = realloc (sdlrects, n * sizeof (SDL_Rect));
320 if (!sdlrects)
321 Sys_Error ("Out of memory!");
322 }
323
324 // Second, copy them to SDL rectangles and update
325 i = 0;
326 for (rect = rects; rect; rect = rect->next) {
327 sdlrects[i].x = rect->x;
328 sdlrects[i].y = rect->y;
329 sdlrects[i].w = rect->width;
330 sdlrects[i].h = rect->height;
331 ++i;
332 }
333 SDL_UpdateRects (screen, n, sdlrects);
334 }
335
336 void
D_BeginDirectRect(int x,int y,byte * pbitmap,int width,int height)337 D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
338 {
339 Uint8 *offset;
340
341 if (!screen)
342 return;
343 if (x < 0)
344 x = screen->w + x - 1;
345 offset = (Uint8 *) screen->pixels + y * screen->pitch + x;
346 while (height--) {
347 memcpy (offset, pbitmap, width);
348 offset += screen->pitch;
349 pbitmap += width;
350 }
351 }
352
353 void
D_EndDirectRect(int x,int y,int width,int height)354 D_EndDirectRect (int x, int y, int width, int height)
355 {
356 if (!screen)
357 return;
358 if (x < 0)
359 x = screen->w + x - 1;
360 SDL_UpdateRect (screen, x, y, width, height);
361 }
362
363 void
VID_LockBuffer(void)364 VID_LockBuffer (void)
365 {
366 }
367
368 void
VID_UnlockBuffer(void)369 VID_UnlockBuffer (void)
370 {
371 }
372