+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;
+ 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;
+ if (r_waterstate.renderingscene)
+ return;
+ flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
+ R_Mesh_Matrix(&identitymatrix);
+
+ 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;
+ 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 (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
+ continue;
+ 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];
+ rtlight->corona_visibility = 0;
+ rtlight->corona_queryindex_visiblepixels = 0;
+ rtlight->corona_queryindex_allpixels = 0;
+ if (!(rtlight->flags & flag))
+ continue;
+ if (rtlight->corona <= 0)
+ continue;
+ 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 = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+ if (!light)
+ continue;
+ rtlight = &light->rtlight;
+ if (rtlight->corona_visibility <= 0)
+ continue;
+ 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;
+ 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);
+ }
+}
+
+