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