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