]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
APPEND forced args, not PREPEND, as earlier arguments win in most DP options.
[xonotic/darkplaces.git] / r_shadow.c
index 1e6aa9a7a3645373e2c3e61d79ed3afe93c5eadc..33c3005fe3c36385479a1143301b7ac09d3340e0 100644 (file)
@@ -442,6 +442,12 @@ void R_Shadow_SetShadowMode(void)
                                        r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
                                break;
                        }
+                       // Cg has very little choice in depth texture sampling
+                       if (vid.cgcontext)
+                       {
+                               r_shadow_shadowmapsampler = false;
+                               r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
+                       }
                }
                break;
        case RENDERPATH_GL13:
@@ -1507,19 +1513,48 @@ int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
        }
        // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
        // check if frustum corners/origin cross plane sides
+#if 1
+    // infinite version, assumes frustum corners merely give direction and extend to infinite distance
+    Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
+    dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
+    masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
+    masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
+    dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
+    masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
+    masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
+    dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
+    masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
+    masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
+    for (i = 0;i < 4;i++)
+    {
+        Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
+        VectorSubtract(n, p, n);
+        dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
+        if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
+        if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
+        dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
+        if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
+        if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
+        dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
+        if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
+        if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
+    }
+#else
+    // finite version, assumes corners are a finite distance from origin dependent on far plane
        for (i = 0;i < 5;i++)
        {
                Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
-               dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
+               dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
                masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
                masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
-               dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
+               dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
                masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
                masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
-               dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
+               dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
                masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
                masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
        }
+#endif
        return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
 }
 
@@ -2108,15 +2143,15 @@ void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
        nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
        farclip = 1.0f;
        bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
