1 /**
2  * @file
3  */
4 
5 /*
6 Copyright (C) 1997-2001 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 the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22 
23 */
24 
25 #define QGL_EXTERN
26 #include "r_gl.h"
27 #include "r_local.h"
28 #include "r_program.h"
29 #include "r_sphere.h"
30 #include "r_draw.h"
31 #include "r_font.h"
32 #include "r_light.h"
33 #include "r_lightmap.h"
34 #include "r_grass.h"
35 #include "r_main.h"
36 #include "r_geoscape.h"
37 #include "r_misc.h"
38 #include "r_error.h"
39 #include "../../common/tracing.h"
40 #include "../ui/ui_windows.h"
41 #include "../../ports/system.h"
42 #include "../client.h"
43 
44 rendererData_t refdef;
45 
46 rconfig_t r_config;
47 rstate_t r_state;
48 rlocals_t r_locals;
49 
50 image_t* r_noTexture;			/* use for bad textures */
51 image_t* r_warpTexture;
52 image_t* r_dummyTexture; /* 1x1 pixel white texture to be used when texturing is required, but texture is not available */
53 
54 static cvar_t* r_maxtexres;
55 
56 cvar_t* r_drawentities;
57 cvar_t* r_drawworld;
58 cvar_t* r_nocull;
59 cvar_t* r_isometric;
60 cvar_t* r_anisotropic;
61 cvar_t* r_texture_lod;			/* lod_bias */
62 cvar_t* r_screenshot_format;
63 cvar_t* r_screenshot_jpeg_quality;
64 cvar_t* r_lightmap;
65 cvar_t* r_debug_normals;
66 cvar_t* r_debug_tangents;
67 cvar_t* r_debug_lights;
68 static cvar_t* r_deluxemap;
69 cvar_t* r_ext_texture_compression;
70 static cvar_t* r_ext_s3tc_compression;
71 static cvar_t* r_ext_nonpoweroftwo;
72 static cvar_t* r_intel_hack;
73 static cvar_t* r_texturemode;
74 static cvar_t* r_texturealphamode;
75 static cvar_t* r_texturesolidmode;
76 cvar_t* r_materials;
77 cvar_t* r_overridematerial;
78 cvar_t* r_default_specular;
79 cvar_t* r_default_hardness;
80 cvar_t* r_checkerror;
81 cvar_t* r_drawbuffer;
82 cvar_t* r_driver;
83 cvar_t* r_shadows;
84 cvar_t* r_stencilshadows;
85 cvar_t* r_swapinterval;
86 cvar_t* r_multisample;
87 cvar_t* r_wire;
88 cvar_t* r_showbox;
89 cvar_t* r_threads;
90 cvar_t* r_vertexbuffers;
91 cvar_t* r_warp;
92 cvar_t* r_dynamic_lights;
93 cvar_t* r_programs;
94 /** @brief The GLSL version being used (not necessarily a supported version by the OpenGL implementation). Stored as a c-string and integer.*/
95 cvar_t* r_glsl_version;
96 cvar_t* r_postprocess;
97 cvar_t* r_maxlightmap;
98 cvar_t* r_shownormals;
99 cvar_t* r_bumpmap;
100 cvar_t* r_specular;
101 cvar_t* r_hardness;
102 cvar_t* r_parallax;
103 cvar_t* r_fog;
104 cvar_t* r_flares;
105 cvar_t* r_coronas;
106 cvar_t* r_drawtags;
107 
R_PrintInfo(const char * pre,const char * msg)108 static void R_PrintInfo (const char* pre, const char* msg)
109 {
110 	char buf[4096];
111 	const size_t length = sizeof(buf);
112 	const size_t maxLength = strlen(msg);
113 	int i;
114 
115 	Com_Printf("%s: ", pre);
116 	for (i = 0; i < maxLength; i += length) {
117 		Q_strncpyz(buf, msg + i, sizeof(buf));
118 		Com_Printf("%s", buf);
119 	}
120 	Com_Printf("\n");
121 }
122 
123 /**
124  * @brief Prints some OpenGL strings
125  */
R_Strings_f(void)126 static void R_Strings_f (void)
127 {
128 	R_PrintInfo("GL_VENDOR", r_config.vendorString);
129 	R_PrintInfo("GL_RENDERER", r_config.rendererString);
130 	R_PrintInfo("GL_VERSION", r_config.versionString);
131 	R_PrintInfo("GL_EXTENSIONS", r_config.extensionsString);
132 }
133 
R_SetupFrustum(void)134 void R_SetupFrustum (void)
135 {
136 	int i;
137 
138 	/* build the transformation matrix for the given view angles */
139 	AngleVectors(refdef.viewAngles, r_locals.forward, r_locals.right, r_locals.up);
140 
141 #if 0
142 	/* if we are not drawing world model, we are on the UI code. It break the default UI SCISSOR
143 	 * Anyway we should merge that code into R_CleanupDepthBuffer (with some rework), it looks better */
144 
145 	/* clear out the portion of the screen that the NOWORLDMODEL defines */
146 	if (refdef.rendererFlags & RDF_NOWORLDMODEL) {
147 		glEnable(GL_SCISSOR_TEST);
148 		glScissor(viddef.x, viddef.height - viddef.viewHeight - viddef.y, viddef.viewWidth, viddef.viewHeight);
149 		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
150 		R_CheckError();
151 		glDisable(GL_SCISSOR_TEST);
152 	}
153 #endif
154 	if (r_isometric->integer) {
155 		/* 4 planes of a cube */
156 		VectorScale(r_locals.right, +1, r_locals.frustum[0].normal);
157 		VectorScale(r_locals.right, -1, r_locals.frustum[1].normal);
158 		VectorScale(r_locals.up, +1, r_locals.frustum[2].normal);
159 		VectorScale(r_locals.up, -1, r_locals.frustum[3].normal);
160 
161 		for (i = 0; i < 4; i++) {
162 			r_locals.frustum[i].type = PLANE_ANYZ;
163 			r_locals.frustum[i].dist = DotProduct(refdef.viewOrigin, r_locals.frustum[i].normal);
164 		}
165 		r_locals.frustum[0].dist -= 10 * refdef.fieldOfViewX;
166 		r_locals.frustum[1].dist -= 10 * refdef.fieldOfViewX;
167 		r_locals.frustum[2].dist -= 10 * refdef.fieldOfViewX * ((float) viddef.viewHeight / viddef.viewWidth);
168 		r_locals.frustum[3].dist -= 10 * refdef.fieldOfViewX * ((float) viddef.viewHeight / viddef.viewWidth);
169 	} else {
170 		/* rotate VPN right by FOV_X/2 degrees */
171 		RotatePointAroundVector(r_locals.frustum[0].normal, r_locals.up, r_locals.forward, -(90 - refdef.fieldOfViewX / 2));
172 		/* rotate VPN left by FOV_X/2 degrees */
173 		RotatePointAroundVector(r_locals.frustum[1].normal, r_locals.up, r_locals.forward, 90 - refdef.fieldOfViewX / 2);
174 		/* rotate VPN up by FOV_X/2 degrees */
175 		RotatePointAroundVector(r_locals.frustum[2].normal, r_locals.right, r_locals.forward, 90 - refdef.fieldOfViewY / 2);
176 		/* rotate VPN down by FOV_X/2 degrees */
177 		RotatePointAroundVector(r_locals.frustum[3].normal, r_locals.right, r_locals.forward, -(90 - refdef.fieldOfViewY / 2));
178 
179 		for (i = 0; i < 4; i++) {
180 			r_locals.frustum[i].type = PLANE_ANYZ;
181 			r_locals.frustum[i].dist = DotProduct(refdef.viewOrigin, r_locals.frustum[i].normal);
182 		}
183 	}
184 }
185 
186 /**
187  * @brief Clears the screens color and depth buffer
188  */
R_Clear(void)189 static inline void R_Clear (void)
190 {
191 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
192 	/* clear the stencil bit if shadows are enabled */
193 	if (r_stencilshadows->integer)
194 		glClear(GL_STENCIL_BUFFER_BIT);
195 	R_CheckError();
196 	glDepthFunc(GL_LEQUAL);
197 	R_CheckError();
198 
199 	glDepthRange(0.0f, 1.0f);
200 	R_CheckError();
201 }
202 
203 /**
204  * @sa CL_ClearState
205  */
R_ClearScene(void)206 static inline void R_ClearScene (void)
207 {
208 	/* lights and coronas are populated as ents are added */
209 	refdef.numEntities = refdef.numDynamicLights = refdef.numCoronas = 0;
210 	R_ClearBspRRefs();
211 }
212 
213 /**
214  * @sa R_RenderFrame
215  * @sa R_EndFrame
216  */
R_BeginFrame(void)217 void R_BeginFrame (void)
218 {
219 	r_locals.frame++;
220 
221 	/* avoid overflows, negatives and zero are reserved */
222 	if (r_locals.frame > 0xffff)
223 		r_locals.frame = 1;
224 
225 	if (Com_IsRenderModified()) {
226 		Com_Printf("Modified render related cvars\n");
227 		if (Cvar_PendingCvars(CVAR_R_PROGRAMS))
228 			R_RestartPrograms_f();
229 
230 		/* prevent reloading of some rendering cvars */
231 		Cvar_ClearVars(CVAR_R_MASK);
232 		Com_SetRenderModified(false);
233 	}
234 
235 	if (r_anisotropic->modified) {
236 		if (r_anisotropic->integer > r_config.maxAnisotropic) {
237 			Com_Printf("...max GL_EXT_texture_filter_anisotropic value is %i\n", r_config.maxAnisotropic);
238 			Cvar_SetValue("r_anisotropic", r_config.maxAnisotropic);
239 		}
240 		/*R_UpdateAnisotropy();*/
241 		r_anisotropic->modified = false;
242 	}
243 
244 	/* draw buffer stuff */
245 #ifndef GL_VERSION_ES_CM_1_0
246 	if (r_drawbuffer->modified) {
247 		r_drawbuffer->modified = false;
248 
249 		if (Q_strcasecmp(r_drawbuffer->string, "GL_FRONT") == 0)
250 			glDrawBuffer(GL_FRONT);
251 		else
252 			glDrawBuffer(GL_BACK);
253 		R_CheckError();
254 	}
255 #endif
256 
257 	/* texturemode stuff */
258 	/* Realtime set level of anisotropy filtering and change texture lod bias */
259 	if (r_texturemode->modified) {
260 		R_TextureMode(r_texturemode->string);
261 		r_texturemode->modified = false;
262 	}
263 
264 	if (r_texturealphamode->modified) {
265 		R_TextureAlphaMode(r_texturealphamode->string);
266 		r_texturealphamode->modified = false;
267 	}
268 
269 	if (r_texturesolidmode->modified) {
270 		R_TextureSolidMode(r_texturesolidmode->string);
271 		r_texturesolidmode->modified = false;
272 	}
273 
274 	/* threads */
275 	if (r_threads->modified) {
276 		if (r_threads->integer)
277 			R_InitThreads();
278 		else
279 			R_ShutdownThreads();
280 		r_threads->modified = false;
281 	}
282 
283 	R_EnableMultisample(true);
284 
285 	R_Setup2D();
286 
287 	/* clear screen if desired */
288 	R_Clear();
289 }
290 
291 /**
292  * @sa R_BeginFrame
293  * @sa R_EndFrame
294  */
R_RenderFrame(void)295 void R_RenderFrame (void)
296 {
297 	R_Setup3D();
298 
299 	/* activate wire mode */
300 	if (r_wire->integer)
301 		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
302 
303 	if (!(refdef.rendererFlags & RDF_NOWORLDMODEL)) {
304 		int tile;
305 		if (r_threads->integer) {
306 			while (r_threadstate.state != THREAD_RENDERER)
307 				Sys_Sleep(0);
308 
309 			r_threadstate.state = THREAD_CLIENT;
310 		} else {
311 			R_SetupFrustum();
312 
313 			/* draw brushes on current worldlevel */
314 			R_GetLevelSurfaceLists();
315 		}
316 
317 		R_UpdateSustainedLights();
318 
319 		R_CheckError();
320 
321 		for (tile = 0; tile < r_numMapTiles; tile++) {
322 			const model_t* mapTile = r_mapTiles[tile];
323 			const mBspModel_t* bsp = &mapTile->bsp;
324 
325 			R_AddBspRRef(bsp, vec3_origin, vec3_origin, false);
326 		}
327 
328 		R_GetEntityLists();
329 
330 		R_EnableFog(true);
331 
332 		R_RenderOpaqueBspRRefs();
333 		R_RenderOpaqueWarpBspRRefs();
334 		R_DrawOpaqueMeshEntities(r_opaque_mesh_entities);
335 
336 		R_RenderAlphaTestBspRRefs();
337 		R_DrawGrass();
338 
339 		R_EnableBlend(true);
340 		R_RenderMaterialBspRRefs();
341 
342 		R_EnableFog(false);
343 
344 		R_RenderBlendBspRRefs();
345 		R_RenderBlendWarpBspRRefs();
346 		R_DrawBlendMeshEntities(r_blend_mesh_entities);
347 
348 		R_EnableFog(true);
349 		R_RenderFlareBspRRefs();
350 		R_EnableFog(false);
351 
352 		if (r_debug_lights->integer) {
353 			int i;
354 
355 			for (i = 0; i < refdef.numStaticLights; i++) {
356 				const light_t* l = &refdef.staticLights[i];
357 				R_AddCorona(l->origin, l->radius, l->color);
358 			}
359 			for (i = 0; i < refdef.numDynamicLights; i++) {
360 				const light_t* l = &refdef.dynamicLights[i];
361 				R_AddCorona(l->origin, l->radius, l->color);
362 			}
363 		}
364 
365 		R_DrawCoronas();
366 		R_EnableBlend(false);
367 
368 		for (tile = 0; tile < r_numMapTiles; tile++) {
369 			R_DrawBspNormals(tile);
370 		}
371 
372 		R_Color(nullptr);
373 		R_DrawSpecialEntities(r_special_entities);
374 		R_DrawNullEntities(r_null_entities);
375 		R_DrawEntityEffects();
376 	} else {
377 		glClear(GL_DEPTH_BUFFER_BIT);
378 
379 		R_GetEntityLists();
380 
381 		R_RenderOpaqueBspRRefs();
382 		R_RenderOpaqueWarpBspRRefs();
383 		R_DrawOpaqueMeshEntities(r_opaque_mesh_entities);
384 		R_RenderAlphaTestBspRRefs();
385 
386 		R_EnableBlend(true);
387 
388 		R_RenderMaterialBspRRefs();
389 
390 		R_RenderBlendBspRRefs();
391 		R_RenderBlendWarpBspRRefs();
392 		R_DrawBlendMeshEntities(r_blend_mesh_entities);
393 
394 		R_RenderFlareBspRRefs();
395 
396 		R_EnableBlend(false);
397 
398 		R_Color(nullptr);
399 		R_DrawSpecialEntities(r_special_entities);
400 		R_DrawNullEntities(r_null_entities);
401 		R_DrawEntityEffects();
402 	}
403 
404 	R_EnableBlend(true);
405 
406 	R_DrawParticles();
407 
408 	R_EnableBlend(false);
409 
410 	/* leave wire mode again */
411 	if (r_wire->integer)
412 		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
413 
414 	R_DrawBloom();
415 
416 	R_DrawBoundingBoxes();
417 
418 	R_ResetArrayState();
419 
420 	/* go back into 2D mode for hud and the like */
421 	R_Setup2D();
422 
423 	R_CheckError();
424 }
425 
426 /**
427  * @sa R_RenderFrame
428  * @sa R_BeginFrame
429  */
R_EndFrame(void)430 void R_EndFrame (void)
431 {
432 	R_EnableBlend(true);
433 
434 	R_DrawChars();  /* draw all chars accumulated above */
435 
436 	/* restore draw color */
437 	R_Color(nullptr);
438 
439 	R_EnableBlend(false);
440 
441 	if (vid_gamma->modified) {
442 		if (!vid_ignoregamma->integer) {
443 			const float g = vid_gamma->value;
444 #if SDL_VERSION_ATLEAST(2,0,0)
445 			SDL_SetWindowBrightness(cls.window, g);
446 #else
447 			SDL_SetGamma(g, g, g);
448 #endif
449 		}
450 		vid_gamma->modified = false;
451 	}
452 
453 	R_EnableMultisample(false);
454 
455 	R_ClearScene();
456 
457 #if SDL_VERSION_ATLEAST(2,0,0)
458 	SDL_GL_SwapWindow(cls.window);
459 #else
460 	SDL_GL_SwapBuffers();
461 #endif
462 }
463 
464 static const cmdList_t r_commands[] = {
465 	{"r_listimages", R_ImageList_f, "Show all loaded images on game console"},
466 	{"r_listfontcache", R_FontListCache_f, "Show information about font cache"},
467 	{"r_screenshot", R_ScreenShot_f, "Take a screenshot"},
468 	{"r_listmodels", R_ModModellist_f, "Show all loaded models on game console"},
469 	{"r_strings", R_Strings_f, "Print openGL vendor and other strings"},
470 	{"r_restartprograms", R_RestartPrograms_f, "Reloads the shaders"},
471 
472 	{nullptr, nullptr, nullptr}
473 };
474 
R_CvarCheckMaxLightmap(cvar_t * cvar)475 static bool R_CvarCheckMaxLightmap (cvar_t* cvar)
476 {
477 	int maxSize = !r_config.maxTextureSize || LIGHTMAP_MAX_PAGE_SIZE < r_config.maxTextureSize ? LIGHTMAP_MAX_PAGE_SIZE : r_config.maxTextureSize;
478 
479 	if (cvar->integer > maxSize) {
480 		Com_Printf("%s exceeded max supported texture size\n", cvar->name);
481 		Cvar_SetValue(cvar->name, maxSize);
482 		return false;
483 	}
484 
485 	if (!Q_IsPowerOfTwo(cvar->integer)) {
486 		Com_Printf("%s must be power of two\n", cvar->name);
487 		Cvar_SetValue(cvar->name, LIGHTMAP_DEFAULT_PAGE_SIZE);
488 		return false;
489 	}
490 
491 	return Cvar_AssertValue(cvar, 128, LIGHTMAP_MAX_PAGE_SIZE, true);
492 }
493 
R_CvarCheckDynamicLights(cvar_t * cvar)494 static bool R_CvarCheckDynamicLights (cvar_t* cvar)
495 {
496 	float maxLights = r_config.maxLights;
497 
498 	if (maxLights > MAX_ENTITY_LIGHTS)
499 		maxLights = MAX_ENTITY_LIGHTS;
500 
501 	return Cvar_AssertValue(cvar, 0, maxLights, true);
502 }
503 
R_CvarPrograms(cvar_t * cvar)504 static bool R_CvarPrograms (cvar_t* cvar)
505 {
506 	if (qglUseProgram) {
507 		return Cvar_AssertValue(cvar, 0, 3, true);
508 	}
509 
510 	Cvar_SetValue(cvar->name, 0);
511 	return true;
512 }
513 
514 /**
515  * @brief Callback that is called when the r_glsl_version cvar is changed,
516  */
R_CvarGLSLVersionCheck(cvar_t * cvar)517 static bool R_CvarGLSLVersionCheck (cvar_t* cvar)
518 {
519 	int glslVersionMajor, glslVersionMinor;
520 	sscanf(cvar->string, "%d.%d", &glslVersionMajor, &glslVersionMinor);
521 	if (glslVersionMajor > r_config.glslVersionMajor) {
522 		Cvar_Reset(cvar);
523 		return false;
524 	}
525 
526 	if (glslVersionMajor == r_config.glslVersionMajor && glslVersionMinor > r_config.glslVersionMinor) {
527 		Cvar_Reset(cvar);
528 		return false;
529 	}
530 
531 	return true;
532 }
533 
R_CvarPostProcess(cvar_t * cvar)534 static bool R_CvarPostProcess (cvar_t* cvar)
535 {
536 	if (r_config.frameBufferObject && r_config.drawBuffers)
537 		return Cvar_AssertValue(cvar, 0, 1, true);
538 
539 	Cvar_SetValue(cvar->name, 0);
540 	return true;
541 }
542 
R_CvarCheckMultisample(cvar_t * cvar)543 static bool R_CvarCheckMultisample (cvar_t* cvar)
544 {
545 	return Cvar_AssertValue(cvar, 0, 4, true);
546 }
547 
R_RegisterSystemVars(void)548 static void R_RegisterSystemVars (void)
549 {
550 	const cmdList_t* commands;
551 
552 	r_driver = Cvar_Get("r_driver", "", CVAR_ARCHIVE | CVAR_R_CONTEXT, "You can define the opengl driver you want to use - empty if you want to use the system default");
553 	r_drawentities = Cvar_Get("r_drawentities", "1", 0, "Draw the local entities");
554 	r_drawworld = Cvar_Get("r_drawworld", "1", 0, "Draw the world brushes");
555 	r_isometric = Cvar_Get("r_isometric", "0", CVAR_ARCHIVE, "Draw the world in isometric mode");
556 	r_nocull = Cvar_Get("r_nocull", "0", 0, "Don't perform culling for brushes and entities");
557 	r_anisotropic = Cvar_Get("r_anisotropic", "1", CVAR_ARCHIVE);
558 	r_texture_lod = Cvar_Get("r_texture_lod", "0", CVAR_ARCHIVE);
559 	r_screenshot_format = Cvar_Get("r_screenshot_format", "jpg", CVAR_ARCHIVE, "png, jpg or tga are valid screenshot formats");
560 	r_screenshot_jpeg_quality = Cvar_Get("r_screenshot_jpeg_quality", "75", CVAR_ARCHIVE, "jpeg quality in percent for jpeg screenshots");
561 	r_threads = Cvar_Get("r_threads", "0", CVAR_ARCHIVE, "Activate threads for the renderer");
562 
563 	r_materials = Cvar_Get("r_materials", "1", CVAR_ARCHIVE, "Activate material subsystem");
564 	r_overridematerial = Cvar_Get("r_overridematerial", "", 0, "Used to override the material for a map");
565 	r_default_specular = Cvar_Get("r_default_specular", "0.2", CVAR_R_CONTEXT, "Default specular exponent");
566 	r_default_hardness = Cvar_Get("r_default_hardness", "0.2", CVAR_R_CONTEXT, "Default specular brightness");
567 	Cvar_RegisterChangeListener("r_default_specular", R_UpdateDefaultMaterial);
568 	Cvar_RegisterChangeListener("r_default_hardness", R_UpdateDefaultMaterial);
569 	r_checkerror = Cvar_Get("r_checkerror", "0", CVAR_ARCHIVE, "Check for opengl errors");
570 	r_shadows = Cvar_Get("r_shadows", "1", CVAR_ARCHIVE, "Multiplier for the alpha of the shadows");
571 	r_stencilshadows = Cvar_Get("r_stencilshadows", "0", CVAR_ARCHIVE, "Activate or deactivate stencil shadows");
572 	r_maxtexres = Cvar_Get("r_maxtexres", "2048", CVAR_ARCHIVE | CVAR_R_IMAGES, "The maximum texture resolution UFO should use");
573 	r_texturemode = Cvar_Get("r_texturemode", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE, "change the filtering and mipmapping for textures");
574 	r_texturealphamode = Cvar_Get("r_texturealphamode", "GL_RGBA", CVAR_ARCHIVE);
575 	r_texturesolidmode = Cvar_Get("r_texturesolidmode", "GL_RGB", CVAR_ARCHIVE);
576 	r_wire = Cvar_Get("r_wire", "0", 0, "Draw the scene in wireframe mode");
577 	r_showbox = Cvar_Get("r_showbox", "0", CVAR_ARCHIVE, "1=Shows model bounding box, 2=show also the brushes bounding boxes");
578 	r_lightmap = Cvar_Get("r_lightmap", "0", CVAR_R_PROGRAMS, "Draw only the lightmap");
579 	r_lightmap->modified = false;
580 	r_deluxemap = Cvar_Get("r_deluxemap", "0", CVAR_R_PROGRAMS, "Draw only the deluxemap");
581 	r_deluxemap->modified = false;
582 	r_debug_normals = Cvar_Get("r_debug_normals", "0", CVAR_R_PROGRAMS, "Draw dot(normal, light_0 direction)");
583 	r_debug_normals->modified = false;
584 	r_debug_tangents = Cvar_Get("r_debug_tangents", "0", CVAR_R_PROGRAMS, "Draw tangent, bitangent, and normal dotted with light dir as RGB espectively");
585 	r_debug_tangents->modified = false;
586 	r_debug_lights = Cvar_Get("r_debug_lights", "0", CVAR_ARCHIVE, "Draw active light sources");
587 	r_ext_texture_compression = Cvar_Get("r_ext_texture_compression", "0", CVAR_ARCHIVE | CVAR_R_CONTEXT);
588 	r_ext_nonpoweroftwo = Cvar_Get("r_ext_nonpoweroftwo", "1", CVAR_ARCHIVE, "Enable or disable the non power of two extension");
589 	r_ext_s3tc_compression = Cvar_Get("r_ext_s3tc_compression", "1", CVAR_ARCHIVE, "Also see r_ext_texture_compression");
590 	r_intel_hack = Cvar_Get("r_intel_hack", "1", CVAR_ARCHIVE, "Intel cards have no shaders until this is set to 0 - to it to a value > 1 to not limit the max texture resolution");
591 	r_vertexbuffers = Cvar_Get("r_vertexbuffers", "0", CVAR_ARCHIVE | CVAR_R_CONTEXT, "Controls usage of OpenGL Vertex Buffer Objects (VBO) versus legacy vertex arrays.");
592 	r_maxlightmap = Cvar_Get("r_maxlightmap", "2048", CVAR_ARCHIVE | CVAR_LATCH, "Reduce this value on older hardware");
593 	Cvar_SetCheckFunction("r_maxlightmap", R_CvarCheckMaxLightmap);
594 
595 	r_drawbuffer = Cvar_Get("r_drawbuffer", "GL_BACK");
596 	r_swapinterval = Cvar_Get("r_swapinterval", "0", CVAR_ARCHIVE | CVAR_R_CONTEXT, "Controls swap interval synchronization (V-Sync). Values between 0 and 2");
597 	r_multisample = Cvar_Get("r_multisample", "0", CVAR_ARCHIVE | CVAR_R_CONTEXT, "Controls multisampling (anti-aliasing). Values between 0 and 4");
598 	Cvar_SetCheckFunction("r_multisample", R_CvarCheckMultisample);
599 	r_warp = Cvar_Get("r_warp", "1", CVAR_ARCHIVE, "Activates or deactivates warping surface rendering");
600 	r_shownormals = Cvar_Get("r_shownormals", "0", CVAR_ARCHIVE, "Show normals on bsp surfaces");
601 	r_bumpmap = Cvar_Get("r_bumpmap", "1.0", CVAR_ARCHIVE | CVAR_R_PROGRAMS, "Activate bump mapping");
602 	r_specular = Cvar_Get("r_specular", "1.0", CVAR_ARCHIVE, "Controls specular parameters");
603 	r_hardness = Cvar_Get("r_hardness", "1.0", CVAR_ARCHIVE, "Hardness control for GLSL shaders (specular, bump, ...)");
604 	r_parallax = Cvar_Get("r_parallax", "1.0", CVAR_ARCHIVE, "Controls parallax parameters");
605 	r_fog = Cvar_Get("r_fog", "1", CVAR_ARCHIVE | CVAR_R_PROGRAMS, "Activate or deactivate fog");
606 	r_flares = Cvar_Get("r_flares", "1", CVAR_ARCHIVE, "Activate or deactivate flares");
607 	r_coronas = Cvar_Get("r_coronas", "1", CVAR_ARCHIVE, "Activate or deactivate coronas");
608 	r_particles = Cvar_Get("r_particles", "1", 0, "Activate or deactivate particle rendering");
609 	r_drawtags = Cvar_Get("r_drawtags", "0", 0, "Activate or deactivate tag rendering");
610 
611 	for (commands = r_commands; commands->name; commands++)
612 		Cmd_AddCommand(commands->name, commands->function, commands->description);
613 }
614 
615 /**
616  * @note image cvars
617  */
R_RegisterImageVars(void)618 static void R_RegisterImageVars (void)
619 {
620 }
621 
622 /**
623  * Update the graphical context according to a valid context.
624  * All the system is updated according to this new value (viddef and cvars)
625  * @param context New graphical context
626  */
R_UpdateVidDef(const viddefContext_t * context)627 static void R_UpdateVidDef (const viddefContext_t* context)
628 {
629 	viddef.context = *context;
630 
631 	/* update cvars */
632 	Cvar_SetValue("vid_width", viddef.context.width);
633 	Cvar_SetValue("vid_height", viddef.context.height);
634 	Cvar_SetValue("vid_mode", viddef.context.mode);
635 	Cvar_SetValue("vid_fullscreen", viddef.context.fullscreen);
636 	Cvar_SetValue("r_multisample", viddef.context.multisample);
637 	Cvar_SetValue("r_swapinterval", viddef.context.swapinterval);
638 	vid_stretch->modified = false;
639 	vid_fullscreen->modified = false;
640 	vid_mode->modified = false;
641 	r_multisample->modified = false;
642 	r_swapinterval->modified = false;
643 
644 	/* update cache values */
645 	if (viddef.stretch) {
646 		viddef.virtualWidth = VID_NORM_WIDTH;
647 		viddef.virtualHeight = VID_NORM_HEIGHT;
648 	} else {
649 		float normRatio = (float) VID_NORM_WIDTH / (float) VID_NORM_HEIGHT;
650 		float screenRatio = (float) viddef.context.width / (float) viddef.context.height;
651 
652 		/* wide screen */
653 		if (screenRatio > normRatio) {
654 			viddef.virtualWidth = VID_NORM_HEIGHT * screenRatio;
655 			viddef.virtualHeight = VID_NORM_HEIGHT;
656 		/* 5:4 or low */
657 		} else if (screenRatio < normRatio) {
658 			viddef.virtualWidth = VID_NORM_WIDTH;
659 			viddef.virtualHeight = VID_NORM_WIDTH / screenRatio;
660 		/* 4:3 */
661 		} else {
662 			viddef.virtualWidth = VID_NORM_WIDTH;
663 			viddef.virtualHeight = VID_NORM_HEIGHT;
664 		}
665 	}
666 	viddef.rx = (float)viddef.context.width / viddef.virtualWidth;
667 	viddef.ry = (float)viddef.context.height / viddef.virtualHeight;
668 }
669 
R_SetMode(void)670 bool R_SetMode (void)
671 {
672 	bool result;
673 	viddefContext_t prevCtx;
674 	viddefContext_t newCtx;
675 	vidmode_t vidmode;
676 
677 	Com_Printf("I: setting mode %d\n", vid_mode->integer);
678 
679 	/* not values we must restitute */
680 	r_ext_texture_compression->modified = false;
681 	viddef.stretch = vid_stretch->integer;
682 
683 	/* store old values if new ones will fail */
684 	prevCtx = viddef.context;
685 
686 	/* new values */
687 	newCtx = viddef.context;
688 	newCtx.mode = vid_mode->integer;
689 	newCtx.fullscreen = vid_fullscreen->integer;
690 	newCtx.multisample = r_multisample->integer;
691 	newCtx.swapinterval = r_swapinterval->integer;
692 	if (!VID_GetModeInfo(newCtx.mode, &vidmode)) {
693 		Com_Printf("I: invalid mode\n");
694 		Cvar_Set("vid_mode", "-1");
695 		return false;
696 	}
697 	newCtx.width = vidmode.width;
698 	newCtx.height = vidmode.height;
699 	result = R_InitGraphics(&newCtx);
700 	if (!result) {
701 		/* failed, revert */
702 		Com_Printf("Failed to set video mode %dx%d %s.\n",
703 				newCtx.width, newCtx.height,
704 				(newCtx.fullscreen ? "fullscreen" : "windowed"));
705 		result = R_InitGraphics(&prevCtx);
706 		if (!result)
707 			return false;
708 		newCtx = prevCtx;
709 	}
710 
711 	R_UpdateVidDef(&newCtx);
712 	R_ShutdownFBObjects();
713 	R_InitFBObjects();
714 	UI_InvalidateStack();
715 	Com_Printf("I: %dx%d (fullscreen: %s)\n", viddef.context.width, viddef.context.height, viddef.context.fullscreen ? "yes" : "no");
716 	return true;
717 }
718 
719 /**
720  * @note SDL_GL_GetProcAddress returns a void*, which is not on all
721  * supported platforms the same size as a function pointer.
722  * This wrapper is a workaround until SDL is fixed.
723  * It is known to produce the "warning: assignment from incompatible pointer type"
724  */
R_GetProcAddress(const char * functionName)725 static inline uintptr_t R_GetProcAddress (const char* functionName)
726 {
727 	return (uintptr_t)SDL_GL_GetProcAddress(functionName);
728 }
729 
R_GetProcAddressExt(const char * functionName)730 static uintptr_t R_GetProcAddressExt (const char* functionName)
731 {
732 	const char* s = strstr(functionName, "###");
733 	if (s == nullptr) {
734 		return R_GetProcAddress(functionName);
735 	}
736 
737 	const char* replace[] = {"EXT", "OES", "ARB"};
738 	char targetBuf[128];
739 	const size_t length = lengthof(targetBuf);
740 	const size_t replaceNo = lengthof(replace);
741 	for (size_t i = 0; i < replaceNo; i++) {
742 		if (Q_strreplace(functionName, "###", replace[i], targetBuf, length)) {
743 			uintptr_t funcAdr = R_GetProcAddress(targetBuf);
744 			if (funcAdr != 0)
745 				return funcAdr;
746 		}
747 	}
748 	Com_Printf("%s not found\n", functionName);
749 	return 0;
750 }
751 
752 /**
753  * @brief Checks for an OpenGL extension that was announced via the OpenGL ext string. If the given extension string
754  * includes a placeholder (###), several types are checked. Those from the ARB, those that official extensions (EXT),
755  * and those from OpenGL ES (OES)
756  * @param extension The extension string to check. Might also contain placeholders. E.g. "GL_###_framebuffer_object",
757  * GL_ARB_framebuffer_object
758  * @return @c true if the extension was announced by the OpenGL driver, @c false otherwise.
759  */
R_CheckExtension(const char * extension)760 static inline bool R_CheckExtension (const char* extension)
761 {
762 	bool found;
763 #ifdef GL_VERSION_ES_CM_1_0
764 	if(strcmp(extension, "GL_ARB_texture_non_power_of_two") == 0) {
765 		extension = "GL_OES_texture_npot";
766 	}
767 #endif
768 	const char* s = strstr(extension, "###");
769 	if (s == nullptr) {
770 		found = strstr(r_config.extensionsString, extension) != nullptr;
771 	} else {
772 		const char* replace[] = {"ARB", "EXT", "OES"};
773 		char targetBuf[128];
774 		const size_t length = lengthof(targetBuf);
775 		const size_t replaceNo = lengthof(replace);
776 		size_t i;
777 		for (i = 0; i < replaceNo; i++) {
778 			if (Q_strreplace(extension, "###", replace[i], targetBuf, length)) {
779 				if (strstr(r_config.extensionsString, targetBuf) != nullptr) {
780 					found = true;
781 					break;
782 				}
783 			}
784 		}
785 		if (i == replaceNo)
786 			found = false;
787 	}
788 
789 	if (found)
790 		Com_Printf("found %s\n", extension);
791 	else
792 		Com_Printf("%s not found\n", extension);
793 
794 #ifdef GL_VERSION_ES_CM_1_0
795 	if (strcmp(extension, "GL_ARB_multitexture") == 0 ||
796 		strcmp(extension, "GL_ARB_vertex_buffer_object") == 0) {
797 		found = true;
798 		Com_Printf("Overriding %s - it is always present in GLES\n", extension);
799 	}
800 #endif
801 
802 	return found;
803 }
804 
805 #define R_CheckGLVersion(max, min) (r_config.glVersionMajor > max || (r_config.glVersionMajor == max && r_config.glVersionMinor >= min))
806 
807 /**
808  * @brief Check and load all needed and supported opengl extensions
809  * @sa R_Init
810  */
R_InitExtensions(void)811 static void R_InitExtensions (void)
812 {
813 	GLenum err;
814 	int tmpInteger;
815 
816 	/* Get OpenGL version.*/
817 	if(sscanf(r_config.versionString, "%d.%d", &r_config.glVersionMajor, &r_config.glVersionMinor) != 2) {
818 		const char*  versionNumbers = r_config.versionString; /* GLES reports version as "OpenGL ES 1.1", so we must skip non-numeric symbols first */
819 		while(*versionNumbers && strchr("0123456789", *versionNumbers) == nullptr) {
820 			versionNumbers ++;
821 		}
822 		if( *versionNumbers )
823 			sscanf(versionNumbers, "%d.%d", &r_config.glVersionMajor, &r_config.glVersionMinor);
824 	}
825 	Com_Printf("OpenGL version detected: %d.%d", r_config.glVersionMajor, r_config.glVersionMinor);
826 
827 	/* multitexture */
828 	qglActiveTexture = nullptr;
829 	qglClientActiveTexture = nullptr;
830 
831 	/* vertex buffer */
832 	qglGenBuffers = nullptr;
833 	qglDeleteBuffers = nullptr;
834 	qglBindBuffer = nullptr;
835 	qglBufferData = nullptr;
836 
837 	/* glsl */
838 	qglCreateShader = nullptr;
839 	qglDeleteShader = nullptr;
840 	qglShaderSource = nullptr;
841 	qglCompileShader = nullptr;
842 	qglGetShaderiv = nullptr;
843 	qglGetShaderInfoLog = nullptr;
844 	qglCreateProgram = nullptr;
845 	qglDeleteProgram = nullptr;
846 	qglAttachShader = nullptr;
847 	qglDetachShader = nullptr;
848 	qglLinkProgram = nullptr;
849 	qglUseProgram = nullptr;
850 	qglGetActiveUniform = nullptr;
851 	qglGetProgramiv = nullptr;
852 	qglGetProgramInfoLog = nullptr;
853 	qglGetUniformLocation = nullptr;
854 	qglUniform1i = nullptr;
855 	qglUniform1f = nullptr;
856 	qglUniform1fv = nullptr;
857 	qglUniform2fv = nullptr;
858 	qglUniform3fv = nullptr;
859 	qglUniform4fv = nullptr;
860 	qglGetAttribLocation = nullptr;
861 	qglUniformMatrix4fv = nullptr;
862 
863 	/* vertex attribute arrays */
864 	qglEnableVertexAttribArray = nullptr;
865 	qglDisableVertexAttribArray = nullptr;
866 	qglVertexAttribPointer = nullptr;
867 
868 	/* framebuffer objects */
869 	qglIsRenderbufferEXT = nullptr;
870 	qglBindRenderbufferEXT = nullptr;
871 	qglDeleteRenderbuffersEXT = nullptr;
872 	qglGenRenderbuffersEXT = nullptr;
873 	qglRenderbufferStorageEXT = nullptr;
874 	qglRenderbufferStorageMultisampleEXT = nullptr;
875 	qglGetRenderbufferParameterivEXT = nullptr;
876 	qglIsFramebufferEXT = nullptr;
877 	qglBindFramebufferEXT = nullptr;
878 	qglDeleteFramebuffersEXT = nullptr;
879 	qglGenFramebuffersEXT = nullptr;
880 	qglCheckFramebufferStatusEXT = nullptr;
881 	qglFramebufferTexture1DEXT = nullptr;
882 	qglFramebufferTexture2DEXT = nullptr;
883 	qglFramebufferTexture3DEXT = nullptr;
884 	qglFramebufferRenderbufferEXT = nullptr;
885 	qglGetFramebufferAttachmentParameterivEXT = nullptr;
886 	qglGenerateMipmapEXT = nullptr;
887 	qglDrawBuffers = nullptr;
888 
889 	/* multitexture */
890 	if (R_CheckExtension("GL_ARB_multitexture")) {
891 		qglActiveTexture = (ActiveTexture_t)R_GetProcAddress("glActiveTexture");
892 		qglClientActiveTexture = (ClientActiveTexture_t)R_GetProcAddress("glClientActiveTexture");
893 	}
894 
895 #ifndef GL_VERSION_ES_CM_1_0
896 	if (R_CheckExtension("GL_ARB_texture_compression")) {
897 		if (r_ext_texture_compression->integer) {
898 			Com_Printf("using GL_ARB_texture_compression\n");
899 			if (r_ext_s3tc_compression->integer && strstr(r_config.extensionsString, "GL_EXT_texture_compression_s3tc")) {
900 				r_config.gl_compressed_solid_format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
901 				r_config.gl_compressed_alpha_format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
902 			} else {
903 				r_config.gl_compressed_solid_format = GL_COMPRESSED_RGB_ARB;
904 				r_config.gl_compressed_alpha_format = GL_COMPRESSED_RGBA_ARB;
905 			}
906 		}
907 	}
908 #endif
909 
910 	if (R_CheckExtension("GL_ARB_texture_non_power_of_two")) {
911 		if (r_ext_nonpoweroftwo->integer) {
912 			Com_Printf("using GL_ARB_texture_non_power_of_two\n");
913 			r_config.nonPowerOfTwo = true;
914 		} else {
915 			r_config.nonPowerOfTwo = false;
916 			Com_Printf("ignoring GL_ARB_texture_non_power_of_two\n");
917 		}
918 	} else {
919 		if (R_CheckGLVersion(2, 0)) {
920 			r_config.nonPowerOfTwo = r_ext_nonpoweroftwo->integer == 1;
921 		} else {
922 			r_config.nonPowerOfTwo = false;
923 		}
924 	}
925 
926 	/* anisotropy */
927 	if (R_CheckExtension("GL_EXT_texture_filter_anisotropic")) {
928 		if (r_anisotropic->integer) {
929 			glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &r_config.maxAnisotropic);
930 			R_CheckError();
931 			if (r_anisotropic->integer > r_config.maxAnisotropic) {
932 				Com_Printf("max GL_EXT_texture_filter_anisotropic value is %i\n", r_config.maxAnisotropic);
933 				Cvar_SetValue("r_anisotropic", r_config.maxAnisotropic);
934 			}
935 
936 			if (r_config.maxAnisotropic)
937 				r_config.anisotropic = true;
938 		}
939 	}
940 
941 	if (R_CheckExtension("GL_EXT_texture_lod_bias"))
942 		r_config.lod_bias = true;
943 
944 	/* vertex buffer objects */
945 	if (R_CheckExtension("GL_ARB_vertex_buffer_object")) {
946 		qglGenBuffers = (GenBuffers_t)R_GetProcAddress("glGenBuffers");
947 		qglDeleteBuffers = (DeleteBuffers_t)R_GetProcAddress("glDeleteBuffers");
948 		qglBindBuffer = (BindBuffer_t)R_GetProcAddress("glBindBuffer");
949 		qglBufferData = (BufferData_t)R_GetProcAddress("glBufferData");
950 		r_config.maxVertexBufferSize = 256 * 256 * 256; // This is only recommended value, so we don't really care about it, and set some big number.
951 #ifndef GL_VERSION_ES_CM_1_0
952 		glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &r_config.maxVertexBufferSize);
953 #endif
954 		Com_Printf("using GL_ARB_vertex_buffer_object\nmax vertex buffer size: %i\n", r_config.maxVertexBufferSize);
955 	}
956 
957 	/* glsl vertex and fragment shaders and programs */
958 	if (R_CheckExtension("GL_ARB_fragment_shader")) {
959 		qglCreateShader = (CreateShader_t)R_GetProcAddress("glCreateShader");
960 		qglDeleteShader = (DeleteShader_t)R_GetProcAddress("glDeleteShader");
961 		qglShaderSource = (ShaderSource_t)R_GetProcAddress("glShaderSource");
962 		qglCompileShader = (CompileShader_t)R_GetProcAddress("glCompileShader");
963 		qglGetShaderiv = (GetShaderiv_t)R_GetProcAddress("glGetShaderiv");
964 		qglGetShaderInfoLog = (GetShaderInfoLog_t)R_GetProcAddress("glGetShaderInfoLog");
965 		qglCreateProgram = (CreateProgram_t)R_GetProcAddress("glCreateProgram");
966 		qglDeleteProgram = (DeleteProgram_t)R_GetProcAddress("glDeleteProgram");
967 		qglAttachShader = (AttachShader_t)R_GetProcAddress("glAttachShader");
968 		qglDetachShader = (DetachShader_t)R_GetProcAddress("glDetachShader");
969 		qglLinkProgram = (LinkProgram_t)R_GetProcAddress("glLinkProgram");
970 		qglUseProgram = (UseProgram_t)R_GetProcAddress("glUseProgram");
971 		qglGetActiveUniform = (GetActiveUniforms_t)R_GetProcAddress("glGetActiveUniform");
972 		qglGetProgramiv = (GetProgramiv_t)R_GetProcAddress("glGetProgramiv");
973 		qglGetProgramInfoLog = (GetProgramInfoLog_t)R_GetProcAddress("glGetProgramInfoLog");
974 		qglGetUniformLocation = (GetUniformLocation_t)R_GetProcAddress("glGetUniformLocation");
975 		qglUniform1i = (Uniform1i_t)R_GetProcAddress("glUniform1i");
976 		qglUniform1f = (Uniform1f_t)R_GetProcAddress("glUniform1f");
977 		qglUniform1fv = (Uniform1fv_t)R_GetProcAddress("glUniform1fv");
978 		qglUniform2fv = (Uniform2fv_t)R_GetProcAddress("glUniform2fv");
979 		qglUniform3fv = (Uniform3fv_t)R_GetProcAddress("glUniform3fv");
980 		qglUniform4fv = (Uniform4fv_t)R_GetProcAddress("glUniform4fv");
981 		qglGetAttribLocation = (GetAttribLocation_t)R_GetProcAddress("glGetAttribLocation");
982 		qglUniformMatrix4fv = (UniformMatrix4fv_t)R_GetProcAddress("glUniformMatrix4fv");
983 
984 		/* vertex attribute arrays */
985 		qglEnableVertexAttribArray = (EnableVertexAttribArray_t)R_GetProcAddress("glEnableVertexAttribArray");
986 		qglDisableVertexAttribArray = (DisableVertexAttribArray_t)R_GetProcAddress("glDisableVertexAttribArray");
987 		qglVertexAttribPointer = (VertexAttribPointer_t)R_GetProcAddress("glVertexAttribPointer");
988 	}
989 
990 	if (R_CheckExtension("GL_ARB_shading_language_100") || r_config.glVersionMajor >= 2) {
991 		/* The GL_ARB_shading_language_100 extension was added to core specification since OpenGL 2.0;
992 		 * it is ideally listed in the extensions for backwards compatibility.  If it isn't there and OpenGL > v2.0
993 		 * then enable shaders as the implementation supports the shading language!*/
994 		const char* shadingVersion = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
995 		sscanf(shadingVersion, "%d.%d", &r_config.glslVersionMajor, &r_config.glslVersionMinor);
996 		Com_Printf("GLSL version guaranteed to be supported by OpenGL implementation postfixed by vender supplied info: %i.%i\n",
997 				r_config.glslVersionMajor, r_config.glslVersionMinor);
998 	} else {
999 		/* The shading language is not supported.*/
1000 		Com_Printf("GLSL shaders unsupported by OpenGL implementation.\n");
1001 	}
1002 
1003 	/* framebuffer objects */
1004 	if (R_CheckExtension("GL_###_framebuffer_object")) {
1005 		qglIsRenderbufferEXT = (IsRenderbufferEXT_t)R_GetProcAddressExt("glIsRenderbuffer###");
1006 		qglBindRenderbufferEXT = (BindRenderbufferEXT_t)R_GetProcAddressExt("glBindRenderbuffer###");
1007 		qglDeleteRenderbuffersEXT = (DeleteRenderbuffersEXT_t)R_GetProcAddressExt("glDeleteRenderbuffers###");
1008 		qglGenRenderbuffersEXT = (GenRenderbuffersEXT_t)R_GetProcAddressExt("glGenRenderbuffers###");
1009 		qglRenderbufferStorageEXT = (RenderbufferStorageEXT_t)R_GetProcAddressExt("glRenderbufferStorage###");
1010 		qglRenderbufferStorageMultisampleEXT = (RenderbufferStorageMultisampleEXT_t)R_GetProcAddressExt("glRenderbufferStorageMultisample###");
1011 		qglGetRenderbufferParameterivEXT = (GetRenderbufferParameterivEXT_t)R_GetProcAddressExt("glGetRenderbufferParameteriv###");
1012 		qglIsFramebufferEXT = (IsFramebufferEXT_t)R_GetProcAddressExt("glIsFramebuffer###");
1013 		qglBindFramebufferEXT = (BindFramebufferEXT_t)R_GetProcAddressExt("glBindFramebuffer###");
1014 		qglDeleteFramebuffersEXT = (DeleteFramebuffersEXT_t)R_GetProcAddressExt("glDeleteFramebuffers###");
1015 		qglGenFramebuffersEXT = (GenFramebuffersEXT_t)R_GetProcAddressExt("glGenFramebuffers###");
1016 		qglCheckFramebufferStatusEXT = (CheckFramebufferStatusEXT_t)R_GetProcAddressExt("glCheckFramebufferStatus###");
1017 		qglFramebufferTexture1DEXT = (FramebufferTexture1DEXT_t)R_GetProcAddressExt("glFramebufferTexture1D###");
1018 		qglFramebufferTexture2DEXT = (FramebufferTexture2DEXT_t)R_GetProcAddressExt("glFramebufferTexture2D###");
1019 		qglFramebufferTexture3DEXT = (FramebufferTexture3DEXT_t)R_GetProcAddressExt("glFramebufferTexture3D###");
1020 		qglFramebufferRenderbufferEXT = (FramebufferRenderbufferEXT_t)R_GetProcAddressExt("glFramebufferRenderbuffer###");
1021 		qglGetFramebufferAttachmentParameterivEXT = (GetFramebufferAttachmentParameterivEXT_t)R_GetProcAddressExt("glGetFramebufferAttachmentParameteriv###");
1022 		qglGenerateMipmapEXT = (GenerateMipmapEXT_t)R_GetProcAddressExt("glGenerateMipmap###");
1023 		qglDrawBuffers = (DrawBuffers_t)R_GetProcAddress("glDrawBuffers");
1024 		qglBlitFramebuffer = (BlitFramebuffer_t)R_GetProcAddress("glBlitFramebuffer");
1025 
1026 		if (qglDeleteRenderbuffersEXT && qglDeleteFramebuffersEXT && qglGenFramebuffersEXT && qglBindFramebufferEXT
1027 		 && qglFramebufferTexture2DEXT && qglBindRenderbufferEXT && qglRenderbufferStorageEXT && qglCheckFramebufferStatusEXT) {
1028 #ifdef GL_VERSION_ES_CM_1_0
1029 			r_config.maxDrawBuffers = 1; /* GLES does not support multiple buffers or color attachments, only COLOR_ATTACHMENT0_OES is available */
1030 			r_config.maxColorAttachments = 1;
1031 #else
1032 			glGetIntegerv(GL_MAX_DRAW_BUFFERS, &r_config.maxDrawBuffers);
1033 			glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &r_config.maxColorAttachments);
1034 #endif
1035 			glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &r_config.maxRenderbufferSize);
1036 
1037 			r_config.frameBufferObject = true;
1038 
1039 			Com_Printf("using GL_ARB_framebuffer_object\n");
1040 			Com_Printf("max draw buffers: %i\n", r_config.maxDrawBuffers);
1041 			Com_Printf("max render buffer size: %i\n", r_config.maxRenderbufferSize);
1042 			Com_Printf("max color attachments: %i\n", r_config.maxColorAttachments);
1043 		} else {
1044 			Com_Printf("skipping GL_ARB_framebuffer_object - not every needed extension is supported\n");
1045 		}
1046 
1047 		if (r_config.maxDrawBuffers > 1 && R_CheckExtension("GL_###_draw_buffers")) {
1048 			Com_Printf("using GL_ARB_draw_buffers\n");
1049 			r_config.drawBuffers = true;
1050 		} else {
1051 			r_config.drawBuffers = false;
1052 		}
1053 	} else {
1054 		Com_Printf("Framebuffer objects unsupported by OpenGL implementation.\n");
1055 	}
1056 
1057 	r_programs = Cvar_Get("r_programs", "1", CVAR_ARCHIVE | CVAR_R_PROGRAMS, "GLSL shaders level: 0 - disabled, 1 - low, 2 - medium, 3 - high");
1058 	r_programs->modified = false;
1059 	Cvar_SetCheckFunction("r_programs", R_CvarPrograms);
1060 
1061 	r_glsl_version = Cvar_Get("r_glsl_version", "1.10", CVAR_ARCHIVE | CVAR_R_PROGRAMS, "GLSL Version");
1062 	Cvar_SetCheckFunction("r_glsl_version", R_CvarGLSLVersionCheck);
1063 
1064 	r_postprocess = Cvar_Get("r_postprocess", "1", CVAR_ARCHIVE | CVAR_R_PROGRAMS, "Activate postprocessing shader effects");
1065 	Cvar_SetCheckFunction("r_postprocess", R_CvarPostProcess);
1066 
1067 	/* reset gl error state */
1068 	R_CheckError();
1069 
1070 	glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, &r_config.maxVertexTextureImageUnits);
1071 	Com_Printf("max supported vertex texture units: %i\n", r_config.maxVertexTextureImageUnits);
1072 
1073 	glGetIntegerv(GL_MAX_LIGHTS, &r_config.maxLights);
1074 	Com_Printf("max supported lights: %i\n", r_config.maxLights);
1075 
1076 	r_dynamic_lights = Cvar_Get("r_dynamic_lights", "1", CVAR_ARCHIVE | CVAR_R_PROGRAMS, "Sets max number of GL lightsources to use in shaders");
1077 	Cvar_SetCheckFunction("r_dynamic_lights", R_CvarCheckDynamicLights);
1078 
1079 	glGetIntegerv(GL_MAX_TEXTURE_UNITS, &r_config.maxTextureUnits);
1080 	Com_Printf("max texture units: %i\n", r_config.maxTextureUnits);
1081 	if (r_config.maxTextureUnits < 2)
1082 		Com_Error(ERR_FATAL, "You need at least 2 texture units to run " GAME_TITLE);
1083 
1084 	glGetIntegerv(GL_MAX_TEXTURE_COORDS, &r_config.maxTextureCoords);
1085 	Com_Printf("max texture coords: %i\n", r_config.maxTextureCoords);
1086 	r_config.maxTextureCoords = std::max(r_config.maxTextureUnits, r_config.maxTextureCoords);
1087 
1088 	glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &r_config.maxVertexAttribs);
1089 	Com_Printf("max vertex attributes: %i\n", r_config.maxVertexAttribs);
1090 
1091 #ifdef GL_VERSION_ES_CM_1_0
1092 	glGetIntegerv(GL_MAX_VARYING_VECTORS, &tmpInteger);
1093 	Com_Printf("max varying floats: %i\n", tmpInteger * 4);
1094 	glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &tmpInteger);
1095 	Com_Printf("max fragment uniform components: %i\n", tmpInteger * 4);
1096 	glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &tmpInteger);
1097 	Com_Printf("max vertex uniform components: %i\n", tmpInteger * 4);
1098 #else
1099 	glGetIntegerv(GL_MAX_VARYING_FLOATS, &tmpInteger);
1100 	Com_Printf("max varying floats: %i\n", tmpInteger);
1101 	glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &tmpInteger);
1102 	Com_Printf("max fragment uniform components: %i\n", tmpInteger);
1103 	glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &tmpInteger);
1104 	Com_Printf("max vertex uniform components: %i\n", tmpInteger);
1105 #endif
1106 
1107 	/* reset gl error state */
1108 	R_CheckError();
1109 
1110 	/* check max texture size */
1111 	glGetIntegerv(GL_MAX_TEXTURE_SIZE, &r_config.maxTextureSize);
1112 	/* stubbed or broken drivers may have reported 0 */
1113 	if (r_config.maxTextureSize <= 0)
1114 		r_config.maxTextureSize = 256;
1115 
1116 	if ((err = glGetError()) != GL_NO_ERROR) {
1117 		Com_Printf("max texture size: cannot detect - using %i! (%s)\n", r_config.maxTextureSize, R_TranslateError(err));
1118 		Cvar_SetValue("r_maxtexres", r_config.maxTextureSize);
1119 	} else {
1120 		Com_Printf("max texture size: detected %d\n", r_config.maxTextureSize);
1121 		if (r_maxtexres->integer > r_config.maxTextureSize) {
1122 			Com_Printf("...downgrading from %i\n", r_maxtexres->integer);
1123 			Cvar_SetValue("r_maxtexres", r_config.maxTextureSize);
1124 		/* check for a minimum */
1125 		} else if (r_maxtexres->integer >= 128 && r_maxtexres->integer < r_config.maxTextureSize) {
1126 			Com_Printf("...but using %i as requested\n", r_maxtexres->integer);
1127 			r_config.maxTextureSize = r_maxtexres->integer;
1128 		}
1129 	}
1130 
1131 	if (r_config.maxTextureSize > 4096 && R_ImageExists("pics/geoscape/%s/map_earth_season_00", "high")) {
1132 		Q_strncpyz(r_config.lodDir, "high", sizeof(r_config.lodDir));
1133 		Com_Printf("Using high resolution globe textures as requested.\n");
1134 	} else if (r_config.maxTextureSize > 2048 && R_ImageExists("pics/geoscape/med/map_earth_season_00")) {
1135 		if (r_config.maxTextureSize > 4096) {
1136 			Com_Printf("Warning: high resolution globe textures requested, but could not be found; falling back to medium resolution globe textures.\n");
1137 		} else {
1138 			Com_Printf("Using medium resolution globe textures as requested.\n");
1139 		}
1140 		Q_strncpyz(r_config.lodDir, "med", sizeof(r_config.lodDir));
1141 	} else {
1142 		if (r_config.maxTextureSize > 2048) {
1143 			Com_Printf("Warning: medium resolution globe textures requested, but could not be found; falling back to low resolution globe textures.\n");
1144 		} else {
1145 			Com_Printf("Using low resolution globe textures as requested.\n");
1146 		}
1147 		Q_strncpyz(r_config.lodDir, "low", sizeof(r_config.lodDir));
1148 	}
1149 }
1150 
1151 /**
1152  * @brief We need at least opengl version 1.2.1
1153  */
R_EnforceVersion(void)1154 static inline void R_EnforceVersion (void)
1155 {
1156 	int maj, min, rel;
1157 
1158 	sscanf(r_config.versionString, "%d.%d.%d ", &maj, &min, &rel);
1159 
1160 #ifndef GL_VERSION_ES_CM_1_0
1161 	if (maj > 1)
1162 		return;
1163 
1164 	if (maj < 1)
1165 		Com_Error(ERR_FATAL, "OpenGL version %s is less than 1.2.1", r_config.versionString);
1166 
1167 	if (min > 2)
1168 		return;
1169 
1170 	if (min < 2)
1171 		Com_Error(ERR_FATAL, "OpenGL Version %s is less than 1.2.1", r_config.versionString);
1172 
1173 	if (rel > 1)
1174 		return;
1175 
1176 	if (rel < 1)
1177 		Com_Error(ERR_FATAL, "OpenGL version %s is less than 1.2.1", r_config.versionString);
1178 #endif
1179 }
1180 
1181 /**
1182  * @brief Searches vendor and renderer GL strings for the given vendor id
1183  */
R_SearchForVendor(const char * vendor)1184 static bool R_SearchForVendor (const char* vendor)
1185 {
1186 	return Q_stristr(r_config.vendorString, vendor)
1187 		|| Q_stristr(r_config.rendererString, vendor);
1188 }
1189 
1190 #define INTEL_TEXTURE_RESOLUTION 1024
1191 
1192 /**
1193  * @brief Checks whether we have hardware acceleration
1194  */
R_VerifyDriver(void)1195 static inline void R_VerifyDriver (void)
1196 {
1197 #ifdef _WIN32
1198 	if (!Q_strcasecmp((const char*)glGetString(GL_RENDERER), "gdi generic"))
1199 		Com_Error(ERR_FATAL, "No hardware acceleration detected.\n"
1200 			"Update your graphic card drivers.");
1201 #else
1202 	if (!Q_strcasecmp((const char*)glGetString(GL_RENDERER), "Software Rasterizer"))
1203 		Com_Error(ERR_FATAL, "No hardware acceleration detected.\n"
1204 			"Update your graphic card drivers.");
1205 #endif
1206 	if (R_SearchForVendor("Intel")) {
1207 		Com_Printf("You might want to activate texture compression if you have visual artifacts.\n");
1208 		if (r_intel_hack->integer) {
1209 			/* HACK: */
1210 			Com_Printf("Disabling shaders for Intel chips - see cvar r_intel_hack\n");
1211 			Cvar_Set("r_programs", "0");
1212 			if (r_intel_hack->integer == 1) {
1213 				if (r_maxtexres->integer > INTEL_TEXTURE_RESOLUTION) {
1214 					Com_Printf("Set max. texture resolution to %i - see cvar r_intel_hack\n", INTEL_TEXTURE_RESOLUTION);
1215 					Cvar_SetValue("r_maxtexres", INTEL_TEXTURE_RESOLUTION);
1216 				}
1217 			}
1218 		}
1219 		r_config.hardwareType = GLHW_INTEL;
1220 	} else if (R_SearchForVendor("NVIDIA")) {
1221 		r_config.hardwareType = GLHW_NVIDIA;
1222 	} else if (R_SearchForVendor("ATI") || R_SearchForVendor("Advanced Micro Devices") || R_SearchForVendor("AMD")) {
1223 		r_config.hardwareType = GLHW_ATI;
1224 	} else if (R_SearchForVendor("mesa") || R_SearchForVendor("gallium") || R_SearchForVendor("nouveau")) {
1225 		r_config.hardwareType = GLHW_MESA;
1226 	} else {
1227 		r_config.hardwareType = GLHW_GENERIC;
1228 	}
1229 	/* disable intel hack for non intel cards */
1230 	if (!R_SearchForVendor("Intel")) {
1231 		Cvar_Set("r_intel_hack", "0");
1232 		Cvar_Set("r_vendor_non_intel", "1");
1233 	}
1234 }
1235 
R_Init(void)1236 bool R_Init (void)
1237 {
1238 	R_RegisterSystemVars();
1239 
1240 	OBJZERO(r_state);
1241 	OBJZERO(r_locals);
1242 	OBJZERO(r_config);
1243 
1244 	/* some config default values */
1245 	r_config.gl_solid_format = GL_RGB;
1246 	r_config.gl_alpha_format = GL_RGBA;
1247 	r_config.gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
1248 	r_config.gl_filter_max = GL_LINEAR;
1249 	r_config.maxTextureSize = 256;
1250 
1251 	/* initialize OS-specific parts of OpenGL */
1252 	if (!Rimp_Init())
1253 		return false;
1254 
1255 	/* get our various GL strings */
1256 	r_config.vendorString = (const char*)glGetString(GL_VENDOR);
1257 	r_config.rendererString = (const char*)glGetString(GL_RENDERER);
1258 	r_config.versionString = (const char*)glGetString(GL_VERSION);
1259 	r_config.extensionsString = (const char*)glGetString(GL_EXTENSIONS);
1260 	R_Strings_f();
1261 
1262 	/* sanity checks and card specific hacks */
1263 	R_VerifyDriver();
1264 	R_EnforceVersion();
1265 
1266 	R_RegisterImageVars();
1267 
1268 	/* prevent reloading of some rendering cvars */
1269 	Cvar_ClearVars(CVAR_R_MASK);
1270 
1271 	R_InitExtensions();
1272 	R_SetDefaultState();
1273 	R_InitPrograms();
1274 	R_InitImages();
1275 	R_InitMiscTexture();
1276 	R_DrawInitLocal();
1277 	R_SphereInit();
1278 	R_FontInit();
1279 	R_InitFBObjects();
1280 	R_UpdateDefaultMaterial("","","", nullptr);
1281 
1282 	R_CheckError();
1283 
1284 	return true;
1285 }
1286 
1287 /**
1288  * @sa R_Init
1289  */
R_Shutdown(void)1290 void R_Shutdown (void)
1291 {
1292 	const cmdList_t* commands;
1293 
1294 	for (commands = r_commands; commands->name; commands++)
1295 		Cmd_RemoveCommand(commands->name);
1296 
1297 	R_ShutdownThreads();
1298 
1299 	R_ShutdownModels(true);
1300 	R_ShutdownImages();
1301 
1302 	R_ShutdownPrograms();
1303 	R_FontShutdown();
1304 	R_ShutdownFBObjects();
1305 
1306 	/* shut down OS specific OpenGL stuff like contexts, etc. */
1307 	Rimp_Shutdown();
1308 }
1309