]> de.git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
implemented occlusion query support on corona rendering, this enables
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Thu, 12 Feb 2009 05:35:34 +0000 (05:35 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Thu, 12 Feb 2009 05:35:34 +0000 (05:35 +0000)
coronas to fade according to the percentage of occluded pixels around
the light origin, giving a more realistic corona behavior
some minor cleanup on shadow volume construction code

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@8702 d7cf8633-e32d-0410-b094-e92efae38249

client.h
gl_rmain.c
gl_rsurf.c
glquake.h
r_shadow.c
r_shadow.h
render.h
vid_shared.c

index 14eacf09bb664c2b8305ea2f6103183491e01857..d75c5e2ff4011079eb2ca7d7eaa60c8acb3d3617 100644 (file)
--- a/client.h
+++ b/client.h
@@ -109,6 +109,10 @@ typedef struct rtlight_s
        // rendering properties, updated each time a light is rendered
        // this is rtlight->color * d_lightstylevalue
        vec3_t currentcolor;
        // rendering properties, updated each time a light is rendered
        // this is rtlight->color * d_lightstylevalue
        vec3_t currentcolor;
+       // used by corona updates, due to occlusion query
+       float corona_visibility;
+       unsigned int corona_queryindex_visiblepixels;
+       unsigned int corona_queryindex_allpixels;
        // this is R_Shadow_Cubemap(rtlight->cubemapname)
        rtexture_t *currentcubemap;
 
        // this is R_Shadow_Cubemap(rtlight->cubemapname)
        rtexture_t *currentcubemap;
 
index e0e7ab43e334a7c2a7b4abc72e2f23554ca250c3..9d83c1f1efc1c9575f3e7a775b68da84248278d4 100644 (file)
@@ -168,6 +168,10 @@ rtexture_t *r_texture_gammaramps;
 unsigned int r_texture_gammaramps_serial;
 //rtexture_t *r_texture_fogintensity;
 
 unsigned int r_texture_gammaramps_serial;
 //rtexture_t *r_texture_fogintensity;
 
+unsigned int r_queries[R_MAX_OCCLUSION_QUERIES];
+unsigned int r_numqueries;
+unsigned int r_maxqueries;
+
 char r_qwskincache[MAX_SCOREBOARD][MAX_QPATH];
 skinframe_t *r_qwskincache_skinframe[MAX_SCOREBOARD];
 
 char r_qwskincache[MAX_SCOREBOARD][MAX_QPATH];
 skinframe_t *r_qwskincache_skinframe[MAX_SCOREBOARD];
 
@@ -1734,7 +1738,7 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                        if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, r_refdef.lightmapintensity * specularscale);
                }
                if (r_glsl_permutation->loc_TintColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_TintColor, rsurface.texture->lightmapcolor[0], rsurface.texture->lightmapcolor[1], rsurface.texture->lightmapcolor[2], rsurface.texture->lightmapcolor[3]);
                        if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, r_refdef.lightmapintensity * specularscale);
                }
                if (r_glsl_permutation->loc_TintColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_TintColor, rsurface.texture->lightmapcolor[0], rsurface.texture->lightmapcolor[1], rsurface.texture->lightmapcolor[2], rsurface.texture->lightmapcolor[3]);
