]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
fixed totally mixed up vis culling (as a result of botched bmodel vis handling -...
[xonotic/darkplaces.git] / r_shadow.c
index 6ae16157bde85a0aeebf9ccbdfc263b2b16a3689..5ff000047040e6f0547fb6d20b11a7372b6f7fd9 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"};
@@ -205,11 +205,10 @@ int c_rtcached_shadowmeshes, c_rtcached_shadowtris;
 
 float r_shadow_attenpower, r_shadow_attenscale;
 
-float varray_vertex3f2[65536*3];
-
 rtlight_t *r_shadow_compilingrtlight;
 dlight_t *r_shadow_worldlightchain;
 dlight_t *r_shadow_selectedlight;
+dlight_t r_shadow_bufferlight;
 vec3_t r_editlights_cursorlocation;
 
 rtexture_t *lighttextures[5];
@@ -392,7 +391,7 @@ void R_Shadow_Init(void)
        }
        Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
        R_Shadow_EditLights_Init();
-       r_shadow_mempool = Mem_AllocPool("R_Shadow");
+       r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
        r_shadow_worldlightchain = NULL;
        maxshadowelements = 0;
        shadowelements = NULL;
@@ -908,7 +907,7 @@ void R_Shadow_Stage_ShadowVolumes(void)
        // optimize for them as noted above
 }
 
-void R_Shadow_Stage_LightWithoutShadows(void)
+void R_Shadow_Stage_Light(int shadowtest)
 {
        rmeshstate_t m;
        memset(&m, 0, sizeof(m));
@@ -919,35 +918,14 @@ void R_Shadow_Stage_LightWithoutShadows(void)
        qglPolygonOffset(0, 0);
        //qglDisable(GL_POLYGON_OFFSET_FILL);
        GL_Color(1, 1, 1, 1);
-       GL_ColorMask(1, 1, 1, 1);
+       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
        qglDepthFunc(GL_EQUAL);
        qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
        qglEnable(GL_CULL_FACE);
-       qglDisable(GL_STENCIL_TEST);
-       if (gl_support_stenciltwoside)
-               qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
-       qglStencilMask(~0);
-       qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
-       qglStencilFunc(GL_EQUAL, 128, ~0);
-       r_shadowstage = SHADOWSTAGE_LIGHT;
-       c_rt_lights++;
-}
-
-void R_Shadow_Stage_LightWithShadows(void)
-{
-       rmeshstate_t m;
-       memset(&m, 0, sizeof(m));
-       R_Mesh_State(&m);
-       GL_BlendFunc(GL_ONE, GL_ONE);
-       GL_DepthMask(false);
-       GL_DepthTest(true);
-       qglPolygonOffset(0, 0);
-       //qglDisable(GL_POLYGON_OFFSET_FILL);
-       GL_Color(1, 1, 1, 1);
-       GL_ColorMask(1, 1, 1, 1);
-       qglDepthFunc(GL_EQUAL);
-       qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
-       qglEnable(GL_STENCIL_TEST);
+       if (shadowtest)
+               qglEnable(GL_STENCIL_TEST);
+       else
+               qglDisable(GL_STENCIL_TEST);
        if (gl_support_stenciltwoside)
                qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
        qglStencilMask(~0);
@@ -970,7 +948,7 @@ void R_Shadow_Stage_End(void)
        qglPolygonOffset(0, 0);
        //qglDisable(GL_POLYGON_OFFSET_FILL);
        GL_Color(1, 1, 1, 1);
-       GL_ColorMask(1, 1, 1, 1);
+       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
        GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
        qglDepthFunc(GL_LEQUAL);
        qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
@@ -1239,10 +1217,12 @@ static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const fl
        }
 }
 
-#define USETEXMATRIX 1
+// TODO: use glTexGen instead of feeding vertices to texcoordpointer?
+#define USETEXMATRIX
+
 #ifndef USETEXMATRIX
