DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

RenderSystem_init.cpp (90858B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition 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 BFG Edition 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 #pragma hdrstop
     30 #include "../idlib/precompiled.h"
     31 
     32 #include "tr_local.h"
     33 
     34 // Vista OpenGL wrapper check
     35 #include "../sys/win32/win_local.h"
     36 
     37 // DeviceContext bypasses RenderSystem to work directly with this
     38 idGuiModel * tr_guiModel;
     39 
     40 // functions that are not called every frame
     41 glconfig_t	glConfig;
     42 
     43 idCVar r_requestStereoPixelFormat( "r_requestStereoPixelFormat", "1", CVAR_RENDERER, "Ask for a stereo GL pixel format on startup" );
     44 idCVar r_debugContext( "r_debugContext", "0", CVAR_RENDERER, "Enable various levels of context debug." );
     45 idCVar r_glDriver( "r_glDriver", "", CVAR_RENDERER, "\"opengl32\", etc." );
     46 idCVar r_skipIntelWorkarounds( "r_skipIntelWorkarounds", "0", CVAR_RENDERER | CVAR_BOOL, "skip workarounds for Intel driver bugs" );
     47 idCVar r_multiSamples( "r_multiSamples", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "number of antialiasing samples" );
     48 idCVar r_vidMode( "r_vidMode", "0", CVAR_ARCHIVE | CVAR_RENDERER | CVAR_INTEGER, "fullscreen video mode number" );
     49 idCVar r_displayRefresh( "r_displayRefresh", "0", CVAR_RENDERER | CVAR_INTEGER | CVAR_NOCHEAT, "optional display refresh rate option for vid mode", 0.0f, 240.0f );
     50 idCVar r_fullscreen( "r_fullscreen", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "0 = windowed, 1 = full screen on monitor 1, 2 = full screen on monitor 2, etc" );
     51 idCVar r_customWidth( "r_customWidth", "1280", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "custom screen width. set r_vidMode to -1 to activate" );
     52 idCVar r_customHeight( "r_customHeight", "720", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "custom screen height. set r_vidMode to -1 to activate" );
     53 idCVar r_windowX( "r_windowX", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "Non-fullscreen parameter" );
     54 idCVar r_windowY( "r_windowY", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "Non-fullscreen parameter" );
     55 idCVar r_windowWidth( "r_windowWidth", "1280", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "Non-fullscreen parameter" );
     56 idCVar r_windowHeight( "r_windowHeight", "720", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "Non-fullscreen parameter" );
     57 
     58 idCVar r_useViewBypass( "r_useViewBypass", "1", CVAR_RENDERER | CVAR_INTEGER, "bypass a frame of latency to the view" );
     59 idCVar r_useLightPortalFlow( "r_useLightPortalFlow", "1", CVAR_RENDERER | CVAR_BOOL, "use a more precise area reference determination" );
     60 idCVar r_singleTriangle( "r_singleTriangle", "0", CVAR_RENDERER | CVAR_BOOL, "only draw a single triangle per primitive" );
     61 idCVar r_checkBounds( "r_checkBounds", "0", CVAR_RENDERER | CVAR_BOOL, "compare all surface bounds with precalculated ones" );
     62 idCVar r_useConstantMaterials( "r_useConstantMaterials", "1", CVAR_RENDERER | CVAR_BOOL, "use pre-calculated material registers if possible" );
     63 idCVar r_useSilRemap( "r_useSilRemap", "1", CVAR_RENDERER | CVAR_BOOL, "consider verts with the same XYZ, but different ST the same for shadows" );
     64 idCVar r_useNodeCommonChildren( "r_useNodeCommonChildren", "1", CVAR_RENDERER | CVAR_BOOL, "stop pushing reference bounds early when possible" );
     65 idCVar r_useShadowSurfaceScissor( "r_useShadowSurfaceScissor", "1", CVAR_RENDERER | CVAR_BOOL, "scissor shadows by the scissor rect of the interaction surfaces" );
     66 idCVar r_useCachedDynamicModels( "r_useCachedDynamicModels", "1", CVAR_RENDERER | CVAR_BOOL, "cache snapshots of dynamic models" );
     67 idCVar r_useSeamlessCubeMap( "r_useSeamlessCubeMap", "1", CVAR_RENDERER | CVAR_BOOL, "use ARB_seamless_cube_map if available" );
     68 idCVar r_useSRGB( "r_useSRGB", "0", CVAR_RENDERER | CVAR_INTEGER | CVAR_ARCHIVE, "1 = both texture and framebuffer, 2 = framebuffer only, 3 = texture only" );
     69 idCVar r_maxAnisotropicFiltering( "r_maxAnisotropicFiltering", "8", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "limit aniso filtering" );
     70 idCVar r_useTrilinearFiltering( "r_useTrilinearFiltering", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "Extra quality filtering" );
     71 idCVar r_lodBias( "r_lodBias", "0.5", CVAR_RENDERER | CVAR_ARCHIVE, "image lod bias" );
     72 
     73 idCVar r_useStateCaching( "r_useStateCaching", "1", CVAR_RENDERER | CVAR_BOOL, "avoid redundant state changes in GL_*() calls" );
     74 
     75 idCVar r_znear( "r_znear", "3", CVAR_RENDERER | CVAR_FLOAT, "near Z clip plane distance", 0.001f, 200.0f );
     76 
     77 idCVar r_ignoreGLErrors( "r_ignoreGLErrors", "1", CVAR_RENDERER | CVAR_BOOL, "ignore GL errors" );
     78 idCVar r_swapInterval( "r_swapInterval", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "0 = tear, 1 = swap-tear where available, 2 = always v-sync" );
     79 
     80 idCVar r_gamma( "r_gamma", "1.0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "changes gamma tables", 0.5f, 3.0f );
     81 idCVar r_brightness( "r_brightness", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "changes gamma tables", 0.5f, 2.0f );
     82 
     83 idCVar r_jitter( "r_jitter", "0", CVAR_RENDERER | CVAR_BOOL, "randomly subpixel jitter the projection matrix" );
     84 
     85 idCVar r_skipStaticInteractions( "r_skipStaticInteractions", "0", CVAR_RENDERER | CVAR_BOOL, "skip interactions created at level load" );
     86 idCVar r_skipDynamicInteractions( "r_skipDynamicInteractions", "0", CVAR_RENDERER | CVAR_BOOL, "skip interactions created after level load" );
     87 idCVar r_skipSuppress( "r_skipSuppress", "0", CVAR_RENDERER | CVAR_BOOL, "ignore the per-view suppressions" );
     88 idCVar r_skipPostProcess( "r_skipPostProcess", "0", CVAR_RENDERER | CVAR_BOOL, "skip all post-process renderings" );
     89 idCVar r_skipInteractions( "r_skipInteractions", "0", CVAR_RENDERER | CVAR_BOOL, "skip all light/surface interaction drawing" );
     90 idCVar r_skipDynamicTextures( "r_skipDynamicTextures", "0", CVAR_RENDERER | CVAR_BOOL, "don't dynamically create textures" );
     91 idCVar r_skipCopyTexture( "r_skipCopyTexture", "0", CVAR_RENDERER | CVAR_BOOL, "do all rendering, but don't actually copyTexSubImage2D" );
     92 idCVar r_skipBackEnd( "r_skipBackEnd", "0", CVAR_RENDERER | CVAR_BOOL, "don't draw anything" );
     93 idCVar r_skipRender( "r_skipRender", "0", CVAR_RENDERER | CVAR_BOOL, "skip 3D rendering, but pass 2D" );
     94 idCVar r_skipRenderContext( "r_skipRenderContext", "0", CVAR_RENDERER | CVAR_BOOL, "NULL the rendering context during backend 3D rendering" );
     95 idCVar r_skipTranslucent( "r_skipTranslucent", "0", CVAR_RENDERER | CVAR_BOOL, "skip the translucent interaction rendering" );
     96 idCVar r_skipAmbient( "r_skipAmbient", "0", CVAR_RENDERER | CVAR_BOOL, "bypasses all non-interaction drawing" );
     97 idCVar r_skipNewAmbient( "r_skipNewAmbient", "0", CVAR_RENDERER | CVAR_BOOL | CVAR_ARCHIVE, "bypasses all vertex/fragment program ambient drawing" );
     98 idCVar r_skipBlendLights( "r_skipBlendLights", "0", CVAR_RENDERER | CVAR_BOOL, "skip all blend lights" );
     99 idCVar r_skipFogLights( "r_skipFogLights", "0", CVAR_RENDERER | CVAR_BOOL, "skip all fog lights" );
    100 idCVar r_skipDeforms( "r_skipDeforms", "0", CVAR_RENDERER | CVAR_BOOL, "leave all deform materials in their original state" );
    101 idCVar r_skipFrontEnd( "r_skipFrontEnd", "0", CVAR_RENDERER | CVAR_BOOL, "bypasses all front end work, but 2D gui rendering still draws" );
    102 idCVar r_skipUpdates( "r_skipUpdates", "0", CVAR_RENDERER | CVAR_BOOL, "1 = don't accept any entity or light updates, making everything static" );
    103 idCVar r_skipDecals( "r_skipDecals", "0", CVAR_RENDERER | CVAR_BOOL, "skip decal surfaces" );
    104 idCVar r_skipOverlays( "r_skipOverlays", "0", CVAR_RENDERER | CVAR_BOOL, "skip overlay surfaces" );
    105 idCVar r_skipSpecular( "r_skipSpecular", "0", CVAR_RENDERER | CVAR_BOOL | CVAR_CHEAT | CVAR_ARCHIVE, "use black for specular1" );
    106 idCVar r_skipBump( "r_skipBump", "0", CVAR_RENDERER | CVAR_BOOL | CVAR_ARCHIVE, "uses a flat surface instead of the bump map" );
    107 idCVar r_skipDiffuse( "r_skipDiffuse", "0", CVAR_RENDERER | CVAR_BOOL, "use black for diffuse" );
    108 idCVar r_skipSubviews( "r_skipSubviews", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = don't render any gui elements on surfaces" );
    109 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> );
    110 idCVar r_skipParticles( "r_skipParticles", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = skip all particle systems", 0, 1, idCmdSystem::ArgCompletion_Integer<0,1> );
    111 idCVar r_skipShadows( "r_skipShadows", "0", CVAR_RENDERER | CVAR_BOOL  | CVAR_ARCHIVE, "disable shadows" );
    112 
    113 idCVar r_useLightPortalCulling( "r_useLightPortalCulling", "1", CVAR_RENDERER | CVAR_INTEGER, "0 = none, 1 = cull frustum corners to plane, 2 = exact clip the frustum faces", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
    114 idCVar r_useLightAreaCulling( "r_useLightAreaCulling", "1", CVAR_RENDERER | CVAR_BOOL, "0 = off, 1 = on" );
    115 idCVar r_useLightScissors( "r_useLightScissors", "3", CVAR_RENDERER | CVAR_INTEGER, "0 = no scissor, 1 = non-clipped scissor, 2 = near-clipped scissor, 3 = fully-clipped scissor", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
    116 idCVar r_useEntityPortalCulling( "r_useEntityPortalCulling", "1", CVAR_RENDERER | CVAR_INTEGER, "0 = none, 1 = cull frustum corners to plane, 2 = exact clip the frustum faces", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
    117 idCVar r_logFile( "r_logFile", "0", CVAR_RENDERER | CVAR_INTEGER, "number of frames to emit GL logs" );
    118 idCVar r_clear( "r_clear", "2", CVAR_RENDERER, "force screen clear every frame, 1 = purple, 2 = black, 'r g b' = custom" );
    119 
    120 idCVar r_offsetFactor( "r_offsetfactor", "0", CVAR_RENDERER | CVAR_FLOAT, "polygon offset parameter" );
    121 idCVar r_offsetUnits( "r_offsetunits", "-600", CVAR_RENDERER | CVAR_FLOAT, "polygon offset parameter" );
    122 
    123 idCVar r_shadowPolygonOffset( "r_shadowPolygonOffset", "-1", CVAR_RENDERER | CVAR_FLOAT, "bias value added to depth test for stencil shadow drawing" );
    124 idCVar r_shadowPolygonFactor( "r_shadowPolygonFactor", "0", CVAR_RENDERER | CVAR_FLOAT, "scale value for stencil shadow drawing" );
    125 idCVar r_subviewOnly( "r_subviewOnly", "0", CVAR_RENDERER | CVAR_BOOL, "1 = don't render main view, allowing subviews to be debugged" );
    126 idCVar r_testGamma( "r_testGamma", "0", CVAR_RENDERER | CVAR_FLOAT, "if > 0 draw a grid pattern to test gamma levels", 0, 195 );
    127 idCVar r_testGammaBias( "r_testGammaBias", "0", CVAR_RENDERER | CVAR_FLOAT, "if > 0 draw a grid pattern to test gamma levels" );
    128 idCVar r_lightScale( "r_lightScale", "3", CVAR_ARCHIVE | CVAR_RENDERER | CVAR_FLOAT, "all light intensities are multiplied by this" );
    129 idCVar r_flareSize( "r_flareSize", "1", CVAR_RENDERER | CVAR_FLOAT, "scale the flare deforms from the material def" ); 
    130 
    131 idCVar r_skipPrelightShadows( "r_skipPrelightShadows", "0", CVAR_RENDERER | CVAR_BOOL, "skip the dmap generated static shadow volumes" );
    132 idCVar r_useScissor( "r_useScissor", "1", CVAR_RENDERER | CVAR_BOOL, "scissor clip as portals and lights are processed" );
    133 idCVar r_useLightDepthBounds( "r_useLightDepthBounds", "1", CVAR_RENDERER | CVAR_BOOL, "use depth bounds test on lights to reduce both shadow and interaction fill" );
    134 idCVar r_useShadowDepthBounds( "r_useShadowDepthBounds", "1", CVAR_RENDERER | CVAR_BOOL, "use depth bounds test on individual shadow volumes to reduce shadow fill" );
    135 
    136 idCVar r_screenFraction( "r_screenFraction", "100", CVAR_RENDERER | CVAR_INTEGER, "for testing fill rate, the resolution of the entire screen can be changed" );
    137 idCVar r_usePortals( "r_usePortals", "1", CVAR_RENDERER | CVAR_BOOL, " 1 = use portals to perform area culling, otherwise draw everything" );
    138 idCVar r_singleLight( "r_singleLight", "-1", CVAR_RENDERER | CVAR_INTEGER, "suppress all but one light" );
    139 idCVar r_singleEntity( "r_singleEntity", "-1", CVAR_RENDERER | CVAR_INTEGER, "suppress all but one entity" );
    140 idCVar r_singleSurface( "r_singleSurface", "-1", CVAR_RENDERER | CVAR_INTEGER, "suppress all but one surface on each entity" );
    141 idCVar r_singleArea( "r_singleArea", "0", CVAR_RENDERER | CVAR_BOOL, "only draw the portal area the view is actually in" );
    142 idCVar r_orderIndexes( "r_orderIndexes", "1", CVAR_RENDERER | CVAR_BOOL, "perform index reorganization to optimize vertex use" );
    143 idCVar r_lightAllBackFaces( "r_lightAllBackFaces", "0", CVAR_RENDERER | CVAR_BOOL, "light all the back faces, even when they would be shadowed" );
    144 
    145 // visual debugging info
    146 idCVar r_showPortals( "r_showPortals", "0", CVAR_RENDERER | CVAR_BOOL, "draw portal outlines in color based on passed / not passed" );
    147 idCVar r_showUnsmoothedTangents( "r_showUnsmoothedTangents", "0", CVAR_RENDERER | CVAR_BOOL, "if 1, put all nvidia register combiner programming in display lists" );
    148 idCVar r_showSilhouette( "r_showSilhouette", "0", CVAR_RENDERER | CVAR_BOOL, "highlight edges that are casting shadow planes" );
    149 idCVar r_showVertexColor( "r_showVertexColor", "0", CVAR_RENDERER | CVAR_BOOL, "draws all triangles with the solid vertex color" );
    150 idCVar r_showUpdates( "r_showUpdates", "0", CVAR_RENDERER | CVAR_BOOL, "report entity and light updates and ref counts" );
    151 idCVar r_showDemo( "r_showDemo", "0", CVAR_RENDERER | CVAR_BOOL, "report reads and writes to the demo file" );
    152 idCVar r_showDynamic( "r_showDynamic", "0", CVAR_RENDERER | CVAR_BOOL, "report stats on dynamic surface generation" );
    153 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> );
    154 idCVar r_showIntensity( "r_showIntensity", "0", CVAR_RENDERER | CVAR_BOOL, "draw the screen colors based on intensity, red = 0, green = 128, blue = 255" );
    155 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> );
    156 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> );
    157 idCVar r_showLightScissors( "r_showLightScissors", "0", CVAR_RENDERER | CVAR_BOOL, "show light scissor rectangles" );
    158 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> );
    159 idCVar r_showViewEntitys( "r_showViewEntitys", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = displays the bounding boxes of all view models, 2 = print index numbers" );
    160 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, 4 = draw with alpha", 0, 4, idCmdSystem::ArgCompletion_Integer<0,4> );
    161 idCVar r_showSurfaceInfo( "r_showSurfaceInfo", "0", CVAR_RENDERER | CVAR_BOOL, "show surface material name under crosshair" );
    162 idCVar r_showNormals( "r_showNormals", "0", CVAR_RENDERER | CVAR_FLOAT, "draws wireframe normals" );
    163 idCVar r_showMemory( "r_showMemory", "0", CVAR_RENDERER | CVAR_BOOL, "print frame memory utilization" );
    164 idCVar r_showCull( "r_showCull", "0", CVAR_RENDERER | CVAR_BOOL, "report sphere and box culling stats" );
    165 idCVar r_showAddModel( "r_showAddModel", "0", CVAR_RENDERER | CVAR_BOOL, "report stats from tr_addModel" );
    166 idCVar r_showDepth( "r_showDepth", "0", CVAR_RENDERER | CVAR_BOOL, "display the contents of the depth buffer and the depth range" );
    167 idCVar r_showSurfaces( "r_showSurfaces", "0", CVAR_RENDERER | CVAR_BOOL, "report surface/light/shadow counts" );
    168 idCVar r_showPrimitives( "r_showPrimitives", "0", CVAR_RENDERER | CVAR_INTEGER, "report drawsurf/index/vertex counts" );
    169 idCVar r_showEdges( "r_showEdges", "0", CVAR_RENDERER | CVAR_BOOL, "draw the sil edges" );
    170 idCVar r_showTexturePolarity( "r_showTexturePolarity", "0", CVAR_RENDERER | CVAR_BOOL, "shade triangles by texture area polarity" );
    171 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> );
    172 idCVar r_showDominantTri( "r_showDominantTri", "0", CVAR_RENDERER | CVAR_BOOL, "draw lines from vertexes to center of dominant triangles" );
    173 idCVar r_showTextureVectors( "r_showTextureVectors", "0", CVAR_RENDERER | CVAR_FLOAT, " if > 0 draw each triangles texture (tangent) vectors" );
    174 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> );
    175 
    176 idCVar r_useEntityCallbacks( "r_useEntityCallbacks", "1", CVAR_RENDERER | CVAR_BOOL, "if 0, issue the callback immediately at update time, rather than defering" );
    177 
    178 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> );
    179 idCVar r_jointNameScale( "r_jointNameScale", "0.02", CVAR_RENDERER | CVAR_FLOAT, "size of joint names when r_showskel is set to 1" );
    180 idCVar r_jointNameOffset( "r_jointNameOffset", "0.5", CVAR_RENDERER | CVAR_FLOAT, "offset of joint names when r_showskel is set to 1" );
    181 
    182 idCVar r_debugLineDepthTest( "r_debugLineDepthTest", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "perform depth test on debug lines" );
    183 idCVar r_debugLineWidth( "r_debugLineWidth", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "width of debug lines" );
    184 idCVar r_debugArrowStep( "r_debugArrowStep", "120", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "step size of arrow cone line rotation in degrees", 0, 120 );
    185 idCVar r_debugPolygonFilled( "r_debugPolygonFilled", "1", CVAR_RENDERER | CVAR_BOOL, "draw a filled polygon" );
    186 
    187 idCVar r_materialOverride( "r_materialOverride", "", CVAR_RENDERER, "overrides all materials", idCmdSystem::ArgCompletion_Decl<DECL_MATERIAL> );
    188 
    189 idCVar r_debugRenderToTexture( "r_debugRenderToTexture", "0", CVAR_RENDERER | CVAR_INTEGER, "" );
    190 
    191 idCVar stereoRender_enable( "stereoRender_enable", "0", CVAR_INTEGER | CVAR_ARCHIVE, "1 = side-by-side compressed, 2 = top and bottom compressed, 3 = side-by-side, 4 = 720 frame packed, 5 = interlaced, 6 = OpenGL quad buffer" );
    192 idCVar stereoRender_swapEyes( "stereoRender_swapEyes", "0", CVAR_BOOL | CVAR_ARCHIVE, "reverse eye adjustments" );
    193 idCVar stereoRender_deGhost( "stereoRender_deGhost", "0.05", CVAR_FLOAT | CVAR_ARCHIVE, "subtract from opposite eye to reduce ghosting" );
    194 
    195 
    196 // GL_ARB_multitexture
    197 PFNGLACTIVETEXTUREPROC					qglActiveTextureARB;
    198 PFNGLCLIENTACTIVETEXTUREPROC			qglClientActiveTextureARB;
    199 
    200 // GL_EXT_direct_state_access
    201 PFNGLBINDMULTITEXTUREEXTPROC			qglBindMultiTextureEXT;
    202 
    203 // GL_ARB_texture_compression
    204 PFNGLCOMPRESSEDTEXIMAGE2DARBPROC		qglCompressedTexImage2DARB;
    205 PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC		qglCompressedTexSubImage2DARB;
    206 PFNGLGETCOMPRESSEDTEXIMAGEARBPROC		qglGetCompressedTexImageARB;
    207 
    208 // GL_ARB_vertex_buffer_object
    209 PFNGLBINDBUFFERARBPROC					qglBindBufferARB;
    210 PFNGLBINDBUFFERRANGEPROC				qglBindBufferRange;
    211 PFNGLDELETEBUFFERSARBPROC				qglDeleteBuffersARB;
    212 PFNGLGENBUFFERSARBPROC					qglGenBuffersARB;
    213 PFNGLISBUFFERARBPROC					qglIsBufferARB;
    214 PFNGLBUFFERDATAARBPROC					qglBufferDataARB;
    215 PFNGLBUFFERSUBDATAARBPROC				qglBufferSubDataARB;
    216 PFNGLGETBUFFERSUBDATAARBPROC			qglGetBufferSubDataARB;
    217 PFNGLMAPBUFFERARBPROC					qglMapBufferARB;
    218 PFNGLUNMAPBUFFERARBPROC					qglUnmapBufferARB;
    219 PFNGLGETBUFFERPARAMETERIVARBPROC		qglGetBufferParameterivARB;
    220 PFNGLGETBUFFERPOINTERVARBPROC			qglGetBufferPointervARB;
    221 
    222 // GL_ARB_map_buffer_range
    223 PFNGLMAPBUFFERRANGEPROC					qglMapBufferRange;
    224 
    225 // GL_ARB_draw_elements_base_vertex
    226 PFNGLDRAWELEMENTSBASEVERTEXPROC  		qglDrawElementsBaseVertex;
    227 
    228 // GL_ARB_vertex_array_object
    229 PFNGLGENVERTEXARRAYSPROC				qglGenVertexArrays;
    230 PFNGLBINDVERTEXARRAYPROC				qglBindVertexArray;
    231 PFNGLDELETEVERTEXARRAYSPROC				qglDeleteVertexArrays;
    232 
    233 // GL_ARB_vertex_program / GL_ARB_fragment_program
    234 PFNGLVERTEXATTRIBPOINTERARBPROC			qglVertexAttribPointerARB;
    235 PFNGLENABLEVERTEXATTRIBARRAYARBPROC		qglEnableVertexAttribArrayARB;
    236 PFNGLDISABLEVERTEXATTRIBARRAYARBPROC	qglDisableVertexAttribArrayARB;
    237 PFNGLPROGRAMSTRINGARBPROC				qglProgramStringARB;
    238 PFNGLBINDPROGRAMARBPROC					qglBindProgramARB;
    239 PFNGLGENPROGRAMSARBPROC					qglGenProgramsARB;
    240 PFNGLDELETEPROGRAMSARBPROC				qglDeleteProgramsARB;
    241 PFNGLPROGRAMENVPARAMETER4FVARBPROC		qglProgramEnvParameter4fvARB;
    242 PFNGLPROGRAMLOCALPARAMETER4FVARBPROC	qglProgramLocalParameter4fvARB;
    243 
    244 // GLSL / OpenGL 2.0
    245 PFNGLCREATESHADERPROC					qglCreateShader;
    246 PFNGLDELETESHADERPROC					qglDeleteShader;
    247 PFNGLSHADERSOURCEPROC					qglShaderSource;
    248 PFNGLCOMPILESHADERPROC					qglCompileShader;
    249 PFNGLGETSHADERIVPROC					qglGetShaderiv;
    250 PFNGLGETSHADERINFOLOGPROC				qglGetShaderInfoLog;
    251 PFNGLCREATEPROGRAMPROC					qglCreateProgram;
    252 PFNGLDELETEPROGRAMPROC					qglDeleteProgram;
    253 PFNGLATTACHSHADERPROC					qglAttachShader;
    254 PFNGLDETACHSHADERPROC					qglDetachShader;
    255 PFNGLLINKPROGRAMPROC					qglLinkProgram;
    256 PFNGLUSEPROGRAMPROC						qglUseProgram;
    257 PFNGLGETPROGRAMIVPROC					qglGetProgramiv;
    258 PFNGLGETPROGRAMINFOLOGPROC				qglGetProgramInfoLog;
    259 PFNGLPROGRAMPARAMETERIPROC				qglProgramParameteri;
    260 PFNGLBINDATTRIBLOCATIONPROC				qglBindAttribLocation;
    261 PFNGLGETUNIFORMLOCATIONPROC				qglGetUniformLocation;
    262 PFNGLUNIFORM1IPROC						qglUniform1i;
    263 PFNGLUNIFORM4FVPROC						qglUniform4fv;
    264 
    265 // GL_ARB_uniform_buffer_object
    266 PFNGLGETUNIFORMBLOCKINDEXPROC			qglGetUniformBlockIndex;
    267 PFNGLUNIFORMBLOCKBINDINGPROC			qglUniformBlockBinding;
    268 
    269 // GL_ATI_separate_stencil / OpenGL 2.0
    270 PFNGLSTENCILOPSEPARATEATIPROC			qglStencilOpSeparate;
    271 PFNGLSTENCILFUNCSEPARATEATIPROC			qglStencilFuncSeparate;
    272 
    273 // GL_EXT_depth_bounds_test
    274 PFNGLDEPTHBOUNDSEXTPROC                 qglDepthBoundsEXT;
    275 
    276 // GL_ARB_sync
    277 PFNGLFENCESYNCPROC						qglFenceSync;
    278 PFNGLISSYNCPROC							qglIsSync;
    279 PFNGLCLIENTWAITSYNCPROC					qglClientWaitSync;
    280 PFNGLDELETESYNCPROC						qglDeleteSync;
    281 
    282 // GL_ARB_occlusion_query
    283 PFNGLGENQUERIESARBPROC					qglGenQueriesARB;
    284 PFNGLDELETEQUERIESARBPROC				qglDeleteQueriesARB;
    285 PFNGLISQUERYARBPROC						qglIsQueryARB;
    286 PFNGLBEGINQUERYARBPROC					qglBeginQueryARB;
    287 PFNGLENDQUERYARBPROC					qglEndQueryARB;
    288 PFNGLGETQUERYIVARBPROC					qglGetQueryivARB;
    289 PFNGLGETQUERYOBJECTIVARBPROC			qglGetQueryObjectivARB;
    290 PFNGLGETQUERYOBJECTUIVARBPROC			qglGetQueryObjectuivARB;
    291 
    292 // GL_ARB_timer_query / GL_EXT_timer_query
    293 PFNGLGETQUERYOBJECTUI64VEXTPROC			qglGetQueryObjectui64vEXT;
    294 
    295 // GL_ARB_debug_output
    296 PFNGLDEBUGMESSAGECONTROLARBPROC			qglDebugMessageControlARB;
    297 PFNGLDEBUGMESSAGEINSERTARBPROC			qglDebugMessageInsertARB;
    298 PFNGLDEBUGMESSAGECALLBACKARBPROC		qglDebugMessageCallbackARB;
    299 PFNGLGETDEBUGMESSAGELOGARBPROC			qglGetDebugMessageLogARB;
    300 
    301 PFNGLGETSTRINGIPROC						qglGetStringi;
    302 
    303 /*
    304 ========================
    305 glBindMultiTextureEXT
    306 
    307 As of 2011/09/16 the Intel drivers for "Sandy Bridge" and "Ivy Bridge" integrated graphics do not support this extension.
    308 ========================
    309 */
    310 void APIENTRY glBindMultiTextureEXT( GLenum texunit, GLenum target, GLuint texture ) {
    311 	qglActiveTextureARB( texunit );
    312 	qglBindTexture( target, texture );
    313 }
    314 
    315 
    316 /*
    317 =================
    318 R_CheckExtension
    319 =================
    320 */
    321 bool R_CheckExtension( char *name ) {
    322 	if ( !strstr( glConfig.extensions_string, name ) ) {
    323 		common->Printf( "X..%s not found\n", name );
    324 		return false;
    325 	}
    326 
    327 	common->Printf( "...using %s\n", name );
    328 	return true;
    329 }
    330 
    331 
    332 /*
    333 ========================
    334 DebugCallback
    335 
    336 For ARB_debug_output
    337 ========================
    338 */
    339 static void CALLBACK DebugCallback(unsigned int source, unsigned int type,
    340 								   unsigned int id, unsigned int severity, int length, const char * message, void * userParam) {
    341 	// it probably isn't safe to do an idLib::Printf at this point
    342 	OutputDebugString( message );
    343 	OutputDebugString( "\n" );
    344 }
    345 
    346 /*
    347 ==================
    348 R_CheckPortableExtensions
    349 ==================
    350 */
    351 static void R_CheckPortableExtensions() {
    352 	glConfig.glVersion = atof( glConfig.version_string );
    353 	const char * badVideoCard = idLocalization::GetString( "#str_06780" );
    354 	if ( glConfig.glVersion < 2.0f ) {
    355 		idLib::FatalError( badVideoCard );
    356 	}
    357 
    358 	if ( idStr::Icmpn( glConfig.renderer_string, "ATI ", 4 ) == 0 || idStr::Icmpn( glConfig.renderer_string, "AMD ", 4 ) == 0 ) {
    359 		glConfig.vendor = VENDOR_AMD;
    360 	} else if ( idStr::Icmpn( glConfig.renderer_string, "NVIDIA", 6 ) == 0 ) {
    361 		glConfig.vendor = VENDOR_NVIDIA;
    362 	} else if ( idStr::Icmpn( glConfig.renderer_string, "Intel", 5 ) == 0 ) {
    363 		glConfig.vendor = VENDOR_INTEL;
    364 	}
    365 
    366 	// GL_ARB_multitexture
    367 	glConfig.multitextureAvailable = R_CheckExtension( "GL_ARB_multitexture" );
    368 	if ( glConfig.multitextureAvailable ) {
    369 		qglActiveTextureARB = (void(APIENTRY *)(GLenum))GLimp_ExtensionPointer( "glActiveTextureARB" );
    370 		qglClientActiveTextureARB = (void(APIENTRY *)(GLenum))GLimp_ExtensionPointer( "glClientActiveTextureARB" );
    371 	}
    372 
    373 	// GL_EXT_direct_state_access
    374 	glConfig.directStateAccess = R_CheckExtension( "GL_EXT_direct_state_access" );
    375 	if ( glConfig.directStateAccess ) {
    376 		qglBindMultiTextureEXT = (PFNGLBINDMULTITEXTUREEXTPROC)GLimp_ExtensionPointer( "glBindMultiTextureEXT" );
    377 	} else {
    378 		qglBindMultiTextureEXT = glBindMultiTextureEXT;
    379 	}
    380 
    381 	// GL_ARB_texture_compression + GL_S3_s3tc
    382 	// DRI drivers may have GL_ARB_texture_compression but no GL_EXT_texture_compression_s3tc
    383 	glConfig.textureCompressionAvailable = R_CheckExtension( "GL_ARB_texture_compression" ) && R_CheckExtension( "GL_EXT_texture_compression_s3tc" );
    384 	if ( glConfig.textureCompressionAvailable ) {
    385 		qglCompressedTexImage2DARB = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)GLimp_ExtensionPointer( "glCompressedTexImage2DARB" );
    386 		qglCompressedTexSubImage2DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC)GLimp_ExtensionPointer( "glCompressedTexSubImage2DARB" );
    387 		qglGetCompressedTexImageARB = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)GLimp_ExtensionPointer( "glGetCompressedTexImageARB" );
    388 	}
    389 
    390 	// GL_EXT_texture_filter_anisotropic
    391 	glConfig.anisotropicFilterAvailable = R_CheckExtension( "GL_EXT_texture_filter_anisotropic" );
    392 	if ( glConfig.anisotropicFilterAvailable ) {
    393 		qglGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig.maxTextureAnisotropy );
    394 		common->Printf( "   maxTextureAnisotropy: %f\n", glConfig.maxTextureAnisotropy );
    395 	} else {
    396 		glConfig.maxTextureAnisotropy = 1;
    397 	}
    398 
    399 	// GL_EXT_texture_lod_bias
    400 	// The actual extension is broken as specificed, storing the state in the texture unit instead
    401 	// of the texture object.  The behavior in GL 1.4 is the behavior we use.
    402 	glConfig.textureLODBiasAvailable = ( glConfig.glVersion >= 1.4 || R_CheckExtension( "GL_EXT_texture_lod_bias" ) );
    403 	if ( glConfig.textureLODBiasAvailable ) {
    404 		common->Printf( "...using %s\n", "GL_EXT_texture_lod_bias" );
    405 	} else {
    406 		common->Printf( "X..%s not found\n", "GL_EXT_texture_lod_bias" );
    407 	}
    408 
    409 	// GL_ARB_seamless_cube_map
    410 	glConfig.seamlessCubeMapAvailable = R_CheckExtension( "GL_ARB_seamless_cube_map" );
    411 	r_useSeamlessCubeMap.SetModified();		// the CheckCvars() next frame will enable / disable it
    412 
    413 	// GL_ARB_framebuffer_sRGB
    414 	glConfig.sRGBFramebufferAvailable = R_CheckExtension( "GL_ARB_framebuffer_sRGB" );
    415 	r_useSRGB.SetModified();		// the CheckCvars() next frame will enable / disable it
    416 
    417 	// GL_ARB_vertex_buffer_object
    418 	glConfig.vertexBufferObjectAvailable = R_CheckExtension( "GL_ARB_vertex_buffer_object" );
    419 	if ( glConfig.vertexBufferObjectAvailable ) {
    420 		qglBindBufferARB = (PFNGLBINDBUFFERARBPROC)GLimp_ExtensionPointer( "glBindBufferARB" );
    421 		qglBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)GLimp_ExtensionPointer( "glBindBufferRange" );
    422 		qglDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)GLimp_ExtensionPointer( "glDeleteBuffersARB" );
    423 		qglGenBuffersARB = (PFNGLGENBUFFERSARBPROC)GLimp_ExtensionPointer( "glGenBuffersARB" );
    424 		qglIsBufferARB = (PFNGLISBUFFERARBPROC)GLimp_ExtensionPointer( "glIsBufferARB" );
    425 		qglBufferDataARB = (PFNGLBUFFERDATAARBPROC)GLimp_ExtensionPointer( "glBufferDataARB" );
    426 		qglBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)GLimp_ExtensionPointer( "glBufferSubDataARB" );
    427 		qglGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC)GLimp_ExtensionPointer( "glGetBufferSubDataARB" );
    428 		qglMapBufferARB = (PFNGLMAPBUFFERARBPROC)GLimp_ExtensionPointer( "glMapBufferARB" );
    429 		qglUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)GLimp_ExtensionPointer( "glUnmapBufferARB" );
    430 		qglGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)GLimp_ExtensionPointer( "glGetBufferParameterivARB" );
    431 		qglGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC)GLimp_ExtensionPointer( "glGetBufferPointervARB" );
    432 	}
    433 
    434 	// GL_ARB_map_buffer_range, map a section of a buffer object's data store
    435 	glConfig.mapBufferRangeAvailable = R_CheckExtension( "GL_ARB_map_buffer_range" );
    436 	if ( glConfig.mapBufferRangeAvailable ) {
    437 		qglMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)GLimp_ExtensionPointer( "glMapBufferRange" );
    438 	}
    439 
    440 	// GL_ARB_vertex_array_object
    441 	glConfig.vertexArrayObjectAvailable = R_CheckExtension( "GL_ARB_vertex_array_object" );
    442 	if ( glConfig.vertexArrayObjectAvailable ) {
    443 		qglGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)GLimp_ExtensionPointer( "glGenVertexArrays" );
    444 		qglBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)GLimp_ExtensionPointer( "glBindVertexArray" );
    445 		qglDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)GLimp_ExtensionPointer( "glDeleteVertexArrays" );
    446 	}
    447 
    448 	// GL_ARB_draw_elements_base_vertex
    449 	glConfig.drawElementsBaseVertexAvailable = R_CheckExtension( "GL_ARB_draw_elements_base_vertex" );
    450 	if ( glConfig.drawElementsBaseVertexAvailable ) {
    451 		qglDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)GLimp_ExtensionPointer( "glDrawElementsBaseVertex" );
    452 	}
    453 
    454 	// GL_ARB_vertex_program / GL_ARB_fragment_program
    455 	glConfig.fragmentProgramAvailable = R_CheckExtension( "GL_ARB_fragment_program" );
    456 	if ( glConfig.fragmentProgramAvailable ) {
    457 		qglVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC)GLimp_ExtensionPointer( "glVertexAttribPointerARB" );
    458 		qglEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)GLimp_ExtensionPointer( "glEnableVertexAttribArrayARB" );
    459 		qglDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)GLimp_ExtensionPointer( "glDisableVertexAttribArrayARB" );
    460 		qglProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)GLimp_ExtensionPointer( "glProgramStringARB" );
    461 		qglBindProgramARB = (PFNGLBINDPROGRAMARBPROC)GLimp_ExtensionPointer( "glBindProgramARB" );
    462 		qglGenProgramsARB = (PFNGLGENPROGRAMSARBPROC)GLimp_ExtensionPointer( "glGenProgramsARB" );
    463 		qglDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)GLimp_ExtensionPointer( "glDeleteProgramsARB" );
    464 		qglProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC)GLimp_ExtensionPointer( "glProgramEnvParameter4fvARB" );
    465 		qglProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)GLimp_ExtensionPointer( "glProgramLocalParameter4fvARB" );
    466 
    467 		qglGetIntegerv( GL_MAX_TEXTURE_COORDS_ARB, (GLint *)&glConfig.maxTextureCoords );
    468 		qglGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS_ARB, (GLint *)&glConfig.maxTextureImageUnits );
    469 	}
    470 
    471 	// GLSL, core in OpenGL > 2.0
    472 	glConfig.glslAvailable = ( glConfig.glVersion >= 2.0f );
    473 	if ( glConfig.glslAvailable ) {
    474 		qglCreateShader = (PFNGLCREATESHADERPROC)GLimp_ExtensionPointer( "glCreateShader" );
    475 		qglDeleteShader = (PFNGLDELETESHADERPROC)GLimp_ExtensionPointer( "glDeleteShader" );
    476 		qglShaderSource = (PFNGLSHADERSOURCEPROC)GLimp_ExtensionPointer( "glShaderSource" );
    477 		qglCompileShader = (PFNGLCOMPILESHADERPROC)GLimp_ExtensionPointer( "glCompileShader" );
    478 		qglGetShaderiv = (PFNGLGETSHADERIVPROC)GLimp_ExtensionPointer( "glGetShaderiv" );
    479 		qglGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)GLimp_ExtensionPointer( "glGetShaderInfoLog" );
    480 		qglCreateProgram = (PFNGLCREATEPROGRAMPROC)GLimp_ExtensionPointer( "glCreateProgram" );
    481 		qglDeleteProgram = (PFNGLDELETEPROGRAMPROC)GLimp_ExtensionPointer( "glDeleteProgram" );
    482 		qglAttachShader = (PFNGLATTACHSHADERPROC)GLimp_ExtensionPointer( "glAttachShader" );
    483 		qglDetachShader = (PFNGLDETACHSHADERPROC)GLimp_ExtensionPointer( "glDetachShader" );
    484 		qglLinkProgram = (PFNGLLINKPROGRAMPROC)GLimp_ExtensionPointer( "glLinkProgram" );
    485 		qglUseProgram = (PFNGLUSEPROGRAMPROC)GLimp_ExtensionPointer( "glUseProgram" );
    486 		qglGetProgramiv = (PFNGLGETPROGRAMIVPROC)GLimp_ExtensionPointer( "glGetProgramiv" );
    487 		qglGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)GLimp_ExtensionPointer( "glGetProgramInfoLog" );
    488 		qglBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)GLimp_ExtensionPointer( "glBindAttribLocation" );
    489 		qglGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)GLimp_ExtensionPointer( "glGetUniformLocation" );
    490 		qglUniform1i = (PFNGLUNIFORM1IPROC)GLimp_ExtensionPointer( "glUniform1i" );
    491 		qglUniform4fv = (PFNGLUNIFORM4FVPROC)GLimp_ExtensionPointer( "glUniform4fv" );
    492 	}
    493 
    494 	// GL_ARB_uniform_buffer_object
    495 	glConfig.uniformBufferAvailable = R_CheckExtension( "GL_ARB_uniform_buffer_object" );
    496 	if ( glConfig.uniformBufferAvailable ) {
    497 		qglGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)GLimp_ExtensionPointer( "glGetUniformBlockIndex" );
    498 		qglUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)GLimp_ExtensionPointer( "glUniformBlockBinding" );
    499 
    500 		qglGetIntegerv( GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, (GLint *)&glConfig.uniformBufferOffsetAlignment );
    501 		if ( glConfig.uniformBufferOffsetAlignment < 256 ) {
    502 			glConfig.uniformBufferOffsetAlignment = 256;
    503 		}
    504 	}
    505 
    506 	// ATI_separate_stencil / OpenGL 2.0 separate stencil
    507 	glConfig.twoSidedStencilAvailable = ( glConfig.glVersion >= 2.0f ) || R_CheckExtension( "GL_ATI_separate_stencil" );
    508 	if ( glConfig.twoSidedStencilAvailable ) {
    509 		qglStencilOpSeparate = (PFNGLSTENCILOPSEPARATEATIPROC)GLimp_ExtensionPointer( "glStencilOpSeparate" );
    510 		qglStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEATIPROC)GLimp_ExtensionPointer( "glStencilFuncSeparate" );
    511 	}
    512 
    513 	// GL_EXT_depth_bounds_test
    514  	glConfig.depthBoundsTestAvailable = R_CheckExtension( "GL_EXT_depth_bounds_test" );
    515  	if ( glConfig.depthBoundsTestAvailable ) {
    516  		qglDepthBoundsEXT = (PFNGLDEPTHBOUNDSEXTPROC)GLimp_ExtensionPointer( "glDepthBoundsEXT" );
    517  	}
    518 
    519 	// GL_ARB_sync
    520 	glConfig.syncAvailable = R_CheckExtension( "GL_ARB_sync" ) &&
    521 		// as of 5/24/2012 (driver version 15.26.12.64.2761) sync objects
    522 		// do not appear to work for the Intel HD 4000 graphics
    523 		( glConfig.vendor != VENDOR_INTEL || r_skipIntelWorkarounds.GetBool() );
    524 	if ( glConfig.syncAvailable ) {
    525 		qglFenceSync = (PFNGLFENCESYNCPROC)GLimp_ExtensionPointer( "glFenceSync" );
    526 		qglIsSync = (PFNGLISSYNCPROC)GLimp_ExtensionPointer( "glIsSync" );
    527 		qglClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)GLimp_ExtensionPointer( "glClientWaitSync" );
    528 		qglDeleteSync = (PFNGLDELETESYNCPROC)GLimp_ExtensionPointer( "glDeleteSync" );
    529 	}
    530 
    531 	// GL_ARB_occlusion_query
    532 	glConfig.occlusionQueryAvailable = R_CheckExtension( "GL_ARB_occlusion_query" );
    533 	if ( glConfig.occlusionQueryAvailable ) {
    534 		// defined in GL_ARB_occlusion_query, which is required for GL_EXT_timer_query
    535 		qglGenQueriesARB = (PFNGLGENQUERIESARBPROC)GLimp_ExtensionPointer( "glGenQueriesARB" );
    536 		qglDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC)GLimp_ExtensionPointer( "glDeleteQueriesARB" );
    537 		qglIsQueryARB = (PFNGLISQUERYARBPROC)GLimp_ExtensionPointer( "glIsQueryARB" );
    538 		qglBeginQueryARB = (PFNGLBEGINQUERYARBPROC)GLimp_ExtensionPointer( "glBeginQueryARB" );
    539 		qglEndQueryARB = (PFNGLENDQUERYARBPROC)GLimp_ExtensionPointer( "glEndQueryARB" );
    540 		qglGetQueryivARB = (PFNGLGETQUERYIVARBPROC)GLimp_ExtensionPointer( "glGetQueryivARB" );
    541 		qglGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC)GLimp_ExtensionPointer( "glGetQueryObjectivARB" );
    542 		qglGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC)GLimp_ExtensionPointer( "glGetQueryObjectuivARB" );
    543 	}
    544 
    545 	// GL_ARB_timer_query
    546 	glConfig.timerQueryAvailable = R_CheckExtension( "GL_ARB_timer_query" ) || R_CheckExtension( "GL_EXT_timer_query" );
    547 	if ( glConfig.timerQueryAvailable ) {
    548 		qglGetQueryObjectui64vEXT = (PFNGLGETQUERYOBJECTUI64VEXTPROC)GLimp_ExtensionPointer( "glGetQueryObjectui64vARB" );
    549 		if ( qglGetQueryObjectui64vEXT == NULL ) {
    550 			qglGetQueryObjectui64vEXT = (PFNGLGETQUERYOBJECTUI64VEXTPROC)GLimp_ExtensionPointer( "glGetQueryObjectui64vEXT" );
    551 		}
    552 	}
    553 
    554 	// GL_ARB_debug_output
    555 	glConfig.debugOutputAvailable = R_CheckExtension( "GL_ARB_debug_output" );
    556 	if ( glConfig.debugOutputAvailable ) {
    557 		qglDebugMessageControlARB   = (PFNGLDEBUGMESSAGECONTROLARBPROC)GLimp_ExtensionPointer( "glDebugMessageControlARB" );
    558 		qglDebugMessageInsertARB    = (PFNGLDEBUGMESSAGEINSERTARBPROC)GLimp_ExtensionPointer( "glDebugMessageInsertARB" );
    559 		qglDebugMessageCallbackARB  = (PFNGLDEBUGMESSAGECALLBACKARBPROC)GLimp_ExtensionPointer( "glDebugMessageCallbackARB" );
    560 		qglGetDebugMessageLogARB    = (PFNGLGETDEBUGMESSAGELOGARBPROC)GLimp_ExtensionPointer( "glGetDebugMessageLogARB" );
    561 
    562 		if ( r_debugContext.GetInteger() >= 1 ) {
    563 			qglDebugMessageCallbackARB( DebugCallback, NULL );
    564 		}
    565 		if ( r_debugContext.GetInteger() >= 2 ) {
    566 			// force everything to happen in the main thread instead of in a separate driver thread
    567 			glEnable( GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB );
    568 		}
    569 		if ( r_debugContext.GetInteger() >= 3 ) {
    570 			// enable all the low priority messages
    571 			qglDebugMessageControlARB( GL_DONT_CARE,
    572 									GL_DONT_CARE,
    573 									GL_DEBUG_SEVERITY_LOW_ARB,
    574 									0, NULL, true );
    575 		}
    576 	}
    577 
    578 	// GL_ARB_multitexture
    579 	if ( !glConfig.multitextureAvailable ) {
    580 		idLib::Error( "GL_ARB_multitexture not available" );
    581 	}
    582 	// GL_ARB_texture_compression + GL_EXT_texture_compression_s3tc
    583 	if ( !glConfig.textureCompressionAvailable ) {
    584 		idLib::Error( "GL_ARB_texture_compression or GL_EXT_texture_compression_s3tc not available" );
    585 	}
    586 	// GL_ARB_vertex_buffer_object
    587 	if ( !glConfig.vertexBufferObjectAvailable ) {
    588 		idLib::Error( "GL_ARB_vertex_buffer_object not available" );
    589 	}
    590 	// GL_ARB_map_buffer_range
    591 	if ( !glConfig.mapBufferRangeAvailable ) {
    592 		idLib::Error( "GL_ARB_map_buffer_range not available" );
    593 	}
    594 	// GL_ARB_vertex_array_object
    595 	if ( !glConfig.vertexArrayObjectAvailable ) {
    596 		idLib::Error( "GL_ARB_vertex_array_object not available" );
    597 	}
    598 	// GL_ARB_draw_elements_base_vertex
    599 	if ( !glConfig.drawElementsBaseVertexAvailable ) {
    600 		idLib::Error( "GL_ARB_draw_elements_base_vertex not available" );
    601 	}
    602 	// GL_ARB_vertex_program / GL_ARB_fragment_program
    603 	if ( !glConfig.fragmentProgramAvailable ) {
    604 		idLib::Error( "GL_ARB_fragment_program not available" );
    605 	}
    606 	// GLSL
    607 	if ( !glConfig.glslAvailable ) {
    608 		idLib::Error( "GLSL not available" );
    609 	}
    610 	// GL_ARB_uniform_buffer_object
    611 	if ( !glConfig.uniformBufferAvailable ) {
    612 		idLib::Error( "GL_ARB_uniform_buffer_object not available" );
    613 	}
    614 	// GL_EXT_stencil_two_side
    615 	if ( !glConfig.twoSidedStencilAvailable ) {
    616 		idLib::Error( "GL_ATI_separate_stencil not available" );
    617 	}
    618 
    619 	// generate one global Vertex Array Object (VAO)
    620 	qglGenVertexArrays( 1, &glConfig.global_vao );
    621 	qglBindVertexArray( glConfig.global_vao );
    622 
    623 }
    624 
    625 
    626 
    627 static bool r_initialized = false;
    628 
    629 /*
    630 =============================
    631 R_IsInitialized
    632 =============================
    633 */
    634 bool R_IsInitialized() {
    635 	return r_initialized;
    636 }
    637 
    638 /*
    639 =============================
    640 R_SetNewMode
    641 
    642 r_fullScreen -1		borderless window at exact desktop coordinates
    643 r_fullScreen 0		bordered window at exact desktop coordinates
    644 r_fullScreen 1		fullscreen on monitor 1 at r_vidMode
    645 r_fullScreen 2		fullscreen on monitor 2 at r_vidMode
    646 ...
    647 
    648 r_vidMode -1		use r_customWidth / r_customHeight, even if they don't appear on the mode list
    649 r_vidMode 0			use first mode returned by EnumDisplaySettings()
    650 r_vidMode 1			use second mode returned by EnumDisplaySettings()
    651 ...
    652 
    653 r_displayRefresh 0	don't specify refresh
    654 r_displayRefresh 70	specify 70 hz, etc
    655 =============================
    656 */
    657 void R_SetNewMode( const bool fullInit ) {
    658 	// try up to three different configurations
    659 
    660 	for ( int i = 0 ; i < 3 ; i++ ) {
    661 		if ( i == 0 && stereoRender_enable.GetInteger() != STEREO3D_QUAD_BUFFER ) {
    662 			continue;		// don't even try for a stereo mode
    663 		}
    664 
    665 		glimpParms_t	parms;
    666 
    667 		if ( r_fullscreen.GetInteger() <= 0 ) {
    668 			// use explicit position / size for window
    669 			parms.x = r_windowX.GetInteger();
    670 			parms.y = r_windowY.GetInteger();
    671 			parms.width = r_windowWidth.GetInteger();
    672 			parms.height = r_windowHeight.GetInteger();
    673 			// may still be -1 to force a borderless window
    674 			parms.fullScreen = r_fullscreen.GetInteger();
    675 			parms.displayHz = 0;		// ignored
    676 		} else {
    677 			// get the mode list for this monitor
    678 			idList<vidMode_t> modeList;
    679 			if ( !R_GetModeListForDisplay( r_fullscreen.GetInteger()-1, modeList ) ) {
    680 				idLib::Printf( "r_fullscreen reset from %i to 1 because mode list failed.", r_fullscreen.GetInteger() );
    681 				r_fullscreen.SetInteger( 1 );
    682 				R_GetModeListForDisplay( r_fullscreen.GetInteger()-1, modeList );
    683 			}
    684 			if ( modeList.Num() < 1 ) {
    685 				idLib::Printf( "Going to safe mode because mode list failed." );
    686 				goto safeMode;
    687 			}
    688 
    689 			parms.x = 0;		// ignored
    690 			parms.y = 0;		// ignored
    691 			parms.fullScreen = r_fullscreen.GetInteger();
    692 
    693 			// set the parameters we are trying
    694 			if ( r_vidMode.GetInteger() < 0 ) {
    695 				// try forcing a specific mode, even if it isn't on the list
    696 				parms.width = r_customWidth.GetInteger();
    697 				parms.height = r_customHeight.GetInteger();
    698 				parms.displayHz = r_displayRefresh.GetInteger();
    699 			} else {
    700 				if ( r_vidMode.GetInteger() > modeList.Num() ) {
    701 					idLib::Printf( "r_vidMode reset from %i to 0.\n", r_vidMode.GetInteger() );
    702 					r_vidMode.SetInteger( 0 );
    703 				}
    704 
    705 				parms.width = modeList[ r_vidMode.GetInteger() ].width;
    706 				parms.height = modeList[ r_vidMode.GetInteger() ].height;
    707 				parms.displayHz = modeList[ r_vidMode.GetInteger() ].displayHz;
    708 			}
    709 		}
    710 
    711 		parms.multiSamples = r_multiSamples.GetInteger();
    712 		if ( i == 0 ) {
    713 			parms.stereo = ( stereoRender_enable.GetInteger() == STEREO3D_QUAD_BUFFER );
    714 		} else {
    715 			parms.stereo = false;
    716 		}
    717 
    718 		if ( fullInit ) {
    719 			// create the context as well as setting up the window
    720 			if ( GLimp_Init( parms ) ) {
    721 				// it worked
    722 				break;
    723 			}
    724 		} else {
    725 			// just rebuild the window
    726 			if ( GLimp_SetScreenParms( parms ) ) {
    727 				// it worked
    728 				break;
    729 			}
    730 		}
    731 
    732 		if ( i == 2 ) {
    733 			common->FatalError( "Unable to initialize OpenGL" );
    734 		}
    735 
    736 		if ( i == 0 ) {
    737 			// same settings, no stereo
    738 			continue;
    739 		}
    740 
    741 safeMode:
    742 		// if we failed, set everything back to "safe mode"
    743 		// and try again
    744 		r_vidMode.SetInteger( 0 );
    745 		r_fullscreen.SetInteger( 1 );
    746 		r_displayRefresh.SetInteger( 0 );
    747 		r_multiSamples.SetInteger( 0 );
    748 	}
    749 }
    750 
    751 idStr extensions_string;
    752 
    753 /*
    754 ==================
    755 R_InitOpenGL
    756 
    757 This function is responsible for initializing a valid OpenGL subsystem
    758 for rendering.  This is done by calling the system specific GLimp_Init,
    759 which gives us a working OGL subsystem, then setting all necessary openGL
    760 state, including images, vertex programs, and display lists.
    761 
    762 Changes to the vertex cache size or smp state require a vid_restart.
    763 
    764 If R_IsInitialized() is false, no rendering can take place, but
    765 all renderSystem functions will still operate properly, notably the material
    766 and model information functions.
    767 ==================
    768 */
    769 void R_InitOpenGL() {
    770 
    771 	common->Printf( "----- R_InitOpenGL -----\n" );
    772 
    773 	if ( R_IsInitialized() ) {
    774 		common->FatalError( "R_InitOpenGL called while active" );
    775 	}
    776 
    777 	R_SetNewMode( true );
    778 
    779 
    780 	// input and sound systems need to be tied to the new window
    781 	Sys_InitInput();
    782 
    783 	// get our config strings
    784 	glConfig.vendor_string = (const char *)qglGetString( GL_VENDOR );
    785 	glConfig.renderer_string = (const char *)qglGetString( GL_RENDERER );
    786 	glConfig.version_string = (const char *)qglGetString( GL_VERSION );
    787 	glConfig.shading_language_string = (const char *)qglGetString( GL_SHADING_LANGUAGE_VERSION );
    788 	glConfig.extensions_string = (const char *)qglGetString( GL_EXTENSIONS );
    789 
    790 	if ( glConfig.extensions_string == NULL ) {
    791 		// As of OpenGL 3.2, glGetStringi is required to obtain the available extensions
    792 		qglGetStringi = (PFNGLGETSTRINGIPROC)GLimp_ExtensionPointer( "glGetStringi" );
    793 
    794 		// Build the extensions string
    795 		GLint numExtensions;
    796 		qglGetIntegerv( GL_NUM_EXTENSIONS, &numExtensions );
    797 		extensions_string.Clear();
    798 		for ( int i = 0; i < numExtensions; i++ ) {
    799 			extensions_string.Append( (const char*)qglGetStringi( GL_EXTENSIONS, i ) );
    800 			// the now deprecated glGetString method usaed to create a single string with each extension separated by a space
    801 			if ( i < numExtensions - 1 ) {
    802 				extensions_string.Append( ' ' );
    803 			}
    804 		}
    805 		glConfig.extensions_string = extensions_string.c_str();
    806 	}
    807 
    808 
    809 	float glVersion = atof( glConfig.version_string );
    810 	float glslVersion = atof( glConfig.shading_language_string );
    811 	idLib::Printf( "OpenGL Version: %3.1f\n", glVersion );
    812 	idLib::Printf( "OpenGL Vendor : %s\n", glConfig.vendor_string );
    813 	idLib::Printf( "OpenGL GLSL   : %3.1f\n", glslVersion );
    814 	
    815 	// OpenGL driver constants
    816 	GLint temp;
    817 	qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp );
    818 	glConfig.maxTextureSize = temp;
    819 
    820 	// stubbed or broken drivers may have reported 0...
    821 	if ( glConfig.maxTextureSize <= 0 ) {
    822 		glConfig.maxTextureSize = 256;
    823 	}
    824 
    825 	r_initialized = true;
    826 
    827 	// recheck all the extensions (FIXME: this might be dangerous)
    828 	R_CheckPortableExtensions();
    829 
    830 	renderProgManager.Init();
    831 
    832 	r_initialized = true;
    833 
    834 	// allocate the vertex array range or vertex objects
    835 	vertexCache.Init();
    836 
    837 	// allocate the frame data, which may be more if smp is enabled
    838 	R_InitFrameData();
    839 
    840 	// Reset our gamma
    841 	R_SetColorMappings();
    842 
    843 	static bool glCheck = false;
    844 	if ( !glCheck && win32.osversion.dwMajorVersion == 6 ) {
    845 		glCheck = true;
    846 		if ( !idStr::Icmp( glConfig.vendor_string, "Microsoft" ) && idStr::FindText( glConfig.renderer_string, "OpenGL-D3D" ) != -1 ) {
    847 			if ( cvarSystem->GetCVarBool( "r_fullscreen" ) ) {
    848 				cmdSystem->BufferCommandText( CMD_EXEC_NOW, "vid_restart partial windowed\n" );
    849 				Sys_GrabMouseCursor( false );
    850 			}
    851 			int ret = MessageBox( NULL, "Please install OpenGL drivers from your graphics hardware vendor to run " GAME_NAME ".\nYour OpenGL functionality is limited.",
    852 				"Insufficient OpenGL capabilities", MB_OKCANCEL | MB_ICONWARNING | MB_TASKMODAL );
    853 			if ( ret == IDCANCEL ) {
    854 				cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "quit\n" );
    855 				cmdSystem->ExecuteCommandBuffer();
    856 			}
    857 			if ( cvarSystem->GetCVarBool( "r_fullscreen" ) ) {
    858 				cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "vid_restart\n" );
    859 			}
    860 		}
    861 	}
    862 }
    863 
    864 /*
    865 ==================
    866 GL_CheckErrors
    867 ==================
    868 */
    869 void GL_CheckErrors() {
    870     int		err;
    871     char	s[64];
    872 	int		i;
    873 
    874 	// check for up to 10 errors pending
    875 	for ( i = 0 ; i < 10 ; i++ ) {
    876 		err = qglGetError();
    877 		if ( err == GL_NO_ERROR ) {
    878 			return;
    879 		}
    880 		switch( err ) {
    881 			case GL_INVALID_ENUM:
    882 				strcpy( s, "GL_INVALID_ENUM" );
    883 				break;
    884 			case GL_INVALID_VALUE:
    885 				strcpy( s, "GL_INVALID_VALUE" );
    886 				break;
    887 			case GL_INVALID_OPERATION:
    888 				strcpy( s, "GL_INVALID_OPERATION" );
    889 				break;
    890 			case GL_STACK_OVERFLOW:
    891 				strcpy( s, "GL_STACK_OVERFLOW" );
    892 				break;
    893 			case GL_STACK_UNDERFLOW:
    894 				strcpy( s, "GL_STACK_UNDERFLOW" );
    895 				break;
    896 			case GL_OUT_OF_MEMORY:
    897 				strcpy( s, "GL_OUT_OF_MEMORY" );
    898 				break;
    899 			default:
    900 				idStr::snPrintf( s, sizeof(s), "%i", err);
    901 				break;
    902 		}
    903 
    904 		if ( !r_ignoreGLErrors.GetBool() ) {
    905 			common->Printf( "GL_CheckErrors: %s\n", s );
    906 		}
    907 	}
    908 }
    909 
    910 /*
    911 =====================
    912 R_ReloadSurface_f
    913 
    914 Reload the material displayed by r_showSurfaceInfo
    915 =====================
    916 */
    917 static void R_ReloadSurface_f( const idCmdArgs &args ) {
    918 	modelTrace_t mt;
    919 	idVec3 start, end;
    920 	
    921 	// start far enough away that we don't hit the player model
    922 	start = tr.primaryView->renderView.vieworg + tr.primaryView->renderView.viewaxis[0] * 16;
    923 	end = start + tr.primaryView->renderView.viewaxis[0] * 1000.0f;
    924 	if ( !tr.primaryWorld->Trace( mt, start, end, 0.0f, false ) ) {
    925 		return;
    926 	}
    927 
    928 	common->Printf( "Reloading %s\n", mt.material->GetName() );
    929 
    930 	// reload the decl
    931 	mt.material->base->Reload();
    932 
    933 	// reload any images used by the decl
    934 	mt.material->ReloadImages( false );
    935 }
    936 
    937 /*
    938 ==============
    939 R_ListModes_f
    940 ==============
    941 */
    942 static void R_ListModes_f( const idCmdArgs &args ) {
    943 	for ( int displayNum = 0 ; ; displayNum++ ) {
    944 		idList<vidMode_t> modeList;
    945 		if ( !R_GetModeListForDisplay( displayNum, modeList ) ) {
    946 			break;
    947 		}
    948 		for ( int i = 0; i < modeList.Num() ; i++ ) {
    949 			common->Printf( "Monitor %i, mode %3i: %4i x %4i @ %ihz\n", displayNum+1, i, modeList[i].width, modeList[i].height, modeList[i].displayHz );
    950 		}
    951 	}
    952 }
    953 
    954 /*
    955 =============
    956 R_TestImage_f
    957 
    958 Display the given image centered on the screen.
    959 testimage <number>
    960 testimage <filename>
    961 =============
    962 */
    963 void R_TestImage_f( const idCmdArgs &args ) {
    964 	int imageNum;
    965 
    966 	if ( tr.testVideo ) {
    967 		delete tr.testVideo;
    968 		tr.testVideo = NULL;
    969 	}
    970 	tr.testImage = NULL;
    971 
    972 	if ( args.Argc() != 2 ) {
    973 		return;
    974 	}
    975 
    976 	if ( idStr::IsNumeric( args.Argv(1) ) ) {
    977 		imageNum = atoi( args.Argv(1) );
    978 		if ( imageNum >= 0 && imageNum < globalImages->images.Num() ) {
    979 			tr.testImage = globalImages->images[imageNum];
    980 		}
    981 	} else {
    982 		tr.testImage = globalImages->ImageFromFile( args.Argv( 1 ), TF_DEFAULT, TR_REPEAT, TD_DEFAULT );
    983 	}
    984 }
    985 
    986 /*
    987 =============
    988 R_TestVideo_f
    989 
    990 Plays the cinematic file in a testImage
    991 =============
    992 */
    993 void R_TestVideo_f( const idCmdArgs &args ) {
    994 	if ( tr.testVideo ) {
    995 		delete tr.testVideo;
    996 		tr.testVideo = NULL;
    997 	}
    998 	tr.testImage = NULL;
    999 
   1000 	if ( args.Argc() < 2 ) {
   1001 		return;
   1002 	}
   1003 
   1004 	tr.testImage = globalImages->ImageFromFile( "_scratch", TF_DEFAULT, TR_REPEAT, TD_DEFAULT );
   1005 	tr.testVideo = idCinematic::Alloc();
   1006 	tr.testVideo->InitFromFile( args.Argv( 1 ), true );
   1007 
   1008 	cinData_t	cin;
   1009 	cin = tr.testVideo->ImageForTime( 0 );
   1010 	if ( cin.imageY == NULL ) {
   1011 		delete tr.testVideo;
   1012 		tr.testVideo = NULL;
   1013 		tr.testImage = NULL;
   1014 		return;
   1015 	}
   1016 
   1017 	common->Printf( "%i x %i images\n", cin.imageWidth, cin.imageHeight );
   1018 
   1019 	int	len = tr.testVideo->AnimationLength();
   1020 	common->Printf( "%5.1f seconds of video\n", len * 0.001 );
   1021 
   1022 	tr.testVideoStartTime = tr.primaryRenderView.time[1];
   1023 
   1024 	// try to play the matching wav file
   1025 	idStr	wavString = args.Argv( ( args.Argc() == 2 ) ? 1 : 2 );
   1026 	wavString.StripFileExtension();
   1027 	wavString = wavString + ".wav";
   1028 	common->SW()->PlayShaderDirectly( wavString.c_str() );
   1029 }
   1030 
   1031 static int R_QsortSurfaceAreas( const void *a, const void *b ) {
   1032 	const idMaterial	*ea, *eb;
   1033 	int	ac, bc;
   1034 
   1035 	ea = *(idMaterial **)a;
   1036 	if ( !ea->EverReferenced() ) {
   1037 		ac = 0;
   1038 	} else {
   1039 		ac = ea->GetSurfaceArea();
   1040 	}
   1041 	eb = *(idMaterial **)b;
   1042 	if ( !eb->EverReferenced() ) {
   1043 		bc = 0;
   1044 	} else {
   1045 		bc = eb->GetSurfaceArea();
   1046 	}
   1047 
   1048 	if ( ac < bc ) {
   1049 		return -1;
   1050 	}
   1051 	if ( ac > bc ) {
   1052 		return 1;
   1053 	}
   1054 
   1055 	return idStr::Icmp( ea->GetName(), eb->GetName() );
   1056 }
   1057 
   1058 
   1059 /*
   1060 ===================
   1061 R_ReportSurfaceAreas_f
   1062 
   1063 Prints a list of the materials sorted by surface area
   1064 ===================
   1065 */
   1066 #pragma warning( disable: 6385 ) // This is simply to get pass a false defect for /analyze -- if you can figure out a better way, please let Shawn know...
   1067 void R_ReportSurfaceAreas_f( const idCmdArgs &args ) {
   1068 	unsigned int		i;
   1069 	idMaterial	**list;
   1070 
   1071 	const unsigned int count = declManager->GetNumDecls( DECL_MATERIAL );
   1072 	if ( count == 0 ) {
   1073 		return;
   1074 	}
   1075 
   1076 	list = (idMaterial **)_alloca( count * sizeof( *list ) );
   1077 
   1078 	for ( i = 0 ; i < count ; i++ ) {
   1079 		list[i] = (idMaterial *)declManager->DeclByIndex( DECL_MATERIAL, i, false );
   1080 	}
   1081 
   1082 	qsort( list, count, sizeof( list[0] ), R_QsortSurfaceAreas );
   1083 
   1084 	// skip over ones with 0 area
   1085 	for ( i = 0 ; i < count ; i++ ) {
   1086 		if ( list[i]->GetSurfaceArea() > 0 ) {
   1087 			break;
   1088 		}
   1089 	}
   1090 
   1091 	for ( ; i < count ; i++ ) {
   1092 		// report size in "editor blocks"
   1093 		int	blocks = list[i]->GetSurfaceArea() / 4096.0;
   1094 		common->Printf( "%7i %s\n", blocks, list[i]->GetName() );
   1095 	}
   1096 }
   1097 #pragma warning( default: 6385 )
   1098 
   1099 
   1100 /* 
   1101 ============================================================================== 
   1102  
   1103 						SCREEN SHOTS 
   1104  
   1105 ============================================================================== 
   1106 */ 
   1107 
   1108 /*
   1109 ====================
   1110 R_ReadTiledPixels
   1111 
   1112 NO LONGER SUPPORTED (FIXME: make standard case work)
   1113 
   1114 Used to allow the rendering of an image larger than the actual window by
   1115 tiling it into window-sized chunks and rendering each chunk separately
   1116 
   1117 If ref isn't specified, the full session UpdateScreen will be done.
   1118 ====================
   1119 */
   1120 void R_ReadTiledPixels( int width, int height, byte *buffer, renderView_t *ref = NULL ) {
   1121 	// include extra space for OpenGL padding to word boundaries
   1122 	int sysWidth = renderSystem->GetWidth();
   1123 	int sysHeight = renderSystem->GetHeight();
   1124 	byte * temp = (byte *)R_StaticAlloc( (sysWidth+3) * sysHeight * 3 );
   1125 
   1126 	// disable scissor, so we don't need to adjust all those rects
   1127 	r_useScissor.SetBool( false );
   1128 
   1129 	for ( int xo = 0 ; xo < width ; xo += sysWidth ) {
   1130 		for ( int yo = 0 ; yo < height ; yo += sysHeight ) {
   1131 			if ( ref ) {
   1132 				// discard anything currently on the list
   1133 				tr.SwapCommandBuffers( NULL, NULL, NULL, NULL );
   1134 
   1135 				// build commands to render the scene
   1136 				tr.primaryWorld->RenderScene( ref );
   1137 
   1138 				// finish off these commands
   1139 				const emptyCommand_t * cmd = tr.SwapCommandBuffers( NULL, NULL, NULL, NULL );
   1140 
   1141 				// issue the commands to the GPU
   1142 				tr.RenderCommandBuffers( cmd );
   1143 			} else {
   1144 				const bool captureToImage = false;
   1145 				common->UpdateScreen( captureToImage );
   1146 			}
   1147 
   1148 			int w = sysWidth;
   1149 			if ( xo + w > width ) {
   1150 				w = width - xo;
   1151 			}
   1152 			int h = sysHeight;
   1153 			if ( yo + h > height ) {
   1154 				h = height - yo;
   1155 			}
   1156 
   1157 			qglReadBuffer( GL_FRONT );
   1158 			qglReadPixels( 0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, temp ); 
   1159 
   1160 			int	row = ( w * 3 + 3 ) & ~3;		// OpenGL pads to dword boundaries
   1161 
   1162 			for ( int y = 0 ; y < h ; y++ ) {
   1163 				memcpy( buffer + ( ( yo + y )* width + xo ) * 3,
   1164 					temp + y * row, w * 3 );
   1165 			}
   1166 		}
   1167 	}
   1168 
   1169 	r_useScissor.SetBool( true );
   1170 
   1171 	R_StaticFree( temp );
   1172 }
   1173 
   1174 
   1175 /*
   1176 ================== 
   1177 TakeScreenshot
   1178 
   1179 Move to tr_imagefiles.c...
   1180 
   1181 Downsample is the number of steps to mipmap the image before saving it
   1182 If ref == NULL, common->UpdateScreen will be used
   1183 ================== 
   1184 */  
   1185 void idRenderSystemLocal::TakeScreenshot( int width, int height, const char *fileName, int blends, renderView_t *ref ) {
   1186 	byte		*buffer;
   1187 	int			i, j, c, temp;
   1188 
   1189 	takingScreenshot = true;
   1190 
   1191 	const int pix = width * height;
   1192 	const int bufferSize = pix * 3 + 18;
   1193 
   1194 	buffer = (byte *)R_StaticAlloc( bufferSize );
   1195 	memset( buffer, 0, bufferSize );
   1196 
   1197 	if ( blends <= 1 ) {
   1198 		R_ReadTiledPixels( width, height, buffer + 18, ref );
   1199 	} else {
   1200 		unsigned short *shortBuffer = (unsigned short *)R_StaticAlloc(pix*2*3);
   1201 		memset (shortBuffer, 0, pix*2*3);
   1202 
   1203 		// enable anti-aliasing jitter
   1204 		r_jitter.SetBool( true );
   1205 
   1206 		for ( i = 0 ; i < blends ; i++ ) {
   1207 			R_ReadTiledPixels( width, height, buffer + 18, ref );
   1208 
   1209 			for ( j = 0 ; j < pix*3 ; j++ ) {
   1210 				shortBuffer[j] += buffer[18+j];
   1211 			}
   1212 		}
   1213 
   1214 		// divide back to bytes
   1215 		for ( i = 0 ; i < pix*3 ; i++ ) {
   1216 			buffer[18+i] = shortBuffer[i] / blends;
   1217 		}
   1218 
   1219 		R_StaticFree( shortBuffer );
   1220 		r_jitter.SetBool( false );
   1221 	}
   1222 
   1223 	// fill in the header (this is vertically flipped, which qglReadPixels emits)
   1224 	buffer[2] = 2;		// uncompressed type
   1225 	buffer[12] = width & 255;
   1226 	buffer[13] = width >> 8;
   1227 	buffer[14] = height & 255;
   1228 	buffer[15] = height >> 8;
   1229 	buffer[16] = 24;	// pixel size
   1230 
   1231 	// swap rgb to bgr
   1232 	c = 18 + width * height * 3;
   1233 	for (i=18 ; i<c ; i+=3) {
   1234 		temp = buffer[i];
   1235 		buffer[i] = buffer[i+2];
   1236 		buffer[i+2] = temp;
   1237 	}
   1238 
   1239 	fileSystem->WriteFile( fileName, buffer, c );
   1240 
   1241 	R_StaticFree( buffer );
   1242 
   1243 	takingScreenshot = false;
   1244 }
   1245 
   1246 /* 
   1247 ================== 
   1248 R_ScreenshotFilename
   1249 
   1250 Returns a filename with digits appended
   1251 if we have saved a previous screenshot, don't scan
   1252 from the beginning, because recording demo avis can involve
   1253 thousands of shots
   1254 ================== 
   1255 */  
   1256 void R_ScreenshotFilename( int &lastNumber, const char *base, idStr &fileName ) {
   1257 	int	a,b,c,d, e;
   1258 
   1259 	bool restrict = cvarSystem->GetCVarBool( "fs_restrict" );
   1260 	cvarSystem->SetCVarBool( "fs_restrict", false );
   1261 
   1262 	lastNumber++;
   1263 	if ( lastNumber > 99999 ) {
   1264 		lastNumber = 99999;
   1265 	}
   1266 	for ( ; lastNumber < 99999 ; lastNumber++ ) {
   1267 		int	frac = lastNumber;
   1268 
   1269 		a = frac / 10000;
   1270 		frac -= a*10000;
   1271 		b = frac / 1000;
   1272 		frac -= b*1000;
   1273 		c = frac / 100;
   1274 		frac -= c*100;
   1275 		d = frac / 10;
   1276 		frac -= d*10;
   1277 		e = frac;
   1278 
   1279 		sprintf( fileName, "%s%i%i%i%i%i.tga", base, a, b, c, d, e );
   1280 		if ( lastNumber == 99999 ) {
   1281 			break;
   1282 		}
   1283 		int len = fileSystem->ReadFile( fileName, NULL, NULL );
   1284 		if ( len <= 0 ) {
   1285 			break;
   1286 		}
   1287 		// check again...
   1288 	}
   1289 	cvarSystem->SetCVarBool( "fs_restrict", restrict );
   1290 }
   1291 
   1292 /*
   1293 ================== 
   1294 R_BlendedScreenShot
   1295 
   1296 screenshot
   1297 screenshot [filename]
   1298 screenshot [width] [height]
   1299 screenshot [width] [height] [samples]
   1300 ================== 
   1301 */ 
   1302 #define	MAX_BLENDS	256	// to keep the accumulation in shorts
   1303 void R_ScreenShot_f( const idCmdArgs &args ) {
   1304 	static int lastNumber = 0;
   1305 	idStr checkname;
   1306 
   1307 	int width = renderSystem->GetWidth();
   1308 	int height = renderSystem->GetHeight();
   1309 	int	blends = 0;
   1310 
   1311 	switch ( args.Argc() ) {
   1312 	case 1:
   1313 		width = renderSystem->GetWidth();
   1314 		height = renderSystem->GetHeight();
   1315 		blends = 1;
   1316 		R_ScreenshotFilename( lastNumber, "screenshots/shot", checkname );
   1317 		break;
   1318 	case 2:
   1319 		width = renderSystem->GetWidth();
   1320 		height = renderSystem->GetHeight();
   1321 		blends = 1;
   1322 		checkname = args.Argv( 1 );
   1323 		break;
   1324 	case 3:
   1325 		width = atoi( args.Argv( 1 ) );
   1326 		height = atoi( args.Argv( 2 ) );
   1327 		blends = 1;
   1328 		R_ScreenshotFilename( lastNumber, "screenshots/shot", checkname );
   1329 		break;
   1330 	case 4:
   1331 		width = atoi( args.Argv( 1 ) );
   1332 		height = atoi( args.Argv( 2 ) );
   1333 		blends = atoi( args.Argv( 3 ) );
   1334 		if ( blends < 1 ) {
   1335 			blends = 1;
   1336 		}
   1337 		if ( blends > MAX_BLENDS ) {
   1338 			blends = MAX_BLENDS;
   1339 		}
   1340 		R_ScreenshotFilename( lastNumber, "screenshots/shot", checkname );
   1341 		break;
   1342 	default:
   1343 		common->Printf( "usage: screenshot\n       screenshot <filename>\n       screenshot <width> <height>\n       screenshot <width> <height> <blends>\n" );
   1344 		return;
   1345 	}
   1346 
   1347 	// put the console away
   1348 	console->Close();
   1349 
   1350 	tr.TakeScreenshot( width, height, checkname, blends, NULL );
   1351 
   1352 	common->Printf( "Wrote %s\n", checkname.c_str() );
   1353 }
   1354 
   1355 /*
   1356 ===============
   1357 R_StencilShot
   1358 Save out a screenshot showing the stencil buffer expanded by 16x range
   1359 ===============
   1360 */
   1361 void R_StencilShot() {
   1362 	int			i, c;
   1363 
   1364 	int	width = tr.GetWidth();
   1365 	int	height = tr.GetHeight();
   1366 
   1367 	int	pix = width * height;
   1368 
   1369 	c = pix * 3 + 18;
   1370 	idTempArray< byte > buffer( c );
   1371 	memset( buffer.Ptr(), 0, 18 );
   1372 
   1373 	idTempArray< byte > byteBuffer( pix );
   1374 
   1375 	qglReadPixels( 0, 0, width, height, GL_STENCIL_INDEX , GL_UNSIGNED_BYTE, byteBuffer.Ptr() ); 
   1376 
   1377 	for ( i = 0 ; i < pix ; i++ ) {
   1378 		buffer[18+i*3] =
   1379 		buffer[18+i*3+1] =
   1380 			//		buffer[18+i*3+2] = ( byteBuffer[i] & 15 ) * 16;
   1381 		buffer[18+i*3+2] = byteBuffer[i];
   1382 	}
   1383 
   1384 	// fill in the header (this is vertically flipped, which qglReadPixels emits)
   1385 	buffer[2] = 2;		// uncompressed type
   1386 	buffer[12] = width & 255;
   1387 	buffer[13] = width >> 8;
   1388 	buffer[14] = height & 255;
   1389 	buffer[15] = height >> 8;
   1390 	buffer[16] = 24;	// pixel size
   1391 
   1392 	fileSystem->WriteFile( "screenshots/stencilShot.tga", buffer.Ptr(), c, "fs_savepath" );
   1393 }
   1394 
   1395 
   1396 //============================================================================
   1397 
   1398 static idMat3		cubeAxis[6];
   1399 
   1400 
   1401 /*
   1402 ==================
   1403 R_SampleCubeMap
   1404 ==================
   1405 */
   1406 void R_SampleCubeMap( const idVec3 &dir, int size, byte *buffers[6], byte result[4] ) {
   1407 	float	adir[3];
   1408 	int		axis, x, y;
   1409 
   1410 	adir[0] = fabs(dir[0]);
   1411 	adir[1] = fabs(dir[1]);
   1412 	adir[2] = fabs(dir[2]);
   1413 
   1414 	if ( dir[0] >= adir[1] && dir[0] >= adir[2] ) {
   1415 		axis = 0;
   1416 	} else if ( -dir[0] >= adir[1] && -dir[0] >= adir[2] ) {
   1417 		axis = 1;
   1418 	} else if ( dir[1] >= adir[0] && dir[1] >= adir[2] ) {
   1419 		axis = 2;
   1420 	} else if ( -dir[1] >= adir[0] && -dir[1] >= adir[2] ) {
   1421 		axis = 3;
   1422 	} else if ( dir[2] >= adir[1] && dir[2] >= adir[2] ) {
   1423 		axis = 4;
   1424 	} else {
   1425 		axis = 5;
   1426 	}
   1427 
   1428 	float	fx = (dir * cubeAxis[axis][1]) / (dir * cubeAxis[axis][0]);
   1429 	float	fy = (dir * cubeAxis[axis][2]) / (dir * cubeAxis[axis][0]);
   1430 
   1431 	fx = -fx;
   1432 	fy = -fy;
   1433 	x = size * 0.5 * (fx + 1);
   1434 	y = size * 0.5 * (fy + 1);
   1435 	if ( x < 0 ) {
   1436 		x = 0;
   1437 	} else if ( x >= size ) {
   1438 		x = size-1;
   1439 	}
   1440 	if ( y < 0 ) {
   1441 		y = 0;
   1442 	} else if ( y >= size ) {
   1443 		y = size-1;
   1444 	}
   1445 
   1446 	result[0] = buffers[axis][(y*size+x)*4+0];
   1447 	result[1] = buffers[axis][(y*size+x)*4+1];
   1448 	result[2] = buffers[axis][(y*size+x)*4+2];
   1449 	result[3] = buffers[axis][(y*size+x)*4+3];
   1450 }
   1451 
   1452 /* 
   1453 ================== 
   1454 R_MakeAmbientMap_f
   1455 
   1456 R_MakeAmbientMap_f <basename> [size]
   1457 
   1458 Saves out env/<basename>_amb_ft.tga, etc
   1459 ================== 
   1460 */  
   1461 void R_MakeAmbientMap_f( const idCmdArgs &args ) {
   1462 	idStr fullname;
   1463 	const char	*baseName;
   1464 	int			i;
   1465 	renderView_t	ref;
   1466 	viewDef_t	primary;
   1467 	int			downSample;
   1468 	char	*extensions[6] =  { "_px.tga", "_nx.tga", "_py.tga", "_ny.tga", 
   1469 		"_pz.tga", "_nz.tga" };
   1470 	int			outSize;
   1471 	byte		*buffers[6];
   1472 	int			width = 0, height = 0;
   1473 
   1474 	if ( args.Argc() != 2 && args.Argc() != 3 ) {
   1475 		common->Printf( "USAGE: ambientshot <basename> [size]\n" );
   1476 		return;
   1477 	}
   1478 	baseName = args.Argv( 1 );
   1479 
   1480 	downSample = 0;
   1481 	if ( args.Argc() == 3 ) {
   1482 		outSize = atoi( args.Argv( 2 ) );
   1483 	} else {
   1484 		outSize = 32;
   1485 	}
   1486 
   1487 	memset( &cubeAxis, 0, sizeof( cubeAxis ) );
   1488 	cubeAxis[0][0][0] = 1;
   1489 	cubeAxis[0][1][2] = 1;
   1490 	cubeAxis[0][2][1] = 1;
   1491 
   1492 	cubeAxis[1][0][0] = -1;
   1493 	cubeAxis[1][1][2] = -1;
   1494 	cubeAxis[1][2][1] = 1;
   1495 
   1496 	cubeAxis[2][0][1] = 1;
   1497 	cubeAxis[2][1][0] = -1;
   1498 	cubeAxis[2][2][2] = -1;
   1499 
   1500 	cubeAxis[3][0][1] = -1;
   1501 	cubeAxis[3][1][0] = -1;
   1502 	cubeAxis[3][2][2] = 1;
   1503 
   1504 	cubeAxis[4][0][2] = 1;
   1505 	cubeAxis[4][1][0] = -1;
   1506 	cubeAxis[4][2][1] = 1;
   1507 
   1508 	cubeAxis[5][0][2] = -1;
   1509 	cubeAxis[5][1][0] = 1;
   1510 	cubeAxis[5][2][1] = 1;
   1511 
   1512 	// read all of the images
   1513 	for ( i = 0 ; i < 6 ; i++ ) {
   1514 		sprintf( fullname, "env/%s%s", baseName, extensions[i] );
   1515 		common->Printf( "loading %s\n", fullname.c_str() );
   1516 		const bool captureToImage = false;
   1517 		common->UpdateScreen( captureToImage );
   1518 		R_LoadImage( fullname, &buffers[i], &width, &height, NULL, true );
   1519 		if ( !buffers[i] ) {
   1520 			common->Printf( "failed.\n" );
   1521 			for ( i-- ; i >= 0 ; i-- ) {
   1522 				Mem_Free( buffers[i] );
   1523 			}
   1524 			return;
   1525 		}
   1526 	}
   1527 
   1528 	// resample with hemispherical blending
   1529 	int	samples = 1000;
   1530 
   1531 	byte	*outBuffer = (byte *)_alloca( outSize * outSize * 4 );
   1532 
   1533 	for ( int map = 0 ; map < 2 ; map++ ) {
   1534 		for ( i = 0 ; i < 6 ; i++ ) {
   1535 			for ( int x = 0 ; x < outSize ; x++ ) {
   1536 				for ( int y = 0 ; y < outSize ; y++ ) {
   1537 					idVec3	dir;
   1538 					float	total[3];
   1539 
   1540 					dir = cubeAxis[i][0] + -( -1 + 2.0*x/(outSize-1) ) * cubeAxis[i][1] + -( -1 + 2.0*y/(outSize-1) ) * cubeAxis[i][2];
   1541 					dir.Normalize();
   1542 					total[0] = total[1] = total[2] = 0;
   1543 	//samples = 1;
   1544 					float	limit = map ? 0.95 : 0.25;		// small for specular, almost hemisphere for ambient
   1545 
   1546 					for ( int s = 0 ; s < samples ; s++ ) {
   1547 						// pick a random direction vector that is inside the unit sphere but not behind dir,
   1548 						// which is a robust way to evenly sample a hemisphere
   1549 						idVec3	test;
   1550 						while( 1 ) {
   1551 							for ( int j = 0 ; j < 3 ; j++ ) {
   1552 								test[j] = -1 + 2 * (rand()&0x7fff)/(float)0x7fff;
   1553 							}
   1554 							if ( test.Length() > 1.0 ) {
   1555 								continue;
   1556 							}
   1557 							test.Normalize();
   1558 							if ( test * dir > limit ) {	// don't do a complete hemisphere
   1559 								break;
   1560 							}
   1561 						}
   1562 						byte	result[4];
   1563 	//test = dir;
   1564 						R_SampleCubeMap( test, width, buffers, result );
   1565 						total[0] += result[0];
   1566 						total[1] += result[1];
   1567 						total[2] += result[2];
   1568 					}
   1569 					outBuffer[(y*outSize+x)*4+0] = total[0] / samples;
   1570 					outBuffer[(y*outSize+x)*4+1] = total[1] / samples;
   1571 					outBuffer[(y*outSize+x)*4+2] = total[2] / samples;
   1572 					outBuffer[(y*outSize+x)*4+3] = 255;
   1573 				}
   1574 			}
   1575 
   1576 			if ( map == 0 ) {
   1577 				sprintf( fullname, "env/%s_amb%s", baseName, extensions[i] );
   1578 			} else {
   1579 				sprintf( fullname, "env/%s_spec%s", baseName, extensions[i] );
   1580 			}
   1581 			common->Printf( "writing %s\n", fullname.c_str() );
   1582 			const bool captureToImage = false;
   1583 			common->UpdateScreen( captureToImage );
   1584 			R_WriteTGA( fullname, outBuffer, outSize, outSize );
   1585 		}
   1586 	}
   1587 
   1588 	for ( i = 0 ; i < 6 ; i++ ) {
   1589 		if ( buffers[i] ) {
   1590 			Mem_Free( buffers[i] );
   1591 		}
   1592 	}
   1593 } 
   1594 
   1595 //============================================================================
   1596 
   1597 
   1598 /*
   1599 ===============
   1600 R_SetColorMappings
   1601 ===============
   1602 */
   1603 void R_SetColorMappings() {
   1604 	float b = r_brightness.GetFloat();
   1605 	float invg = 1.0f / r_gamma.GetFloat();
   1606 
   1607 	float j = 0.0f;
   1608 	for ( int i = 0; i < 256; i++, j += b ) {
   1609 		int inf = idMath::Ftoi( 0xffff * pow( j / 255.0f, invg ) + 0.5f );
   1610 		tr.gammaTable[i] = idMath::ClampInt( 0, 0xFFFF, inf );
   1611 	}
   1612 
   1613 	GLimp_SetGamma( tr.gammaTable, tr.gammaTable, tr.gammaTable );
   1614 }
   1615 
   1616 /*
   1617 ================
   1618 GfxInfo_f
   1619 ================
   1620 */
   1621 void GfxInfo_f( const idCmdArgs &args ) {
   1622 	common->Printf( "CPU: %s\n", Sys_GetProcessorString() );
   1623 
   1624 	const char *fsstrings[] =
   1625 	{
   1626 		"windowed",
   1627 		"fullscreen"
   1628 	};
   1629 
   1630 	common->Printf( "\nGL_VENDOR: %s\n", glConfig.vendor_string );
   1631 	common->Printf( "GL_RENDERER: %s\n", glConfig.renderer_string );
   1632 	common->Printf( "GL_VERSION: %s\n", glConfig.version_string );
   1633 	common->Printf( "GL_EXTENSIONS: %s\n", glConfig.extensions_string );
   1634 	if ( glConfig.wgl_extensions_string ) {
   1635 		common->Printf( "WGL_EXTENSIONS: %s\n", glConfig.wgl_extensions_string );
   1636 	}
   1637 	common->Printf( "GL_MAX_TEXTURE_SIZE: %d\n", glConfig.maxTextureSize );
   1638 	common->Printf( "GL_MAX_TEXTURE_COORDS_ARB: %d\n", glConfig.maxTextureCoords );
   1639 	common->Printf( "GL_MAX_TEXTURE_IMAGE_UNITS_ARB: %d\n", glConfig.maxTextureImageUnits );
   1640 
   1641 	// print all the display adapters, monitors, and video modes
   1642 	void DumpAllDisplayDevices();
   1643 	DumpAllDisplayDevices();
   1644 
   1645 	common->Printf( "\nPIXELFORMAT: color(%d-bits) Z(%d-bit) stencil(%d-bits)\n", glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits );
   1646 	common->Printf( "MODE: %d, %d x %d %s hz:", r_vidMode.GetInteger(), renderSystem->GetWidth(), renderSystem->GetHeight(), fsstrings[r_fullscreen.GetBool()] );
   1647 	if ( glConfig.displayFrequency ) {
   1648 		common->Printf( "%d\n", glConfig.displayFrequency );
   1649 	} else {
   1650 		common->Printf( "N/A\n" );
   1651 	}
   1652 
   1653 	common->Printf( "-------\n" );
   1654 
   1655 	// WGL_EXT_swap_interval
   1656 	typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);
   1657 	extern	PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
   1658 
   1659 	if ( r_swapInterval.GetInteger() && wglSwapIntervalEXT != NULL ) {
   1660 		common->Printf( "Forcing swapInterval %i\n", r_swapInterval.GetInteger() );
   1661 	} else {
   1662 		common->Printf( "swapInterval not forced\n" );
   1663 	}
   1664 
   1665 	if ( glConfig.stereoPixelFormatAvailable && glConfig.isStereoPixelFormat ) {
   1666 		idLib::Printf( "OpenGl quad buffer stereo pixel format active\n" );
   1667 	} else if ( glConfig.stereoPixelFormatAvailable ) {
   1668 		idLib::Printf( "OpenGl quad buffer stereo pixel available but not selected\n" );
   1669 	} else {
   1670 		idLib::Printf( "OpenGl quad buffer stereo pixel format not available\n" );
   1671 	}
   1672 
   1673 	idLib::Printf( "Stereo mode: " );
   1674 	switch ( renderSystem->GetStereo3DMode() ) {
   1675 		case STEREO3D_OFF:						idLib::Printf( "STEREO3D_OFF\n" ); break;
   1676 		case STEREO3D_SIDE_BY_SIDE_COMPRESSED:	idLib::Printf( "STEREO3D_SIDE_BY_SIDE_COMPRESSED\n" ); break;
   1677 		case STEREO3D_TOP_AND_BOTTOM_COMPRESSED:idLib::Printf( "STEREO3D_TOP_AND_BOTTOM_COMPRESSED\n" ); break;
   1678 		case STEREO3D_SIDE_BY_SIDE:				idLib::Printf( "STEREO3D_SIDE_BY_SIDE\n" ); break;
   1679 		case STEREO3D_HDMI_720:					idLib::Printf( "STEREO3D_HDMI_720\n" ); break;
   1680 		case STEREO3D_INTERLACED:				idLib::Printf( "STEREO3D_INTERLACED\n" ); break;
   1681 		case STEREO3D_QUAD_BUFFER:				idLib::Printf( "STEREO3D_QUAD_BUFFER\n" ); break;
   1682 		default:idLib::Printf( "Unknown (%i)\n", renderSystem->GetStereo3DMode() ); break;
   1683 	}
   1684 
   1685 	idLib::Printf( "%i multisamples\n", glConfig.multisamples );
   1686 
   1687 	common->Printf( "%5.1f cm screen width (%4.1f\" diagonal)\n",
   1688 		glConfig.physicalScreenWidthInCentimeters, glConfig.physicalScreenWidthInCentimeters / 2.54f
   1689 			* sqrt( (float)(16*16 + 9*9) ) / 16.0f );
   1690 	extern idCVar r_forceScreenWidthCentimeters;
   1691 	if ( r_forceScreenWidthCentimeters.GetFloat() ) {
   1692 		common->Printf( "screen size manually forced to %5.1f cm width (%4.1f\" diagonal)\n",
   1693 			renderSystem->GetPhysicalScreenWidthInCentimeters(), renderSystem->GetPhysicalScreenWidthInCentimeters() / 2.54f
   1694 				* sqrt( (float)(16*16 + 9*9) ) / 16.0f );
   1695 	}
   1696 }
   1697 
   1698 /*
   1699 =================
   1700 R_VidRestart_f
   1701 =================
   1702 */
   1703 void R_VidRestart_f( const idCmdArgs &args ) {
   1704 	// if OpenGL isn't started, do nothing
   1705 	if ( !R_IsInitialized() ) {
   1706 		return;
   1707 	}
   1708 
   1709 	// set the mode without re-initializing the context
   1710 	R_SetNewMode( false );
   1711 
   1712 #if 0
   1713 	bool full = true;
   1714 	bool forceWindow = false;
   1715 	for ( int i = 1 ; i < args.Argc() ; i++ ) {
   1716 		if ( idStr::Icmp( args.Argv( i ), "partial" ) == 0 ) {
   1717 			full = false;
   1718 			continue;
   1719 		}
   1720 		if ( idStr::Icmp( args.Argv( i ), "windowed" ) == 0 ) {
   1721 			forceWindow = true;
   1722 			continue;
   1723 		}
   1724 	}
   1725 
   1726 	// this could take a while, so give them the cursor back ASAP
   1727 	Sys_GrabMouseCursor( false );
   1728 
   1729 	// dump ambient caches
   1730 	renderModelManager->FreeModelVertexCaches();
   1731 
   1732 	// free any current world interaction surfaces and vertex caches
   1733 	R_FreeDerivedData();
   1734 
   1735 	// make sure the defered frees are actually freed
   1736 	R_ToggleSmpFrame();
   1737 	R_ToggleSmpFrame();
   1738 
   1739 	// free the vertex caches so they will be regenerated again
   1740 	vertexCache.PurgeAll();
   1741 
   1742 	// sound and input are tied to the window we are about to destroy
   1743 
   1744 	if ( full ) {
   1745 		// free all of our texture numbers
   1746 		Sys_ShutdownInput();
   1747 		globalImages->PurgeAllImages();
   1748 		// free the context and close the window
   1749 		GLimp_Shutdown();
   1750 		r_initialized = false;
   1751 
   1752 		// create the new context and vertex cache
   1753 		bool latch = cvarSystem->GetCVarBool( "r_fullscreen" );
   1754 		if ( forceWindow ) {
   1755 			cvarSystem->SetCVarBool( "r_fullscreen", false );
   1756 		}
   1757 		R_InitOpenGL();
   1758 		cvarSystem->SetCVarBool( "r_fullscreen", latch );
   1759 
   1760 		// regenerate all images
   1761 		globalImages->ReloadImages( true );
   1762 	} else {
   1763 		glimpParms_t parms;
   1764 		parms.width = glConfig.nativeScreenWidth;
   1765 		parms.height = glConfig.nativeScreenHeight;
   1766 		parms.fullScreen = ( forceWindow ) ? false : r_fullscreen.GetInteger();
   1767 		parms.displayHz = r_displayRefresh.GetInteger();
   1768 		parms.multiSamples = r_multiSamples.GetInteger();
   1769 		parms.stereo = false;
   1770 		GLimp_SetScreenParms( parms );
   1771 	}
   1772 
   1773 
   1774 
   1775 	// make sure the regeneration doesn't use anything no longer valid
   1776 	tr.viewCount++;
   1777 	tr.viewDef = NULL;
   1778 
   1779 	// check for problems
   1780 	int err = qglGetError();
   1781 	if ( err != GL_NO_ERROR ) {
   1782 		common->Printf( "glGetError() = 0x%x\n", err );
   1783 	}
   1784 #endif
   1785 
   1786 }
   1787 
   1788 /*
   1789 =================
   1790 R_InitMaterials
   1791 =================
   1792 */
   1793 void R_InitMaterials() {
   1794 	tr.defaultMaterial = declManager->FindMaterial( "_default", false );
   1795 	if ( !tr.defaultMaterial ) {
   1796 		common->FatalError( "_default material not found" );
   1797 	}
   1798 	tr.defaultPointLight = declManager->FindMaterial( "lights/defaultPointLight" );
   1799 	tr.defaultProjectedLight = declManager->FindMaterial( "lights/defaultProjectedLight" );
   1800 	tr.whiteMaterial = declManager->FindMaterial( "_white" );
   1801 	tr.charSetMaterial = declManager->FindMaterial( "textures/bigchars" );
   1802 }
   1803 
   1804 
   1805 /*
   1806 =================
   1807 R_SizeUp_f
   1808 
   1809 Keybinding command
   1810 =================
   1811 */
   1812 static void R_SizeUp_f( const idCmdArgs &args ) {
   1813 	if ( r_screenFraction.GetInteger() + 10 > 100 ) {
   1814 		r_screenFraction.SetInteger( 100 );
   1815 	} else {
   1816 		r_screenFraction.SetInteger( r_screenFraction.GetInteger() + 10 );
   1817 	}
   1818 }
   1819 
   1820 
   1821 /*
   1822 =================
   1823 R_SizeDown_f
   1824 
   1825 Keybinding command
   1826 =================
   1827 */
   1828 static void R_SizeDown_f( const idCmdArgs &args ) {
   1829 	if ( r_screenFraction.GetInteger() - 10 < 10 ) {
   1830 		r_screenFraction.SetInteger( 10 );
   1831 	} else {
   1832 		r_screenFraction.SetInteger( r_screenFraction.GetInteger() - 10 );
   1833 	}
   1834 }
   1835 
   1836 
   1837 /*
   1838 ===============
   1839 TouchGui_f
   1840 
   1841   this is called from the main thread
   1842 ===============
   1843 */
   1844 void R_TouchGui_f( const idCmdArgs &args ) {
   1845 	const char	*gui = args.Argv( 1 );
   1846 
   1847 	if ( !gui[0] ) {
   1848 		common->Printf( "USAGE: touchGui <guiName>\n" );
   1849 		return;
   1850 	}
   1851 
   1852 	common->Printf( "touchGui %s\n", gui );
   1853 	const bool captureToImage = false;
   1854 	common->UpdateScreen( captureToImage );
   1855 	uiManager->Touch( gui );
   1856 }
   1857 
   1858 /*
   1859 =================
   1860 R_InitCvars
   1861 =================
   1862 */
   1863 void R_InitCvars() {
   1864 	// update latched cvars here
   1865 }
   1866 
   1867 /*
   1868 =================
   1869 R_InitCommands
   1870 =================
   1871 */
   1872 void R_InitCommands() {
   1873 	cmdSystem->AddCommand( "sizeUp", R_SizeUp_f, CMD_FL_RENDERER, "makes the rendered view larger" );
   1874 	cmdSystem->AddCommand( "sizeDown", R_SizeDown_f, CMD_FL_RENDERER, "makes the rendered view smaller" );
   1875 	cmdSystem->AddCommand( "reloadGuis", R_ReloadGuis_f, CMD_FL_RENDERER, "reloads guis" );
   1876 	cmdSystem->AddCommand( "listGuis", R_ListGuis_f, CMD_FL_RENDERER, "lists guis" );
   1877 	cmdSystem->AddCommand( "touchGui", R_TouchGui_f, CMD_FL_RENDERER, "touches a gui" );
   1878 	cmdSystem->AddCommand( "screenshot", R_ScreenShot_f, CMD_FL_RENDERER, "takes a screenshot" );
   1879 	cmdSystem->AddCommand( "makeAmbientMap", R_MakeAmbientMap_f, CMD_FL_RENDERER|CMD_FL_CHEAT, "makes an ambient map" );
   1880 	cmdSystem->AddCommand( "gfxInfo", GfxInfo_f, CMD_FL_RENDERER, "show graphics info" );
   1881 	cmdSystem->AddCommand( "modulateLights", R_ModulateLights_f, CMD_FL_RENDERER | CMD_FL_CHEAT, "modifies shader parms on all lights" );
   1882 	cmdSystem->AddCommand( "testImage", R_TestImage_f, CMD_FL_RENDERER | CMD_FL_CHEAT, "displays the given image centered on screen", idCmdSystem::ArgCompletion_ImageName );
   1883 	cmdSystem->AddCommand( "testVideo", R_TestVideo_f, CMD_FL_RENDERER | CMD_FL_CHEAT, "displays the given cinematic", idCmdSystem::ArgCompletion_VideoName );
   1884 	cmdSystem->AddCommand( "reportSurfaceAreas", R_ReportSurfaceAreas_f, CMD_FL_RENDERER, "lists all used materials sorted by surface area" );
   1885 	cmdSystem->AddCommand( "showInteractionMemory", R_ShowInteractionMemory_f, CMD_FL_RENDERER, "shows memory used by interactions" );
   1886 	cmdSystem->AddCommand( "vid_restart", R_VidRestart_f, CMD_FL_RENDERER, "restarts renderSystem" );
   1887 	cmdSystem->AddCommand( "listRenderEntityDefs", R_ListRenderEntityDefs_f, CMD_FL_RENDERER, "lists the entity defs" );
   1888 	cmdSystem->AddCommand( "listRenderLightDefs", R_ListRenderLightDefs_f, CMD_FL_RENDERER, "lists the light defs" );
   1889 	cmdSystem->AddCommand( "listModes", R_ListModes_f, CMD_FL_RENDERER, "lists all video modes" );
   1890 	cmdSystem->AddCommand( "reloadSurface", R_ReloadSurface_f, CMD_FL_RENDERER, "reloads the decl and images for selected surface" );
   1891 }
   1892 
   1893 /*
   1894 ===============
   1895 idRenderSystemLocal::Clear
   1896 ===============
   1897 */
   1898 void idRenderSystemLocal::Clear() {
   1899 	registered = false;
   1900 	frameCount = 0;
   1901 	viewCount = 0;
   1902 	frameShaderTime = 0.0f;
   1903 	ambientLightVector.Zero();
   1904 	worlds.Clear();
   1905 	primaryWorld = NULL;
   1906 	memset( &primaryRenderView, 0, sizeof( primaryRenderView ) );
   1907 	primaryView = NULL;
   1908 	defaultMaterial = NULL;
   1909 	testImage = NULL;
   1910 	ambientCubeImage = NULL;
   1911 	viewDef = NULL;
   1912 	memset( &pc, 0, sizeof( pc ) );
   1913 	memset( &identitySpace, 0, sizeof( identitySpace ) );
   1914 	memset( renderCrops, 0, sizeof( renderCrops ) );
   1915 	currentRenderCrop = 0;
   1916 	currentColorNativeBytesOrder = 0xFFFFFFFF;
   1917 	currentGLState = 0;
   1918 	guiRecursionLevel = 0;
   1919 	guiModel = NULL;
   1920 	memset( gammaTable, 0, sizeof( gammaTable ) );
   1921 	takingScreenshot = false;
   1922 
   1923 	if ( unitSquareTriangles != NULL ) {
   1924 		Mem_Free( unitSquareTriangles );
   1925 		unitSquareTriangles = NULL;
   1926 	}
   1927 
   1928 	if ( zeroOneCubeTriangles != NULL ) {
   1929 		Mem_Free( zeroOneCubeTriangles );
   1930 		zeroOneCubeTriangles = NULL;
   1931 	}
   1932 
   1933 	if ( testImageTriangles != NULL ) {
   1934 		Mem_Free( testImageTriangles );
   1935 		testImageTriangles = NULL;
   1936 	}
   1937 
   1938 	frontEndJobList = NULL;
   1939 }
   1940 
   1941 /*
   1942 =============
   1943 R_MakeFullScreenTris
   1944 =============
   1945 */
   1946 static srfTriangles_t * R_MakeFullScreenTris() {
   1947 	// copy verts and indexes
   1948 	srfTriangles_t * tri = (srfTriangles_t *)Mem_ClearedAlloc( sizeof( *tri ), TAG_RENDER_TOOLS );
   1949 
   1950 	tri->numIndexes = 6;
   1951 	tri->numVerts = 4;
   1952 
   1953 	int indexSize = tri->numIndexes * sizeof( tri->indexes[0] );
   1954 	int allocatedIndexBytes = ALIGN( indexSize, 16 );
   1955 	tri->indexes = (triIndex_t *)Mem_Alloc( allocatedIndexBytes, TAG_RENDER_TOOLS );
   1956 
   1957 	int vertexSize = tri->numVerts * sizeof( tri->verts[0] );
   1958 	int allocatedVertexBytes =  ALIGN( vertexSize, 16 );
   1959 	tri->verts = (idDrawVert *)Mem_ClearedAlloc( allocatedVertexBytes, TAG_RENDER_TOOLS );
   1960 
   1961 	idDrawVert * verts = tri->verts;
   1962 
   1963 	triIndex_t tempIndexes[6] = { 3, 0, 2, 2, 0, 1 };
   1964 	memcpy( tri->indexes, tempIndexes, indexSize );
   1965 	
   1966 	verts[0].xyz[0] = -1.0f;
   1967 	verts[0].xyz[1] = 1.0f;
   1968 	verts[0].SetTexCoord( 0.0f, 1.0f );
   1969 
   1970 	verts[1].xyz[0] = 1.0f;
   1971 	verts[1].xyz[1] = 1.0f;
   1972 	verts[1].SetTexCoord( 1.0f, 1.0f );
   1973 
   1974 	verts[2].xyz[0] = 1.0f;
   1975 	verts[2].xyz[1] = -1.0f;
   1976 	verts[2].SetTexCoord( 1.0f, 0.0f );
   1977 
   1978 	verts[3].xyz[0] = -1.0f;
   1979 	verts[3].xyz[1] = -1.0f;
   1980 	verts[3].SetTexCoord( 0.0f, 0.0f );
   1981 
   1982 	for ( int i = 0 ; i < 4 ; i++ ) {
   1983 		verts[i].SetColor( 0xffffffff );
   1984 	}
   1985 
   1986 
   1987 	return tri;
   1988 }
   1989 
   1990 /*
   1991 =============
   1992 R_MakeZeroOneCubeTris
   1993 =============
   1994 */
   1995 static srfTriangles_t * R_MakeZeroOneCubeTris() {
   1996 	srfTriangles_t * tri = (srfTriangles_t *)Mem_ClearedAlloc( sizeof( *tri ), TAG_RENDER_TOOLS );
   1997 
   1998 	tri->numVerts = 8;
   1999 	tri->numIndexes = 36;
   2000 
   2001 	const int indexSize = tri->numIndexes * sizeof( tri->indexes[0] );
   2002 	const int allocatedIndexBytes = ALIGN( indexSize, 16 );
   2003 	tri->indexes = (triIndex_t *)Mem_Alloc( allocatedIndexBytes, TAG_RENDER_TOOLS );
   2004 
   2005 	const int vertexSize = tri->numVerts * sizeof( tri->verts[0] );
   2006 	const int allocatedVertexBytes =  ALIGN( vertexSize, 16 );
   2007 	tri->verts = (idDrawVert *)Mem_ClearedAlloc( allocatedVertexBytes, TAG_RENDER_TOOLS );
   2008 
   2009 	idDrawVert * verts = tri->verts;
   2010 
   2011 	const float low = 0.0f;
   2012 	const float high = 1.0f;
   2013 
   2014 	idVec3 center( 0.0f );
   2015 	idVec3 mx(  low, 0.0f, 0.0f );
   2016 	idVec3 px( high, 0.0f, 0.0f );
   2017 	idVec3 my( 0.0f,  low, 0.0f );
   2018 	idVec3 py( 0.0f, high, 0.0f );
   2019 	idVec3 mz( 0.0f, 0.0f,  low );
   2020 	idVec3 pz( 0.0f, 0.0f, high );
   2021 
   2022 	verts[0].xyz = center + mx + my + mz;
   2023 	verts[1].xyz = center + px + my + mz;
   2024 	verts[2].xyz = center + px + py + mz;
   2025 	verts[3].xyz = center + mx + py + mz;
   2026 	verts[4].xyz = center + mx + my + pz;
   2027 	verts[5].xyz = center + px + my + pz;
   2028 	verts[6].xyz = center + px + py + pz;
   2029 	verts[7].xyz = center + mx + py + pz;
   2030 
   2031 	// bottom
   2032 	tri->indexes[ 0*3+0] = 2;
   2033 	tri->indexes[ 0*3+1] = 3;
   2034 	tri->indexes[ 0*3+2] = 0;
   2035 	tri->indexes[ 1*3+0] = 1;
   2036 	tri->indexes[ 1*3+1] = 2;
   2037 	tri->indexes[ 1*3+2] = 0;
   2038 	// back
   2039 	tri->indexes[ 2*3+0] = 5;
   2040 	tri->indexes[ 2*3+1] = 1;
   2041 	tri->indexes[ 2*3+2] = 0;
   2042 	tri->indexes[ 3*3+0] = 4;
   2043 	tri->indexes[ 3*3+1] = 5;
   2044 	tri->indexes[ 3*3+2] = 0;
   2045 	// left
   2046 	tri->indexes[ 4*3+0] = 7;
   2047 	tri->indexes[ 4*3+1] = 4;
   2048 	tri->indexes[ 4*3+2] = 0;
   2049 	tri->indexes[ 5*3+0] = 3;
   2050 	tri->indexes[ 5*3+1] = 7;
   2051 	tri->indexes[ 5*3+2] = 0;
   2052 	// right
   2053 	tri->indexes[ 6*3+0] = 1;
   2054 	tri->indexes[ 6*3+1] = 5;
   2055 	tri->indexes[ 6*3+2] = 6;
   2056 	tri->indexes[ 7*3+0] = 2;
   2057 	tri->indexes[ 7*3+1] = 1;
   2058 	tri->indexes[ 7*3+2] = 6;
   2059 	// front
   2060 	tri->indexes[ 8*3+0] = 3;
   2061 	tri->indexes[ 8*3+1] = 2;
   2062 	tri->indexes[ 8*3+2] = 6;
   2063 	tri->indexes[ 9*3+0] = 7;
   2064 	tri->indexes[ 9*3+1] = 3;
   2065 	tri->indexes[ 9*3+2] = 6;
   2066 	// top
   2067 	tri->indexes[10*3+0] = 4;
   2068 	tri->indexes[10*3+1] = 7;
   2069 	tri->indexes[10*3+2] = 6;
   2070 	tri->indexes[11*3+0] = 5;
   2071 	tri->indexes[11*3+1] = 4;
   2072 	tri->indexes[11*3+2] = 6;
   2073 
   2074 	for ( int i = 0 ; i < 4 ; i++ ) {
   2075 		verts[i].SetColor( 0xffffffff );
   2076 	}
   2077 
   2078 	return tri;
   2079 }
   2080 
   2081 /*
   2082 ================
   2083 R_MakeTestImageTriangles
   2084 
   2085 Initializes the Test Image Triangles
   2086 ================
   2087 */
   2088 srfTriangles_t* R_MakeTestImageTriangles() {
   2089 	srfTriangles_t * tri = (srfTriangles_t *)Mem_ClearedAlloc( sizeof( *tri ), TAG_RENDER_TOOLS );
   2090 
   2091 	tri->numIndexes = 6;
   2092 	tri->numVerts = 4;
   2093 
   2094 	int indexSize = tri->numIndexes * sizeof( tri->indexes[0] );
   2095 	int allocatedIndexBytes = ALIGN( indexSize, 16 );
   2096 	tri->indexes = (triIndex_t *)Mem_Alloc( allocatedIndexBytes, TAG_RENDER_TOOLS );
   2097 
   2098 	int vertexSize = tri->numVerts * sizeof( tri->verts[0] );
   2099 	int allocatedVertexBytes =  ALIGN( vertexSize, 16 );
   2100 	tri->verts = (idDrawVert *)Mem_ClearedAlloc( allocatedVertexBytes, TAG_RENDER_TOOLS );
   2101 
   2102 	ALIGNTYPE16 triIndex_t tempIndexes[6] = { 3, 0, 2, 2, 0, 1 };
   2103 	memcpy( tri->indexes, tempIndexes, indexSize );
   2104 
   2105 	idDrawVert* tempVerts = tri->verts;
   2106 	tempVerts[0].xyz[0] = 0.0f;
   2107 	tempVerts[0].xyz[1] = 0.0f;
   2108 	tempVerts[0].xyz[2] = 0;
   2109 	tempVerts[0].SetTexCoord( 0.0, 0.0f );
   2110 
   2111 	tempVerts[1].xyz[0] = 1.0f;
   2112 	tempVerts[1].xyz[1] = 0.0f;
   2113 	tempVerts[1].xyz[2] = 0;
   2114 	tempVerts[1].SetTexCoord( 1.0f, 0.0f );
   2115 
   2116 	tempVerts[2].xyz[0] = 1.0f;
   2117 	tempVerts[2].xyz[1] = 1.0f;
   2118 	tempVerts[2].xyz[2] = 0;
   2119 	tempVerts[2].SetTexCoord( 1.0f, 1.0f );
   2120 
   2121 	tempVerts[3].xyz[0] = 0.0f;
   2122 	tempVerts[3].xyz[1] = 1.0f;
   2123 	tempVerts[3].xyz[2] = 0;
   2124 	tempVerts[3].SetTexCoord( 0.0f, 1.0f );
   2125 
   2126 	for ( int i = 0; i < 4; i++ ) {
   2127 		tempVerts[i].SetColor( 0xFFFFFFFF );
   2128 	}
   2129 	return tri;
   2130 }
   2131 
   2132 /*
   2133 ===============
   2134 idRenderSystemLocal::Init
   2135 ===============
   2136 */
   2137 void idRenderSystemLocal::Init() {	
   2138 
   2139 	common->Printf( "------- Initializing renderSystem --------\n" );
   2140 
   2141 	// clear all our internal state
   2142 	viewCount = 1;		// so cleared structures never match viewCount
   2143 	// we used to memset tr, but now that it is a class, we can't, so
   2144 	// there may be other state we need to reset
   2145 
   2146 	ambientLightVector[0] = 0.5f;
   2147 	ambientLightVector[1] = 0.5f - 0.385f;
   2148 	ambientLightVector[2] = 0.8925f;
   2149 	ambientLightVector[3] = 1.0f;
   2150 
   2151 	memset( &backEnd, 0, sizeof( backEnd ) );
   2152 
   2153 	R_InitCvars();
   2154 
   2155 	R_InitCommands();
   2156 
   2157 	guiModel = new (TAG_RENDER) idGuiModel;
   2158 	guiModel->Clear();
   2159 	tr_guiModel = guiModel;	// for DeviceContext fast path
   2160 
   2161 	globalImages->Init();
   2162 
   2163 	idCinematic::InitCinematic( );
   2164 
   2165 	// build brightness translation tables
   2166 	R_SetColorMappings();
   2167 
   2168 	R_InitMaterials();
   2169 
   2170 	renderModelManager->Init();
   2171 
   2172 	// set the identity space
   2173 	identitySpace.modelMatrix[0*4+0] = 1.0f;
   2174 	identitySpace.modelMatrix[1*4+1] = 1.0f;
   2175 	identitySpace.modelMatrix[2*4+2] = 1.0f;
   2176 
   2177 	// make sure the tr.unitSquareTriangles data is current in the vertex / index cache
   2178 	if ( unitSquareTriangles == NULL ) {
   2179 		unitSquareTriangles = R_MakeFullScreenTris();
   2180 	}
   2181 	// make sure the tr.zeroOneCubeTriangles data is current in the vertex / index cache
   2182 	if ( zeroOneCubeTriangles == NULL ) {
   2183 		zeroOneCubeTriangles = R_MakeZeroOneCubeTris();
   2184 	}
   2185 	// make sure the tr.testImageTriangles data is current in the vertex / index cache
   2186 	if ( testImageTriangles == NULL )  {
   2187 		testImageTriangles = R_MakeTestImageTriangles();
   2188 	}
   2189 
   2190 	frontEndJobList = parallelJobManager->AllocJobList( JOBLIST_RENDERER_FRONTEND, JOBLIST_PRIORITY_MEDIUM, 2048, 0, NULL );
   2191 
   2192 	// make sure the command buffers are ready to accept the first screen update
   2193 	SwapCommandBuffers( NULL, NULL, NULL, NULL );
   2194 
   2195 	common->Printf( "renderSystem initialized.\n" );
   2196 	common->Printf( "--------------------------------------\n" );
   2197 }
   2198 
   2199 /*
   2200 ===============
   2201 idRenderSystemLocal::Shutdown
   2202 ===============
   2203 */
   2204 void idRenderSystemLocal::Shutdown() {	
   2205 	common->Printf( "idRenderSystem::Shutdown()\n" );
   2206 
   2207 	fonts.DeleteContents();
   2208 
   2209 	if ( R_IsInitialized() ) {
   2210 		globalImages->PurgeAllImages();
   2211 	}
   2212 
   2213 	renderModelManager->Shutdown();
   2214 
   2215 	idCinematic::ShutdownCinematic( );
   2216 
   2217 	globalImages->Shutdown();
   2218 
   2219 	// free frame memory
   2220 	R_ShutdownFrameData();
   2221 
   2222 	UnbindBufferObjects();
   2223 
   2224 	// free the vertex cache, which should have nothing allocated now
   2225 	vertexCache.Shutdown();
   2226 
   2227 	RB_ShutdownDebugTools();
   2228 
   2229 	delete guiModel;
   2230 
   2231 	parallelJobManager->FreeJobList( frontEndJobList );
   2232 
   2233 	Clear();
   2234 
   2235 	ShutdownOpenGL();
   2236 }
   2237 
   2238 /*
   2239 ========================
   2240 idRenderSystemLocal::ResetGuiModels
   2241 ========================
   2242 */
   2243 void idRenderSystemLocal::ResetGuiModels() {
   2244 	delete guiModel;
   2245 	guiModel = new (TAG_RENDER) idGuiModel;
   2246 	guiModel->Clear();
   2247 	guiModel->BeginFrame();
   2248 	tr_guiModel = guiModel;	// for DeviceContext fast path
   2249 }
   2250 
   2251 /*
   2252 ========================
   2253 idRenderSystemLocal::BeginLevelLoad
   2254 ========================
   2255 */
   2256 void idRenderSystemLocal::BeginLevelLoad() {
   2257 	globalImages->BeginLevelLoad();
   2258 	renderModelManager->BeginLevelLoad();
   2259 
   2260 	// Re-Initialize the Default Materials if needed. 
   2261 	R_InitMaterials();
   2262 }
   2263 
   2264 /*
   2265 ========================
   2266 idRenderSystemLocal::LoadLevelImages
   2267 ========================
   2268 */
   2269 void idRenderSystemLocal::LoadLevelImages() {
   2270 	globalImages->LoadLevelImages( false );
   2271 }
   2272 
   2273 /*
   2274 ========================
   2275 idRenderSystemLocal::Preload
   2276 ========================
   2277 */
   2278 void idRenderSystemLocal::Preload( const idPreloadManifest &manifest, const char *mapName ) {
   2279 	globalImages->Preload( manifest, true );
   2280 	uiManager->Preload( mapName );
   2281 	renderModelManager->Preload( manifest );
   2282 }
   2283 
   2284 /*
   2285 ========================
   2286 idRenderSystemLocal::EndLevelLoad
   2287 ========================
   2288 */
   2289 void idRenderSystemLocal::EndLevelLoad() {
   2290 	renderModelManager->EndLevelLoad();
   2291 	globalImages->EndLevelLoad();
   2292 }
   2293 
   2294 /*
   2295 ========================
   2296 idRenderSystemLocal::BeginAutomaticBackgroundSwaps
   2297 ========================
   2298 */
   2299 void idRenderSystemLocal::BeginAutomaticBackgroundSwaps( autoRenderIconType_t icon ) {
   2300 }
   2301 
   2302 /*
   2303 ========================
   2304 idRenderSystemLocal::EndAutomaticBackgroundSwaps
   2305 ========================
   2306 */
   2307 void idRenderSystemLocal::EndAutomaticBackgroundSwaps() {
   2308 }
   2309 
   2310 /*
   2311 ========================
   2312 idRenderSystemLocal::AreAutomaticBackgroundSwapsRunning
   2313 ========================
   2314 */
   2315 bool idRenderSystemLocal::AreAutomaticBackgroundSwapsRunning( autoRenderIconType_t * icon ) const {
   2316 	return false;
   2317 }
   2318 
   2319 /*
   2320 ============
   2321 idRenderSystemLocal::RegisterFont
   2322 ============
   2323 */
   2324 idFont * idRenderSystemLocal::RegisterFont( const char * fontName ) {
   2325 
   2326 	idStrStatic< MAX_OSPATH > baseFontName = fontName;
   2327 	baseFontName.Replace( "fonts/", "" );
   2328 	for ( int i = 0; i < fonts.Num(); i++ ) {
   2329 		if ( idStr::Icmp( fonts[i]->GetName(), baseFontName ) == 0 ) {
   2330 			fonts[i]->Touch();
   2331 			return fonts[i];
   2332 		}
   2333 	}
   2334 	idFont * newFont = new (TAG_FONT) idFont( baseFontName );
   2335 	fonts.Append( newFont );
   2336 	return newFont;
   2337 }
   2338 
   2339 /*
   2340 ========================
   2341 idRenderSystemLocal::ResetFonts
   2342 ========================
   2343 */
   2344 void idRenderSystemLocal::ResetFonts() {
   2345 	fonts.DeleteContents( true );
   2346 }
   2347 /*
   2348 ========================
   2349 idRenderSystemLocal::InitOpenGL
   2350 ========================
   2351 */
   2352 void idRenderSystemLocal::InitOpenGL() {
   2353 	// if OpenGL isn't started, start it now
   2354 	if ( !R_IsInitialized() ) {
   2355 		R_InitOpenGL();
   2356 
   2357 		// Reloading images here causes the rendertargets to get deleted. Figure out how to handle this properly on 360
   2358 		globalImages->ReloadImages( true );
   2359 		
   2360 		int err = qglGetError();
   2361 		if ( err != GL_NO_ERROR ) {
   2362 			common->Printf( "glGetError() = 0x%x\n", err );
   2363 		}
   2364 	}
   2365 }
   2366 
   2367 /*
   2368 ========================
   2369 idRenderSystemLocal::ShutdownOpenGL
   2370 ========================
   2371 */
   2372 void idRenderSystemLocal::ShutdownOpenGL() {
   2373 	// free the context and close the window
   2374 	R_ShutdownFrameData();
   2375 	GLimp_Shutdown();
   2376 	r_initialized = false;
   2377 }
   2378 
   2379 /*
   2380 ========================
   2381 idRenderSystemLocal::IsOpenGLRunning
   2382 ========================
   2383 */
   2384 bool idRenderSystemLocal::IsOpenGLRunning() const {
   2385 	return R_IsInitialized();
   2386 }
   2387 
   2388 /*
   2389 ========================
   2390 idRenderSystemLocal::IsFullScreen
   2391 ========================
   2392 */
   2393 bool idRenderSystemLocal::IsFullScreen() const {
   2394 	return glConfig.isFullscreen != 0;
   2395 }
   2396 
   2397 /*
   2398 ========================
   2399 idRenderSystemLocal::GetWidth
   2400 ========================
   2401 */
   2402 int idRenderSystemLocal::GetWidth() const {
   2403 	if ( glConfig.stereo3Dmode == STEREO3D_SIDE_BY_SIDE || glConfig.stereo3Dmode == STEREO3D_SIDE_BY_SIDE_COMPRESSED ) {
   2404 		return glConfig.nativeScreenWidth >> 1;
   2405 	}
   2406 	return glConfig.nativeScreenWidth;
   2407 }
   2408 
   2409 /*
   2410 ========================
   2411 idRenderSystemLocal::GetHeight
   2412 ========================
   2413 */
   2414 int idRenderSystemLocal::GetHeight() const {
   2415 	if ( glConfig.stereo3Dmode == STEREO3D_HDMI_720 ) {
   2416 		return 720;
   2417 	}
   2418 	extern idCVar stereoRender_warp;
   2419 	if ( glConfig.stereo3Dmode == STEREO3D_SIDE_BY_SIDE && stereoRender_warp.GetBool() ) {
   2420 		// for the Rift, render a square aspect view that will be symetric for the optics
   2421 		return glConfig.nativeScreenWidth >> 1;
   2422 	}
   2423 	if ( glConfig.stereo3Dmode == STEREO3D_INTERLACED || glConfig.stereo3Dmode == STEREO3D_TOP_AND_BOTTOM_COMPRESSED ) {
   2424 		return glConfig.nativeScreenHeight >> 1;
   2425 	}
   2426 	return glConfig.nativeScreenHeight;
   2427 }
   2428 
   2429 /*
   2430 ========================
   2431 idRenderSystemLocal::GetStereo3DMode
   2432 ========================
   2433 */
   2434 stereo3DMode_t idRenderSystemLocal::GetStereo3DMode() const {
   2435 	return glConfig.stereo3Dmode;
   2436 }
   2437 
   2438 /*
   2439 ========================
   2440 idRenderSystemLocal::IsStereoScopicRenderingSupported
   2441 ========================
   2442 */
   2443 bool idRenderSystemLocal::IsStereoScopicRenderingSupported() const {
   2444 	return true;
   2445 }
   2446 
   2447 /*
   2448 ========================
   2449 idRenderSystemLocal::HasQuadBufferSupport
   2450 ========================
   2451 */
   2452 bool idRenderSystemLocal::HasQuadBufferSupport() const {
   2453 	return glConfig.stereoPixelFormatAvailable;
   2454 }
   2455 
   2456 /*
   2457 ========================
   2458 idRenderSystemLocal::GetStereoScopicRenderingMode
   2459 ========================
   2460 */
   2461 stereo3DMode_t idRenderSystemLocal::GetStereoScopicRenderingMode() const {
   2462 	return ( !IsStereoScopicRenderingSupported() ) ? STEREO3D_OFF : (stereo3DMode_t)stereoRender_enable.GetInteger();
   2463 }
   2464 
   2465 /*
   2466 ========================
   2467 idRenderSystemLocal::IsStereoScopicRenderingSupported
   2468 ========================
   2469 */
   2470 void idRenderSystemLocal::EnableStereoScopicRendering( const stereo3DMode_t mode ) const {
   2471 	stereoRender_enable.SetInteger( mode );
   2472 }
   2473 
   2474 /*
   2475 ========================
   2476 idRenderSystemLocal::GetPixelAspect
   2477 ========================
   2478 */
   2479 float idRenderSystemLocal::GetPixelAspect() const {
   2480 	switch( glConfig.stereo3Dmode ) {
   2481 	case STEREO3D_SIDE_BY_SIDE_COMPRESSED:
   2482 		return glConfig.pixelAspect * 2.0f;
   2483 	case STEREO3D_TOP_AND_BOTTOM_COMPRESSED:
   2484 	case STEREO3D_INTERLACED:
   2485 		return glConfig.pixelAspect * 0.5f;
   2486 	default:
   2487 		return glConfig.pixelAspect;
   2488 	}
   2489 }
   2490 
   2491 /*
   2492 ========================
   2493 idRenderSystemLocal::GetPhysicalScreenWidthInCentimeters
   2494 
   2495 This is used to calculate stereoscopic screen offset for a given interocular distance.
   2496 ========================
   2497 */
   2498 idCVar	r_forceScreenWidthCentimeters( "r_forceScreenWidthCentimeters", "0", CVAR_RENDERER | CVAR_ARCHIVE, "Override screen width returned by hardware" );
   2499 float idRenderSystemLocal::GetPhysicalScreenWidthInCentimeters() const {
   2500 	if ( r_forceScreenWidthCentimeters.GetFloat() > 0 ) {
   2501 		return r_forceScreenWidthCentimeters.GetFloat();
   2502 	}
   2503 	return glConfig.physicalScreenWidthInCentimeters;
   2504 }