-               if (r_glsl_permutation->loc_GlowScale     >= 0) qglUniform1fARB(r_glsl_permutation->loc_GlowScale, r_hdr_glowintensity.value);
+               if (r_glsl_permutation->loc_GlowScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_GlowScale, r_hdr_glowintensity.value);
                // additive passes are only darkened by fog, not tinted
                if (r_glsl_permutation->loc_FogColor >= 0)
                {
                // additive passes are only darkened by fog, not tinted
                if (r_glsl_permutation->loc_FogColor >= 0)
                {
@@ -2246,6 +2250,10 @@ skinframe_t *R_SkinFrame_LoadMissing(void)
 
 void gl_main_start(void)
 {
 
 void gl_main_start(void)
 {
+       r_numqueries = 0;
+       r_maxqueries = 0;
+       memset(r_queries, 0, sizeof(r_queries));
+
        memset(r_qwskincache, 0, sizeof(r_qwskincache));
        memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
 
        memset(r_qwskincache, 0, sizeof(r_qwskincache));
        memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
 
@@ -2275,6 +2283,13 @@ void gl_main_start(void)
 
 void gl_main_shutdown(void)
 {
 
 void gl_main_shutdown(void)
 {
+       if (r_maxqueries)
+               qglDeleteQueriesARB(r_maxqueries, r_queries);
+
+       r_numqueries = 0;
+       r_maxqueries = 0;
+       memset(r_queries, 0, sizeof(r_queries));
+
        memset(r_qwskincache, 0, sizeof(r_qwskincache));
        memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
 
        memset(r_qwskincache, 0, sizeof(r_qwskincache));
        memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
 
@@ -2473,8 +2488,8 @@ void GL_Init (void)
        Con_Printf("GL_VENDOR: %s\n", gl_vendor);
        Con_Printf("GL_RENDERER: %s\n", gl_renderer);
        Con_Printf("GL_VERSION: %s\n", gl_version);
        Con_Printf("GL_VENDOR: %s\n", gl_vendor);
        Con_Printf("GL_RENDERER: %s\n", gl_renderer);
        Con_Printf("GL_VERSION: %s\n", gl_version);
-       Con_Printf("GL_EXTENSIONS: %s\n", gl_extensions);
-       Con_Printf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions);
+       Con_DPrintf("GL_EXTENSIONS: %s\n", gl_extensions);
+       Con_DPrintf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions);
 
        VID_CheckExtensions();
 
 
        VID_CheckExtensions();
 
index c6fe69e8006f16e13b000f13c1966dae59ed9b9f..e84263106c10274ad16e4b44b97ef0357dc86d9d 100644 (file)
@@ -974,7 +974,7 @@ void R_Q1BSP_CompileShadowVolume(entity_render_t *ent, vec3_t relativelightorigi
                        continue;
                R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, relativelightdirection, r_shadow_compilingrtlight->cullmins, r_shadow_compilingrtlight->cullmaxs, surface->mins, surface->maxs);
        }
                        continue;
                R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, relativelightdirection, r_shadow_compilingrtlight->cullmins, r_shadow_compilingrtlight->cullmaxs, surface->mins, surface->maxs);
        }
-       R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist);
+       R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist, ent->mins, ent->maxs);
        r_shadow_compilingrtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, false, false, true);
 }
 
        r_shadow_compilingrtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, false, false, true);
 }
 
@@ -1002,7 +1002,7 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, const vec3_t relativelightor
                                continue;
                        R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, relativelightdirection, lightmins, lightmaxs, surface->mins, surface->maxs);
                }
                                continue;
                        R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, relativelightdirection, lightmins, lightmaxs, surface->mins, surface->maxs);
                }
-               R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist);
+               R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist, ent->mins, ent->maxs);
        }
        else
        {
        }
        else
        {
@@ -1018,7 +1018,7 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, const vec3_t relativelightor
                        RSurf_PrepareVerticesForBatch(false, false, 1, &surface);
                        R_Shadow_MarkVolumeFromBox(surface->num_firsttriangle, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i, relativelightorigin, relativelightdirection, lightmins, lightmaxs, surface->mins, surface->maxs);
                }
                        RSurf_PrepareVerticesForBatch(false, false, 1, &surface);
                        R_Shadow_MarkVolumeFromBox(surface->num_firsttriangle, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i, relativelightorigin, relativelightdirection, lightmins, lightmaxs, surface->mins, surface->maxs);
                }
-               R_Shadow_VolumeFromList(model->surfmesh.num_vertices, model->surfmesh.num_triangles, rsurface.vertex3f, model->surfmesh.data_element3i, model->surfmesh.data_neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist);
+               R_Shadow_VolumeFromList(model->surfmesh.num_vertices, model->surfmesh.num_triangles, rsurface.vertex3f, model->surfmesh.data_element3i, model->surfmesh.data_neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist, ent->mins, ent->maxs);
        }
        if (ent->model->brush.submodel)
                GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);
        }
        if (ent->model->brush.submodel)
                GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);