-// FIXME: this should be done in a texture matrix or vertex program when possible
-// FIXME: if vertex program not available, this would really benefit from 3DNow! or SSE
+// this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
+// if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
 {
        do
@@ -1338,7 +1318,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                m.pointer_texcoord3f[1] = varray_texcoord3f[1];
                                R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
                                m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                m.pointer_texcoord3f[2] = vertex3f;
                                m.texmatrix[2] = *matrix_modeltoattenuationxyz;
 #else
@@ -1361,7 +1341,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                if (lightcubemap)
                                {
                                        m.texcubemap[1] = R_GetTexture(lightcubemap);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
                                        m.texmatrix[1] = *matrix_modeltolight;
 #else
@@ -1376,7 +1356,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                memset(&m, 0, sizeof(m));
                                m.pointer_vertex = vertex3f;
                                m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                m.pointer_texcoord3f[0] = vertex3f;
                                m.texmatrix[0] = *matrix_modeltoattenuationxyz;
 #else
@@ -1416,7 +1396,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                if (lightcubemap)
                                {
                                        m.texcubemap[1] = R_GetTexture(lightcubemap);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
                                        m.texmatrix[1] = *matrix_modeltolight;
 #else
@@ -1451,7 +1431,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                m.tex[0] = R_GetTexture(basetexture);
                                m.pointer_texcoord[0] = texcoord2f;
                                m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                m.pointer_texcoord3f[1] = vertex3f;
                                m.texmatrix[1] = *matrix_modeltoattenuationxyz;
 #else
@@ -1472,7 +1452,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                m.pointer_texcoord3f[1] = varray_texcoord3f[1];
                                R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
                                m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                m.pointer_texcoord3f[2] = vertex3f;
                                m.texmatrix[2] = *matrix_modeltoattenuationxyz;
 #else
@@ -1480,7 +1460,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
 #endif
                                m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                m.pointer_texcoord3f[3] = vertex3f;
                                m.texmatrix[3] = *matrix_modeltoattenuationz;
 #else
@@ -1503,7 +1483,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                if (lightcubemap)
                                {
                                        m.texcubemap[1] = R_GetTexture(lightcubemap);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
                                        m.texmatrix[1] = *matrix_modeltolight;
 #else
@@ -1518,7 +1498,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                memset(&m, 0, sizeof(m));
                                m.pointer_vertex = vertex3f;
                                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                m.pointer_texcoord3f[0] = vertex3f;
                                m.texmatrix[0] = *matrix_modeltoattenuationxyz;
 #else
@@ -1526,7 +1506,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
 #endif
                                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                m.pointer_texcoord3f[1] = vertex3f;
                                m.texmatrix[1] = *matrix_modeltoattenuationz;
 #else
@@ -1566,7 +1546,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                if (lightcubemap)
                                {
                                        m.texcubemap[1] = R_GetTexture(lightcubemap);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
                                        m.texmatrix[1] = *matrix_modeltolight;
 #else
@@ -1577,7 +1557,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                        }
                        // this final code is shared
                        R_Mesh_State(&m);
-                       GL_ColorMask(1,1,1,0);
+                       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
                        GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                        VectorScale(lightcolor, colorscale, color2);
                        for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
@@ -1641,7 +1621,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                        memset(&m, 0, sizeof(m));
                                        m.pointer_vertex = vertex3f;
                                        m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[0] = vertex3f;
                                        m.texmatrix[0] = *matrix_modeltoattenuationxyz;
 #else
@@ -1663,7 +1643,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                        if (lightcubemap)
                                        {
                                                m.texcubemap[1] = R_GetTexture(lightcubemap);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                                m.pointer_texcoord3f[1] = vertex3f;
                                                m.texmatrix[1] = *matrix_modeltolight;
 #else
@@ -1716,7 +1696,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                        m.tex[0] = R_GetTexture(glosstexture);
                                        m.pointer_texcoord[0] = texcoord2f;
                                        m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
                                        m.texmatrix[1] = *matrix_modeltoattenuationxyz;
 #else
@@ -1766,7 +1746,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                        memset(&m, 0, sizeof(m));
                                        m.pointer_vertex = vertex3f;
                                        m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[0] = vertex3f;
                                        m.texmatrix[0] = *matrix_modeltoattenuationxyz;
 #else
@@ -1774,7 +1754,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                        R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
 #endif
                                        m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
                                        m.texmatrix[1] = *matrix_modeltoattenuationz;
 #else
@@ -1796,7 +1776,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                        if (lightcubemap)
                                        {
                                                m.texcubemap[1] = R_GetTexture(lightcubemap);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                                m.pointer_texcoord3f[1] = vertex3f;
                                                m.texmatrix[1] = *matrix_modeltolight;
 #else
@@ -1807,7 +1787,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                }
                        }
                        R_Mesh_State(&m);
-                       GL_ColorMask(1,1,1,0);
+                       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
                        GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                        VectorScale(lightcolor, colorscale, color2);
                        GL_LockArrays(0, numverts);
@@ -1836,7 +1816,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                        {
                                // voodoo2
                                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                m.pointer_texcoord3f[1] = vertex3f;
                                m.texmatrix[1] = *matrix_modeltoattenuationxyz;
 #else
@@ -1847,7 +1827,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                                {
                                        // Geforce3/Radeon class but not using dot3
                                        m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
-#if USETEXMATRIX
+#ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[2] = vertex3f;
                                        m.texmatrix[2] = *matrix_modeltoattenuationz;
 #else
@@ -2204,10 +2184,7 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
 
        if (!visiblevolumes)
        {
-               if (shadow && gl_stencil)
-                       R_Shadow_Stage_LightWithShadows();
-               else
-                       R_Shadow_Stage_LightWithoutShadows();
+               R_Shadow_Stage_Light(shadow && gl_stencil);
 
                ent = &cl_entities[0].render;
                if (ent->model && ent->model->DrawLight)
@@ -2410,21 +2387,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)
        {
@@ -2436,8 +2417,6 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra
        if (cubemapname && cubemapname[0] && strlen(cubemapname) < sizeof(light->cubemapname))
                strcpy(light->cubemapname, 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);
 }
@@ -2593,7 +2572,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++;
                }
@@ -2683,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++;
                }
@@ -2693,11 +2672,14 @@ void R_Shadow_LoadLightsFile(void)
        }
 }
 
+// tyrlite/hmap2 light types in the delay field
+typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
+
 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
 {
-       int entnum, style, islight, skin, pflags, effects;
+       int entnum, style, islight, skin, pflags, effects, type, n;
        char key[256], value[1024];
-       float origin[3], angles[3], radius, color[3], light, fadescale, lightscale, originhack[3], overridecolor[3];
+       float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
        const char *data;
 
        if (cl.worldmodel == NULL)
@@ -2710,11 +2692,12 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                return;
        for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
        {
-               light = 0;
+               type = LIGHTTYPE_MINUSX;
                origin[0] = origin[1] = origin[2] = 0;
                originhack[0] = originhack[1] = originhack[2] = 0;
                angles[0] = angles[1] = angles[2] = 0;
                color[0] = color[1] = color[2] = 1;
+               light[0] = light[1] = light[2] = 1;light[3] = 300;
                overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
                fadescale = 1;
                lightscale = 1;
@@ -2741,7 +2724,27 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
 
                        // now that we have the key pair worked out...
                        if (!strcmp("light", key))
-                               light = atof(value);
+                       {
+                               n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
+                               if (n == 1)
+                               {
+                                       // quake
+                                       light[0] = vec[0] * (1.0f / 256.0f);
+                                       light[1] = vec[0] * (1.0f / 256.0f);
+                                       light[2] = vec[0] * (1.0f / 256.0f);
+                                       light[3] = vec[0];
+                               }
+                               else if (n == 4)
+                               {
+                                       // halflife
+                                       light[0] = vec[0] * (1.0f / 255.0f);
+                                       light[1] = vec[1] * (1.0f / 255.0f);
+                                       light[2] = vec[2] * (1.0f / 255.0f);
+                                       light[3] = vec[3];
+                               }
+                       }
+                       else if (!strcmp("delay", key))
+                               type = atoi(value);
                        else if (!strcmp("origin", key))
                                sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
                        else if (!strcmp("angle", key))
@@ -2838,28 +2841,45 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                        else if (!strcmp("effects", key))
                                effects = (int)atof(value);
                }
-               if (light <= 0 && islight)
-                       light = 300;
+               if (!islight)
+                       continue;
                if (lightscale <= 0)
                        lightscale = 1;
                if (fadescale <= 0)
                        fadescale = 1;
-               if (gamemode == GAME_TENEBRAE)
+               if (color[0] == color[1] && color[0] == color[2])
                {
-                       if (effects & EF_NODRAW)
-                       {
-                               pflags |= PFLAGS_FULLDYNAMIC;
-                               effects &= ~EF_NODRAW;
-                       }
+                       color[0] *= overridecolor[0];
+                       color[1] *= overridecolor[1];
+                       color[2] *= overridecolor[2];
+               }
+               radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
+               color[0] = color[0] * light[0];
+               color[1] = color[1] * light[1];
+               color[2] = color[2] * light[2];
+               switch (type)
+               {
+               case LIGHTTYPE_MINUSX:
+                       break;
+               case LIGHTTYPE_RECIPX:
+                       radius *= 2;
+                       VectorScale(color, (1.0f / 16.0f), color);
+                       break;
+               case LIGHTTYPE_RECIPXX:
+                       radius *= 2;
+                       VectorScale(color, (1.0f / 16.0f), color);
+                       break;
+               default:
+               case LIGHTTYPE_NONE:
+                       break;
+               case LIGHTTYPE_SUN:
+                       break;
+               case LIGHTTYPE_MINUSXX:
+                       break;
                }
-               radius = min(light * r_editlights_quakelightsizescale.value * lightscale / fadescale, 1048576);
-               light = sqrt(bound(0, light, 1048576)) * (1.0f / 16.0f);
-               if (color[0] == 1 && color[1] == 1 && color[2] == 1)
-                       VectorCopy(overridecolor, color);
-               VectorScale(color, light, color);
                VectorAdd(origin, originhack, origin);
-               if (radius >= 15 && !(pflags & PFLAGS_FULLDYNAMIC))
-                       R_Shadow_NewWorldLight(origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
+               if (radius >= 1)
+                       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);
        }
 }
 
@@ -2950,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)
@@ -3167,19 +3187,37 @@ 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)
+{
+       dlight_t *light;
+
+       if (!r_editlights.integer)
+       {
+               Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
+               return;
+       }
+
+       for (light = r_shadow_worldlightchain;light;light = light->next)
+       {
+               R_Shadow_SelectLight(light);
+               R_Shadow_EditLights_Edit_f();
+       }
 }
 
 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
 {
        float x, y;
        char temp[256];
-       if (r_shadow_selectedlight == NULL)
+       if (!r_editlights.integer)
                return;
        x = 0;
        y = con_vislines;
+       sprintf(temp, "Cursor  %f %f %f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+       if (r_shadow_selectedlight == NULL)
+               return;
        sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
        sprintf(temp, "Origin  %f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
        sprintf(temp, "Angles  %f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
@@ -3203,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)
@@ -3220,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)
@@ -3288,6 +3322,45 @@ void R_Shadow_EditLights_Help_f(void)
        );
 }
 
+void R_Shadow_EditLights_CopyInfo_f(void)
+{
+       if (!r_editlights.integer)
+       {
+               Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
+               return;
+       }
+       if (!r_shadow_selectedlight)
+       {
+               Con_Print("No selected light.\n");
+               return;
+       }
+       VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
+       VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
+       r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
+       r_shadow_bufferlight.style = r_shadow_selectedlight->style;
+       if (r_shadow_selectedlight->cubemapname)
+               strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
+       else
+               r_shadow_bufferlight.cubemapname[0] = 0;
+       r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
+       r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
+}
+
+void R_Shadow_EditLights_PasteInfo_f(void)
+{
+       if (!r_editlights.integer)
+       {
+               Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
+               return;
+       }
+       if (!r_shadow_selectedlight)
+       {
+               Con_Print("No selected light.\n");
+               return;
+       }
+       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)
 {
        Cvar_RegisterVariable(&r_editlights);
@@ -3304,10 +3377,13 @@ void R_Shadow_EditLights_Init(void)
        Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
        Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
        Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
+       Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
        Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
        Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
        Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
        Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
        Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
+       Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
+       Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);
 }