-       r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
-       r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
+       r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
+       r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
        r_shadow_shadowmapside = side;
        r_shadow_shadowmapsize = size;
        switch (r_shadow_shadowmode)
        {
        case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
                r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
-               r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
+               r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
                R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
                if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
 
@@ -2133,7 +2168,7 @@ void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
                break;
        case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
                r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
-               r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
+               r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
                R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
                if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
 
@@ -2150,7 +2185,7 @@ void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
                break;
        case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
                r_shadow_shadowmap_parameters[0] = 1.0f;
-               r_shadow_shadowmap_parameters[1] = 1.0f;
+               r_shadow_shadowmap_parameters[2] = 1.0f;
                R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
                if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
 
@@ -3456,19 +3491,19 @@ void R_Shadow_PrepareLight(rtlight_t *rtlight)
        static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
        static entity_render_t *shadowentities[MAX_EDICTS];
        static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
+       qboolean nolight;
 
        rtlight->draw = false;
 
        // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
        // skip lights that are basically invisible (color 0 0 0)
-       if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
-               return;
+       nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
 
        // loading is done before visibility checks because loading should happen
        // all at once at the start of a level, not when it stalls gameplay.
        // (especially important to benchmarks)
        // compile light
-       if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
+       if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
        {
                if (rtlight->compiled)
                        R_RTLight_Uncompile(rtlight);
@@ -3493,6 +3528,10 @@ void R_Shadow_PrepareLight(rtlight_t *rtlight)
        if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
                return;
 
+       // skip processing on corona-only lights
+       if (nolight)
+               return;
+
        // if the light box is offscreen, skip it
        if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
                return;
@@ -4203,12 +4242,13 @@ extern cvar_t r_shadows_castfrombmodels;
 extern cvar_t r_shadows_throwdistance;
 extern cvar_t r_shadows_throwdirection;
 extern cvar_t r_shadows_focus;
+extern cvar_t r_shadows_shadowmapscale;
 
 void R_Shadow_PrepareModelShadows(void)
 {
        int i;
        float scale, size, radius, dot1, dot2;
-       vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowmins, shadowmaxs;
+       vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
        entity_render_t *ent;
 
        if (!r_refdef.scene.numentities)
@@ -4218,7 +4258,9 @@ void R_Shadow_PrepareModelShadows(void)
        {
        case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
        case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
-               break;
+               if (r_shadows.integer >= 2) 
+                       break;
+               // fall through
        case R_SHADOW_SHADOWMODE_STENCIL:
                for (i = 0;i < r_refdef.scene.numentities;i++)
                {
@@ -4232,8 +4274,9 @@ void R_Shadow_PrepareModelShadows(void)
        }
 
        size = 2*r_shadow_shadowmapmaxsize;
-       scale = r_shadow_shadowmapping_precision.value;
+       scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
        radius = 0.5f * size / scale;
+
        Math_atov(r_shadows_throwdirection.string, shadowdir);
        VectorNormalize(shadowdir);
        dot1 = DotProduct(r_refdef.view.forward, shadowdir);
@@ -4244,8 +4287,13 @@ void R_Shadow_PrepareModelShadows(void)
                VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
        VectorNormalize(shadowforward);
        CrossProduct(shadowdir, shadowforward, shadowright);
-       Math_atov(r_shadows_focus.string, shadoworigin);
+       Math_atov(r_shadows_focus.string, shadowfocus);
+       VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
+       VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
+       VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
        VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
+       if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
+               dot1 = 1;
        VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
 
        shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
@@ -4269,14 +4317,14 @@ void R_Shadow_PrepareModelShadows(void)
 void R_DrawModelShadowMaps(void)
 {
        int i;
-       float relativethrowdistance, scale, size, radius, nearclip, farclip, dot1, dot2;
+       float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
        entity_render_t *ent;
        vec3_t relativelightorigin;
        vec3_t relativelightdirection, relativeforward, relativeright;
        vec3_t relativeshadowmins, relativeshadowmaxs;
-       vec3_t shadowdir, shadowforward, shadowright, shadoworigin;
+       vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
        float m[12];
-       matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix;
+       matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
        r_viewport_t viewport;
        GLuint fbo = 0;
 
@@ -4320,19 +4368,23 @@ void R_DrawModelShadowMaps(void)
        }
 
        size = 2*r_shadow_shadowmapmaxsize;
-
-       r_shadow_shadowmap_parameters[0] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
-       r_shadow_shadowmap_parameters[1] = 1.0f;
-       r_shadow_shadowmap_parameters[2] = size;
-       r_shadow_shadowmap_parameters[3] = size;
-
-       scale = r_shadow_shadowmapping_precision.value;
-       radius = 0.5f * size / scale;
+       scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
+       radius = 0.5f / scale;
        nearclip = -r_shadows_throwdistance.value;
        farclip = r_shadows_throwdistance.value;
+       bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
+
+       r_shadow_shadowmap_parameters[0] = size;
+       r_shadow_shadowmap_parameters[1] = size;
+       r_shadow_shadowmap_parameters[2] = 1.0;
+       r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
+
        Math_atov(r_shadows_throwdirection.string, shadowdir);
        VectorNormalize(shadowdir);
-       Math_atov(r_shadows_focus.string, shadoworigin);
+       Math_atov(r_shadows_focus.string, shadowfocus);
+       VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
+       VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
+       VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
        VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
        dot1 = DotProduct(r_refdef.view.forward, shadowdir);
        dot2 = DotProduct(r_refdef.view.up, shadowdir);
@@ -4342,15 +4394,17 @@ void R_DrawModelShadowMaps(void)
                VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
        VectorNormalize(shadowforward);
        VectorM(scale, shadowforward, &m[0]);
-       m[3] = fabs(dot1) * 0.5f * size - DotProduct(shadoworigin, &m[0]);
+       if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
+               dot1 = 1;
+       m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
        CrossProduct(shadowdir, shadowforward, shadowright);
        VectorM(scale, shadowright, &m[4]);
-       m[7] = 0.5f * size - DotProduct(shadoworigin, &m[4]);
+       m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
        VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
        m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
        Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
        Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
-       R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, size, size, 0, 0, -1, NULL); 
+       R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL); 
 
        VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
  
@@ -4377,10 +4431,6 @@ void R_DrawModelShadowMaps(void)
        GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
        CHECKGLERROR
 
-       r_refdef.view.cullface_front = r_shadow_cullface_back;
-       r_refdef.view.cullface_back = r_shadow_cullface_front;
-       GL_CullFace(r_refdef.view.cullface_back);
-
        for (i = 0;i < r_refdef.scene.numentities;i++)
        {
                ent = r_refdef.scene.entities[i];
@@ -4409,7 +4459,10 @@ void R_DrawModelShadowMaps(void)
 
        Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
        Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
-       Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &shadowmatrix, &invmvpmatrix);
+       Matrix4x4_CreateScale3(&scalematrix, size, -size, 1); 
+       Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
+       Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
+       Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
 
        r_shadow_usingshadowmaportho = true;
        switch (r_shadow_shadowmode)
@@ -4435,7 +4488,7 @@ void R_DrawModelShadows(void)
        vec3_t relativeshadowmins, relativeshadowmaxs;
        vec3_t tmp, shadowdir;
 
-       if (!r_refdef.scene.numentities || !vid.stencil || r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL)
+       if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
                return;
 
        CHECKGLERROR
@@ -4475,26 +4528,34 @@ void R_DrawModelShadows(void)
                        {
                                if(ent->entitynumber != 0)
                                {
-                                       // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
-                                       int entnum, entnum2, recursion;
-                                       entnum = entnum2 = ent->entitynumber;
-                                       for(recursion = 32; recursion > 0; --recursion)
+                                       if(ent->entitynumber >= MAX_EDICTS) // csqc entity
                                        {
-                                               entnum2 = cl.entities[entnum].state_current.tagentity;
-                                               if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
-                                                       entnum = entnum2;
-                                               else
-                                                       break;
+                                               // FIXME handle this
+                                               VectorNegate(ent->modellight_lightdir, relativelightdirection);
                                        }
-                                       if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
+                                       else
                                        {
-                                               VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
-                                               // transform into modelspace of OUR entity
-                                               Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
-                                               Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
+                                               // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
+                                               int entnum, entnum2, recursion;
+                                               entnum = entnum2 = ent->entitynumber;
+                                               for(recursion = 32; recursion > 0; --recursion)
+                                               {
+                                                       entnum2 = cl.entities[entnum].state_current.tagentity;
+                                                       if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
+                                                               entnum = entnum2;
+                                                       else
+                                                               break;
+                                               }
+                                               if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
+                                               {
+                                                       VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
+                                                       // transform into modelspace of OUR entity
+                                                       Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
+                                                       Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
+                                               }
+                                               else
+                                                       VectorNegate(ent->modellight_lightdir, relativelightdirection);
                                        }
-                                       else
-                                               VectorNegate(ent->modellight_lightdir, relativelightdirection);
                                }
                                else
                                        VectorNegate(ent->modellight_lightdir, relativelightdirection);