index 5acbc4469a6e02126c2f9918ff75793c211d006a..4ff40cd3f91790f21320c57c70ac0e1aaf59ba35 100644 (file)
--- a/glquake.h
+++ b/glquake.h
@@ -807,7 +807,25 @@ extern void (GLAPIENTRY *qglGetCompressedTexImageARB)(GLenum target, GLint lod,
 #define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB          0x86A2
 #define GL_COMPRESSED_TEXTURE_FORMATS_ARB                      0x86A3
 #endif
 #define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB          0x86A2
 #define GL_COMPRESSED_TEXTURE_FORMATS_ARB                      0x86A3
 #endif
+
+// GL_ARB_occlusion_query
+extern int gl_support_arb_occlusion_query;
+extern void (GLAPIENTRY *qglGenQueriesARB)(GLsizei n, GLuint *ids);
+extern void (GLAPIENTRY *qglDeleteQueriesARB)(GLsizei n, const GLuint *ids);
+extern GLboolean (GLAPIENTRY *qglIsQueryARB)(GLuint qid);
+extern void (GLAPIENTRY *qglBeginQueryARB)(GLenum target, GLuint qid);
+extern void (GLAPIENTRY *qglEndQueryARB)(GLenum target);
+extern void (GLAPIENTRY *qglGetQueryivARB)(GLenum target, GLenum pname, GLint *params);
+extern void (GLAPIENTRY *qglGetQueryObjectivARB)(GLuint qid, GLenum pname, GLint *params);
+extern void (GLAPIENTRY *qglGetQueryObjectuivARB)(GLuint qid, GLenum pname, GLuint *params);
+#ifndef GL_SAMPLES_PASSED_ARB
+#define GL_SAMPLES_PASSED_ARB                             0x8914
+#define GL_QUERY_COUNTER_BITS_ARB                         0x8864
+#define GL_CURRENT_QUERY_ARB                              0x8865
+#define GL_QUERY_RESULT_ARB                               0x8866
+#define GL_QUERY_RESULT_AVAILABLE_ARB                     0x8867
+#endif
+
 // GL_EXT_bgr
 #define GL_BGR                                 0x80E0
 
 // GL_EXT_bgr
 #define GL_BGR                                 0x80E0
 
index 284f569eb10348182f009af754a221f1480d5726..cfb1d58a19956224e4c2e5bcd62b02d221b9bd0a 100644 (file)
@@ -236,6 +236,8 @@ cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to
 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect r_glsl lighting)"};
 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect r_glsl lighting)"};
 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
+cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksm the proportion of hidden pixels controls corona intensity"};
+cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
@@ -466,6 +468,8 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_polygonoffset);
        Cvar_RegisterVariable(&r_shadow_texture3d);
        Cvar_RegisterVariable(&r_coronas);
        Cvar_RegisterVariable(&r_shadow_polygonoffset);
        Cvar_RegisterVariable(&r_shadow_texture3d);
        Cvar_RegisterVariable(&r_coronas);
+       Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
+       Cvar_RegisterVariable(&r_coronas_occlusionquery);
        Cvar_RegisterVariable(&gl_flashblend);
        Cvar_RegisterVariable(&gl_ext_separatestencil);
        Cvar_RegisterVariable(&gl_ext_stenciltwoside);
        Cvar_RegisterVariable(&gl_flashblend);
        Cvar_RegisterVariable(&gl_ext_separatestencil);
        Cvar_RegisterVariable(&gl_ext_stenciltwoside);
@@ -624,28 +628,6 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *
        else
                VectorClear(projectvector);
 
        else
                VectorClear(projectvector);
 
-       if (maxvertexupdate < innumvertices)
-       {
-               maxvertexupdate = innumvertices;
-               if (vertexupdate)
-                       Mem_Free(vertexupdate);
-               if (vertexremap)
-                       Mem_Free(vertexremap);
-               vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
-               vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
-               vertexupdatenum = 0;
-       }
-       vertexupdatenum++;
-       if (vertexupdatenum == 0)
-       {
-               vertexupdatenum = 1;
-               memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
-               memset(vertexremap, 0, maxvertexupdate * sizeof(int));
-       }
-
-       for (i = 0;i < numshadowmarktris;i++)
-               shadowmark[shadowmarktris[i]] = shadowmarkcount;
-
        // create the vertices
        if (projectdirection)
        {
        // create the vertices
        if (projectdirection)
        {
@@ -889,36 +871,9 @@ void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *inv
        }
 }
 
        }
 }
 
