]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
CL_VM_GetLight: allow 2'nd optional parm which sets sampling mask: 1 lightmap (defaul...
[xonotic/darkplaces.git] / r_shadow.c
index 8e6958522cdb9fcc4763ea084bcdd7e512f7a973..279736d37fc42db58fa2cd36a881fab6f454745a 100644 (file)
@@ -312,6 +312,7 @@ cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nea
 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
+cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
 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 OpenGL 2.0 render path)"};
@@ -668,6 +669,7 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
+       Cvar_RegisterVariable(&r_shadow_sortsurfaces);
        Cvar_RegisterVariable(&r_shadow_polygonfactor);
        Cvar_RegisterVariable(&r_shadow_polygonoffset);
        Cvar_RegisterVariable(&r_shadow_texture3d);
@@ -2286,131 +2288,21 @@ int bboxedges[12][2] =
 
 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
 {
-       int i, ix1, iy1, ix2, iy2;
-       float x1, y1, x2, y2;
-       vec4_t v, v2;
-       float vertex[20][3];
-       int j, k;
-       vec4_t plane4f;
-       int numvertices;
-       float corner[8][4];
-       float dist[8];
-       int sign[8];
-       float f;
-
-       r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
-       r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
-       r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
-       r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
-
        if (!r_shadow_scissor.integer)
-               return false;
-
-       // if view is inside the light box, just say yes it's visible
-       if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
-               return false;
-
-       x1 = y1 = x2 = y2 = 0;
-
-       // transform all corners that are infront of the nearclip plane
-       VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
-       plane4f[3] = r_refdef.view.frustum[4].dist;
-       numvertices = 0;
-       for (i = 0;i < 8;i++)
-       {
-               Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
-               dist[i] = DotProduct4(corner[i], plane4f);
-               sign[i] = dist[i] > 0;
-               if (!sign[i])
-               {
-                       VectorCopy(corner[i], vertex[numvertices]);
-                       numvertices++;
-               }
-       }
-       // if some points are behind the nearclip, add clipped edge points to make
-       // sure that the scissor boundary is complete
-       if (numvertices > 0 && numvertices < 8)
-       {
-               // add clipped edge points
-               for (i = 0;i < 12;i++)
-               {
-                       j = bboxedges[i][0];
-                       k = bboxedges[i][1];
-                       if (sign[j] != sign[k])
-                       {
-                               f = dist[j] / (dist[j] - dist[k]);
-                               VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
-                               numvertices++;
-                       }
-               }
-       }
-
-       // if we have no points to check, the light is behind the view plane
-       if (!numvertices)
-               return true;
-
-       // if we have some points to transform, check what screen area is covered
-       x1 = y1 = x2 = y2 = 0;
-       v[3] = 1.0f;
-       //Con_Printf("%i vertices to transform...\n", numvertices);
-       for (i = 0;i < numvertices;i++)
-       {
-               VectorCopy(vertex[i], v);
-               R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
-               //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
-               if (i)
-               {
-                       if (x1 > v2[0]) x1 = v2[0];
-                       if (x2 < v2[0]) x2 = v2[0];
-                       if (y1 > v2[1]) y1 = v2[1];
-                       if (y2 < v2[1]) y2 = v2[1];
-               }
-               else
-               {
-                       x1 = x2 = v2[0];
-                       y1 = y2 = v2[1];
-               }
-       }
-
-       // now convert the scissor rectangle to integer screen coordinates
-       ix1 = (int)(x1 - 1.0f);
-       iy1 = vid.height - (int)(y2 - 1.0f);
-       ix2 = (int)(x2 + 1.0f);
-       iy2 = vid.height - (int)(y1 + 1.0f);
-       //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
-
-       // clamp it to the screen
-       if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
-       if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
-       if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
-       if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
-
-       // if it is inside out, it's not visible
-       if (ix2 <= ix1 || iy2 <= iy1)
-               return true;
-
-       // the light area is visible, set up the scissor rectangle
-       r_shadow_lightscissor[0] = ix1;
-       r_shadow_lightscissor[1] = iy1;
-       r_shadow_lightscissor[2] = ix2 - ix1;
-       r_shadow_lightscissor[3] = iy2 - iy1;
-
-       // D3D Y coordinate is top to bottom, OpenGL is bottom to top, fix the D3D one
-       switch(vid.renderpath)
        {
-       case RENDERPATH_D3D9:
-       case RENDERPATH_D3D10:
-       case RENDERPATH_D3D11:
-               r_shadow_lightscissor[1] = vid.height - r_shadow_lightscissor[1] - r_shadow_lightscissor[3];
-               break;
-       case RENDERPATH_GL11:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
-               break;
+               r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
+               r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
+               r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
+               r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
+               return false;
        }
-
-       r_refdef.stats.lights_scissored++;
+       if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
+               return true; // invisible
+       if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
+       || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
+       || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
+       || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
+               r_refdef.stats.lights_scissored++;
        return false;
 }
 
