]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
Attempt to fix issues with spectating / demos
[xonotic/darkplaces.git] / r_shadow.c
index bcc699cd111ac0134bdc6dc3c8835adb1ac3fac3..7fb56308f56f1b6dfb32680816db69a28617adeb 100644 (file)
@@ -349,6 +349,7 @@ static memexpandablearray_t r_shadow_worldlightsarray;
 dlight_t *r_shadow_selectedlight;
 dlight_t r_shadow_bufferlight;
 vec3_t r_editlights_cursorlocation;
+qboolean r_editlights_lockcursor;
 
 extern int con_vislines;
 
@@ -442,6 +443,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:
@@ -659,7 +666,7 @@ void r_shadow_newmap(void)
        if (r_editlights_sprcubemaplight)         R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
        if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
        if (r_editlights_sprselection)            R_SkinFrame_MarkUsed(r_editlights_sprselection);
-       if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
+       if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
                R_Shadow_EditLights_Reload_f();
 }
 
@@ -1507,19 +1514,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];
 }
 
@@ -3456,19 +3492,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 +3529,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;
@@ -4219,7 +4259,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++)
                {
@@ -4447,7 +4489,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
@@ -4487,26 +4529,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);
@@ -4881,7 +4931,8 @@ void R_Shadow_DrawLightSprites(void)
                if (light)
                        R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
        }
-       R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
+       if (!r_editlights_lockcursor)
+               R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
 }
 
 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
@@ -4913,6 +4964,9 @@ void R_Shadow_SelectLightInView(void)
        size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
        best = NULL;
        bestrating = 0;
+
+       if (r_editlights_lockcursor)
+               return;
        for (lightindex = 0;lightindex < range;lightindex++)
        {
                light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
@@ -4943,8 +4997,7 @@ void R_Shadow_LoadWorldLights(void)
                Con_Print("No map loaded.\n");
                return;
        }
-       FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
-       strlcat (name, ".rtlights", sizeof (name));
+       dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
        lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
        if (lightsstring)
        {
@@ -5054,8 +5107,7 @@ void R_Shadow_SaveWorldLights(void)
                Con_Print("No map loaded.\n");
                return;
        }
-       FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
-       strlcat (name, ".rtlights", sizeof (name));
+       dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
        bufchars = bufmaxchars = 0;
        buf = NULL;
        for (lightindex = 0;lightindex < range;lightindex++)
@@ -5103,8 +5155,7 @@ void R_Shadow_LoadLightsFile(void)
                Con_Print("No map loaded.\n");
                return;
        }
-       FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
-       strlcat (name, ".lights", sizeof (name));
+       dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
        lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
        if (lightsstring)
        {
@@ -5166,8 +5217,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                return;
        }
        // try to load a .ent file first
-       FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
-       strlcat (key, ".ent", sizeof (key));
+       dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
        data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
        // and if that is not found, fall back to the bsp file entity string
        if (!data)
@@ -5416,7 +5466,7 @@ void R_Shadow_EditLights_Reload_f(void)
 {
        if (!cl.worldmodel)
                return;
-       strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
+       strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
        R_Shadow_ClearWorldLights();
        R_Shadow_LoadWorldLights();
        if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
@@ -5781,7 +5831,7 @@ void R_Shadow_EditLights_Edit_f(void)
 void R_Shadow_EditLights_EditAll_f(void)
 {
        size_t lightindex;
-       dlight_t *light;
+       dlight_t *light, *oldselected;
        size_t range;
 
        if (!r_editlights.integer)
@@ -5790,6 +5840,7 @@ void R_Shadow_EditLights_EditAll_f(void)
                return;
        }
 
+       oldselected = r_shadow_selectedlight;
        // EditLights doesn't seem to have a "remove" command or something so:
        range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
        for (lightindex = 0;lightindex < range;lightindex++)
@@ -5800,6 +5851,8 @@ void R_Shadow_EditLights_EditAll_f(void)
                R_Shadow_SelectLight(light);
                R_Shadow_EditLights_Edit_f();
        }
+       // return to old selected (to not mess editing once selection is locked)
+       R_Shadow_SelectLight(oldselected);
 }
 
 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
@@ -5909,6 +5962,7 @@ void R_Shadow_EditLights_Help_f(void)
 "r_editlights_help : this help\n"
 "r_editlights_clear : remove all lights\n"
 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
+"r_editlights_lock : lock selection to current light, if already locked - unlock\n"
 "r_editlights_save : save to .rtlights file\n"
 "r_editlights_spawn : create a light with default settings\n"
 "r_editlights_edit command : edit selected light - more documentation below\n"
@@ -5993,6 +6047,26 @@ void R_Shadow_EditLights_PasteInfo_f(void)
        R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_bufferlight.angles, r_shadow_bufferlight.color, r_shadow_bufferlight.radius, r_shadow_bufferlight.corona, r_shadow_bufferlight.style, r_shadow_bufferlight.shadow, r_shadow_bufferlight.cubemapname, r_shadow_bufferlight.coronasizescale, r_shadow_bufferlight.ambientscale, r_shadow_bufferlight.diffusescale, r_shadow_bufferlight.specularscale, r_shadow_bufferlight.flags);
 }
 
+void R_Shadow_EditLights_Lock_f(void)
+{
+       if (!r_editlights.integer)
+       {
+               Con_Print("Cannot lock on light when not in editing mode.  Set r_editlights to 1.\n");
+               return;
+       }
+       if (r_editlights_lockcursor)
+       {
+               r_editlights_lockcursor = false;
+               return;
+       }
+       if (!r_shadow_selectedlight)
+       {
+               Con_Print("No selected light to lock on.\n");
+               return;
+       }
+       r_editlights_lockcursor = true;
+}
+
 void R_Shadow_EditLights_Init(void)
 {
        Cvar_RegisterVariable(&r_editlights);
@@ -6015,6 +6089,7 @@ void R_Shadow_EditLights_Init(void)
        Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
        Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
        Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f, "apply the stored properties onto the selected light (making it exactly identical except for origin)");
+       Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
 }