]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
-Added static, global baseDC and baseRC variables to avoid having to call
[xonotic/darkplaces.git] / r_shadow.c
index 66ceaa7ae02eaa434130625eca350f3a6fadbdfb..12da8519697f9a36a7c57870b689fbd4ea6e45a9 100644 (file)
@@ -168,7 +168,7 @@ cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0
 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
-cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"};
+cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
@@ -176,12 +176,12 @@ cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1
 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
-cvar_t r_shadow_realtime_dlight = {0, "r_shadow_realtime_dlight", "1"};
-cvar_t r_shadow_realtime_dlight_shadows = {0, "r_shadow_realtime_dlight_shadows", "0"};
-cvar_t r_shadow_realtime_world = {0, "r_shadow_realtime_world", "0"};
-cvar_t r_shadow_realtime_world_dlightshadows = {0, "r_shadow_realtime_world_dlightshadows", "1"};
-cvar_t r_shadow_realtime_world_lightmaps = {0, "r_shadow_realtime_world_lightmaps", "0"};
-cvar_t r_shadow_realtime_world_shadows = {0, "r_shadow_realtime_world_shadows", "1"};
+cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
+cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "0"};
+cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
+cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
+cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
+cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
@@ -503,8 +503,9 @@ void R_Shadow_PrepareShadowMark(int numtris)
 int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
 {
        int i, j, tris = 0, vr[3], t, outvertices = 0;
-       const int *e, *n;
        float f, temp[3];
+       const int *e, *n;
+       const float *v;
 
        if (maxvertexupdate < innumvertices)
        {
@@ -525,10 +526,12 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *
                memset(vertexremap, 0, maxvertexupdate * sizeof(int));
        }
        
+       for (i = 0;i < numshadowmarktris;i++)
+               shadowmark[shadowmarktris[i]] = shadowmarkcount;
+
        for (i = 0;i < numshadowmarktris;i++)
        {
                t = shadowmarktris[i];
-               shadowmark[t] = shadowmarkcount;
                e = inelement3i + t * 3;
                // make sure the vertices are created
                for (j = 0;j < 3;j++)
@@ -537,14 +540,24 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *
                        {
                                vertexupdate[e[j]] = vertexupdatenum;
                                vertexremap[e[j]] = outvertices;
-                               VectorSubtract(invertex3f + e[j] * 3, projectorigin, temp);
+                               v = invertex3f + e[j] * 3;
+                               // project one copy of the vertex to the sphere radius of the light
+                               // (FIXME: would projecting it to the light box be better?)
+                               VectorSubtract(v, projectorigin, temp);
                                f = projectdistance / VectorLength(temp);
-                               VectorCopy(invertex3f + e[j] * 3, outvertex3f);
+                               VectorCopy(v, outvertex3f);
                                VectorMA(projectorigin, f, temp, (outvertex3f + 3));
                                outvertex3f += 6;
                                outvertices += 2;
                        }
                }
+       }
+
+       for (i = 0;i < numshadowmarktris;i++)
+       {
+               t = shadowmarktris[i];
+               e = inelement3i + t * 3;
+               n = inneighbor3i + t * 3;
                // output the front and back triangles
                outelement3i[0] = vertexremap[e[0]];
                outelement3i[1] = vertexremap[e[1]];
@@ -554,13 +567,6 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *
                outelement3i[5] = vertexremap[e[0]] + 1;
                outelement3i += 6;
                tris += 2;
-       }
-
-       for (i = 0;i < numshadowmarktris;i++)
-       {
-               t = shadowmarktris[i];
-               e = inelement3i + t * 3;
-               n = inneighbor3i + t * 3;
                // output the sides (facing outward from this triangle)
                if (shadowmark[n[0]] != shadowmarkcount)
                {
@@ -624,39 +630,41 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f,
        R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
 }
 
-void R_Shadow_VolumeFromBox(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, const vec3_t mins, const vec3_t maxs)
+void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, vec3_t lightmins, vec3_t lightmaxs, vec3_t surfacemins, vec3_t surfacemaxs)
 {
-       int i;
+       int t, tend;
+       const int *e;
        const float *v[3];
-
-       // check which triangles are facing the , and then output
-       // triangle elements and vertices...  by clever use of elements we
-       // can construct the whole shadow from the unprojected vertices and
-       // the projected vertices
-
-       // identify lit faces within the bounding box
-       R_Shadow_PrepareShadowMark(numtris);
-       for (i = 0;i < numtris;i++)
+       if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
+               return;
+       tend = firsttriangle + numtris;
+       if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
+        && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
+        && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
        {
-               v[0] = invertex3f + elements[i*3+0] * 3;
-               v[1] = invertex3f + elements[i*3+1] * 3;
-               v[2] = invertex3f + elements[i*3+2] * 3;
-               if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]) && maxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && mins[0] < max(v[0][0], max(v[1][0], v[2][0])) && maxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && mins[1] < max(v[0][1], max(v[1][1], v[2][1])) && maxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && mins[2] < max(v[0][2], max(v[1][2], v[2][2])))
-                       shadowmarklist[numshadowmark++] = i;
+               // surface box entirely inside light box, no box cull
+               for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
+                       if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
+                               shadowmarklist[numshadowmark++] = t;
+       }
+       else
+       {
+               // surface box not entirely inside light box, cull each triangle
+               for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
+               {
+                       v[0] = invertex3f + e[0] * 3;
+                       v[1] = invertex3f + e[1] * 3;
+                       v[2] = invertex3f + e[2] * 3;
+                       if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
+                        && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
+                        && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
+                        && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
+                        && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
+                        && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
+                        && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
+                               shadowmarklist[numshadowmark++] = t;
+               }
        }
