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