1 //----------------------------------------------------------------------------
2 //  EDGE OpenGL Rendering (Main Stuff)
3 //----------------------------------------------------------------------------
4 //
5 //  Copyright (c) 1999-2009  The EDGE Team.
6 //
7 //  This program is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU General Public License
9 //  as published by the Free Software Foundation; either version 2
10 //  of the License, or (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //  GNU General Public License for more details.
16 //
17 //----------------------------------------------------------------------------
18 
19 #include "i_defs.h"
20 #include "i_defs_gl.h"
21 
22 #include "g_game.h"
23 #include "r_misc.h"
24 #include "r_gldefs.h"
25 #include "r_units.h"
26 #include "r_colormap.h"
27 #include "r_draw.h"
28 #include "r_modes.h"
29 #include "r_image.h"
30 
31 #define DEBUG  0
32 
33 // implementation limits
34 
35 int glmax_lights;
36 int glmax_clip_planes;
37 int glmax_tex_size;
38 int glmax_tex_units;
39 
40 cvar_c r_aspect;
41 
42 cvar_c r_nearclip;
43 cvar_c r_farclip;
44 
45 
46 typedef enum
47 {
48 	PFT_LIGHTING   = (1 << 0),
49 	PFT_COLOR_MAT  = (1 << 1),
50 	PFT_SKY        = (1 << 2),
51 	PFT_MULTI_TEX  = (1 << 3),
52 }
53 problematic_feature_e;
54 
55 typedef struct
56 {
57 	// these are substrings that may be matched anywhere
58 	const char *renderer;
59 	const char *vendor;
60 	const char *version;
61 
62 	// problematic features to force on or off (bitmasks)
63 	int disable;
64 	int enable;
65 }
66 driver_bug_t;
67 
68 static const driver_bug_t driver_bugs[] =
69 {
70 	{ "Radeon",   NULL, NULL, PFT_LIGHTING | PFT_COLOR_MAT, 0 },
71 	{ "RADEON",   NULL, NULL, PFT_LIGHTING | PFT_COLOR_MAT, 0 },
72 
73 //	{ "R200",     NULL, "Mesa 6.4", PFT_VERTEX_ARRAY, 0 },
74 //	{ "R200",     NULL, "Mesa 6.5", PFT_VERTEX_ARRAY, 0 },
75 //	{ "Intel",    NULL, "Mesa 6.5", PFT_VERTEX_ARRAY, 0 },
76 
77 	{ "TNT2",     NULL, NULL, PFT_COLOR_MAT, 0 },
78 
79 	{ "Velocity", NULL, NULL, PFT_COLOR_MAT | PFT_SKY, 0 },
80 	{ "Voodoo3",  NULL, NULL, PFT_SKY | PFT_MULTI_TEX, 0 },
81 };
82 
83 #define NUM_DRIVER_BUGS  (sizeof(driver_bugs) / sizeof(driver_bug_t))
84 
85 
86 
87 //
88 // RGL_SetupMatrices2D
89 //
90 // Setup the GL matrices for drawing 2D stuff.
91 //
RGL_SetupMatrices2D(void)92 void RGL_SetupMatrices2D(void)
93 {
94 	glViewport(0, 0, SCREENWIDTH, SCREENHEIGHT);
95 
96 	glMatrixMode(GL_PROJECTION);
97 	glLoadIdentity();
98 	glOrtho(0.0f, (float)SCREENWIDTH,
99 			0.0f, (float)SCREENHEIGHT, -1.0f, 1.0f);
100 
101 	glMatrixMode(GL_MODELVIEW);
102 	glLoadIdentity();
103 
104 	// turn off lighting stuff
105 	glDisable(GL_LIGHTING);
106 	glDisable(GL_COLOR_MATERIAL);
107 
108 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
109 }
110 
111 
112 //
113 // RGL_SetupMatrices3D
114 //
115 // Setup the GL matrices for drawing 3D stuff.
116 //
RGL_SetupMatrices3D(void)117 void RGL_SetupMatrices3D(void)
118 {
119 	GLfloat ambient[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
120 
121 	glViewport(viewwindow_x, viewwindow_y, viewwindow_w, viewwindow_h);
122 
123 	// calculate perspective matrix
124 
125 	glMatrixMode(GL_PROJECTION);
126 
127 	glLoadIdentity();
128 
129 	glFrustum(-view_x_slope * r_nearclip.f, view_x_slope * r_nearclip.f,
130 			  -view_y_slope * r_nearclip.f, view_y_slope * r_nearclip.f,
131 			  r_nearclip.f, r_farclip.f);
132 
133 	// calculate look-at matrix
134 
135 	glMatrixMode(GL_MODELVIEW);
136 
137 	glLoadIdentity();
138 	glRotatef(270.0f - ANG_2_FLOAT(viewvertangle), 1.0f, 0.0f, 0.0f);
139 	glRotatef(90.0f - ANG_2_FLOAT(viewangle), 0.0f, 0.0f, 1.0f);
140 	glTranslatef(-viewx, -viewy, -viewz);
141 
142 	// turn on lighting.  Some drivers (e.g. TNT2) don't work properly
143 	// without it.
144 	if (r_colorlighting.d)
145 	{
146 		glEnable(GL_LIGHTING);
147 		glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
148 	}
149 	else
150 		glDisable(GL_LIGHTING);
151 
152 	if (r_colormaterial.d)
153 	{
154 		glEnable(GL_COLOR_MATERIAL);
155 		glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
156 	}
157 	else
158 		glDisable(GL_COLOR_MATERIAL);
159 
160 	/* glBlendFunc(GL_SRC_ALPHA, GL_ONE);  // Additive lighting */
161 }
162 
SafeStr(const void * s)163 static inline const char *SafeStr(const void *s)
164 {
165 	return s ? (const char *)s : "";
166 }
167 
168 //
169 // RGL_CheckExtensions
170 //
171 // Based on code by Bruce Lewis.
172 //
RGL_CheckExtensions(void)173 void RGL_CheckExtensions(void)
174 {
175 	GLenum err = glewInit();
176 
177 	if (err != GLEW_OK)
178 		I_Error("Unable to initialise GLEW: %s\n",
179 			glewGetErrorString(err));
180 
181 	// -ACB- 2004/08/11 Made local: these are not yet used elsewhere
182 	std::string glstr_version (SafeStr(glGetString(GL_VERSION)));
183 	std::string glstr_renderer(SafeStr(glGetString(GL_RENDERER)));
184 	std::string glstr_vendor  (SafeStr(glGetString(GL_VENDOR)));
185 
186 	I_Printf("OpenGL: Version: %s\n", glstr_version.c_str());
187 	I_Printf("OpenGL: Renderer: %s\n", glstr_renderer.c_str());
188 	I_Printf("OpenGL: Vendor: %s\n", glstr_vendor.c_str());
189 	I_Printf("OpenGL: GLEW version: %s\n", glewGetString(GLEW_VERSION));
190 
191 #if 0  // FIXME: this crashes (buffer overflow?)
192 	I_Printf("OpenGL: EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS));
193 #endif
194 
195 	// Check for a windows software renderer
196 	if (stricmp(glstr_vendor.c_str(), "Microsoft Corporation") == 0)
197 	{
198 		if (stricmp(glstr_renderer.c_str(), "GDI Generic") == 0)
199 		{
200 			I_Error("OpenGL: SOFTWARE Renderer!\n");
201 		}
202 	}
203 
204 	// Check for various extensions
205 
206 	if (GLEW_VERSION_1_3 || GLEW_ARB_multitexture)
207 	{ /* OK */ }
208 	else
209 		I_Error("OpenGL driver does not support Multitexturing.\n");
210 
211 	if (GLEW_VERSION_1_3 ||
212 		GLEW_ARB_texture_env_combine ||
213 		GLEW_EXT_texture_env_combine)
214 	{ /* OK */ }
215 	else
216 	{
217 		I_Warning("OpenGL driver does not support COMBINE.\n");
218 		r_dumbcombine = 1;
219 	}
220 
221 	if (GLEW_VERSION_1_2 ||
222 		GLEW_EXT_texture_edge_clamp ||
223 		GLEW_SGIS_texture_edge_clamp)
224 	{ /* OK */ }
225 	else
226 	{
227 		I_Warning("OpenGL driver does not support Edge-Clamp.\n");
228 		r_dumbclamp = 1;
229 	}
230 
231 
232 	// --- Detect buggy drivers, enable workarounds ---
233 
234 	for (int j = 0; j < (int)NUM_DRIVER_BUGS; j++)
235 	{
236 		const driver_bug_t *bug = &driver_bugs[j];
237 
238 		if (bug->renderer && !strstr(glstr_renderer.c_str(), bug->renderer))
239 			continue;
240 
241 		if (bug->vendor && !strstr(glstr_vendor.c_str(), bug->vendor))
242 			continue;
243 
244 		if (bug->version && !strstr(glstr_version.c_str(), bug->version))
245 			continue;
246 
247 		I_Printf("OpenGL: Enabling workarounds for %s.\n",
248 				bug->renderer ? bug->renderer :
249 				bug->vendor   ? bug->vendor : "the Axis of Evil");
250 
251 		if (bug->disable & PFT_LIGHTING)  r_colorlighting = 0;
252 		if (bug->disable & PFT_COLOR_MAT) r_colormaterial = 0;
253 		if (bug->disable & PFT_SKY)       r_dumbsky = 1;
254 		if (bug->disable & PFT_MULTI_TEX) r_dumbmulti = 1;
255 
256 		if (bug->enable & PFT_LIGHTING)   r_colorlighting = 1;
257 		if (bug->enable & PFT_COLOR_MAT)  r_colormaterial = 1;
258 		if (bug->enable & PFT_SKY)        r_dumbsky = 0;
259 		if (bug->enable & PFT_MULTI_TEX)  r_dumbmulti = 0;
260 	}
261 }
262 
263 //
264 // RGL_SoftInit
265 //
266 // All the stuff that can be re-initialised multiple times.
267 //
RGL_SoftInit(void)268 void RGL_SoftInit(void)
269 {
270 	glDisable(GL_FOG);
271 	glDisable(GL_BLEND);
272 	glDisable(GL_LIGHTING);
273 	glDisable(GL_CULL_FACE);
274 	glDisable(GL_DEPTH_TEST);
275 	glDisable(GL_SCISSOR_TEST);
276 	glDisable(GL_STENCIL_TEST);
277 
278 	glDisable(GL_LINE_SMOOTH);
279 	glDisable(GL_POLYGON_SMOOTH);
280 
281 	if (var_dithering)
282 		glEnable(GL_DITHER);
283 	else
284 		glDisable(GL_DITHER);
285 
286 	glEnable(GL_NORMALIZE);
287 
288 	glShadeModel(GL_SMOOTH);
289 	glDepthFunc(GL_LEQUAL);
290 	glAlphaFunc(GL_GREATER, 0);
291 
292 	glFrontFace(GL_CW);
293 	glCullFace(GL_BACK);
294 	glDisable(GL_CULL_FACE);
295 
296 	glHint(GL_FOG_HINT, GL_NICEST);
297 	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
298 }
299 
300 //
301 // RGL_Init
302 //
RGL_Init(void)303 void RGL_Init(void)
304 {
305 	I_Printf("OpenGL: Initialising...\n");
306 
307 	RGL_CheckExtensions();
308 
309 
310 	// read implementation limits
311 	{
312 		GLint max_lights;
313 		GLint max_clip_planes;
314 		GLint max_tex_size;
315 		GLint max_tex_units;
316 
317 		glGetIntegerv(GL_MAX_LIGHTS,        &max_lights);
318 		glGetIntegerv(GL_MAX_CLIP_PLANES,   &max_clip_planes);
319 		glGetIntegerv(GL_MAX_TEXTURE_SIZE,  &max_tex_size);
320 		glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_tex_units);
321 
322 		glmax_lights = max_lights;
323 		glmax_clip_planes = max_clip_planes;
324 		glmax_tex_size = max_tex_size;
325 		glmax_tex_units = max_tex_units;
326 	}
327 
328 	I_Printf("OpenGL: Lights: %d  Clips: %d  Tex: %d  Units: %d\n",
329 			 glmax_lights, glmax_clip_planes, glmax_tex_size, glmax_tex_units);
330 
331 	RGL_SoftInit();
332 
333 	R2_InitUtil();
334 
335 	// initialise unit system
336 	RGL_InitUnits();
337 
338 	RGL_SetupMatrices2D();
339 }
340 
341 
342 //--- editor settings ---
343 // vi:ts=4:sw=4:noexpandtab
344