-static void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
-{
-       if (r_shadow_compilingrtlight)
-       {
-               // if we're compiling an rtlight, capture the mesh
-               Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
-               return;
-       }
-       r_refdef.stats.lights_shadowtriangles += numtriangles;
-       CHECKGLERROR
-       R_Mesh_VertexPointer(vertex3f, 0, 0);
-       GL_LockArrays(0, numvertices);
-       if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
-       {
-               // decrement stencil if backface is behind depthbuffer
-               GL_CullFace(r_refdef.view.cullface_front);
-               qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
-               R_Mesh_Draw(0, numvertices, 0, numtriangles, element3i, NULL, 0, 0);
-               // increment stencil if frontface is behind depthbuffer
-               GL_CullFace(r_refdef.view.cullface_back);
-               qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
-       }
-       R_Mesh_Draw(0, numvertices, 0, numtriangles, element3i, NULL, 0, 0);
-       GL_LockArrays(0, 0);
-       CHECKGLERROR
-}
-
-void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris)
+void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris, vec3_t trismins, vec3_t trismaxs)
 {
 {
-       int tris, outverts;
+       int i, tris, outverts;
        if (projectdistance < 0.1)
        {
                Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
        if (projectdistance < 0.1)
        {
                Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
@@ -929,9 +884,57 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f,
        // make sure shadowelements is big enough for this volume
        if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
                R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
        // make sure shadowelements is big enough for this volume
        if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
                R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
-       tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
-       r_refdef.stats.lights_dynamicshadowtriangles += tris;
-       R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
+
+       if (maxvertexupdate < numverts)
+       {
+               maxvertexupdate = numverts;
+               if (vertexupdate)
+                       Mem_Free(vertexupdate);
+               if (vertexremap)
+                       Mem_Free(vertexremap);
+               vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
+               vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
+               vertexupdatenum = 0;
+       }
+       vertexupdatenum++;
+       if (vertexupdatenum == 0)
+       {
+               vertexupdatenum = 1;
+               memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
+               memset(vertexremap, 0, maxvertexupdate * sizeof(int));
+       }
+
+       for (i = 0;i < nummarktris;i++)
+               shadowmark[marktris[i]] = shadowmarkcount;
+
+       if (r_shadow_compilingrtlight)
+       {
+               // if we're compiling an rtlight, capture the mesh
+               tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
+               Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
+       }
+       else
+       {
+               tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
+               r_refdef.stats.lights_dynamicshadowtriangles += tris;
+               r_refdef.stats.lights_shadowtriangles += tris;
+               CHECKGLERROR
+               R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
+               GL_LockArrays(0, outverts);
+               if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
+               {
+                       // decrement stencil if backface is behind depthbuffer
+                       GL_CullFace(r_refdef.view.cullface_front);
+                       qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
+                       R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
+                       // increment stencil if frontface is behind depthbuffer
+                       GL_CullFace(r_refdef.view.cullface_back);
+                       qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
+               }
+               R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
+               GL_LockArrays(0, 0);
+               CHECKGLERROR
+       }
 }
 
 static void R_Shadow_MakeTextures_MakeCorona(void)
 }
 
 static void R_Shadow_MakeTextures_MakeCorona(void)
@@ -1092,7 +1095,14 @@ void R_Shadow_RenderMode_Reset(void)
        R_SetupGenericShader(false);
 }
 
        R_SetupGenericShader(false);
 }
 
-void R_Shadow_RenderMode_StencilShadowVolumes(qboolean clearstencil)
+void R_Shadow_ClearStencil(void)
+{
+       CHECKGLERROR
+       GL_Clear(GL_STENCIL_BUFFER_BIT);
+       r_refdef.stats.lights_clears++;
+}
+
+void R_Shadow_RenderMode_StencilShadowVolumes(void)
 {
        CHECKGLERROR
        R_Shadow_RenderMode_Reset();
 {
        CHECKGLERROR
        R_Shadow_RenderMode_Reset();
@@ -1119,9 +1129,6 @@ void R_Shadow_RenderMode_StencilShadowVolumes(qboolean clearstencil)
                qglStencilMask(~0);CHECKGLERROR
                qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
        }
                qglStencilMask(~0);CHECKGLERROR
                qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
        }
-       if (clearstencil)
-               GL_Clear(GL_STENCIL_BUFFER_BIT);
-       r_refdef.stats.lights_clears++;
 }
 
 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
 }
 
 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
@@ -2787,7 +2794,7 @@ void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned
                                if (CHECKPVSBIT(trispvs, t))
                                        shadowmarklist[numshadowmark++] = t;
                }
                                if (CHECKPVSBIT(trispvs, t))
                                        shadowmarklist[numshadowmark++] = t;
                }
