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