@@ -3928,7 +3820,7 @@ void R_Shadow_DrawPrepass(void)
        {
                lightindex = r_shadow_debuglight.integer;
                light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
-               if (light && (light->flags & flag))
+               if (light && (light->flags & flag) && light->rtlight.draw)
                        R_Shadow_DrawLight(&light->rtlight);
        }
        else
@@ -3937,13 +3829,14 @@ void R_Shadow_DrawPrepass(void)
                for (lightindex = 0;lightindex < range;lightindex++)
                {
                        light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
-                       if (light && (light->flags & flag))
+                       if (light && (light->flags & flag) && light->rtlight.draw)
                                R_Shadow_DrawLight(&light->rtlight);
                }
        }
        if (r_refdef.scene.rtdlight)
                for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
-                       R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
+                       if (r_refdef.scene.lights[lnum]->draw)
+                               R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
 
        R_Mesh_ResetRenderTargets();
 
@@ -6111,31 +6004,72 @@ LIGHT SAMPLING
 =============================================================================
 */
 
-void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
+void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, const int flags)
 {
+       int i, numlights, flag;
+       float f, relativepoint[3], dist, dist2, lightradius2;
+       rtlight_t *light;
+       dlight_t *dlight;
+
        VectorClear(diffusecolor);
        VectorClear(diffusenormal);
 
-       if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
+       if (flags & LP_LIGHTMAP)
        {
-               ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
-               r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
+               if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
+               {
+                       ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
+                       r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
+               }
+               else
+                       VectorSet(ambientcolor, 1, 1, 1);
        }
-       else
-               VectorSet(ambientcolor, 1, 1, 1);
-
-       if (dynamic)
+       if (flags & LP_RTWORLD)
+       {
+               flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
+               numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
+               for (i = 0; i < numlights; i++)
+               {
+                       dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
+                       if (!dlight)
+                               continue;
+                       light = &dlight->rtlight;
+                       if (!(light->flags & flag))
+                               continue;
+                       // sample
+                       lightradius2 = light->radius * light->radius;
+                       VectorSubtract(light->shadoworigin, p, relativepoint);
+                       dist2 = VectorLength2(relativepoint);
+                       if (dist2 >= lightradius2)
+                               continue;
+                       dist = sqrt(dist2) / light->radius;
+                       f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
+                       if (f <= 0)
+                               continue;
+                       // todo: add to both ambient and diffuse
+                       if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
+                               VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
+               }
+       }
+       if (flags & LP_DYNLIGHT)
        {
-               int i;
-               float f, v[3];
-               rtlight_t *light;
+               // sample dlights
                for (i = 0;i < r_refdef.scene.numlights;i++)
                {
                        light = r_refdef.scene.lights[i];
-                       Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
-                       f = 1 - VectorLength2(v);
-                       if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
-                               VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
+                       // sample
+                       lightradius2 = light->radius * light->radius;
+                       VectorSubtract(light->shadoworigin, p, relativepoint);
+                       dist2 = VectorLength2(relativepoint);
+                       if (dist2 >= lightradius2)
+                               continue;
+                       dist = sqrt(dist2) / light->radius;
+                       f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
+                       if (f <= 0)
+                               continue;
+                       // todo: add to both ambient and diffuse
+                       if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
+                               VectorMA(ambientcolor, f, light->color, ambientcolor);
                }
        }
 }