-       R_Shadow_VolumeFromList(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, numshadowmark, shadowmarklist);
-}
-
-void R_Shadow_VolumeFromSphere(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, float radius)
-{
-       vec3_t mins, maxs;
-       mins[0] = projectorigin[0] - radius;
-       mins[1] = projectorigin[1] - radius;
-       mins[2] = projectorigin[2] - radius;
-       maxs[0] = projectorigin[0] + radius;
-       maxs[1] = projectorigin[1] + radius;
-       maxs[2] = projectorigin[2] + radius;
-       R_Shadow_VolumeFromBox(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, mins, maxs);
 }
 
 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
@@ -1290,6 +1298,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                bumptexture = r_shadow_blankbumptexture;
        if (!glosstexture)
                glosstexture = r_shadow_blankglosstexture;
+       // FIXME: support EF_NODEPTHTEST
        GL_DepthMask(false);
        GL_DepthTest(true);
        if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
@@ -2020,7 +2029,7 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
        int i, shadow;
        entity_render_t *ent;
        float f;
-       vec3_t relativelightorigin, relativeeyeorigin, lightcolor;
+       vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
        rtexture_t *cubemaptexture;
        matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
        int numclusters, numsurfaces;
@@ -2103,23 +2112,7 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
        }
        */
 
-#if 1
-       shadow = rtlight->shadow && (rtlight->isstatic ? r_shadow_realtime_world_shadows.integer : (r_shadow_realtime_world.integer ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer));
-#else
-       shadow = false;
-       if (rtlight->shadow)
-       {
-               if (rtlight->isstatic)
-                       shadow = r_shadow_realtime_world_shadows.integer;
-               else
-               {
-                       if (r_shadow_realtime_world.integer)
-                               shadow = r_shadow_realtime_world_dlightshadows.integer;
-                       else
-                               shadow = r_shadow_realtime_dlight_shadows.integer;
-               }
-       }
-#endif
+       shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
 
        if (shadow && (gl_stencil || visiblevolumes))
        {
@@ -2187,7 +2180,7 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
                R_Shadow_Stage_Light(shadow && gl_stencil);
 
                ent = &cl_entities[0].render;
-               if (ent->model && ent->model->DrawLight)
+               if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
                {
                        Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
                        Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
@@ -2208,14 +2201,17 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
                        for (i = 0;i < r_refdef.numentities;i++)
                        {
                                ent = r_refdef.entities[i];
-                               if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
+                               // can't draw transparent entity lighting here because
+                               // transparent meshes are deferred for later
+                               if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & (RENDER_LIGHT | RENDER_TRANSPARENT)) == RENDER_LIGHT)
                                {
+                                       VectorScale(lightcolor, ent->alpha, lightcolor2);
                                        Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
                                        Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
                                        Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
                                        Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
                                        Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
-                                       ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->nummodelsurfaces, ent->model->surfacelist);
+                                       ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->nummodelsurfaces, ent->model->surfacelist);
                                }
                        }
                }
@@ -2244,7 +2240,7 @@ void R_ShadowVolumeLighting(int visiblevolumes)
        }
        else
                R_Shadow_Stage_Begin();
-       if (r_shadow_realtime_world.integer)
+       if (r_rtworld)
        {
                if (r_shadow_debuglight.integer >= 0)
                {
@@ -2256,7 +2252,7 @@ void R_ShadowVolumeLighting(int visiblevolumes)
                        for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
                                R_DrawRTLight(&light->rtlight, visiblevolumes);
        }
-       if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
+       if (r_rtdlight)
                for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
                        R_DrawRTLight(&light->rtlight, visiblevolumes);
 
@@ -2387,21 +2383,25 @@ void R_Shadow_FreeCubemaps(void)
        R_FreeTexturePool(&r_shadow_filters_texturepool);
 }
 
