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 }