-               R_Shadow_VolumeFromList(r_refdef.scene.worldmodel->brush.shadowmesh->numverts, r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles, r_refdef.scene.worldmodel->brush.shadowmesh->vertex3f, r_refdef.scene.worldmodel->brush.shadowmesh->element3i, r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius + r_refdef.scene.worldmodel->radius*2 + r_shadow_projectdistance.value, numshadowmark, shadowmarklist);
+               R_Shadow_VolumeFromList(r_refdef.scene.worldmodel->brush.shadowmesh->numverts, r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles, r_refdef.scene.worldmodel->brush.shadowmesh->vertex3f, r_refdef.scene.worldmodel->brush.shadowmesh->element3i, r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius + r_refdef.scene.worldmodel->radius*2 + r_shadow_projectdistance.value, numshadowmark, shadowmarklist, r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
        }
        else if (numsurfaces)
                r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
        }
        else if (numsurfaces)
                r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
@@ -3057,7 +3064,8 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
        {
                // draw stencil shadow volumes to mask off pixels that are in shadow
                // so that they won't receive lighting
        {
                // draw stencil shadow volumes to mask off pixels that are in shadow
                // so that they won't receive lighting
-               R_Shadow_RenderMode_StencilShadowVolumes(true);
+               R_Shadow_ClearStencil();
+               R_Shadow_RenderMode_StencilShadowVolumes();
                if (numsurfaces)
                        R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
                for (i = 0;i < numshadowentities;i++)
                if (numsurfaces)
                        R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
                for (i = 0;i < numshadowentities;i++)
@@ -3078,7 +3086,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                                        R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
                        }
 
                                        R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
                        }
 
-                       R_Shadow_RenderMode_StencilShadowVolumes(false);
+                       R_Shadow_RenderMode_StencilShadowVolumes();
                }
                for (i = 0;i < numshadowentities_noselfshadow;i++)
                        R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
                }
                for (i = 0;i < numshadowentities_noselfshadow;i++)
                        R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
@@ -3201,7 +3209,8 @@ void R_DrawModelShadows(void)
        else
                r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
 
        else
                r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
 
-       R_Shadow_RenderMode_StencilShadowVolumes(true);
+       R_Shadow_ClearStencil();
+       R_Shadow_RenderMode_StencilShadowVolumes();
 
        for (i = 0;i < r_refdef.scene.numentities;i++)
        {
 
        for (i = 0;i < r_refdef.scene.numentities;i++)
        {
@@ -3297,64 +3306,145 @@ void R_DrawModelShadows(void)
        R_Shadow_RenderMode_End();
 }
 
        R_Shadow_RenderMode_End();
 }
 