-void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname)
+dlight_t *R_Shadow_NewWorldLight(void)
 {
        dlight_t *light;
-
-       if (radius < 15 || DotProduct(color, color) < 0.03)
-       {
-               Con_Print("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
-               return;
-       }
-
        light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
+       light->next = r_shadow_worldlightchain;
+       r_shadow_worldlightchain = light;
+       return light;
+}
+
+void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname)
+{
        VectorCopy(origin, light->origin);
-       VectorCopy(angles, light->angles);
-       VectorCopy(color, light->color);
-       light->radius = radius;
+       light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
+       light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
+       light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
+       light->color[0] = max(color[0], 0);
+       light->color[1] = max(color[1], 0);
+       light->color[2] = max(color[2], 0);
+       light->radius = max(radius, 0);
        light->style = style;
        if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
        {
@@ -2410,11 +2410,10 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra
        }
        light->shadow = shadowenable;
        light->corona = corona;
-       if (cubemapname && cubemapname[0] && strlen(cubemapname) < sizeof(light->cubemapname))
-               strcpy(light->cubemapname, cubemapname);
+       if (!cubemapname)
+               cubemapname = "";
+       strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
        Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
-       light->next = r_shadow_worldlightchain;
-       r_shadow_worldlightchain = light;
 
        R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
 }
@@ -2479,8 +2478,8 @@ void R_Shadow_DrawLightSprites(void)
                        lighttextures[i] = pic->tex;
        }
 
-       for (light = r_shadow_worldlightchain;light;light = light->next)
-               R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5);
+       for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
+               R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
        R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
 }
 
@@ -2570,7 +2569,7 @@ void R_Shadow_LoadWorldLights(void)
                        }
                        VectorScale(color, r_editlights_rtlightscolorscale.value, color);
                        radius *= r_editlights_rtlightssizescale.value;
-                       R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadow, cubemapname);
+                       R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname);
                        s++;
                        n++;
                }
@@ -2600,7 +2599,10 @@ void R_Shadow_SaveWorldLights(void)
        buf = NULL;
        for (light = r_shadow_worldlightchain;light;light = light->next)
        {
-               sprintf(line, "%s%f %f %f %f %f %f %f %d %s %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname[0] ? light->cubemapname : "\"\"", light->corona, light->angles[0], light->angles[1], light->angles[2]);
+               if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
+                       sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
+               else
+                       sprintf(line, "%s%f %f %f %f %f %f %f %d\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style);
                if (bufchars + (int) strlen(line) > bufmaxchars)
                {
                        bufmaxchars = bufchars + strlen(line) + 2048;
@@ -2660,7 +2662,7 @@ void R_Shadow_LoadLightsFile(void)
                        radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
                        radius = bound(15, radius, 4096);
                        VectorScale(color, (2.0f / (8388608.0f)), color);
-                       R_Shadow_NewWorldLight(origin, vec3_origin, color, radius, 0, style, true, NULL);
+                       R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL);
                        s++;
                        n++;
                }
@@ -2877,7 +2879,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                }
                VectorAdd(origin, originhack, origin);
                if (radius >= 1)
-                       R_Shadow_NewWorldLight(origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
+                       R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
        }
 }
 
@@ -2968,7 +2970,7 @@ void R_Shadow_EditLights_Spawn_f(void)
                return;
        }
        color[0] = color[1] = color[2] = 1;
-       R_Shadow_NewWorldLight(r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
+       R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
 }
 
 void R_Shadow_EditLights_Edit_f(void)
@@ -3185,9 +3187,7 @@ void R_Shadow_EditLights_Edit_f(void)
                Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
                return;
        }
-       R_Shadow_FreeWorldLight(r_shadow_selectedlight);
-       r_shadow_selectedlight = NULL;
-       R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadows, cubemapname);
+       R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname);
 }
 
 void R_Shadow_EditLights_EditAll_f(void)
@@ -3241,9 +3241,7 @@ void R_Shadow_EditLights_ToggleShadow_f(void)
                Con_Print("No selected light.\n");
                return;
        }
-       R_Shadow_NewWorldLight(r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname);
-       R_Shadow_FreeWorldLight(r_shadow_selectedlight);
-       r_shadow_selectedlight = NULL;
+       R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname);
 }
 
 void R_Shadow_EditLights_ToggleCorona_f(void)
@@ -3258,9 +3256,7 @@ void R_Shadow_EditLights_ToggleCorona_f(void)
                Con_Print("No selected light.\n");
                return;
        }
-       R_Shadow_NewWorldLight(r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname);
-       R_Shadow_FreeWorldLight(r_shadow_selectedlight);
-       r_shadow_selectedlight = NULL;
+       R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname);
 }
 
 void R_Shadow_EditLights_Remove_f(void)
@@ -3352,8 +3348,6 @@ void R_Shadow_EditLights_CopyInfo_f(void)
 
 void R_Shadow_EditLights_PasteInfo_f(void)
 {
-       vec3_t origin;
-       VectorCopy(r_shadow_selectedlight->origin, origin);
        if (!r_editlights.integer)
        {
                Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
@@ -3364,9 +3358,7 @@ void R_Shadow_EditLights_PasteInfo_f(void)
                Con_Print("No selected light.\n");
                return;
        }
-       R_Shadow_FreeWorldLight(r_shadow_selectedlight);
-       r_shadow_selectedlight = NULL;
-       R_Shadow_NewWorldLight(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_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);
 }
 
 void R_Shadow_EditLights_Init(void)