1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "sys/platform.h"
30 #include "idlib/LangDict.h"
31 #include "framework/Licensee.h"
32 #include "framework/Console.h"
33 #include "framework/Session.h"
34 #include "renderer/VertexCache.h"
35 #include "renderer/ModelManager.h"
36 #include "renderer/RenderWorld_local.h"
37 #include "renderer/GuiModel.h"
38 #include "sound/sound.h"
39 #include "ui/UserInterface.h"
40 
41 #include "renderer/tr_local.h"
42 
43 #include "framework/GameCallbacks_local.h"
44 
45 // Vista OpenGL wrapper check
46 #ifdef _WIN32
47 #include "sys/win32/win_local.h"
48 #endif
49 
50 // functions that are not called every frame
51 
52 glconfig_t	glConfig;
53 
54 const char *r_rendererArgs[] = { "best", "arb2", NULL };
55 
56 idCVar r_inhibitFragmentProgram( "r_inhibitFragmentProgram", "0", CVAR_RENDERER | CVAR_BOOL, "ignore the fragment program extension" );
57 idCVar r_useLightPortalFlow( "r_useLightPortalFlow", "1", CVAR_RENDERER | CVAR_BOOL, "use a more precise area reference determination" );
58 idCVar r_multiSamples( "r_multiSamples", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "number of antialiasing samples" );
59 idCVar r_mode( "r_mode", "5", CVAR_ARCHIVE | CVAR_RENDERER | CVAR_INTEGER, "video mode number" );
60 idCVar r_displayRefresh( "r_displayRefresh", "0", CVAR_RENDERER | CVAR_INTEGER | CVAR_NOCHEAT, "optional display refresh rate option for vid mode", 0.0f, 200.0f );
61 idCVar r_fullscreen( "r_fullscreen", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "0 = windowed, 1 = full screen" );
62 idCVar r_fullscreenDesktop( "r_fullscreenDesktop", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "0: 'real' fullscreen mode 1: keep resolution 'desktop' fullscreen mode" );
63 idCVar r_customWidth( "r_customWidth", "720", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "custom screen width. set r_mode to -1 to activate" );
64 idCVar r_customHeight( "r_customHeight", "486", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "custom screen height. set r_mode to -1 to activate" );
65 idCVar r_singleTriangle( "r_singleTriangle", "0", CVAR_RENDERER | CVAR_BOOL, "only draw a single triangle per primitive" );
66 idCVar r_checkBounds( "r_checkBounds", "0", CVAR_RENDERER | CVAR_BOOL, "compare all surface bounds with precalculated ones" );
67 
68 idCVar r_useConstantMaterials( "r_useConstantMaterials", "1", CVAR_RENDERER | CVAR_BOOL, "use pre-calculated material registers if possible" );
69 idCVar r_useSilRemap( "r_useSilRemap", "1", CVAR_RENDERER | CVAR_BOOL, "consider verts with the same XYZ, but different ST the same for shadows" );
70 idCVar r_useNodeCommonChildren( "r_useNodeCommonChildren", "1", CVAR_RENDERER | CVAR_BOOL, "stop pushing reference bounds early when possible" );
71 idCVar r_useShadowProjectedCull( "r_useShadowProjectedCull", "1", CVAR_RENDERER | CVAR_BOOL, "discard triangles outside light volume before shadowing" );
72 idCVar r_useShadowVertexProgram( "r_useShadowVertexProgram", "1", CVAR_RENDERER | CVAR_BOOL, "do the shadow projection in the vertex program on capable cards" );
73 idCVar r_useShadowSurfaceScissor( "r_useShadowSurfaceScissor", "1", CVAR_RENDERER | CVAR_BOOL, "scissor shadows by the scissor rect of the interaction surfaces" );
74 idCVar r_useInteractionTable( "r_useInteractionTable", "1", CVAR_RENDERER | CVAR_BOOL, "create a full entityDefs * lightDefs table to make finding interactions faster" );
75 idCVar r_useTurboShadow( "r_useTurboShadow", "1", CVAR_RENDERER | CVAR_BOOL, "use the infinite projection with W technique for dynamic shadows" );
76 idCVar r_useTwoSidedStencil( "r_useTwoSidedStencil", "1", CVAR_RENDERER | CVAR_BOOL, "do stencil shadows in one pass with different ops on each side" );
77 idCVar r_useDeferredTangents( "r_useDeferredTangents", "1", CVAR_RENDERER | CVAR_BOOL, "defer tangents calculations after deform" );
78 idCVar r_useCachedDynamicModels( "r_useCachedDynamicModels", "1", CVAR_RENDERER | CVAR_BOOL, "cache snapshots of dynamic models" );
79 
80 idCVar r_useVertexBuffers( "r_useVertexBuffers", "1", CVAR_RENDERER | CVAR_INTEGER, "use ARB_vertex_buffer_object for vertexes", 0, 1, idCmdSystem::ArgCompletion_Integer<0,1>  );
81 idCVar r_useIndexBuffers( "r_useIndexBuffers", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "use ARB_vertex_buffer_object for indexes", 0, 1, idCmdSystem::ArgCompletion_Integer<0,1>  );
82 
83 idCVar r_useStateCaching( "r_useStateCaching", "1", CVAR_RENDERER | CVAR_BOOL, "avoid redundant state changes in GL_*() calls" );
84 idCVar r_useInfiniteFarZ( "r_useInfiniteFarZ", "1", CVAR_RENDERER | CVAR_BOOL, "use the no-far-clip-plane trick" );
85 
86 idCVar r_znear( "r_znear", "3", CVAR_RENDERER | CVAR_FLOAT, "near Z clip plane distance", 0.001f, 200.0f );
87 
88 idCVar r_ignoreGLErrors( "r_ignoreGLErrors", "1", CVAR_RENDERER | CVAR_BOOL, "ignore GL errors" );
89 idCVar r_finish( "r_finish", "0", CVAR_RENDERER | CVAR_BOOL, "force a call to glFinish() every frame" );
90 idCVar r_swapInterval( "r_swapInterval", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "changes the GL swap interval" );
91 
92 idCVar r_gamma( "r_gamma", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "changes gamma tables", 0.5f, 3.0f );
93 idCVar r_brightness( "r_brightness", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "changes gamma tables", 0.5f, 2.0f );
94 
95 idCVar r_renderer( "r_renderer", "best", CVAR_RENDERER | CVAR_ARCHIVE, "hardware specific renderer path to use", r_rendererArgs, idCmdSystem::ArgCompletion_String<r_rendererArgs> );
96 
97 idCVar r_jitter( "r_jitter", "0", CVAR_RENDERER | CVAR_BOOL, "randomly subpixel jitter the projection matrix" );
98 
99 idCVar r_skipSuppress( "r_skipSuppress", "0", CVAR_RENDERER | CVAR_BOOL, "ignore the per-view suppressions" );
100 idCVar r_skipPostProcess( "r_skipPostProcess", "0", CVAR_RENDERER | CVAR_BOOL, "skip all post-process renderings" );
101 idCVar r_skipLightScale( "r_skipLightScale", "0", CVAR_RENDERER | CVAR_BOOL, "don't do any post-interaction light scaling, makes things dim on low-dynamic range cards" );
102 idCVar r_skipInteractions( "r_skipInteractions", "0", CVAR_RENDERER | CVAR_BOOL, "skip all light/surface interaction drawing" );
103 idCVar r_skipDynamicTextures( "r_skipDynamicTextures", "0", CVAR_RENDERER | CVAR_BOOL, "don't dynamically create textures" );
104 idCVar r_skipCopyTexture( "r_skipCopyTexture", "0", CVAR_RENDERER | CVAR_BOOL, "do all rendering, but don't actually copyTexSubImage2D" );
105 idCVar r_skipBackEnd( "r_skipBackEnd", "0", CVAR_RENDERER | CVAR_BOOL, "don't draw anything" );
106 idCVar r_skipRender( "r_skipRender", "0", CVAR_RENDERER | CVAR_BOOL, "skip 3D rendering, but pass 2D" );
107 idCVar r_skipRenderContext( "r_skipRenderContext", "0", CVAR_RENDERER | CVAR_BOOL, "NULL the rendering context during backend 3D rendering" );
108 idCVar r_skipTranslucent( "r_skipTranslucent", "0", CVAR_RENDERER | CVAR_BOOL, "skip the translucent interaction rendering" );
109 idCVar r_skipAmbient( "r_skipAmbient", "0", CVAR_RENDERER | CVAR_BOOL, "bypasses all non-interaction drawing" );
110 idCVar r_skipNewAmbient( "r_skipNewAmbient", "0", CVAR_RENDERER | CVAR_BOOL | CVAR_ARCHIVE, "bypasses all vertex/fragment program ambient drawing" );
111 idCVar r_skipBlendLights( "r_skipBlendLights", "0", CVAR_RENDERER | CVAR_BOOL, "skip all blend lights" );
112 idCVar r_skipFogLights( "r_skipFogLights", "0", CVAR_RENDERER | CVAR_BOOL, "skip all fog lights" );
113 idCVar r_skipDeforms( "r_skipDeforms", "0", CVAR_RENDERER | CVAR_BOOL, "leave all deform materials in their original state" );
114 idCVar r_skipFrontEnd( "r_skipFrontEnd", "0", CVAR_RENDERER | CVAR_BOOL, "bypasses all front end work, but 2D gui rendering still draws" );
115 idCVar r_skipUpdates( "r_skipUpdates", "0", CVAR_RENDERER | CVAR_BOOL, "1 = don't accept any entity or light updates, making everything static" );
116 idCVar r_skipOverlays( "r_skipOverlays", "0", CVAR_RENDERER | CVAR_BOOL, "skip overlay surfaces" );
117 idCVar r_skipSpecular( "r_skipSpecular", "0", CVAR_RENDERER | CVAR_BOOL | CVAR_CHEAT | CVAR_ARCHIVE, "use black for specular1" );
118 idCVar r_skipBump( "r_skipBump", "0", CVAR_RENDERER | CVAR_BOOL | CVAR_ARCHIVE, "uses a flat surface instead of the bump map" );
119 idCVar r_skipDiffuse( "r_skipDiffuse", "0", CVAR_RENDERER | CVAR_BOOL, "use black for diffuse" );
120 idCVar r_skipROQ( "r_skipROQ", "0", CVAR_RENDERER | CVAR_BOOL, "skip ROQ decoding" );
121 
122 idCVar r_ignore( "r_ignore", "0", CVAR_RENDERER, "used for random debugging without defining new vars" );
123 idCVar r_ignore2( "r_ignore2", "0", CVAR_RENDERER, "used for random debugging without defining new vars" );
124 idCVar r_usePreciseTriangleInteractions( "r_usePreciseTriangleInteractions", "0", CVAR_RENDERER | CVAR_BOOL, "1 = do winding clipping to determine if each ambiguous tri should be lit" );
125 idCVar r_useCulling( "r_useCulling", "2", CVAR_RENDERER | CVAR_INTEGER, "0 = none, 1 = sphere, 2 = sphere + box", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
126 idCVar r_useLightCulling( "r_useLightCulling", "3", CVAR_RENDERER | CVAR_INTEGER, "0 = none, 1 = box, 2 = exact clip of polyhedron faces, 3 = also areas", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
127 idCVar r_useLightScissors( "r_useLightScissors", "1", CVAR_RENDERER | CVAR_BOOL, "1 = use custom scissor rectangle for each light" );
128 idCVar r_useClippedLightScissors( "r_useClippedLightScissors", "1", CVAR_RENDERER | CVAR_INTEGER, "0 = full screen when near clipped, 1 = exact when near clipped, 2 = exact always", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
129 idCVar r_useEntityCulling( "r_useEntityCulling", "1", CVAR_RENDERER | CVAR_BOOL, "0 = none, 1 = box" );
130 idCVar r_useEntityScissors( "r_useEntityScissors", "0", CVAR_RENDERER | CVAR_BOOL, "1 = use custom scissor rectangle for each entity" );
131 idCVar r_useInteractionCulling( "r_useInteractionCulling", "1", CVAR_RENDERER | CVAR_BOOL, "1 = cull interactions" );
132 idCVar r_useInteractionScissors( "r_useInteractionScissors", "2", CVAR_RENDERER | CVAR_INTEGER, "1 = use a custom scissor rectangle for each shadow interaction, 2 = also crop using portal scissors", -2, 2, idCmdSystem::ArgCompletion_Integer<-2,2> );
133 idCVar r_useShadowCulling( "r_useShadowCulling", "1", CVAR_RENDERER | CVAR_BOOL, "try to cull shadows from partially visible lights" );
134 idCVar r_useFrustumFarDistance( "r_useFrustumFarDistance", "0", CVAR_RENDERER | CVAR_FLOAT, "if != 0 force the view frustum far distance to this distance" );
135 idCVar r_clear( "r_clear", "2", CVAR_RENDERER, "force screen clear every frame, 1 = purple, 2 = black, 'r g b' = custom" );
136 idCVar r_offsetFactor( "r_offsetfactor", "0", CVAR_RENDERER | CVAR_FLOAT, "polygon offset parameter" );
137 idCVar r_offsetUnits( "r_offsetunits", "-600", CVAR_RENDERER | CVAR_FLOAT, "polygon offset parameter" );
138 idCVar r_shadowPolygonOffset( "r_shadowPolygonOffset", "-1", CVAR_RENDERER | CVAR_FLOAT, "bias value added to depth test for stencil shadow drawing" );
139 idCVar r_shadowPolygonFactor( "r_shadowPolygonFactor", "0", CVAR_RENDERER | CVAR_FLOAT, "scale value for stencil shadow drawing" );
140 idCVar r_frontBuffer( "r_frontBuffer", "0", CVAR_RENDERER | CVAR_BOOL, "draw to front buffer for debugging" );
141 idCVar r_skipSubviews( "r_skipSubviews", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = don't render any gui elements on surfaces" );
142 idCVar r_skipGuiShaders( "r_skipGuiShaders", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = skip all gui elements on surfaces, 2 = skip drawing but still handle events, 3 = draw but skip events", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
143 idCVar r_skipParticles( "r_skipParticles", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = skip all particle systems", 0, 1, idCmdSystem::ArgCompletion_Integer<0,1> );
144 idCVar r_subviewOnly( "r_subviewOnly", "0", CVAR_RENDERER | CVAR_BOOL, "1 = don't render main view, allowing subviews to be debugged" );
145 idCVar r_shadows( "r_shadows", "1", CVAR_RENDERER | CVAR_BOOL  | CVAR_ARCHIVE, "enable shadows" );
146 idCVar r_testARBProgram( "r_testARBProgram", "0", CVAR_RENDERER | CVAR_BOOL, "experiment with vertex/fragment programs" );
147 idCVar r_testGamma( "r_testGamma", "0", CVAR_RENDERER | CVAR_FLOAT, "if > 0 draw a grid pattern to test gamma levels", 0, 195 );
148 idCVar r_testGammaBias( "r_testGammaBias", "0", CVAR_RENDERER | CVAR_FLOAT, "if > 0 draw a grid pattern to test gamma levels" );
149 idCVar r_testStepGamma( "r_testStepGamma", "0", CVAR_RENDERER | CVAR_FLOAT, "if > 0 draw a grid pattern to test gamma levels" );
150 idCVar r_lightScale( "r_lightScale", "2", CVAR_RENDERER | CVAR_FLOAT, "all light intensities are multiplied by this" );
151 idCVar r_lightSourceRadius( "r_lightSourceRadius", "0", CVAR_RENDERER | CVAR_FLOAT, "for soft-shadow sampling" );
152 idCVar r_flareSize( "r_flareSize", "1", CVAR_RENDERER | CVAR_FLOAT, "scale the flare deforms from the material def" );
153 
154 idCVar r_useExternalShadows( "r_useExternalShadows", "1", CVAR_RENDERER | CVAR_INTEGER, "1 = skip drawing caps when outside the light volume, 2 = force to no caps for testing", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
155 idCVar r_useOptimizedShadows( "r_useOptimizedShadows", "1", CVAR_RENDERER | CVAR_BOOL, "use the dmap generated static shadow volumes" );
156 idCVar r_useScissor( "r_useScissor", "1", CVAR_RENDERER | CVAR_BOOL, "scissor clip as portals and lights are processed" );
157 idCVar r_useCombinerDisplayLists( "r_useCombinerDisplayLists", "1", CVAR_RENDERER | CVAR_BOOL | CVAR_NOCHEAT, "put all nvidia register combiner programming in display lists" );
158 idCVar r_useDepthBoundsTest( "r_useDepthBoundsTest", "1", CVAR_RENDERER | CVAR_BOOL, "use depth bounds test to reduce shadow fill" );
159 
160 idCVar r_screenFraction( "r_screenFraction", "100", CVAR_RENDERER | CVAR_INTEGER, "for testing fill rate, the resolution of the entire screen can be changed" );
161 idCVar r_demonstrateBug( "r_demonstrateBug", "0", CVAR_RENDERER | CVAR_BOOL, "used during development to show IHV's their problems" );
162 idCVar r_usePortals( "r_usePortals", "1", CVAR_RENDERER | CVAR_BOOL, " 1 = use portals to perform area culling, otherwise draw everything" );
163 idCVar r_singleLight( "r_singleLight", "-1", CVAR_RENDERER | CVAR_INTEGER, "suppress all but one light" );
164 idCVar r_singleEntity( "r_singleEntity", "-1", CVAR_RENDERER | CVAR_INTEGER, "suppress all but one entity" );
165 idCVar r_singleSurface( "r_singleSurface", "-1", CVAR_RENDERER | CVAR_INTEGER, "suppress all but one surface on each entity" );
166 idCVar r_singleArea( "r_singleArea", "0", CVAR_RENDERER | CVAR_BOOL, "only draw the portal area the view is actually in" );
167 idCVar r_forceLoadImages( "r_forceLoadImages", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "draw all images to screen after registration" );
168 idCVar r_orderIndexes( "r_orderIndexes", "1", CVAR_RENDERER | CVAR_BOOL, "perform index reorganization to optimize vertex use" );
169 idCVar r_lightAllBackFaces( "r_lightAllBackFaces", "0", CVAR_RENDERER | CVAR_BOOL, "light all the back faces, even when they would be shadowed" );
170 
171 // visual debugging info
172 idCVar r_showPortals( "r_showPortals", "0", CVAR_RENDERER | CVAR_BOOL, "draw portal outlines in color based on passed / not passed" );
173 idCVar r_showUnsmoothedTangents( "r_showUnsmoothedTangents", "0", CVAR_RENDERER | CVAR_BOOL, "if 1, put all nvidia register combiner programming in display lists" );
174 idCVar r_showSilhouette( "r_showSilhouette", "0", CVAR_RENDERER | CVAR_BOOL, "highlight edges that are casting shadow planes" );
175 idCVar r_showVertexColor( "r_showVertexColor", "0", CVAR_RENDERER | CVAR_BOOL, "draws all triangles with the solid vertex color" );
176 idCVar r_showUpdates( "r_showUpdates", "0", CVAR_RENDERER | CVAR_BOOL, "report entity and light updates and ref counts" );
177 idCVar r_showDemo( "r_showDemo", "0", CVAR_RENDERER | CVAR_BOOL, "report reads and writes to the demo file" );
178 idCVar r_showDynamic( "r_showDynamic", "0", CVAR_RENDERER | CVAR_BOOL, "report stats on dynamic surface generation" );
179 idCVar r_showLightScale( "r_showLightScale", "0", CVAR_RENDERER | CVAR_BOOL, "report the scale factor applied to drawing for overbrights" );
180 idCVar r_showDefs( "r_showDefs", "0", CVAR_RENDERER | CVAR_BOOL, "report the number of modeDefs and lightDefs in view" );
181 idCVar r_showTrace( "r_showTrace", "0", CVAR_RENDERER | CVAR_INTEGER, "show the intersection of an eye trace with the world", idCmdSystem::ArgCompletion_Integer<0,2> );
182 idCVar r_showIntensity( "r_showIntensity", "0", CVAR_RENDERER | CVAR_BOOL, "draw the screen colors based on intensity, red = 0, green = 128, blue = 255" );
183 idCVar r_showImages( "r_showImages", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = show all images instead of rendering, 2 = show in proportional size", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
184 idCVar r_showSmp( "r_showSmp", "0", CVAR_RENDERER | CVAR_BOOL, "show which end (front or back) is blocking" );
185 idCVar r_showLights( "r_showLights", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = just print volumes numbers, highlighting ones covering the view, 2 = also draw planes of each volume, 3 = also draw edges of each volume", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
186 idCVar r_showShadows( "r_showShadows", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = visualize the stencil shadow volumes, 2 = draw filled in", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
187 idCVar r_showShadowCount( "r_showShadowCount", "0", CVAR_RENDERER | CVAR_INTEGER, "colors screen based on shadow volume depth complexity, >= 2 = print overdraw count based on stencil index values, 3 = only show turboshadows, 4 = only show static shadows", 0, 4, idCmdSystem::ArgCompletion_Integer<0,4> );
188 idCVar r_showLightScissors( "r_showLightScissors", "0", CVAR_RENDERER | CVAR_BOOL, "show light scissor rectangles" );
189 idCVar r_showEntityScissors( "r_showEntityScissors", "0", CVAR_RENDERER | CVAR_BOOL, "show entity scissor rectangles" );
190 idCVar r_showInteractionFrustums( "r_showInteractionFrustums", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = show a frustum for each interaction, 2 = also draw lines to light origin, 3 = also draw entity bbox", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
191 idCVar r_showInteractionScissors( "r_showInteractionScissors", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = show screen rectangle which contains the interaction frustum, 2 = also draw construction lines", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
192 idCVar r_showLightCount( "r_showLightCount", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = colors surfaces based on light count, 2 = also count everything through walls, 3 = also print overdraw", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
193 idCVar r_showViewEntitys( "r_showViewEntitys", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = displays the bounding boxes of all view models, 2 = print index numbers" );
194 idCVar r_showTris( "r_showTris", "0", CVAR_RENDERER | CVAR_INTEGER, "enables wireframe rendering of the world, 1 = only draw visible ones, 2 = draw all front facing, 3 = draw all", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
195 idCVar r_showSurfaceInfo( "r_showSurfaceInfo", "0", CVAR_RENDERER | CVAR_BOOL, "show surface material name under crosshair" );
196 idCVar r_showNormals( "r_showNormals", "0", CVAR_RENDERER | CVAR_FLOAT, "draws wireframe normals" );
197 idCVar r_showMemory( "r_showMemory", "0", CVAR_RENDERER | CVAR_BOOL, "print frame memory utilization" );
198 idCVar r_showCull( "r_showCull", "0", CVAR_RENDERER | CVAR_BOOL, "report sphere and box culling stats" );
199 idCVar r_showInteractions( "r_showInteractions", "0", CVAR_RENDERER | CVAR_BOOL, "report interaction generation activity" );
200 idCVar r_showDepth( "r_showDepth", "0", CVAR_RENDERER | CVAR_BOOL, "display the contents of the depth buffer and the depth range" );
201 idCVar r_showSurfaces( "r_showSurfaces", "0", CVAR_RENDERER | CVAR_BOOL, "report surface/light/shadow counts" );
202 idCVar r_showPrimitives( "r_showPrimitives", "0", CVAR_RENDERER | CVAR_INTEGER, "report drawsurf/index/vertex counts" );
203 idCVar r_showEdges( "r_showEdges", "0", CVAR_RENDERER | CVAR_BOOL, "draw the sil edges" );
204 idCVar r_showTexturePolarity( "r_showTexturePolarity", "0", CVAR_RENDERER | CVAR_BOOL, "shade triangles by texture area polarity" );
205 idCVar r_showTangentSpace( "r_showTangentSpace", "0", CVAR_RENDERER | CVAR_INTEGER, "shade triangles by tangent space, 1 = use 1st tangent vector, 2 = use 2nd tangent vector, 3 = use normal vector", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
206 idCVar r_showDominantTri( "r_showDominantTri", "0", CVAR_RENDERER | CVAR_BOOL, "draw lines from vertexes to center of dominant triangles" );
207 idCVar r_showAlloc( "r_showAlloc", "0", CVAR_RENDERER | CVAR_BOOL, "report alloc/free counts" );
208 idCVar r_showTextureVectors( "r_showTextureVectors", "0", CVAR_RENDERER | CVAR_FLOAT, " if > 0 draw each triangles texture (tangent) vectors" );
209 idCVar r_showOverDraw( "r_showOverDraw", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = geometry overdraw, 2 = light interaction overdraw, 3 = geometry and light interaction overdraw", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
210 
211 idCVar r_lockSurfaces( "r_lockSurfaces", "0", CVAR_RENDERER | CVAR_BOOL, "allow moving the view point without changing the composition of the scene, including culling" );
212 idCVar r_useEntityCallbacks( "r_useEntityCallbacks", "1", CVAR_RENDERER | CVAR_BOOL, "if 0, issue the callback immediately at update time, rather than defering" );
213 
214 idCVar r_showSkel( "r_showSkel", "0", CVAR_RENDERER | CVAR_INTEGER, "draw the skeleton when model animates, 1 = draw model with skeleton, 2 = draw skeleton only", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
215 idCVar r_jointNameScale( "r_jointNameScale", "0.02", CVAR_RENDERER | CVAR_FLOAT, "size of joint names when r_showskel is set to 1" );
216 idCVar r_jointNameOffset( "r_jointNameOffset", "0.5", CVAR_RENDERER | CVAR_FLOAT, "offset of joint names when r_showskel is set to 1" );
217 
218 idCVar r_debugLineDepthTest( "r_debugLineDepthTest", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "perform depth test on debug lines" );
219 idCVar r_debugLineWidth( "r_debugLineWidth", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "width of debug lines" );
220 idCVar r_debugArrowStep( "r_debugArrowStep", "120", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "step size of arrow cone line rotation in degrees", 0, 120 );
221 idCVar r_debugPolygonFilled( "r_debugPolygonFilled", "1", CVAR_RENDERER | CVAR_BOOL, "draw a filled polygon" );
222 
223 idCVar r_materialOverride( "r_materialOverride", "", CVAR_RENDERER, "overrides all materials", idCmdSystem::ArgCompletion_Decl<DECL_MATERIAL> );
224 
225 idCVar r_debugRenderToTexture( "r_debugRenderToTexture", "0", CVAR_RENDERER | CVAR_INTEGER, "" );
226 
227 // DG: let users disable the "scale menus to 4:3" hack
228 idCVar r_scaleMenusTo43( "r_scaleMenusTo43", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "Scale menus, fullscreen videos and PDA to 4:3 aspect ratio" );
229 // DG: the fscking patent has finally expired
230 idCVar r_useCarmacksReverse( "r_useCarmacksReverse", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "Use Z-Fail (Carmack's Reverse) when rendering shadows" );
231 idCVar r_useStencilOpSeparate( "r_useStencilOpSeparate", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "Use glStencilOpSeparate() (if available) when rendering shadows" );
232 
233 // define qgl functions
234 #define QGLPROC(name, rettype, args) rettype (APIENTRYP q##name) args;
235 #include "renderer/qgl_proc.h"
236 
237 void ( APIENTRY * qglMultiTexCoord2fARB )( GLenum texture, GLfloat s, GLfloat t );
238 void ( APIENTRY * qglMultiTexCoord2fvARB )( GLenum texture, GLfloat *st );
239 void ( APIENTRY * qglActiveTextureARB )( GLenum texture );
240 void ( APIENTRY * qglClientActiveTextureARB )( GLenum texture );
241 
242 void (APIENTRY *qglTexImage3D)(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
243 
244 void (APIENTRY * qglColorTableEXT)( int, int, int, int, int, const void * );
245 
246 // EXT_stencil_two_side
247 PFNGLACTIVESTENCILFACEEXTPROC			qglActiveStencilFaceEXT;
248 
249 // ARB_texture_compression
250 PFNGLCOMPRESSEDTEXIMAGE2DARBPROC		qglCompressedTexImage2DARB;
251 PFNGLGETCOMPRESSEDTEXIMAGEARBPROC		qglGetCompressedTexImageARB;
252 
253 // ARB_vertex_buffer_object
254 PFNGLBINDBUFFERARBPROC					qglBindBufferARB;
255 PFNGLDELETEBUFFERSARBPROC				qglDeleteBuffersARB;
256 PFNGLGENBUFFERSARBPROC					qglGenBuffersARB;
257 PFNGLISBUFFERARBPROC					qglIsBufferARB;
258 PFNGLBUFFERDATAARBPROC					qglBufferDataARB;
259 PFNGLBUFFERSUBDATAARBPROC				qglBufferSubDataARB;
260 PFNGLGETBUFFERSUBDATAARBPROC			qglGetBufferSubDataARB;
261 PFNGLMAPBUFFERARBPROC					qglMapBufferARB;
262 PFNGLUNMAPBUFFERARBPROC					qglUnmapBufferARB;
263 PFNGLGETBUFFERPARAMETERIVARBPROC		qglGetBufferParameterivARB;
264 PFNGLGETBUFFERPOINTERVARBPROC			qglGetBufferPointervARB;
265 
266 // ARB_vertex_program / ARB_fragment_program
267 PFNGLVERTEXATTRIBPOINTERARBPROC			qglVertexAttribPointerARB;
268 PFNGLENABLEVERTEXATTRIBARRAYARBPROC		qglEnableVertexAttribArrayARB;
269 PFNGLDISABLEVERTEXATTRIBARRAYARBPROC	qglDisableVertexAttribArrayARB;
270 PFNGLPROGRAMSTRINGARBPROC				qglProgramStringARB;
271 PFNGLBINDPROGRAMARBPROC					qglBindProgramARB;
272 PFNGLGENPROGRAMSARBPROC					qglGenProgramsARB;
273 PFNGLPROGRAMENVPARAMETER4FVARBPROC		qglProgramEnvParameter4fvARB;
274 PFNGLPROGRAMLOCALPARAMETER4FVARBPROC	qglProgramLocalParameter4fvARB;
275 
276 // GL_EXT_depth_bounds_test
277 PFNGLDEPTHBOUNDSEXTPROC                 qglDepthBoundsEXT;
278 
279 // DG: couldn't find any extension for this, it's supported in GL2.0 and newer, incl OpenGL ES2.0
280 PFNGLSTENCILOPSEPARATEPROC qglStencilOpSeparate;
281 
282 /*
283 =================
284 R_CheckExtension
285 =================
286 */
R_CheckExtension(const char * name)287 bool R_CheckExtension( const char *name ) {
288 	if ( !strstr( glConfig.extensions_string, name ) ) {
289 		common->Printf( "X..%s not found\n", name );
290 		return false;
291 	}
292 
293 	common->Printf( "...using %s\n", name );
294 	return true;
295 }
296 
297 /*
298 ==================
299 R_CheckPortableExtensions
300 
301 ==================
302 */
R_CheckPortableExtensions(void)303 static void R_CheckPortableExtensions( void ) {
304 	glConfig.glVersion = atof( glConfig.version_string );
305 
306 	// GL_ARB_multitexture
307 	glConfig.multitextureAvailable = R_CheckExtension( "GL_ARB_multitexture" );
308 	if ( glConfig.multitextureAvailable ) {
309 		qglMultiTexCoord2fARB = (void(APIENTRY *)(GLenum, GLfloat, GLfloat))GLimp_ExtensionPointer( "glMultiTexCoord2fARB" );
310 		qglMultiTexCoord2fvARB = (void(APIENTRY *)(GLenum, GLfloat *))GLimp_ExtensionPointer( "glMultiTexCoord2fvARB" );
311 		qglActiveTextureARB = (void(APIENTRY *)(GLenum))GLimp_ExtensionPointer( "glActiveTextureARB" );
312 		qglClientActiveTextureARB = (void(APIENTRY *)(GLenum))GLimp_ExtensionPointer( "glClientActiveTextureARB" );
313 		qglGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, (GLint *)&glConfig.maxTextureUnits );
314 		if ( glConfig.maxTextureUnits > MAX_MULTITEXTURE_UNITS ) {
315 			glConfig.maxTextureUnits = MAX_MULTITEXTURE_UNITS;
316 		}
317 		if ( glConfig.maxTextureUnits < 2 ) {
318 			glConfig.multitextureAvailable = false;	// shouldn't ever happen
319 		}
320 		qglGetIntegerv( GL_MAX_TEXTURE_COORDS_ARB, (GLint *)&glConfig.maxTextureCoords );
321 		qglGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS_ARB, (GLint *)&glConfig.maxTextureImageUnits );
322 	}
323 
324 	// GL_ARB_texture_env_combine
325 	glConfig.textureEnvCombineAvailable = R_CheckExtension( "GL_ARB_texture_env_combine" );
326 
327 	// GL_ARB_texture_cube_map
328 	glConfig.cubeMapAvailable = R_CheckExtension( "GL_ARB_texture_cube_map" );
329 
330 	// GL_ARB_texture_env_dot3
331 	glConfig.envDot3Available = R_CheckExtension( "GL_ARB_texture_env_dot3" );
332 
333 	// GL_ARB_texture_env_add
334 	glConfig.textureEnvAddAvailable = R_CheckExtension( "GL_ARB_texture_env_add" );
335 
336 	// GL_ARB_texture_non_power_of_two
337 	glConfig.textureNonPowerOfTwoAvailable = R_CheckExtension( "GL_ARB_texture_non_power_of_two" );
338 
339 	// GL_ARB_texture_compression + GL_S3_s3tc
340 	// DRI drivers may have GL_ARB_texture_compression but no GL_EXT_texture_compression_s3tc
341 	if ( R_CheckExtension( "GL_ARB_texture_compression" ) && R_CheckExtension( "GL_EXT_texture_compression_s3tc" ) ) {
342 		glConfig.textureCompressionAvailable = true;
343 		qglCompressedTexImage2DARB = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)GLimp_ExtensionPointer( "glCompressedTexImage2DARB" );
344 		qglGetCompressedTexImageARB = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)GLimp_ExtensionPointer( "glGetCompressedTexImageARB" );
345 	} else {
346 		glConfig.textureCompressionAvailable = false;
347 	}
348 
349 	// GL_EXT_texture_filter_anisotropic
350 	glConfig.anisotropicAvailable = R_CheckExtension( "GL_EXT_texture_filter_anisotropic" );
351 	if ( glConfig.anisotropicAvailable ) {
352 		qglGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig.maxTextureAnisotropy );
353 		common->Printf( "   maxTextureAnisotropy: %f\n", glConfig.maxTextureAnisotropy );
354 	} else {
355 		glConfig.maxTextureAnisotropy = 1;
356 	}
357 
358 	// GL_EXT_texture_lod_bias
359 	// The actual extension is broken as specificed, storing the state in the texture unit instead
360 	// of the texture object.  The behavior in GL 1.4 is the behavior we use.
361 	if ( glConfig.glVersion >= 1.4 || R_CheckExtension( "GL_EXT_texture_lod" ) ) {
362 		common->Printf( "...using %s\n", "GL_1.4_texture_lod_bias" );
363 		glConfig.textureLODBiasAvailable = true;
364 	} else {
365 		common->Printf( "X..%s not found\n", "GL_1.4_texture_lod_bias" );
366 		glConfig.textureLODBiasAvailable = false;
367 	}
368 
369 	// GL_EXT_shared_texture_palette
370 	glConfig.sharedTexturePaletteAvailable = R_CheckExtension( "GL_EXT_shared_texture_palette" );
371 	if ( glConfig.sharedTexturePaletteAvailable ) {
372 		qglColorTableEXT = ( void ( APIENTRY * ) ( int, int, int, int, int, const void * ) ) GLimp_ExtensionPointer( "glColorTableEXT" );
373 	}
374 
375 	// GL_EXT_texture3D (not currently used for anything)
376 	glConfig.texture3DAvailable = R_CheckExtension( "GL_EXT_texture3D" );
377 	if ( glConfig.texture3DAvailable ) {
378 		qglTexImage3D =
379 			(void (APIENTRY *)(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *) )
380 			GLimp_ExtensionPointer( "glTexImage3D" );
381 	}
382 
383 	// EXT_stencil_wrap
384 	// This isn't very important, but some pathological case might cause a clamp error and give a shadow bug.
385 	// Nvidia also believes that future hardware may be able to run faster with this enabled to avoid the
386 	// serialization of clamping.
387 	if ( R_CheckExtension( "GL_EXT_stencil_wrap" ) ) {
388 		tr.stencilIncr = GL_INCR_WRAP_EXT;
389 		tr.stencilDecr = GL_DECR_WRAP_EXT;
390 	} else {
391 		tr.stencilIncr = GL_INCR;
392 		tr.stencilDecr = GL_DECR;
393 	}
394 
395 	// GL_EXT_stencil_two_side
396 	glConfig.twoSidedStencilAvailable = R_CheckExtension( "GL_EXT_stencil_two_side" );
397 	if ( glConfig.twoSidedStencilAvailable )
398 		qglActiveStencilFaceEXT = (PFNGLACTIVESTENCILFACEEXTPROC)GLimp_ExtensionPointer( "glActiveStencilFaceEXT" );
399 
400 	if( glConfig.glVersion >= 2.0) {
401 		common->Printf( "... got GL2.0+ glStencilOpSeparate()\n" );
402 		qglStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)GLimp_ExtensionPointer( "glStencilOpSeparate" );
403 	} else {
404 		// TODO: there was an extension by ATI providing glStencilOpSeparateATI - do we care?
405 		common->Printf( "... don't have GL2.0+ glStencilOpSeparate()\n" );
406 		qglStencilOpSeparate = NULL;
407 	}
408 
409 	// ARB_vertex_buffer_object
410 	glConfig.ARBVertexBufferObjectAvailable = R_CheckExtension( "GL_ARB_vertex_buffer_object" );
411 	if(glConfig.ARBVertexBufferObjectAvailable) {
412 		qglBindBufferARB = (PFNGLBINDBUFFERARBPROC)GLimp_ExtensionPointer( "glBindBufferARB");
413 		qglDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)GLimp_ExtensionPointer( "glDeleteBuffersARB");
414 		qglGenBuffersARB = (PFNGLGENBUFFERSARBPROC)GLimp_ExtensionPointer( "glGenBuffersARB");
415 		qglIsBufferARB = (PFNGLISBUFFERARBPROC)GLimp_ExtensionPointer( "glIsBufferARB");
416 		qglBufferDataARB = (PFNGLBUFFERDATAARBPROC)GLimp_ExtensionPointer( "glBufferDataARB");
417 		qglBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)GLimp_ExtensionPointer( "glBufferSubDataARB");
418 		qglGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC)GLimp_ExtensionPointer( "glGetBufferSubDataARB");
419 		qglMapBufferARB = (PFNGLMAPBUFFERARBPROC)GLimp_ExtensionPointer( "glMapBufferARB");
420 		qglUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)GLimp_ExtensionPointer( "glUnmapBufferARB");
421 		qglGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)GLimp_ExtensionPointer( "glGetBufferParameterivARB");
422 		qglGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC)GLimp_ExtensionPointer( "glGetBufferPointervARB");
423 	}
424 
425 	// ARB_vertex_program
426 	glConfig.ARBVertexProgramAvailable = R_CheckExtension( "GL_ARB_vertex_program" );
427 	if (glConfig.ARBVertexProgramAvailable) {
428 		qglVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC)GLimp_ExtensionPointer( "glVertexAttribPointerARB" );
429 		qglEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)GLimp_ExtensionPointer( "glEnableVertexAttribArrayARB" );
430 		qglDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)GLimp_ExtensionPointer( "glDisableVertexAttribArrayARB" );
431 		qglProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)GLimp_ExtensionPointer( "glProgramStringARB" );
432 		qglBindProgramARB = (PFNGLBINDPROGRAMARBPROC)GLimp_ExtensionPointer( "glBindProgramARB" );
433 		qglGenProgramsARB = (PFNGLGENPROGRAMSARBPROC)GLimp_ExtensionPointer( "glGenProgramsARB" );
434 		qglProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC)GLimp_ExtensionPointer( "glProgramEnvParameter4fvARB" );
435 		qglProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)GLimp_ExtensionPointer( "glProgramLocalParameter4fvARB" );
436 	}
437 
438 	// ARB_fragment_program
439 	if ( r_inhibitFragmentProgram.GetBool() ) {
440 		glConfig.ARBFragmentProgramAvailable = false;
441 	} else {
442 		glConfig.ARBFragmentProgramAvailable = R_CheckExtension( "GL_ARB_fragment_program" );
443 		if (glConfig.ARBFragmentProgramAvailable) {
444 			// these are the same as ARB_vertex_program
445 			qglProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)GLimp_ExtensionPointer( "glProgramStringARB" );
446 			qglBindProgramARB = (PFNGLBINDPROGRAMARBPROC)GLimp_ExtensionPointer( "glBindProgramARB" );
447 			qglProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC)GLimp_ExtensionPointer( "glProgramEnvParameter4fvARB" );
448 			qglProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)GLimp_ExtensionPointer( "glProgramLocalParameter4fvARB" );
449 		}
450 	}
451 
452 	// check for minimum set
453 	if ( !glConfig.multitextureAvailable || !glConfig.textureEnvCombineAvailable || !glConfig.cubeMapAvailable
454 		|| !glConfig.envDot3Available ) {
455 			common->Error( common->GetLanguageDict()->GetString( "#str_06780" ) );
456 	}
457 
458 	// GL_EXT_depth_bounds_test
459 	glConfig.depthBoundsTestAvailable = R_CheckExtension( "EXT_depth_bounds_test" );
460 	if ( glConfig.depthBoundsTestAvailable ) {
461 		qglDepthBoundsEXT = (PFNGLDEPTHBOUNDSEXTPROC)GLimp_ExtensionPointer( "glDepthBoundsEXT" );
462 	}
463 
464 }
465 
466 
467 /*
468 ====================
469 R_GetModeInfo
470 
471 r_mode is normally a small non-negative integer that
472 looks resolutions up in a table, but if it is set to -1,
473 the values from r_customWidth, and r_customHeight
474 will be used instead.
475 ====================
476 */
477 typedef struct vidmode_s {
478 	const char *description;
479 	int         width, height;
480 } vidmode_t;
481 
482 vidmode_t r_vidModes[] = {
483 	{ "Mode  0: 320x240",		320,	240 },
484 	{ "Mode  1: 400x300",		400,	300 },
485 	{ "Mode  2: 512x384",		512,	384 },
486 	{ "Mode  3: 640x480",		640,	480 },
487 	{ "Mode  4: 800x600",		800,	600 },
488 	{ "Mode  5: 1024x768",		1024,	768 },
489 	{ "Mode  6: 1152x864",		1152,	864 },
490 	{ "Mode  7: 1280x1024",		1280,	1024 },
491 	{ "Mode  8: 1600x1200",		1600,	1200 },
492 	// DG: from here on: modes I added.
493 	{ "Mode  9: 1280x720",		1280,	720 },
494 	{ "Mode 10: 1366x768",		1366,	768 },
495 	{ "Mode 11: 1440x900",		1440,	900 },
496 	{ "Mode 12: 1400x1050",		1400,	1050 },
497 	{ "Mode 13: 1600x900",		1600,	900 },
498 	{ "Mode 14: 1680x1050",		1680,	1050 },
499 	{ "Mode 15: 1920x1080",		1920,	1080 },
500 	{ "Mode 16: 1920x1200",		1920,	1200 },
501 	{ "Mode 17: 2048x1152",		2048,	1152 },
502 	{ "Mode 18: 2560x1600",		2560,	1600 },
503 	{ "Mode 19: 3200x2400",		3200,	2400 },
504 	{ "Mode 20: 3840x2160",		3840,   2160 },
505 	{ "Mode 21: 4096x2304",		4096,   2304 },
506 	{ "Mode 22: 2880x1800",		2880,   1800 },
507 	{ "Mode 23: 2560x1440",		2560,   1440 },
508 };
509 // DG: made this an enum so even stupid compilers accept it as array length below
510 enum {	s_numVidModes = sizeof( r_vidModes ) / sizeof( r_vidModes[0] ) };
511 
R_GetModeInfo(int * width,int * height,int mode)512 static bool R_GetModeInfo( int *width, int *height, int mode ) {
513 	vidmode_t	*vm;
514 
515 	if ( mode < -1 ) {
516 		return false;
517 	}
518 	if ( mode >= s_numVidModes ) {
519 		return false;
520 	}
521 
522 	if ( mode == -1 ) {
523 		*width = r_customWidth.GetInteger();
524 		*height = r_customHeight.GetInteger();
525 		return true;
526 	}
527 
528 	vm = &r_vidModes[mode];
529 
530 	if ( width ) {
531 		*width  = vm->width;
532 	}
533 	if ( height ) {
534 		*height = vm->height;
535 	}
536 
537 	return true;
538 }
539 
540 // DG: I added all this vidModeInfoPtr stuff, so I can have a second list of vidmodes
541 //     that are sorted (by width, height), instead of just r_mode index.
542 //     That way I can add modes without breaking r_mode, but still display them
543 //     sorted in the menu.
544 
545 struct vidModePtr {
546 	vidmode_t* vidMode;
547 	int modeIndex;
548 };
549 
550 static vidModePtr sortedVidModes[s_numVidModes];
551 
vidModeCmp(const void * vm1,const void * vm2)552 static int vidModeCmp(const void* vm1, const void* vm2)
553 {
554 	const vidModePtr* v1 = static_cast<const vidModePtr*>(vm1);
555 	const vidModePtr* v2 = static_cast<const vidModePtr*>(vm2);
556 
557 	// sort primarily by width, secondarily by height
558 	int wdiff = v1->vidMode->width - v2->vidMode->width;
559 	return (wdiff != 0) ? wdiff : (v1->vidMode->height - v2->vidMode->height);
560 }
561 
initSortedVidModes()562 static void initSortedVidModes()
563 {
564 	if(sortedVidModes[0].vidMode != NULL)
565 	{
566 		// already initialized
567 		return;
568 	}
569 
570 	for(int i=0; i<s_numVidModes; ++i)
571 	{
572 		sortedVidModes[i].modeIndex = i;
573 		sortedVidModes[i].vidMode = &r_vidModes[i];
574 	}
575 
576 	qsort(sortedVidModes, s_numVidModes, sizeof(vidModePtr), vidModeCmp);
577 }
578 
579 // DG: the following two functions are part of a horrible hack in ChoiceWindow.cpp
580 //     to overwrite the default resolution list in the system options menu
581 
582 // "r_custom*;640x480;800x600;1024x768;..."
R_GetVidModeListString(bool addCustom)583 idStr R_GetVidModeListString(bool addCustom)
584 {
585 	idStr ret = addCustom ? "r_custom*" : "";
586 
587 	for(int i=0; i<s_numVidModes; ++i)
588 	{
589 		// for some reason, modes 0-2 are not used. maybe too small for GUI?
590 		if(sortedVidModes[i].modeIndex >= 3 && sortedVidModes[i].vidMode != NULL)
591 		{
592 			idStr modeStr;
593 			sprintf(modeStr, ";%dx%d", sortedVidModes[i].vidMode->width, sortedVidModes[i].vidMode->height);
594 			ret += modeStr;
595 		}
596 	}
597 	return ret;
598 }
599 
600 // r_mode values for resolutions from R_GetVidModeListString(): "-1;3;4;5;..."
R_GetVidModeValsString(bool addCustom)601 idStr R_GetVidModeValsString(bool addCustom)
602 {
603 	idStr ret = addCustom ? "-1" : ""; // for custom resolutions using r_customWidth/r_customHeight
604 	for(int i=0; i<s_numVidModes; ++i)
605 	{
606 		// for some reason, modes 0-2 are not used. maybe too small for GUI?
607 		if(sortedVidModes[i].modeIndex >= 3 && sortedVidModes[i].vidMode != NULL)
608 		{
609 			ret += ";";
610 			ret += sortedVidModes[i].modeIndex;
611 		}
612 	}
613 	return ret;
614 }
615 // DG end
616 
617 
618 /*
619 ==================
620 R_InitOpenGL
621 
622 This function is responsible for initializing a valid OpenGL subsystem
623 for rendering.  This is done by calling the system specific GLimp_Init,
624 which gives us a working OGL subsystem, then setting all necessary openGL
625 state, including images, vertex programs, and display lists.
626 
627 Changes to the vertex cache size or smp state require a vid_restart.
628 
629 If glConfig.isInitialized is false, no rendering can take place, but
630 all renderSystem functions will still operate properly, notably the material
631 and model information functions.
632 ==================
633 */
R_InitOpenGL(void)634 void R_InitOpenGL( void ) {
635 	GLint			temp;
636 	glimpParms_t	parms;
637 	int				i;
638 
639 	common->Printf( "----- Initializing OpenGL -----\n" );
640 
641 	if ( glConfig.isInitialized ) {
642 		common->FatalError( "R_InitOpenGL called while active" );
643 	}
644 
645 	// in case we had an error while doing a tiled rendering
646 	tr.viewportOffset[0] = 0;
647 	tr.viewportOffset[1] = 0;
648 
649 	initSortedVidModes();
650 
651 	//
652 	// initialize OS specific portions of the renderSystem
653 	//
654 	for ( i = 0 ; i < 2 ; i++ ) {
655 		// set the parameters we are trying
656 		R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, r_mode.GetInteger() );
657 
658 		parms.width = glConfig.vidWidth;
659 		parms.height = glConfig.vidHeight;
660 		parms.fullScreen = r_fullscreen.GetBool();
661 		parms.displayHz = r_displayRefresh.GetInteger();
662 		parms.multiSamples = r_multiSamples.GetInteger();
663 		parms.stereo = false;
664 
665 		if ( GLimp_Init( parms ) ) {
666 			// it worked
667 			break;
668 		}
669 
670 		if ( i == 1 ) {
671 			common->FatalError( "Unable to initialize OpenGL" );
672 		}
673 
674 		// if we failed, set everything back to "safe mode"
675 		// and try again
676 		r_mode.SetInteger( 3 );
677 		r_fullscreen.SetInteger( 0 );
678 		r_displayRefresh.SetInteger( 0 );
679 		r_multiSamples.SetInteger( 0 );
680 	}
681 
682 // load qgl function pointers
683 #define QGLPROC(name, rettype, args) \
684 	q##name = (rettype(APIENTRYP)args)GLimp_ExtensionPointer(#name); \
685 	if (!q##name) \
686 		common->FatalError("Unable to initialize OpenGL (%s)", #name);
687 
688 #include "renderer/qgl_proc.h"
689 
690 	// input and sound systems need to be tied to the new window
691 	Sys_InitInput();
692 	soundSystem->InitHW();
693 
694 	// get our config strings
695 	glConfig.vendor_string = (const char *)qglGetString(GL_VENDOR);
696 	glConfig.renderer_string = (const char *)qglGetString(GL_RENDERER);
697 	glConfig.version_string = (const char *)qglGetString(GL_VERSION);
698 	glConfig.extensions_string = (const char *)qglGetString(GL_EXTENSIONS);
699 
700 	// OpenGL driver constants
701 	qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp );
702 	glConfig.maxTextureSize = temp;
703 
704 	// stubbed or broken drivers may have reported 0...
705 	if ( glConfig.maxTextureSize <= 0 ) {
706 		glConfig.maxTextureSize = 256;
707 	}
708 
709 	glConfig.isInitialized = true;
710 
711 	common->Printf("OpenGL vendor: %s\n", glConfig.vendor_string );
712 	common->Printf("OpenGL renderer: %s\n", glConfig.renderer_string );
713 	common->Printf("OpenGL version: %s\n", glConfig.version_string );
714 
715 	// recheck all the extensions (FIXME: this might be dangerous)
716 	R_CheckPortableExtensions();
717 
718 	// parse our vertex and fragment programs, possibly disably support for
719 	// one of the paths if there was an error
720 	R_ARB2_Init();
721 
722 	cmdSystem->AddCommand( "reloadARBprograms", R_ReloadARBPrograms_f, CMD_FL_RENDERER, "reloads ARB programs" );
723 	R_ReloadARBPrograms_f( idCmdArgs() );
724 
725 	// allocate the vertex array range or vertex objects
726 	vertexCache.Init();
727 
728 	// select which renderSystem we are going to use
729 	r_renderer.SetModified();
730 	tr.SetBackEndRenderer();
731 
732 	// allocate the frame data, which may be more if smp is enabled
733 	R_InitFrameData();
734 
735 	// Reset our gamma
736 	R_SetColorMappings();
737 
738 #ifdef _WIN32
739 	static bool glCheck = false;
740 	if ( !glCheck && win32.osversion.dwMajorVersion == 6 ) {
741 		glCheck = true;
742 		if ( !idStr::Icmp( glConfig.vendor_string, "Microsoft" ) && idStr::FindText( glConfig.renderer_string, "OpenGL-D3D" ) != -1 ) {
743 			if ( cvarSystem->GetCVarBool( "r_fullscreen" ) ) {
744 				cmdSystem->BufferCommandText( CMD_EXEC_NOW, "vid_restart partial windowed\n" );
745 				Sys_GrabMouseCursor( false );
746 			}
747 			int ret = MessageBox( NULL, "Please install OpenGL drivers from your graphics hardware vendor to run " GAME_NAME ".\nYour OpenGL functionality is limited.",
748 				"Insufficient OpenGL capabilities", MB_OKCANCEL | MB_ICONWARNING | MB_TASKMODAL );
749 			if ( ret == IDCANCEL ) {
750 				cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "quit\n" );
751 				cmdSystem->ExecuteCommandBuffer();
752 			}
753 			if ( cvarSystem->GetCVarBool( "r_fullscreen" ) ) {
754 				cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "vid_restart\n" );
755 			}
756 		}
757 	}
758 #endif
759 }
760 
761 /*
762 ==================
763 GL_CheckErrors
764 ==================
765 */
GL_CheckErrors(void)766 void GL_CheckErrors( void ) {
767 	int		err;
768 	char	s[64];
769 	int		i;
770 
771 	// check for up to 10 errors pending
772 	for ( i = 0 ; i < 10 ; i++ ) {
773 		err = qglGetError();
774 		if ( err == GL_NO_ERROR ) {
775 			return;
776 		}
777 		switch( err ) {
778 			case GL_INVALID_ENUM:
779 				strcpy( s, "GL_INVALID_ENUM" );
780 				break;
781 			case GL_INVALID_VALUE:
782 				strcpy( s, "GL_INVALID_VALUE" );
783 				break;
784 			case GL_INVALID_OPERATION:
785 				strcpy( s, "GL_INVALID_OPERATION" );
786 				break;
787 			case GL_STACK_OVERFLOW:
788 				strcpy( s, "GL_STACK_OVERFLOW" );
789 				break;
790 			case GL_STACK_UNDERFLOW:
791 				strcpy( s, "GL_STACK_UNDERFLOW" );
792 				break;
793 			case GL_OUT_OF_MEMORY:
794 				strcpy( s, "GL_OUT_OF_MEMORY" );
795 				break;
796 			default:
797 				idStr::snPrintf( s, sizeof(s), "%i", err);
798 				break;
799 		}
800 
801 		if ( !r_ignoreGLErrors.GetBool() ) {
802 			common->Printf( "GL_CheckErrors: %s\n", s );
803 		}
804 	}
805 }
806 
807 /*
808 =====================
809 R_ReloadSurface_f
810 
811 Reload the material displayed by r_showSurfaceInfo
812 =====================
813 */
R_ReloadSurface_f(const idCmdArgs & args)814 static void R_ReloadSurface_f( const idCmdArgs &args ) {
815 	modelTrace_t mt;
816 	idVec3 start, end;
817 
818 	// start far enough away that we don't hit the player model
819 	start = tr.primaryView->renderView.vieworg + tr.primaryView->renderView.viewaxis[0] * 16;
820 	end = start + tr.primaryView->renderView.viewaxis[0] * 1000.0f;
821 	if ( !tr.primaryWorld->Trace( mt, start, end, 0.0f, false ) ) {
822 		return;
823 	}
824 
825 	common->Printf( "Reloading %s\n", mt.material->GetName() );
826 
827 	// reload the decl
828 	mt.material->base->Reload();
829 
830 	// reload any images used by the decl
831 	mt.material->ReloadImages( false );
832 }
833 
834 
835 
836 /*
837 ==============
838 R_ListModes_f
839 ==============
840 */
R_ListModes_f(const idCmdArgs & args)841 static void R_ListModes_f( const idCmdArgs &args ) {
842 	int i;
843 
844 	common->Printf( "\n" );
845 	for ( i = 0; i < s_numVidModes; i++ ) {
846 		common->Printf( "%s\n", r_vidModes[i].description );
847 	}
848 	common->Printf( "\n" );
849 }
850 
851 
852 
853 /*
854 =============
855 R_TestImage_f
856 
857 Display the given image centered on the screen.
858 testimage <number>
859 testimage <filename>
860 =============
861 */
R_TestImage_f(const idCmdArgs & args)862 void R_TestImage_f( const idCmdArgs &args ) {
863 	int imageNum;
864 
865 	if ( tr.testVideo ) {
866 		delete tr.testVideo;
867 		tr.testVideo = NULL;
868 	}
869 	tr.testImage = NULL;
870 
871 	if ( args.Argc() != 2 ) {
872 		return;
873 	}
874 
875 	if ( idStr::IsNumeric( args.Argv(1) ) ) {
876 		imageNum = atoi( args.Argv(1) );
877 		if ( imageNum >= 0 && imageNum < globalImages->images.Num() ) {
878 			tr.testImage = globalImages->images[imageNum];
879 		}
880 	} else {
881 		tr.testImage = globalImages->ImageFromFile( args.Argv( 1 ), TF_DEFAULT, false, TR_REPEAT, TD_DEFAULT );
882 	}
883 }
884 
885 /*
886 =============
887 R_TestVideo_f
888 
889 Plays the cinematic file in a testImage
890 =============
891 */
R_TestVideo_f(const idCmdArgs & args)892 void R_TestVideo_f( const idCmdArgs &args ) {
893 	if ( tr.testVideo ) {
894 		delete tr.testVideo;
895 		tr.testVideo = NULL;
896 	}
897 	tr.testImage = NULL;
898 
899 	if ( args.Argc() < 2 ) {
900 		return;
901 	}
902 
903 	tr.testImage = globalImages->ImageFromFile( "_scratch", TF_DEFAULT, false, TR_REPEAT, TD_DEFAULT );
904 	tr.testVideo = idCinematic::Alloc();
905 	tr.testVideo->InitFromFile( args.Argv( 1 ), true );
906 
907 	cinData_t	cin;
908 	cin = tr.testVideo->ImageForTime( 0 );
909 	if ( !cin.image ) {
910 		delete tr.testVideo;
911 		tr.testVideo = NULL;
912 		tr.testImage = NULL;
913 		return;
914 	}
915 
916 	common->Printf( "%i x %i images\n", cin.imageWidth, cin.imageHeight );
917 
918 	int	len = tr.testVideo->AnimationLength();
919 	common->Printf( "%5.1f seconds of video\n", len * 0.001 );
920 
921 	tr.testVideoStartTime = tr.primaryRenderView.time * 0.001;
922 
923 	// try to play the matching wav file
924 	idStr	wavString = args.Argv( ( args.Argc() == 2 ) ? 1 : 2 );
925 	wavString.StripFileExtension();
926 	wavString = wavString + ".wav";
927 	session->sw->PlayShaderDirectly( wavString.c_str() );
928 }
929 
R_QsortSurfaceAreas(const void * a,const void * b)930 static int R_QsortSurfaceAreas( const void *a, const void *b ) {
931 	const idMaterial	*ea, *eb;
932 	int	ac, bc;
933 
934 	ea = *(idMaterial **)a;
935 	if ( !ea->EverReferenced() ) {
936 		ac = 0;
937 	} else {
938 		ac = ea->GetSurfaceArea();
939 	}
940 	eb = *(idMaterial **)b;
941 	if ( !eb->EverReferenced() ) {
942 		bc = 0;
943 	} else {
944 		bc = eb->GetSurfaceArea();
945 	}
946 
947 	if ( ac < bc ) {
948 		return -1;
949 	}
950 	if ( ac > bc ) {
951 		return 1;
952 	}
953 
954 	return idStr::Icmp( ea->GetName(), eb->GetName() );
955 }
956 
957 
958 /*
959 ===================
960 R_ReportSurfaceAreas_f
961 
962 Prints a list of the materials sorted by surface area
963 ===================
964 */
R_ReportSurfaceAreas_f(const idCmdArgs & args)965 void R_ReportSurfaceAreas_f( const idCmdArgs &args ) {
966 	int		i, count;
967 	idMaterial	**list;
968 
969 	count = declManager->GetNumDecls( DECL_MATERIAL );
970 	list = (idMaterial **)_alloca( count * sizeof( *list ) );
971 
972 	for ( i = 0 ; i < count ; i++ ) {
973 		list[i] = (idMaterial *)declManager->DeclByIndex( DECL_MATERIAL, i, false );
974 	}
975 
976 	qsort( list, count, sizeof( list[0] ), R_QsortSurfaceAreas );
977 
978 	// skip over ones with 0 area
979 	for ( i = 0 ; i < count ; i++ ) {
980 		if ( list[i]->GetSurfaceArea() > 0 ) {
981 			break;
982 		}
983 	}
984 
985 	for ( ; i < count ; i++ ) {
986 		// report size in "editor blocks"
987 		int	blocks = list[i]->GetSurfaceArea() / 4096.0;
988 		common->Printf( "%7i %s\n", blocks, list[i]->GetName() );
989 	}
990 }
991 
992 /*
993 ===================
994 R_ReportImageDuplication_f
995 
996 Checks for images with the same hash value and does a better comparison
997 ===================
998 */
R_ReportImageDuplication_f(const idCmdArgs & args)999 void R_ReportImageDuplication_f( const idCmdArgs &args ) {
1000 	int		i, j;
1001 
1002 	common->Printf( "Images with duplicated contents:\n" );
1003 
1004 	int	count = 0;
1005 
1006 	for ( i = 0 ; i < globalImages->images.Num() ; i++ ) {
1007 		idImage	*image1 = globalImages->images[i];
1008 
1009 		if ( image1->isPartialImage ) {
1010 			// ignore background loading stubs
1011 			continue;
1012 		}
1013 		if ( image1->generatorFunction ) {
1014 			// ignore procedural images
1015 			continue;
1016 		}
1017 		if ( image1->cubeFiles != CF_2D ) {
1018 			// ignore cube maps
1019 			continue;
1020 		}
1021 		if ( image1->defaulted ) {
1022 			continue;
1023 		}
1024 		byte	*data1;
1025 		int		w1, h1;
1026 
1027 		R_LoadImageProgram( image1->imgName, &data1, &w1, &h1, NULL );
1028 
1029 		for ( j = 0 ; j < i ; j++ ) {
1030 			idImage	*image2 = globalImages->images[j];
1031 
1032 			if ( image2->isPartialImage ) {
1033 				continue;
1034 			}
1035 			if ( image2->generatorFunction ) {
1036 				continue;
1037 			}
1038 			if ( image2->cubeFiles != CF_2D ) {
1039 				continue;
1040 			}
1041 			if ( image2->defaulted ) {
1042 				continue;
1043 			}
1044 			if ( image1->imageHash != image2->imageHash ) {
1045 				continue;
1046 			}
1047 			if ( image2->uploadWidth != image1->uploadWidth
1048 				|| image2->uploadHeight != image1->uploadHeight ) {
1049 				continue;
1050 			}
1051 			if ( !idStr::Icmp( image1->imgName, image2->imgName ) ) {
1052 				// ignore same image-with-different-parms
1053 				continue;
1054 			}
1055 
1056 			byte	*data2;
1057 			int		w2, h2;
1058 
1059 			R_LoadImageProgram( image2->imgName, &data2, &w2, &h2, NULL );
1060 
1061 			if ( w2 != w1 || h2 != h1 ) {
1062 				R_StaticFree( data2 );
1063 				continue;
1064 			}
1065 
1066 			if ( memcmp( data1, data2, w1*h1*4 ) ) {
1067 				R_StaticFree( data2 );
1068 				continue;
1069 			}
1070 
1071 			R_StaticFree( data2 );
1072 
1073 			common->Printf( "%s == %s\n", image1->imgName.c_str(), image2->imgName.c_str() );
1074 			session->UpdateScreen( true );
1075 			count++;
1076 			break;
1077 		}
1078 
1079 		R_StaticFree( data1 );
1080 	}
1081 	common->Printf( "%i / %i collisions\n", count, globalImages->images.Num() );
1082 }
1083 
1084 /*
1085 ==============================================================================
1086 
1087 						THROUGHPUT BENCHMARKING
1088 
1089 ==============================================================================
1090 */
1091 
1092 /*
1093 ================
1094 R_RenderingFPS
1095 ================
1096 */
R_RenderingFPS(const renderView_t * renderView)1097 static float R_RenderingFPS( const renderView_t *renderView ) {
1098 	qglFinish();
1099 
1100 	int		start = Sys_Milliseconds();
1101 	static const int SAMPLE_MSEC = 1000;
1102 	int		end;
1103 	int		count = 0;
1104 
1105 	while( 1 ) {
1106 		// render
1107 		renderSystem->BeginFrame( glConfig.vidWidth, glConfig.vidHeight );
1108 		tr.primaryWorld->RenderScene( renderView );
1109 		renderSystem->EndFrame( NULL, NULL );
1110 		qglFinish();
1111 		count++;
1112 		end = Sys_Milliseconds();
1113 		if ( end - start > SAMPLE_MSEC ) {
1114 			break;
1115 		}
1116 	}
1117 
1118 	float fps = count * 1000.0 / ( end - start );
1119 
1120 	return fps;
1121 }
1122 
1123 /*
1124 ================
1125 R_Benchmark_f
1126 ================
1127 */
R_Benchmark_f(const idCmdArgs & args)1128 void R_Benchmark_f( const idCmdArgs &args ) {
1129 	float	fps, msec;
1130 	renderView_t	view;
1131 
1132 	if ( !tr.primaryView ) {
1133 		common->Printf( "No primaryView for benchmarking\n" );
1134 		return;
1135 	}
1136 	view = tr.primaryRenderView;
1137 
1138 	for ( int size = 100 ; size >= 10 ; size -= 10 ) {
1139 		r_screenFraction.SetInteger( size );
1140 		fps = R_RenderingFPS( &view );
1141 		int	kpix = glConfig.vidWidth * glConfig.vidHeight * ( size * 0.01 ) * ( size * 0.01 ) * 0.001;
1142 		msec = 1000.0 / fps;
1143 		common->Printf( "kpix: %4i  msec:%5.1f fps:%5.1f\n", kpix, msec, fps );
1144 	}
1145 
1146 	// enable r_singleTriangle 1 while r_screenFraction is still at 10
1147 	r_singleTriangle.SetBool( 1 );
1148 	fps = R_RenderingFPS( &view );
1149 	msec = 1000.0 / fps;
1150 	common->Printf( "single tri  msec:%5.1f fps:%5.1f\n", msec, fps );
1151 	r_singleTriangle.SetBool( 0 );
1152 	r_screenFraction.SetInteger( 100 );
1153 
1154 	// enable r_skipRenderContext 1
1155 	r_skipRenderContext.SetBool( true );
1156 	fps = R_RenderingFPS( &view );
1157 	msec = 1000.0 / fps;
1158 	common->Printf( "no context  msec:%5.1f fps:%5.1f\n", msec, fps );
1159 	r_skipRenderContext.SetBool( false );
1160 }
1161 
1162 
1163 /*
1164 ==============================================================================
1165 
1166 						SCREEN SHOTS
1167 
1168 ==============================================================================
1169 */
1170 
1171 /*
1172 ====================
1173 R_ReadTiledPixels
1174 
1175 Allows the rendering of an image larger than the actual window by
1176 tiling it into window-sized chunks and rendering each chunk separately
1177 
1178 If ref isn't specified, the full session UpdateScreen will be done.
1179 ====================
1180 */
R_ReadTiledPixels(int width,int height,byte * buffer,renderView_t * ref=NULL)1181 void R_ReadTiledPixels( int width, int height, byte *buffer, renderView_t *ref = NULL ) {
1182 	// include extra space for OpenGL padding to word boundaries
1183 	byte	*temp = (byte *)R_StaticAlloc( (glConfig.vidWidth+3) * glConfig.vidHeight * 3 );
1184 
1185 	int	oldWidth = glConfig.vidWidth;
1186 	int oldHeight = glConfig.vidHeight;
1187 
1188 	tr.tiledViewport[0] = width;
1189 	tr.tiledViewport[1] = height;
1190 
1191 	// disable scissor, so we don't need to adjust all those rects
1192 	r_useScissor.SetBool( false );
1193 
1194 	for ( int xo = 0 ; xo < width ; xo += oldWidth ) {
1195 		for ( int yo = 0 ; yo < height ; yo += oldHeight ) {
1196 			tr.viewportOffset[0] = -xo;
1197 			tr.viewportOffset[1] = -yo;
1198 
1199 			if ( ref ) {
1200 				tr.BeginFrame( oldWidth, oldHeight );
1201 				tr.primaryWorld->RenderScene( ref );
1202 				tr.EndFrame( NULL, NULL );
1203 			} else {
1204 				session->UpdateScreen(false);
1205 			}
1206 
1207 			int w = oldWidth;
1208 			if ( xo + w > width ) {
1209 				w = width - xo;
1210 			}
1211 			int h = oldHeight;
1212 			if ( yo + h > height ) {
1213 				h = height - yo;
1214 			}
1215 
1216 			qglReadBuffer( GL_FRONT );
1217 			qglReadPixels( 0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, temp );
1218 
1219 			int	row = ( w * 3 + 3 ) & ~3;		// OpenGL pads to dword boundaries
1220 
1221 			for ( int y = 0 ; y < h ; y++ ) {
1222 				memcpy( buffer + ( ( yo + y )* width + xo ) * 3,
1223 					temp + y * row, w * 3 );
1224 			}
1225 		}
1226 	}
1227 
1228 	r_useScissor.SetBool( true );
1229 
1230 	tr.viewportOffset[0] = 0;
1231 	tr.viewportOffset[1] = 0;
1232 	tr.tiledViewport[0] = 0;
1233 	tr.tiledViewport[1] = 0;
1234 
1235 	R_StaticFree( temp );
1236 
1237 	glConfig.vidWidth = oldWidth;
1238 	glConfig.vidHeight = oldHeight;
1239 }
1240 
1241 
1242 /*
1243 ==================
1244 TakeScreenshot
1245 
1246 Move to tr_imagefiles.c...
1247 
1248 Will automatically tile render large screen shots if necessary
1249 Downsample is the number of steps to mipmap the image before saving it
1250 If ref == NULL, session->updateScreen will be used
1251 ==================
1252 */
TakeScreenshot(int width,int height,const char * fileName,int blends,renderView_t * ref)1253 void idRenderSystemLocal::TakeScreenshot( int width, int height, const char *fileName, int blends, renderView_t *ref ) {
1254 	byte		*buffer;
1255 	int			i, j, c, temp;
1256 
1257 	takingScreenshot = true;
1258 
1259 	int	pix = width * height;
1260 
1261 	buffer = (byte *)R_StaticAlloc(pix*3 + 18);
1262 	memset (buffer, 0, 18);
1263 
1264 	if ( blends <= 1 ) {
1265 		R_ReadTiledPixels( width, height, buffer + 18, ref );
1266 	} else {
1267 		unsigned short *shortBuffer = (unsigned short *)R_StaticAlloc(pix*2*3);
1268 		memset (shortBuffer, 0, pix*2*3);
1269 
1270 		// enable anti-aliasing jitter
1271 		r_jitter.SetBool( true );
1272 
1273 		for ( i = 0 ; i < blends ; i++ ) {
1274 			R_ReadTiledPixels( width, height, buffer + 18, ref );
1275 
1276 			for ( j = 0 ; j < pix*3 ; j++ ) {
1277 				shortBuffer[j] += buffer[18+j];
1278 			}
1279 		}
1280 
1281 		// divide back to bytes
1282 		for ( i = 0 ; i < pix*3 ; i++ ) {
1283 			buffer[18+i] = shortBuffer[i] / blends;
1284 		}
1285 
1286 		R_StaticFree( shortBuffer );
1287 		r_jitter.SetBool( false );
1288 	}
1289 
1290 	// fill in the header (this is vertically flipped, which qglReadPixels emits)
1291 	buffer[2] = 2;		// uncompressed type
1292 	buffer[12] = width & 255;
1293 	buffer[13] = width >> 8;
1294 	buffer[14] = height & 255;
1295 	buffer[15] = height >> 8;
1296 	buffer[16] = 24;	// pixel size
1297 
1298 	// swap rgb to bgr
1299 	c = 18 + width * height * 3;
1300 	for (i=18 ; i<c ; i+=3) {
1301 		temp = buffer[i];
1302 		buffer[i] = buffer[i+2];
1303 		buffer[i+2] = temp;
1304 	}
1305 
1306 	// _D3XP adds viewnote screenie save to cdpath
1307 	if ( strstr( fileName, "viewnote" ) ) {
1308 		fileSystem->WriteFile( fileName, buffer, c, "fs_cdpath" );
1309 	} else {
1310 		fileSystem->WriteFile( fileName, buffer, c );
1311 	}
1312 
1313 	R_StaticFree( buffer );
1314 
1315 	takingScreenshot = false;
1316 
1317 }
1318 
1319 
1320 /*
1321 ==================
1322 R_ScreenshotFilename
1323 
1324 Returns a filename with digits appended
1325 if we have saved a previous screenshot, don't scan
1326 from the beginning, because recording demo avis can involve
1327 thousands of shots
1328 ==================
1329 */
R_ScreenshotFilename(int & lastNumber,const char * base,idStr & fileName)1330 void R_ScreenshotFilename( int &lastNumber, const char *base, idStr &fileName ) {
1331 	int	a,b,c,d, e;
1332 
1333 	bool fsrestrict = cvarSystem->GetCVarBool( "fs_restrict" );
1334 	cvarSystem->SetCVarBool( "fs_restrict", false );
1335 
1336 	lastNumber++;
1337 	if ( lastNumber > 99999 ) {
1338 		lastNumber = 99999;
1339 	}
1340 	for ( ; lastNumber < 99999 ; lastNumber++ ) {
1341 		int	frac = lastNumber;
1342 
1343 		a = frac / 10000;
1344 		frac -= a*10000;
1345 		b = frac / 1000;
1346 		frac -= b*1000;
1347 		c = frac / 100;
1348 		frac -= c*100;
1349 		d = frac / 10;
1350 		frac -= d*10;
1351 		e = frac;
1352 
1353 		sprintf( fileName, "%s%i%i%i%i%i.tga", base, a, b, c, d, e );
1354 		if ( lastNumber == 99999 ) {
1355 			break;
1356 		}
1357 		int len = fileSystem->ReadFile( fileName, NULL, NULL );
1358 		if ( len <= 0 ) {
1359 			break;
1360 		}
1361 		// check again...
1362 	}
1363 	cvarSystem->SetCVarBool( "fs_restrict", fsrestrict );
1364 }
1365 
1366 /*
1367 ==================
1368 R_BlendedScreenShot
1369 
1370 screenshot
1371 screenshot [filename]
1372 screenshot [width] [height]
1373 screenshot [width] [height] [samples]
1374 ==================
1375 */
1376 #define	MAX_BLENDS	256	// to keep the accumulation in shorts
R_ScreenShot_f(const idCmdArgs & args)1377 void R_ScreenShot_f( const idCmdArgs &args ) {
1378 	static int lastNumber = 0;
1379 	idStr checkname;
1380 
1381 	int width = glConfig.vidWidth;
1382 	int height = glConfig.vidHeight;
1383 	int	blends = 0;
1384 
1385 	switch ( args.Argc() ) {
1386 	case 1:
1387 		width = glConfig.vidWidth;
1388 		height = glConfig.vidHeight;
1389 		blends = 1;
1390 		R_ScreenshotFilename( lastNumber, "screenshots/shot", checkname );
1391 		break;
1392 	case 2:
1393 		width = glConfig.vidWidth;
1394 		height = glConfig.vidHeight;
1395 		blends = 1;
1396 		checkname = args.Argv( 1 );
1397 		break;
1398 	case 3:
1399 		width = atoi( args.Argv( 1 ) );
1400 		height = atoi( args.Argv( 2 ) );
1401 		blends = 1;
1402 		R_ScreenshotFilename( lastNumber, "screenshots/shot", checkname );
1403 		break;
1404 	case 4:
1405 		width = atoi( args.Argv( 1 ) );
1406 		height = atoi( args.Argv( 2 ) );
1407 		blends = atoi( args.Argv( 3 ) );
1408 		if ( blends < 1 ) {
1409 			blends = 1;
1410 		}
1411 		if ( blends > MAX_BLENDS ) {
1412 			blends = MAX_BLENDS;
1413 		}
1414 		R_ScreenshotFilename( lastNumber, "screenshots/shot", checkname );
1415 		break;
1416 	default:
1417 		common->Printf( "usage: screenshot\n       screenshot <filename>\n       screenshot <width> <height>\n       screenshot <width> <height> <blends>\n" );
1418 		return;
1419 	}
1420 
1421 	// put the console away
1422 	console->Close();
1423 
1424 	tr.TakeScreenshot( width, height, checkname, blends, NULL );
1425 
1426 	common->Printf( "Wrote %s\n", checkname.c_str() );
1427 }
1428 
1429 /*
1430 ===============
1431 R_StencilShot
1432 Save out a screenshot showing the stencil buffer expanded by 16x range
1433 ===============
1434 */
R_StencilShot(void)1435 void R_StencilShot( void ) {
1436 	byte		*buffer;
1437 	int			i, c;
1438 
1439 	int	width = tr.GetScreenWidth();
1440 	int	height = tr.GetScreenHeight();
1441 
1442 	int	pix = width * height;
1443 
1444 	c = pix * 3 + 18;
1445 	buffer = (byte *)Mem_Alloc(c);
1446 	memset (buffer, 0, 18);
1447 
1448 	byte *byteBuffer = (byte *)Mem_Alloc(pix);
1449 
1450 	qglReadPixels( 0, 0, width, height, GL_STENCIL_INDEX , GL_UNSIGNED_BYTE, byteBuffer );
1451 
1452 	for ( i = 0 ; i < pix ; i++ ) {
1453 		buffer[18+i*3] =
1454 		buffer[18+i*3+1] =
1455 			//		buffer[18+i*3+2] = ( byteBuffer[i] & 15 ) * 16;
1456 		buffer[18+i*3+2] = byteBuffer[i];
1457 	}
1458 
1459 	// fill in the header (this is vertically flipped, which qglReadPixels emits)
1460 	buffer[2] = 2;		// uncompressed type
1461 	buffer[12] = width & 255;
1462 	buffer[13] = width >> 8;
1463 	buffer[14] = height & 255;
1464 	buffer[15] = height >> 8;
1465 	buffer[16] = 24;	// pixel size
1466 
1467 	fileSystem->WriteFile( "screenshots/stencilShot.tga", buffer, c, "fs_savepath" );
1468 
1469 	Mem_Free( buffer );
1470 	Mem_Free( byteBuffer );
1471 }
1472 
1473 /*
1474 ==================
1475 R_EnvShot_f
1476 
1477 envshot <basename>
1478 
1479 Saves out env/<basename>_ft.tga, etc
1480 ==================
1481 */
R_EnvShot_f(const idCmdArgs & args)1482 void R_EnvShot_f( const idCmdArgs &args ) {
1483 	idStr		fullname;
1484 	const char	*baseName;
1485 	int			i;
1486 	idMat3		axis[6];
1487 	renderView_t	ref;
1488 	viewDef_t	primary;
1489 	int			blends;
1490 	const char	*extensions[6] =  { "_px.tga", "_nx.tga", "_py.tga", "_ny.tga",
1491 		"_pz.tga", "_nz.tga" };
1492 	int			size;
1493 
1494 	if ( args.Argc() != 2 && args.Argc() != 3 && args.Argc() != 4 ) {
1495 		common->Printf( "USAGE: envshot <basename> [size] [blends]\n" );
1496 		return;
1497 	}
1498 	baseName = args.Argv( 1 );
1499 
1500 	blends = 1;
1501 	if ( args.Argc() == 4 ) {
1502 		size = atoi( args.Argv( 2 ) );
1503 		blends = atoi( args.Argv( 3 ) );
1504 	} else if ( args.Argc() == 3 ) {
1505 		size = atoi( args.Argv( 2 ) );
1506 		blends = 1;
1507 	} else {
1508 		size = 256;
1509 		blends = 1;
1510 	}
1511 
1512 	if ( !tr.primaryView ) {
1513 		common->Printf( "No primary view.\n" );
1514 		return;
1515 	}
1516 
1517 	primary = *tr.primaryView;
1518 
1519 	memset( &axis, 0, sizeof( axis ) );
1520 	axis[0][0][0] = 1;
1521 	axis[0][1][2] = 1;
1522 	axis[0][2][1] = 1;
1523 
1524 	axis[1][0][0] = -1;
1525 	axis[1][1][2] = -1;
1526 	axis[1][2][1] = 1;
1527 
1528 	axis[2][0][1] = 1;
1529 	axis[2][1][0] = -1;
1530 	axis[2][2][2] = -1;
1531 
1532 	axis[3][0][1] = -1;
1533 	axis[3][1][0] = -1;
1534 	axis[3][2][2] = 1;
1535 
1536 	axis[4][0][2] = 1;
1537 	axis[4][1][0] = -1;
1538 	axis[4][2][1] = 1;
1539 
1540 	axis[5][0][2] = -1;
1541 	axis[5][1][0] = 1;
1542 	axis[5][2][1] = 1;
1543 
1544 	for ( i = 0 ; i < 6 ; i++ ) {
1545 		ref = primary.renderView;
1546 		ref.x = ref.y = 0;
1547 		ref.fov_x = ref.fov_y = 90;
1548 		ref.width = glConfig.vidWidth;
1549 		ref.height = glConfig.vidHeight;
1550 		ref.viewaxis = axis[i];
1551 		sprintf( fullname, "env/%s%s", baseName, extensions[i] );
1552 		tr.TakeScreenshot( size, size, fullname, blends, &ref );
1553 	}
1554 
1555 	common->Printf( "Wrote %s, etc\n", fullname.c_str() );
1556 }
1557 
1558 //============================================================================
1559 
1560 static idMat3		cubeAxis[6];
1561 
1562 
1563 /*
1564 ==================
1565 R_SampleCubeMap
1566 ==================
1567 */
R_SampleCubeMap(const idVec3 & dir,int size,byte * buffers[6],byte result[4])1568 void R_SampleCubeMap( const idVec3 &dir, int size, byte *buffers[6], byte result[4] ) {
1569 	float	adir[3];
1570 	int		axis, x, y;
1571 
1572 	adir[0] = fabs(dir[0]);
1573 	adir[1] = fabs(dir[1]);
1574 	adir[2] = fabs(dir[2]);
1575 
1576 	if ( dir[0] >= adir[1] && dir[0] >= adir[2] ) {
1577 		axis = 0;
1578 	} else if ( -dir[0] >= adir[1] && -dir[0] >= adir[2] ) {
1579 		axis = 1;
1580 	} else if ( dir[1] >= adir[0] && dir[1] >= adir[2] ) {
1581 		axis = 2;
1582 	} else if ( -dir[1] >= adir[0] && -dir[1] >= adir[2] ) {
1583 		axis = 3;
1584 	} else if ( dir[2] >= adir[1] && dir[2] >= adir[2] ) {
1585 		axis = 4;
1586 	} else {
1587 		axis = 5;
1588 	}
1589 
1590 	float	fx = (dir * cubeAxis[axis][1]) / (dir * cubeAxis[axis][0]);
1591 	float	fy = (dir * cubeAxis[axis][2]) / (dir * cubeAxis[axis][0]);
1592 
1593 	fx = -fx;
1594 	fy = -fy;
1595 	x = size * 0.5 * (fx + 1);
1596 	y = size * 0.5 * (fy + 1);
1597 	if ( x < 0 ) {
1598 		x = 0;
1599 	} else if ( x >= size ) {
1600 		x = size-1;
1601 	}
1602 	if ( y < 0 ) {
1603 		y = 0;
1604 	} else if ( y >= size ) {
1605 		y = size-1;
1606 	}
1607 
1608 	result[0] = buffers[axis][(y*size+x)*4+0];
1609 	result[1] = buffers[axis][(y*size+x)*4+1];
1610 	result[2] = buffers[axis][(y*size+x)*4+2];
1611 	result[3] = buffers[axis][(y*size+x)*4+3];
1612 }
1613 
1614 /*
1615 ==================
1616 R_MakeAmbientMap_f
1617 
1618 R_MakeAmbientMap_f <basename> [size]
1619 
1620 Saves out env/<basename>_amb_ft.tga, etc
1621 ==================
1622 */
R_MakeAmbientMap_f(const idCmdArgs & args)1623 void R_MakeAmbientMap_f( const idCmdArgs &args ) {
1624 	idStr fullname;
1625 	const char	*baseName;
1626 	int			i;
1627 	const char	*extensions[6] =  { "_px.tga", "_nx.tga", "_py.tga", "_ny.tga",
1628 		"_pz.tga", "_nz.tga" };
1629 	int			outSize;
1630 	byte		*buffers[6];
1631 	int			width, height;
1632 
1633 	if ( args.Argc() != 2 && args.Argc() != 3 ) {
1634 		common->Printf( "USAGE: ambientshot <basename> [size]\n" );
1635 		return;
1636 	}
1637 	baseName = args.Argv( 1 );
1638 
1639 	if ( args.Argc() == 3 ) {
1640 		outSize = atoi( args.Argv( 2 ) );
1641 	} else {
1642 		outSize = 32;
1643 	}
1644 
1645 	memset( &cubeAxis, 0, sizeof( cubeAxis ) );
1646 	cubeAxis[0][0][0] = 1;
1647 	cubeAxis[0][1][2] = 1;
1648 	cubeAxis[0][2][1] = 1;
1649 
1650 	cubeAxis[1][0][0] = -1;
1651 	cubeAxis[1][1][2] = -1;
1652 	cubeAxis[1][2][1] = 1;
1653 
1654 	cubeAxis[2][0][1] = 1;
1655 	cubeAxis[2][1][0] = -1;
1656 	cubeAxis[2][2][2] = -1;
1657 
1658 	cubeAxis[3][0][1] = -1;
1659 	cubeAxis[3][1][0] = -1;
1660 	cubeAxis[3][2][2] = 1;
1661 
1662 	cubeAxis[4][0][2] = 1;
1663 	cubeAxis[4][1][0] = -1;
1664 	cubeAxis[4][2][1] = 1;
1665 
1666 	cubeAxis[5][0][2] = -1;
1667 	cubeAxis[5][1][0] = 1;
1668 	cubeAxis[5][2][1] = 1;
1669 
1670 	// read all of the images
1671 	for ( i = 0 ; i < 6 ; i++ ) {
1672 		sprintf( fullname, "env/%s%s", baseName, extensions[i] );
1673 		common->Printf( "loading %s\n", fullname.c_str() );
1674 		session->UpdateScreen();
1675 		R_LoadImage( fullname, &buffers[i], &width, &height, NULL, true );
1676 		if ( !buffers[i] ) {
1677 			common->Printf( "failed.\n" );
1678 			for ( i-- ; i >= 0 ; i-- ) {
1679 				Mem_Free( buffers[i] );
1680 			}
1681 			return;
1682 		}
1683 	}
1684 
1685 	// resample with hemispherical blending
1686 	int	samples = 1000;
1687 
1688 	byte	*outBuffer = (byte *)_alloca( outSize * outSize * 4 );
1689 
1690 	for ( int map = 0 ; map < 2 ; map++ ) {
1691 		for ( i = 0 ; i < 6 ; i++ ) {
1692 			for ( int x = 0 ; x < outSize ; x++ ) {
1693 				for ( int y = 0 ; y < outSize ; y++ ) {
1694 					idVec3	dir;
1695 					float	total[3];
1696 
1697 					dir = cubeAxis[i][0] + -( -1 + 2.0*x/(outSize-1) ) * cubeAxis[i][1] + -( -1 + 2.0*y/(outSize-1) ) * cubeAxis[i][2];
1698 					dir.Normalize();
1699 					total[0] = total[1] = total[2] = 0;
1700 	//samples = 1;
1701 					float	limit = map ? 0.95 : 0.25;		// small for specular, almost hemisphere for ambient
1702 
1703 					for ( int s = 0 ; s < samples ; s++ ) {
1704 						// pick a random direction vector that is inside the unit sphere but not behind dir,
1705 						// which is a robust way to evenly sample a hemisphere
1706 						idVec3	test;
1707 						while( 1 ) {
1708 							for ( int j = 0 ; j < 3 ; j++ ) {
1709 								test[j] = -1 + 2 * (rand()&0x7fff)/(float)0x7fff;
1710 							}
1711 							if ( test.Length() > 1.0 ) {
1712 								continue;
1713 							}
1714 							test.Normalize();
1715 							if ( test * dir > limit ) {	// don't do a complete hemisphere
1716 								break;
1717 							}
1718 						}
1719 						byte	result[4];
1720 	//test = dir;
1721 						R_SampleCubeMap( test, width, buffers, result );
1722 						total[0] += result[0];
1723 						total[1] += result[1];
1724 						total[2] += result[2];
1725 					}
1726 					outBuffer[(y*outSize+x)*4+0] = total[0] / samples;
1727 					outBuffer[(y*outSize+x)*4+1] = total[1] / samples;
1728 					outBuffer[(y*outSize+x)*4+2] = total[2] / samples;
1729 					outBuffer[(y*outSize+x)*4+3] = 255;
1730 				}
1731 			}
1732 
1733 			if ( map == 0 ) {
1734 				sprintf( fullname, "env/%s_amb%s", baseName, extensions[i] );
1735 			} else {
1736 				sprintf( fullname, "env/%s_spec%s", baseName, extensions[i] );
1737 			}
1738 			common->Printf( "writing %s\n", fullname.c_str() );
1739 			session->UpdateScreen();
1740 			R_WriteTGA( fullname, outBuffer, outSize, outSize );
1741 		}
1742 	}
1743 
1744 	for ( i = 0 ; i < 6 ; i++ ) {
1745 		if ( buffers[i] ) {
1746 			Mem_Free( buffers[i] );
1747 		}
1748 	}
1749 }
1750 
1751 //============================================================================
1752 
1753 
1754 /*
1755 ===============
1756 R_SetColorMappings
1757 ===============
1758 */
R_SetColorMappings(void)1759 void R_SetColorMappings( void ) {
1760 	int		i, j;
1761 	float	g, b;
1762 	int		inf;
1763 	unsigned short gammaTable[256];
1764 
1765 	b = r_brightness.GetFloat();
1766 	g = r_gamma.GetFloat();
1767 
1768 	for ( i = 0; i < 256; i++ ) {
1769 		j = i * b;
1770 		if (j > 255) {
1771 			j = 255;
1772 		}
1773 
1774 		if ( g == 1 ) {
1775 			inf = (j<<8) | j;
1776 		} else {
1777 			inf = 0xffff * pow ( j/255.0f, 1.0f / g ) + 0.5f;
1778 		}
1779 		if (inf < 0) {
1780 			inf = 0;
1781 		}
1782 		if (inf > 0xffff) {
1783 			inf = 0xffff;
1784 		}
1785 
1786 		gammaTable[i] = inf;
1787 	}
1788 
1789 	GLimp_SetGamma( gammaTable, gammaTable, gammaTable );
1790 }
1791 
1792 
1793 /*
1794 ================
1795 GfxInfo_f
1796 ================
1797 */
GfxInfo_f(const idCmdArgs & args)1798 static void GfxInfo_f( const idCmdArgs &args ) {
1799 	const char *fsstrings[] =
1800 	{
1801 		"windowed",
1802 		"fullscreen"
1803 	};
1804 
1805 	common->Printf( "\nGL_VENDOR: %s\n", glConfig.vendor_string );
1806 	common->Printf( "GL_RENDERER: %s\n", glConfig.renderer_string );
1807 	common->Printf( "GL_VERSION: %s\n", glConfig.version_string );
1808 	common->Printf( "GL_EXTENSIONS: %s\n", glConfig.extensions_string );
1809 	common->Printf( "GL_MAX_TEXTURE_SIZE: %d\n", glConfig.maxTextureSize );
1810 	common->Printf( "GL_MAX_TEXTURE_UNITS_ARB: %d\n", glConfig.maxTextureUnits );
1811 	common->Printf( "GL_MAX_TEXTURE_COORDS_ARB: %d\n", glConfig.maxTextureCoords );
1812 	common->Printf( "GL_MAX_TEXTURE_IMAGE_UNITS_ARB: %d\n", glConfig.maxTextureImageUnits );
1813 	common->Printf( "\nPIXELFORMAT: color(%d-bits) Z(%d-bit) stencil(%d-bits)\n", glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits );
1814 	common->Printf( "MODE: %d, %d x %d %s hz:", r_mode.GetInteger(), glConfig.vidWidth, glConfig.vidHeight, fsstrings[r_fullscreen.GetBool()] );
1815 
1816 	if ( glConfig.displayFrequency ) {
1817 		common->Printf( "%d\n", glConfig.displayFrequency );
1818 	} else {
1819 		common->Printf( "N/A\n" );
1820 	}
1821 
1822 	const char *active[2] = { "", " (ACTIVE)" };
1823 
1824 	if ( glConfig.allowARB2Path ) {
1825 		common->Printf( "ARB2 path ENABLED%s\n", active[tr.backEndRenderer == BE_ARB2] );
1826 	} else {
1827 		common->Printf( "ARB2 path disabled\n" );
1828 	}
1829 
1830 	if ( r_finish.GetBool() ) {
1831 		common->Printf( "Forcing glFinish\n" );
1832 	} else {
1833 		common->Printf( "glFinish not forced\n" );
1834 	}
1835 
1836 	bool tss = glConfig.twoSidedStencilAvailable;
1837 
1838 	if ( !r_useTwoSidedStencil.GetBool() && tss ) {
1839 		common->Printf( "Two sided stencil available but disabled\n" );
1840 	} else if ( !tss ) {
1841 		common->Printf( "Two sided stencil not available\n" );
1842 	} else if ( tss ) {
1843 		common->Printf( "Using two sided stencil\n" );
1844 	}
1845 
1846 	if ( vertexCache.IsFast() ) {
1847 		common->Printf( "Vertex cache is fast\n" );
1848 	} else {
1849 		common->Printf( "Vertex cache is SLOW\n" );
1850 	}
1851 }
1852 
1853 /*
1854 =================
1855 R_VidRestart_f
1856 =================
1857 */
R_VidRestart_f(const idCmdArgs & args)1858 void R_VidRestart_f( const idCmdArgs &args ) {
1859 	int	err;
1860 
1861 	// if OpenGL isn't started, do nothing
1862 	if ( !glConfig.isInitialized ) {
1863 		return;
1864 	}
1865 
1866 	// DG: notify the game DLL about the reloadImages and vid_restart commands
1867 	if(gameCallbacks.reloadImagesCB != NULL)
1868 	{
1869 		gameCallbacks.reloadImagesCB(gameCallbacks.reloadImagesUserArg, args);
1870 	}
1871 
1872 	bool full = true;
1873 	bool forceWindow = false;
1874 	for ( int i = 1 ; i < args.Argc() ; i++ ) {
1875 		if ( idStr::Icmp( args.Argv( i ), "partial" ) == 0 ) {
1876 			full = false;
1877 			continue;
1878 		}
1879 		if ( idStr::Icmp( args.Argv( i ), "windowed" ) == 0 ) {
1880 			forceWindow = true;
1881 			continue;
1882 		}
1883 	}
1884 
1885 	// this could take a while, so give them the cursor back ASAP
1886 	Sys_GrabMouseCursor( false );
1887 
1888 	// dump ambient caches
1889 	renderModelManager->FreeModelVertexCaches();
1890 
1891 	// free any current world interaction surfaces and vertex caches
1892 	R_FreeDerivedData();
1893 
1894 	// make sure the defered frees are actually freed
1895 	R_ToggleSmpFrame();
1896 	R_ToggleSmpFrame();
1897 
1898 	// free the vertex caches so they will be regenerated again
1899 	vertexCache.PurgeAll();
1900 
1901 	// sound and input are tied to the window we are about to destroy
1902 
1903 	if ( full ) {
1904 		// free all of our texture numbers
1905 		soundSystem->ShutdownHW();
1906 		Sys_ShutdownInput();
1907 		globalImages->PurgeAllImages();
1908 		// free the context and close the window
1909 		GLimp_Shutdown();
1910 		glConfig.isInitialized = false;
1911 
1912 		// create the new context and vertex cache
1913 		bool latch = cvarSystem->GetCVarBool( "r_fullscreen" );
1914 		if ( forceWindow ) {
1915 			cvarSystem->SetCVarBool( "r_fullscreen", false );
1916 		}
1917 		R_InitOpenGL();
1918 		cvarSystem->SetCVarBool( "r_fullscreen", latch );
1919 
1920 		// regenerate all images
1921 		globalImages->ReloadAllImages();
1922 	} else {
1923 		glimpParms_t	parms;
1924 		parms.width = glConfig.vidWidth;
1925 		parms.height = glConfig.vidHeight;
1926 		parms.fullScreen = ( forceWindow ) ? false : r_fullscreen.GetBool();
1927 		parms.displayHz = r_displayRefresh.GetInteger();
1928 		parms.multiSamples = r_multiSamples.GetInteger();
1929 		parms.stereo = false;
1930 		GLimp_SetScreenParms( parms );
1931 	}
1932 
1933 
1934 
1935 	// make sure the regeneration doesn't use anything no longer valid
1936 	tr.viewCount++;
1937 	tr.viewDef = NULL;
1938 
1939 	// regenerate all necessary interactions
1940 	R_RegenerateWorld_f( idCmdArgs() );
1941 
1942 	// check for problems
1943 	err = qglGetError();
1944 	if ( err != GL_NO_ERROR ) {
1945 		common->Printf( "glGetError() = 0x%x\n", err );
1946 	}
1947 
1948 	// start sound playing again
1949 	soundSystem->SetMute( false );
1950 }
1951 
1952 
1953 /*
1954 =================
1955 R_InitMaterials
1956 =================
1957 */
R_InitMaterials(void)1958 void R_InitMaterials( void ) {
1959 	tr.defaultMaterial = declManager->FindMaterial( "_default", false );
1960 	if ( !tr.defaultMaterial ) {
1961 		common->FatalError( "_default material not found" );
1962 	}
1963 	declManager->FindMaterial( "_default", false );
1964 
1965 	// needed by R_DeriveLightData
1966 	declManager->FindMaterial( "lights/defaultPointLight" );
1967 	declManager->FindMaterial( "lights/defaultProjectedLight" );
1968 }
1969 
1970 
1971 /*
1972 =================
1973 R_SizeUp_f
1974 
1975 Keybinding command
1976 =================
1977 */
R_SizeUp_f(const idCmdArgs & args)1978 static void R_SizeUp_f( const idCmdArgs &args ) {
1979 	if ( r_screenFraction.GetInteger() + 10 > 100 ) {
1980 		r_screenFraction.SetInteger( 100 );
1981 	} else {
1982 		r_screenFraction.SetInteger( r_screenFraction.GetInteger() + 10 );
1983 	}
1984 }
1985 
1986 
1987 /*
1988 =================
1989 R_SizeDown_f
1990 
1991 Keybinding command
1992 =================
1993 */
R_SizeDown_f(const idCmdArgs & args)1994 static void R_SizeDown_f( const idCmdArgs &args ) {
1995 	if ( r_screenFraction.GetInteger() - 10 < 10 ) {
1996 		r_screenFraction.SetInteger( 10 );
1997 	} else {
1998 		r_screenFraction.SetInteger( r_screenFraction.GetInteger() - 10 );
1999 	}
2000 }
2001 
2002 
2003 /*
2004 ===============
2005 TouchGui_f
2006 
2007   this is called from the main thread
2008 ===============
2009 */
R_TouchGui_f(const idCmdArgs & args)2010 void R_TouchGui_f( const idCmdArgs &args ) {
2011 	const char	*gui = args.Argv( 1 );
2012 
2013 	if ( !gui[0] ) {
2014 		common->Printf( "USAGE: touchGui <guiName>\n" );
2015 		return;
2016 	}
2017 
2018 	common->Printf( "touchGui %s\n", gui );
2019 	session->UpdateScreen();
2020 	uiManager->Touch( gui );
2021 }
2022 
2023 /*
2024 =================
2025 R_InitCvars
2026 =================
2027 */
R_InitCvars(void)2028 void R_InitCvars( void ) {
2029 	// update latched cvars here
2030 }
2031 
2032 /*
2033 =================
2034 R_InitCommands
2035 =================
2036 */
R_InitCommands(void)2037 void R_InitCommands( void ) {
2038 	cmdSystem->AddCommand( "MakeMegaTexture", idMegaTexture::MakeMegaTexture_f, CMD_FL_RENDERER|CMD_FL_CHEAT, "processes giant images" );
2039 	cmdSystem->AddCommand( "sizeUp", R_SizeUp_f, CMD_FL_RENDERER, "makes the rendered view larger" );
2040 	cmdSystem->AddCommand( "sizeDown", R_SizeDown_f, CMD_FL_RENDERER, "makes the rendered view smaller" );
2041 	cmdSystem->AddCommand( "reloadGuis", R_ReloadGuis_f, CMD_FL_RENDERER, "reloads guis" );
2042 	cmdSystem->AddCommand( "listGuis", R_ListGuis_f, CMD_FL_RENDERER, "lists guis" );
2043 	cmdSystem->AddCommand( "touchGui", R_TouchGui_f, CMD_FL_RENDERER, "touches a gui" );
2044 	cmdSystem->AddCommand( "screenshot", R_ScreenShot_f, CMD_FL_RENDERER, "takes a screenshot" );
2045 	cmdSystem->AddCommand( "envshot", R_EnvShot_f, CMD_FL_RENDERER, "takes an environment shot" );
2046 	cmdSystem->AddCommand( "makeAmbientMap", R_MakeAmbientMap_f, CMD_FL_RENDERER|CMD_FL_CHEAT, "makes an ambient map" );
2047 	cmdSystem->AddCommand( "benchmark", R_Benchmark_f, CMD_FL_RENDERER, "benchmark" );
2048 	cmdSystem->AddCommand( "gfxInfo", GfxInfo_f, CMD_FL_RENDERER, "show graphics info" );
2049 	cmdSystem->AddCommand( "modulateLights", R_ModulateLights_f, CMD_FL_RENDERER | CMD_FL_CHEAT, "modifies shader parms on all lights" );
2050 	cmdSystem->AddCommand( "testImage", R_TestImage_f, CMD_FL_RENDERER | CMD_FL_CHEAT, "displays the given image centered on screen", idCmdSystem::ArgCompletion_ImageName );
2051 	cmdSystem->AddCommand( "testVideo", R_TestVideo_f, CMD_FL_RENDERER | CMD_FL_CHEAT, "displays the given cinematic", idCmdSystem::ArgCompletion_VideoName );
2052 	cmdSystem->AddCommand( "reportSurfaceAreas", R_ReportSurfaceAreas_f, CMD_FL_RENDERER, "lists all used materials sorted by surface area" );
2053 	cmdSystem->AddCommand( "reportImageDuplication", R_ReportImageDuplication_f, CMD_FL_RENDERER, "checks all referenced images for duplications" );
2054 	cmdSystem->AddCommand( "regenerateWorld", R_RegenerateWorld_f, CMD_FL_RENDERER, "regenerates all interactions" );
2055 	cmdSystem->AddCommand( "showInteractionMemory", R_ShowInteractionMemory_f, CMD_FL_RENDERER, "shows memory used by interactions" );
2056 	cmdSystem->AddCommand( "showTriSurfMemory", R_ShowTriSurfMemory_f, CMD_FL_RENDERER, "shows memory used by triangle surfaces" );
2057 	cmdSystem->AddCommand( "vid_restart", R_VidRestart_f, CMD_FL_RENDERER, "restarts renderSystem" );
2058 	cmdSystem->AddCommand( "listRenderEntityDefs", R_ListRenderEntityDefs_f, CMD_FL_RENDERER, "lists the entity defs" );
2059 	cmdSystem->AddCommand( "listRenderLightDefs", R_ListRenderLightDefs_f, CMD_FL_RENDERER, "lists the light defs" );
2060 	cmdSystem->AddCommand( "listModes", R_ListModes_f, CMD_FL_RENDERER, "lists all video modes" );
2061 	cmdSystem->AddCommand( "reloadSurface", R_ReloadSurface_f, CMD_FL_RENDERER, "reloads the decl and images for selected surface" );
2062 }
2063 
2064 /*
2065 ===============
2066 idRenderSystemLocal::Clear
2067 ===============
2068 */
Clear(void)2069 void idRenderSystemLocal::Clear( void ) {
2070 	registered = false;
2071 	frameCount = 0;
2072 	viewCount = 0;
2073 	staticAllocCount = 0;
2074 	frameShaderTime = 0.0f;
2075 	viewportOffset[0] = 0;
2076 	viewportOffset[1] = 0;
2077 	tiledViewport[0] = 0;
2078 	tiledViewport[1] = 0;
2079 	backEndRenderer = BE_BAD;
2080 	backEndRendererHasVertexPrograms = false;
2081 	backEndRendererMaxLight = 1.0f;
2082 	ambientLightVector.Zero();
2083 	sortOffset = 0;
2084 	worlds.Clear();
2085 	primaryWorld = NULL;
2086 	memset( &primaryRenderView, 0, sizeof( primaryRenderView ) );
2087 	primaryView = NULL;
2088 	defaultMaterial = NULL;
2089 	testImage = NULL;
2090 	ambientCubeImage = NULL;
2091 	viewDef = NULL;
2092 	memset( &pc, 0, sizeof( pc ) );
2093 	memset( &lockSurfacesCmd, 0, sizeof( lockSurfacesCmd ) );
2094 	memset( &identitySpace, 0, sizeof( identitySpace ) );
2095 	stencilIncr = 0;
2096 	stencilDecr = 0;
2097 	memset( renderCrops, 0, sizeof( renderCrops ) );
2098 	currentRenderCrop = 0;
2099 	guiRecursionLevel = 0;
2100 	guiModel = NULL;
2101 	demoGuiModel = NULL;
2102 	takingScreenshot = false;
2103 }
2104 
2105 /*
2106 ===============
2107 idRenderSystemLocal::Init
2108 ===============
2109 */
Init(void)2110 void idRenderSystemLocal::Init( void ) {
2111 	// clear all our internal state
2112 	viewCount = 1;		// so cleared structures never match viewCount
2113 	// we used to memset tr, but now that it is a class, we can't, so
2114 	// there may be other state we need to reset
2115 
2116 	ambientLightVector[0] = 0.5f;
2117 	ambientLightVector[1] = 0.5f - 0.385f;
2118 	ambientLightVector[2] = 0.8925f;
2119 	ambientLightVector[3] = 1.0f;
2120 
2121 	memset( &backEnd, 0, sizeof( backEnd ) );
2122 
2123 	R_InitCvars();
2124 
2125 	R_InitCommands();
2126 
2127 	guiModel = new idGuiModel;
2128 	guiModel->Clear();
2129 
2130 	demoGuiModel = new idGuiModel;
2131 	demoGuiModel->Clear();
2132 
2133 	R_InitTriSurfData();
2134 
2135 	globalImages->Init();
2136 
2137 	idCinematic::InitCinematic( );
2138 
2139 	R_InitMaterials();
2140 
2141 	renderModelManager->Init();
2142 
2143 	// set the identity space
2144 	identitySpace.modelMatrix[0*4+0] = 1.0f;
2145 	identitySpace.modelMatrix[1*4+1] = 1.0f;
2146 	identitySpace.modelMatrix[2*4+2] = 1.0f;
2147 
2148 	origWidth = origHeight = 0; // DG: for resetting width/height in EndFrame()
2149 }
2150 
2151 /*
2152 ===============
2153 idRenderSystemLocal::Shutdown
2154 ===============
2155 */
Shutdown(void)2156 void idRenderSystemLocal::Shutdown( void ) {
2157 	common->Printf( "idRenderSystem::Shutdown()\n" );
2158 
2159 	R_DoneFreeType( );
2160 
2161 	if ( glConfig.isInitialized ) {
2162 		globalImages->PurgeAllImages();
2163 	}
2164 
2165 	renderModelManager->Shutdown();
2166 
2167 	idCinematic::ShutdownCinematic( );
2168 
2169 	globalImages->Shutdown();
2170 
2171 	// free frame memory
2172 	R_ShutdownFrameData();
2173 
2174 	// free the vertex cache, which should have nothing allocated now
2175 	vertexCache.Shutdown();
2176 
2177 	R_ShutdownTriSurfData();
2178 
2179 	RB_ShutdownDebugTools();
2180 
2181 	delete guiModel;
2182 	delete demoGuiModel;
2183 
2184 	Clear();
2185 
2186 	ShutdownOpenGL();
2187 }
2188 
2189 /*
2190 ========================
2191 idRenderSystemLocal::BeginLevelLoad
2192 ========================
2193 */
BeginLevelLoad(void)2194 void idRenderSystemLocal::BeginLevelLoad( void ) {
2195 	renderModelManager->BeginLevelLoad();
2196 	globalImages->BeginLevelLoad();
2197 }
2198 
2199 /*
2200 ========================
2201 idRenderSystemLocal::EndLevelLoad
2202 ========================
2203 */
EndLevelLoad(void)2204 void idRenderSystemLocal::EndLevelLoad( void ) {
2205 	renderModelManager->EndLevelLoad();
2206 	globalImages->EndLevelLoad();
2207 	if ( r_forceLoadImages.GetBool() ) {
2208 		RB_ShowImages();
2209 	}
2210 }
2211 
2212 /*
2213 ========================
2214 idRenderSystemLocal::InitOpenGL
2215 ========================
2216 */
InitOpenGL(void)2217 void idRenderSystemLocal::InitOpenGL( void ) {
2218 	// if OpenGL isn't started, start it now
2219 	if ( !glConfig.isInitialized ) {
2220 		int	err;
2221 
2222 		R_InitOpenGL();
2223 
2224 		globalImages->ReloadAllImages();
2225 
2226 		err = qglGetError();
2227 		if ( err != GL_NO_ERROR ) {
2228 			common->Printf( "glGetError() = 0x%x\n", err );
2229 		}
2230 	}
2231 }
2232 
2233 /*
2234 ========================
2235 idRenderSystemLocal::ShutdownOpenGL
2236 ========================
2237 */
ShutdownOpenGL(void)2238 void idRenderSystemLocal::ShutdownOpenGL( void ) {
2239 	// free the context and close the window
2240 	R_ShutdownFrameData();
2241 	GLimp_Shutdown();
2242 	glConfig.isInitialized = false;
2243 }
2244 
2245 /*
2246 ========================
2247 idRenderSystemLocal::IsOpenGLRunning
2248 ========================
2249 */
IsOpenGLRunning(void) const2250 bool idRenderSystemLocal::IsOpenGLRunning( void ) const {
2251 	if ( !glConfig.isInitialized ) {
2252 		return false;
2253 	}
2254 	return true;
2255 }
2256 
2257 /*
2258 ========================
2259 idRenderSystemLocal::IsFullScreen
2260 ========================
2261 */
IsFullScreen(void) const2262 bool idRenderSystemLocal::IsFullScreen( void ) const {
2263 	return glConfig.isFullscreen;
2264 }
2265 
2266 /*
2267 ========================
2268 idRenderSystemLocal::GetScreenWidth
2269 ========================
2270 */
GetScreenWidth(void) const2271 int idRenderSystemLocal::GetScreenWidth( void ) const {
2272 	return glConfig.vidWidth;
2273 }
2274 
2275 /*
2276 ========================
2277 idRenderSystemLocal::GetScreenHeight
2278 ========================
2279 */
GetScreenHeight(void) const2280 int idRenderSystemLocal::GetScreenHeight( void ) const {
2281 	return glConfig.vidHeight;
2282 }
2283