+void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
+{
+       // if it's too close, skip it
+       if (VectorLength(rtlight->color) < (1.0f / 256.0f))
+               return;
+       if (VectorDistance2(rtlight->shadoworigin, r_refdef.view.origin) < 32.0f * 32.0f)
+               return;
+       if (usequery && r_numqueries + 2 <= r_maxqueries)
+       {
+               rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
+               rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
+               CHECKGLERROR
+               qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
+               R_DrawSprite(GL_ONE, GL_ZERO, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, 1, 1, 1, 1);
+               qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
+               qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
+               R_DrawSprite(GL_ONE, GL_ZERO, r_shadow_lightcorona, NULL, false, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, 1, 1, 1, 1);
+               qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
+               CHECKGLERROR
+       }
+       rtlight->corona_visibility = 1;
+}
+
+void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
+{
+       vec3_t color;
+       GLint allpixels = 0, visiblepixels = 0;
+       // now we have to check the query result
+       if (rtlight->corona_queryindex_visiblepixels)
+       {
+               CHECKGLERROR
+               qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
+               qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
+               CHECKGLERROR
+               //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
+               if (visiblepixels < 1 || allpixels < 1)
+                       return;
+               rtlight->corona_visibility *= (float)visiblepixels / (float)allpixels;
+               cscale *= rtlight->corona_visibility;
+       }
+       else
+       {
+               // FIXME: these traces should scan all render entities instead of cl.world
+               if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
+                       return;
+       }
+       VectorScale(rtlight->color, cscale, color);
+       if (VectorLength(color) > (1.0f / 256.0f))
+               R_DrawSprite(GL_ONE, GL_ONE, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, color[0], color[1], color[2], 1);
+}
+
 void R_DrawCoronas(void)
 {
        int i, flag;
 void R_DrawCoronas(void)
 {
        int i, flag;
-       float cscale, scale;
+       qboolean usequery;
        size_t lightindex;
        dlight_t *light;
        rtlight_t *rtlight;
        size_t range;
        if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
                return;
        size_t lightindex;
        dlight_t *light;
        rtlight_t *rtlight;
        size_t range;
        if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
                return;
-       R_Mesh_Matrix(&identitymatrix);
+       if (r_waterstate.renderingscene)
+               return;
        flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
        flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
-       // FIXME: these traces should scan all render entities instead of cl.world
+       R_Mesh_Matrix(&identitymatrix);
+
        range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
        range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
+
+       // check occlusion of coronas
+       // use GL_ARB_occlusion_query if available
+       // otherwise use raytraces
+       r_numqueries = 0;
+       usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
+       if (usequery)
+       {
+               GL_ColorMask(0,0,0,0);
+               if (r_maxqueries < range + r_refdef.scene.numlights)
+               if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
+               {
+                       i = r_maxqueries;
+                       r_maxqueries = (range + r_refdef.scene.numlights) * 2;
+                       r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
+                       CHECKGLERROR
+                       qglGenQueriesARB(r_maxqueries - i, r_queries + i);
+                       CHECKGLERROR
+               }
+       }
        for (lightindex = 0;lightindex < range;lightindex++)
        {
                light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
                if (!light)
                        continue;
                rtlight = &light->rtlight;
        for (lightindex = 0;lightindex < range;lightindex++)
        {
                light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
                if (!light)
                        continue;
                rtlight = &light->rtlight;
+               rtlight->corona_visibility = 0;
+               rtlight->corona_queryindex_visiblepixels = 0;
+               rtlight->corona_queryindex_allpixels = 0;
                if (!(rtlight->flags & flag))
                        continue;
                if (!(rtlight->flags & flag))
                        continue;
-               if (rtlight->corona * r_coronas.value <= 0)
+               if (rtlight->corona <= 0)
                        continue;
                if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
                        continue;
                        continue;
                if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
                        continue;
-               cscale = rtlight->corona * r_coronas.value* 0.25f;
-               scale = rtlight->radius * rtlight->coronasizescale;
-               if (VectorDistance2(rtlight->shadoworigin, r_refdef.view.origin) < 16.0f * 16.0f)
-                       continue;
-               if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
-                       continue;
-               R_DrawSprite(GL_ONE, GL_ONE, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, rtlight->color[0] * cscale, rtlight->color[1] * cscale, rtlight->color[2] * cscale, 1);
+               R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
        }
        for (i = 0;i < r_refdef.scene.numlights;i++)
        {
                rtlight = &r_refdef.scene.lights[i];
        }
        for (i = 0;i < r_refdef.scene.numlights;i++)
        {
                rtlight = &r_refdef.scene.lights[i];
+               rtlight->corona_visibility = 0;
+               rtlight->corona_queryindex_visiblepixels = 0;
+               rtlight->corona_queryindex_allpixels = 0;
                if (!(rtlight->flags & flag))
                        continue;
                if (rtlight->corona <= 0)
                        continue;
                if (!(rtlight->flags & flag))
                        continue;
                if (rtlight->corona <= 0)
                        continue;
-               if (VectorDistance2(rtlight->shadoworigin, r_refdef.view.origin) < 32.0f * 32.0f)
+               R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
+       }
+       if (usequery)
+               GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
+
+       // now draw the coronas using the query data for intensity info
+       for (lightindex = 0;lightindex < range;lightindex++)
+       {
+               light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+               if (!light)
                        continue;
                        continue;
-               if (gl_flashblend.integer)
-               {
-                       cscale = rtlight->corona * 1.0f;
-                       scale = rtlight->radius * rtlight->coronasizescale * 2.0f;
-               }
-               else
-               {
-                       cscale = rtlight->corona * r_coronas.value* 0.25f;
-                       scale = rtlight->radius * rtlight->coronasizescale;
-               }
-               if (VectorLength(rtlight->color) * cscale < (1.0f / 256.0f))
+               rtlight = &light->rtlight;
+               if (rtlight->corona_visibility <= 0)
                        continue;
                        continue;
-               if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
+               R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
+       }
+       for (i = 0;i < r_refdef.scene.numlights;i++)
+       {
+               rtlight = &r_refdef.scene.lights[i];
+               if (rtlight->corona_visibility <= 0)
                        continue;
                        continue;
-               R_DrawSprite(GL_ONE, GL_ONE, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, rtlight->color[0] * cscale, rtlight->color[1] * cscale, rtlight->color[2] * cscale, 1);
+               if (gl_flashblend.integer)
+                       R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
+               else
+                       R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
        }
 }
 
        }
 }
 
index 33fc453e518a607fef59cf3219d33c2cd324a2b5..706f75aa88f764a20f28520963fd1c8966e4d438 100644 (file)
@@ -38,17 +38,18 @@ extern cvar_t gl_ext_separatestencil;
 extern cvar_t gl_ext_stenciltwoside;
 
 void R_Shadow_Init(void);
 extern cvar_t gl_ext_stenciltwoside;
 
 void R_Shadow_Init(void);
-void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris);
+void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris, vec3_t trismins, vec3_t trismaxs);
 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs);
 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject);
 void R_Shadow_RenderMode_Begin(void);
 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight);
 void R_Shadow_RenderMode_Reset(void);
 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs);
 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject);
 void R_Shadow_RenderMode_Begin(void);
 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight);
 void R_Shadow_RenderMode_Reset(void);
-void R_Shadow_RenderMode_StencilShadowVolumes(qboolean clearstencil);
+void R_Shadow_RenderMode_StencilShadowVolumes(void);
 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent);
 void R_Shadow_RenderMode_VisibleShadowVolumes(void);
 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent);
 void R_Shadow_RenderMode_End(void);
 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent);
 void R_Shadow_RenderMode_VisibleShadowVolumes(void);
 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent);
 void R_Shadow_RenderMode_End(void);
+void R_Shadow_ClearStencil(void);
 void R_Shadow_SetupEntityLight(const entity_render_t *ent);
 
 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs);
 void R_Shadow_SetupEntityLight(const entity_render_t *ent);
 
 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs);
index c39b4032901dd277c6a7e0518338a58a9e77b1d9..f2b617b921ca53576f22784b3a853a71c153c10a 100644 (file)
--- a/render.h
+++ b/render.h
@@ -191,6 +191,11 @@ extern rtexture_t *r_texture_normalizationcube;
 extern rtexture_t *r_texture_fogattenuation;
 //extern rtexture_t *r_texture_fogintensity;
 
 extern rtexture_t *r_texture_fogattenuation;
 //extern rtexture_t *r_texture_fogintensity;
 
+#define R_MAX_OCCLUSION_QUERIES 4096
+extern unsigned int r_queries[R_MAX_OCCLUSION_QUERIES];
+extern unsigned int r_numqueries;
+extern unsigned int r_maxqueries;
+
 void R_TimeReport(char *name);
 
 // r_stain
 void R_TimeReport(char *name);
 
 // r_stain
index 5edba6706b02e1faf57d244bc7ce4126eebae742..3848c5f96712a690711142ab2d4b1b83defa191f 100644 (file)
@@ -63,6 +63,8 @@ int gl_support_fragment_shader = false;
 int gl_support_arb_vertex_buffer_object = false;
 //GL_ARB_texture_compression
 int gl_support_texture_compression = false;
 int gl_support_arb_vertex_buffer_object = false;
 //GL_ARB_texture_compression
 int gl_support_texture_compression = false;
+//GL_ARB_occlusion_query
+int gl_support_arb_occlusion_query = false;
 
 // LordHavoc: if window is hidden, don't update screen
 qboolean vid_hidden = true;
 
 // LordHavoc: if window is hidden, don't update screen
 qboolean vid_hidden = true;
@@ -382,6 +384,15 @@ void (GLAPIENTRY *qglCompressedTexSubImage2DARB)(GLenum target, GLint level, GLi
 void (GLAPIENTRY *qglCompressedTexSubImage1DARB)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
 void (GLAPIENTRY *qglGetCompressedTexImageARB)(GLenum target, GLint lod, void *img);
 
 void (GLAPIENTRY *qglCompressedTexSubImage1DARB)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
 void (GLAPIENTRY *qglGetCompressedTexImageARB)(GLenum target, GLint lod, void *img);
 
+void (GLAPIENTRY *qglGenQueriesARB)(GLsizei n, GLuint *ids);
+void (GLAPIENTRY *qglDeleteQueriesARB)(GLsizei n, const GLuint *ids);
+GLboolean (GLAPIENTRY *qglIsQueryARB)(GLuint qid);
+void (GLAPIENTRY *qglBeginQueryARB)(GLenum target, GLuint qid);
+void (GLAPIENTRY *qglEndQueryARB)(GLenum target);
+void (GLAPIENTRY *qglGetQueryivARB)(GLenum target, GLenum pname, GLint *params);
+void (GLAPIENTRY *qglGetQueryObjectivARB)(GLuint qid, GLenum pname, GLint *params);
+void (GLAPIENTRY *qglGetQueryObjectuivARB)(GLuint qid, GLenum pname, GLuint *params);
+
 int GL_CheckExtension(const char *name, const dllfunction_t *funcs, const char *disableparm, int silent)
 {
        int failed = false;
 int GL_CheckExtension(const char *name, const dllfunction_t *funcs, const char *disableparm, int silent)
 {
        int failed = false;
@@ -705,6 +716,19 @@ static dllfunction_t texturecompressionfuncs[] =
        {NULL, NULL}
 };
 
        {NULL, NULL}
 };
 
+static dllfunction_t occlusionqueryfuncs[] =
+{
+       {"glGenQueriesARB",              (void **) &qglGenQueriesARB},
+       {"glDeleteQueriesARB",           (void **) &qglDeleteQueriesARB},
+       {"glIsQueryARB",                 (void **) &qglIsQueryARB},
+       {"glBeginQueryARB",              (void **) &qglBeginQueryARB},
+       {"glEndQueryARB",                (void **) &qglEndQueryARB},
+       {"glGetQueryivARB",              (void **) &qglGetQueryivARB},
+       {"glGetQueryObjectivARB",        (void **) &qglGetQueryObjectivARB},
+       {"glGetQueryObjectuivARB",       (void **) &qglGetQueryObjectuivARB},
+       {NULL, NULL}
+};
+
 void VID_CheckExtensions(void)
 {
        gl_stencil = vid_bitsperpixel.integer == 32;
 void VID_CheckExtensions(void)
 {
        gl_stencil = vid_bitsperpixel.integer == 32;
@@ -734,6 +758,7 @@ void VID_CheckExtensions(void)
        gl_support_fragment_shader = false;
        gl_support_arb_vertex_buffer_object = false;
        gl_support_texture_compression = false;
        gl_support_fragment_shader = false;
        gl_support_arb_vertex_buffer_object = false;
        gl_support_texture_compression = false;
+       gl_support_arb_occlusion_query = false;
 
        if (!GL_CheckExtension("OpenGL 1.1.0", opengl110funcs, NULL, false))
                Sys_Error("OpenGL 1.1.0 functions not found");
 
        if (!GL_CheckExtension("OpenGL 1.1.0", opengl110funcs, NULL, false))
                Sys_Error("OpenGL 1.1.0 functions not found");
@@ -813,6 +838,9 @@ void VID_CheckExtensions(void)
                        if ((gl_support_vertex_shader = GL_CheckExtension("GL_ARB_vertex_shader", vertexshaderfuncs, "-novertexshader", false)))
                                gl_support_fragment_shader = GL_CheckExtension("GL_ARB_fragment_shader", NULL, "-nofragmentshader", false);
        CHECKGLERROR
                        if ((gl_support_vertex_shader = GL_CheckExtension("GL_ARB_vertex_shader", vertexshaderfuncs, "-novertexshader", false)))
                                gl_support_fragment_shader = GL_CheckExtension("GL_ARB_fragment_shader", NULL, "-nofragmentshader", false);
        CHECKGLERROR
+
+// COMMANDLINEOPTION: GL: -noocclusionquery disables GL_ARB_occlusion_query (which allows coronas to fade according to visibility, and potentially used for rendering optimizations)
+       gl_support_arb_occlusion_query = GL_CheckExtension("GL_ARB_occlusion_query", occlusionqueryfuncs, "-noocclusionquery", false);
 }
 
 void Force_CenterView_f (void)
 }
 
 void Force_CenterView_f (void)