X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=r_shadow.c;h=5ff000047040e6f0547fb6d20b11a7372b6f7fd9;hb=8e199f361385dcd993117e6fb3b4e4fea0b22182;hp=0b1ec40795b3a775b0e6c45482ce4122a3cc3d46;hpb=3b8b31726da557e99a3019ce561482d175ae2f5a;p=xonotic%2Fdarkplaces.git diff --git a/r_shadow.c b/r_shadow.c index 0b1ec407..5ff00004 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -125,7 +125,6 @@ extern void R_Shadow_EditLights_Init(void); #define SHADOWSTAGE_STENCILTWOSIDE 3 int r_shadowstage = SHADOWSTAGE_NONE; -int r_shadow_reloadlights = false; mempool_t *r_shadow_mempool; @@ -159,6 +158,9 @@ rtexture_t *r_shadow_blankbumptexture; rtexture_t *r_shadow_blankglosstexture; rtexture_t *r_shadow_blankwhitetexture; +// lights are reloaded when this changes +char r_shadow_mapname[MAX_QPATH]; + // used only for light filters (cubemaps) rtexturepool_t *r_shadow_filters_texturepool; @@ -166,43 +168,89 @@ 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"}; cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"}; cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"}; -cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0"}; -cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "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"}; cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"}; cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"}; cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"}; cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"}; cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"}; +cvar_t r_editlights = {0, "r_editlights", "0"}; +cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"}; +cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"}; +cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"}; +cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"}; +cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"}; +cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"}; +cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"}; int c_rt_lights, c_rt_clears, c_rt_scissored; int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris; int c_rtcached_shadowmeshes, c_rtcached_shadowtris; +float r_shadow_attenpower, r_shadow_attenscale; + +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]; + +extern int con_vislines; + +typedef struct cubemapinfo_s +{ + char basename[64]; + rtexture_t *texture; +} +cubemapinfo_t; + +#define MAX_CUBEMAPS 256 +static int numcubemaps; +static cubemapinfo_t cubemaps[MAX_CUBEMAPS]; + +void R_Shadow_UncompileWorldLights(void); void R_Shadow_ClearWorldLights(void); void R_Shadow_SaveWorldLights(void); void R_Shadow_LoadWorldLights(void); void R_Shadow_LoadLightsFile(void); void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void); +void R_Shadow_EditLights_Reload_f(void); +void R_Shadow_ValidateCvars(void); +static void R_Shadow_MakeTextures(void); +void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light); void r_shadow_start(void) { // allocate vertex processing arrays - r_shadow_mempool = Mem_AllocPool("R_Shadow"); + numcubemaps = 0; + r_shadow_normalcubetexture = NULL; + r_shadow_attenuation2dtexture = NULL; + r_shadow_attenuation3dtexture = NULL; + r_shadow_blankbumptexture = NULL; + r_shadow_blankglosstexture = NULL; + r_shadow_blankwhitetexture = NULL; + r_shadow_texturepool = NULL; + r_shadow_filters_texturepool = NULL; + R_Shadow_ValidateCvars(); + R_Shadow_MakeTextures(); maxshadowelements = 0; shadowelements = NULL; maxvertexupdate = 0; @@ -220,22 +268,12 @@ void r_shadow_start(void) r_shadow_buffer_numsurfacepvsbytes = 0; r_shadow_buffer_surfacepvs = NULL; r_shadow_buffer_surfacelist = NULL; - r_shadow_normalcubetexture = NULL; - r_shadow_attenuation2dtexture = NULL; - r_shadow_attenuation3dtexture = NULL; - r_shadow_blankbumptexture = NULL; - r_shadow_blankglosstexture = NULL; - r_shadow_blankwhitetexture = NULL; - r_shadow_texturepool = NULL; - r_shadow_filters_texturepool = NULL; - R_Shadow_ClearWorldLights(); - r_shadow_reloadlights = true; } void r_shadow_shutdown(void) { - R_Shadow_ClearWorldLights(); - r_shadow_reloadlights = true; + R_Shadow_UncompileWorldLights(); + numcubemaps = 0; r_shadow_normalcubetexture = NULL; r_shadow_attenuation2dtexture = NULL; r_shadow_attenuation3dtexture = NULL; @@ -245,29 +283,44 @@ void r_shadow_shutdown(void) R_FreeTexturePool(&r_shadow_texturepool); R_FreeTexturePool(&r_shadow_filters_texturepool); maxshadowelements = 0; + if (shadowelements) + Mem_Free(shadowelements); shadowelements = NULL; maxvertexupdate = 0; + if (vertexupdate) + Mem_Free(vertexupdate); vertexupdate = NULL; + if (vertexremap) + Mem_Free(vertexremap); vertexremap = NULL; vertexupdatenum = 0; maxshadowmark = 0; numshadowmark = 0; + if (shadowmark) + Mem_Free(shadowmark); shadowmark = NULL; + if (shadowmarklist) + Mem_Free(shadowmarklist); shadowmarklist = NULL; shadowmarkcount = 0; r_shadow_buffer_numclusterpvsbytes = 0; + if (r_shadow_buffer_clusterpvs) + Mem_Free(r_shadow_buffer_clusterpvs); r_shadow_buffer_clusterpvs = NULL; + if (r_shadow_buffer_clusterlist) + Mem_Free(r_shadow_buffer_clusterlist); r_shadow_buffer_clusterlist = NULL; r_shadow_buffer_numsurfacepvsbytes = 0; + if (r_shadow_buffer_surfacepvs) + Mem_Free(r_shadow_buffer_surfacepvs); r_shadow_buffer_surfacepvs = NULL; + if (r_shadow_buffer_surfacelist) + Mem_Free(r_shadow_buffer_surfacelist); r_shadow_buffer_surfacelist = NULL; - Mem_FreePool(&r_shadow_mempool); } void r_shadow_newmap(void) { - R_Shadow_ClearWorldLights(); - r_shadow_reloadlights = true; } void R_Shadow_Help_f(void) @@ -284,8 +337,6 @@ void R_Shadow_Help_f(void) "r_shadow_lightattenuationpower : used to generate attenuation texture\n" "r_shadow_lightattenuationscale : used to generate attenuation texture\n" "r_shadow_lightintensityscale : scale rendering brightness of all lights\n" -"r_shadow_polygonfactor : nudge shadow volumes closer/further\n" -"r_shadow_polygonoffset : nudge shadow volumes closer/further\n" "r_shadow_portallight : use portal visibility for static light precomputation\n" "r_shadow_projectdistance : shadow volume projection distance\n" "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n" @@ -295,6 +346,8 @@ void R_Shadow_Help_f(void) "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n" "r_shadow_realtime_world_shadows : cast shadows from world lights\n" "r_shadow_scissor : use scissor optimization\n" +"r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n" +"r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n" "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n" "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n" "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n" @@ -315,8 +368,6 @@ void R_Shadow_Init(void) Cvar_RegisterVariable(&r_shadow_lightattenuationpower); Cvar_RegisterVariable(&r_shadow_lightattenuationscale); Cvar_RegisterVariable(&r_shadow_lightintensityscale); - Cvar_RegisterVariable(&r_shadow_polygonfactor); - Cvar_RegisterVariable(&r_shadow_polygonoffset); Cvar_RegisterVariable(&r_shadow_portallight); Cvar_RegisterVariable(&r_shadow_projectdistance); Cvar_RegisterVariable(&r_shadow_realtime_dlight); @@ -326,6 +377,8 @@ void R_Shadow_Init(void) Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps); Cvar_RegisterVariable(&r_shadow_realtime_world_shadows); Cvar_RegisterVariable(&r_shadow_scissor); + Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor); + Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset); Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration); Cvar_RegisterVariable(&r_shadow_staticworldlights); Cvar_RegisterVariable(&r_shadow_texture3d); @@ -338,6 +391,25 @@ 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", 0, NULL); + r_shadow_worldlightchain = NULL; + maxshadowelements = 0; + shadowelements = NULL; + maxvertexupdate = 0; + vertexupdate = NULL; + vertexremap = NULL; + vertexupdatenum = 0; + maxshadowmark = 0; + numshadowmark = 0; + shadowmark = NULL; + shadowmarklist = NULL; + shadowmarkcount = 0; + r_shadow_buffer_numclusterpvsbytes = 0; + r_shadow_buffer_clusterpvs = NULL; + r_shadow_buffer_clusterlist = NULL; + r_shadow_buffer_numsurfacepvsbytes = 0; + r_shadow_buffer_surfacepvs = NULL; + r_shadow_buffer_surfacelist = NULL; R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap); } @@ -535,8 +607,6 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int * return tris; } -float varray_vertex3f2[65536*3]; - void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, int nummarktris, const int *marktris) { int tris, outverts; @@ -620,7 +690,6 @@ void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *verte GL_LockArrays(0, 0); } -float r_shadow_attenpower, r_shadow_attenscale; static void R_Shadow_MakeTextures(void) { int x, y, z, d, side; @@ -749,14 +818,19 @@ static void R_Shadow_MakeTextures(void) Mem_Free(data); } -void R_Shadow_Stage_Begin(void) +void R_Shadow_ValidateCvars(void) { - rmeshstate_t m; - if (r_shadow_texture3d.integer && !gl_texture3d) Cvar_SetValueQuick(&r_shadow_texture3d, 0); if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside) Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0); +} + +void R_Shadow_Stage_Begin(void) +{ + rmeshstate_t m; + + R_Shadow_ValidateCvars(); if (!r_shadow_attenuation2dtexture || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer) @@ -780,22 +854,6 @@ void R_Shadow_Stage_Begin(void) c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0; } -void R_Shadow_LoadWorldLightsIfNeeded(void) -{ - if (r_shadow_reloadlights && cl.worldmodel) - { - R_Shadow_ClearWorldLights(); - r_shadow_reloadlights = false; - R_Shadow_LoadWorldLights(); - if (r_shadow_worldlightchain == NULL) - { - R_Shadow_LoadLightsFile(); - if (r_shadow_worldlightchain == NULL) - R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(); - } - } -} - void R_Shadow_Stage_ShadowVolumes(void) { rmeshstate_t m; @@ -806,10 +864,10 @@ void R_Shadow_Stage_ShadowVolumes(void) GL_BlendFunc(GL_ONE, GL_ZERO); GL_DepthMask(false); GL_DepthTest(true); - qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value); - //if (r_shadow_polygonoffset.value != 0) + qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value); + //if (r_shadow_shadow_polygonoffset.value != 0) //{ - // qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value); + // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value); // qglEnable(GL_POLYGON_OFFSET_FILL); //} //else @@ -849,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)); @@ -860,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); @@ -911,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 @@ -1108,7 +1145,7 @@ static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float * if ((dot = DotProduct(n, v)) > 0) { dist = sqrt(dist); - intensity = dot / (VectorLength(v) * VectorLength(n)); + intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n)); intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale; VectorScale(lightcolor, intensity, color4f); color4f[3] = 1; @@ -1139,7 +1176,7 @@ static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *ve Matrix4x4_Transform3x3(m, normal3f, n); if ((dot = DotProduct(n, v)) > 0) { - intensity = dot / (VectorLength(v) * VectorLength(n)); + intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n)); intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale; VectorScale(lightcolor, intensity, color4f); color4f[3] = 1; @@ -1168,7 +1205,7 @@ static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const fl Matrix4x4_Transform3x3(m, normal3f, n); if ((dot = DotProduct(n, v)) > 0) { - intensity = dot / (VectorLength(v) * VectorLength(n)); + intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n)); VectorScale(lightcolor, intensity, color4f); color4f[3] = 1; } @@ -1180,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 @@ -1279,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 @@ -1302,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 @@ -1317,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 @@ -1357,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 @@ -1392,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 @@ -1413,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 @@ -1421,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 @@ -1444,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 @@ -1459,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 @@ -1467,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 @@ -1507,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 @@ -1518,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]--) @@ -1582,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 @@ -1604,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 @@ -1657,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 @@ -1707,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 @@ -1715,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 @@ -1737,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 @@ -1748,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); @@ -1777,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 @@ -1788,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 @@ -1862,8 +1901,6 @@ void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int i rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2; } -rtlight_t *r_shadow_compilingrtlight; - // compiles rtlight geometry // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls) void R_RTLight_Compile(rtlight_t *rtlight) @@ -1971,9 +2008,12 @@ void R_RTLight_Uncompile(rtlight_t *rtlight) } } -int shadowframecount = 0; - -void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light); +void R_Shadow_UncompileWorldLights(void) +{ + dlight_t *light; + for (light = r_shadow_worldlightchain;light;light = light->next) + R_RTLight_Uncompile(&light->rtlight); +} void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes) { @@ -1990,18 +2030,24 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes) shadowmesh_t *mesh; rmeshstate_t m; - if (d_lightstylevalue[rtlight->style] <= 0) - return; + // 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) + if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer) + R_RTLight_Compile(rtlight); + if (rtlight->cubemapname[0]) + cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname); + else + cubemaptexture = NULL; + cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius; cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius; cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius; cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius; cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius; cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius; - if (R_CullBox(cullmins, cullmaxs)) + if (d_lightstylevalue[rtlight->style] <= 0) return; - if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer) - R_RTLight_Compile(rtlight); numclusters = 0; clusterlist = NULL; clusterpvs = NULL; @@ -2009,6 +2055,8 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes) surfacelist = NULL; if (rtlight->compiled && r_shadow_staticworldlights.integer) { + // compiled light, world available and can receive realtime lighting + // retrieve cluster information numclusters = rtlight->static_numclusters; clusterlist = rtlight->static_clusterlist; clusterpvs = rtlight->static_clusterpvs; @@ -2017,6 +2065,11 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes) } else if (cl.worldmodel && cl.worldmodel->GetLightInfo) { + // dynamic light, world available and can receive realtime lighting + // if the light box is offscreen, skip it right away + if (R_CullBox(cullmins, cullmaxs)) + return; + // calculate lit surfaces and clusters R_Shadow_EnlargeClusterBuffer(cl.worldmodel->brush.num_pvsclusters); R_Shadow_EnlargeSurfaceBuffer(cl.worldmodel->nummodelsurfaces); cl.worldmodel->GetLightInfo(&cl_entities[0].render, rtlight->shadoworigin, rtlight->radius, cullmins, cullmaxs, r_shadow_buffer_clusterlist, r_shadow_buffer_clusterpvs, &numclusters, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces); @@ -2024,6 +2077,10 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes) clusterpvs = r_shadow_buffer_clusterpvs; surfacelist = r_shadow_buffer_surfacelist; } + // if the reduced cluster bounds are offscreen, skip it + if (R_CullBox(cullmins, cullmaxs)) + return; + // check if light is illuminating any visible clusters if (numclusters) { for (i = 0;i < numclusters;i++) @@ -2032,8 +2089,7 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes) if (i == numclusters) return; } - if (R_CullBox(cullmins, cullmaxs)) - return; + // set up a scissor rectangle for this light if (R_Shadow_ScissorForBBox(cullmins, cullmaxs)) return; @@ -2047,11 +2103,6 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes) } */ - if (rtlight->cubemapname[0]) - cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname); - else - cubemaptexture = NULL; - #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 @@ -2133,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) @@ -2180,6 +2228,9 @@ void R_ShadowVolumeLighting(int visiblevolumes) dlight_t *light; rmeshstate_t m; + if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname))) + R_Shadow_EditLights_Reload_f(); + if (visiblevolumes) { memset(&m, 0, sizeof(m)); @@ -2193,10 +2244,8 @@ void R_ShadowVolumeLighting(int visiblevolumes) } else R_Shadow_Stage_Begin(); - shadowframecount++; if (r_shadow_realtime_world.integer) { - R_Shadow_LoadWorldLightsIfNeeded(); if (r_shadow_debuglight.integer >= 0) { for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next) @@ -2220,38 +2269,23 @@ void R_ShadowVolumeLighting(int visiblevolumes) R_Shadow_Stage_End(); } -cvar_t r_editlights = {0, "r_editlights", "0"}; -cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"}; -cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"}; -cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"}; -cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"}; -cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"}; -cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"}; -cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"}; -dlight_t *r_shadow_worldlightchain; -dlight_t *r_shadow_selectedlight; -vec3_t r_editlights_cursorlocation; - -typedef struct cubemapinfo_s -{ - char basename[64]; - rtexture_t *texture; -} -cubemapinfo_t; - -#define MAX_CUBEMAPS 128 -static int numcubemaps; -static cubemapinfo_t cubemaps[MAX_CUBEMAPS]; - //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"}; typedef struct suffixinfo_s { char *suffix; - int flipx, flipy, flipdiagonal; + qboolean flipx, flipy, flipdiagonal; } suffixinfo_t; static suffixinfo_t suffix[3][6] = { + { + {"px", false, false, false}, + {"nx", false, false, false}, + {"py", false, false, false}, + {"ny", false, false, false}, + {"pz", false, false, false}, + {"nz", false, false, false} + }, { {"posx", false, false, false}, {"negx", false, false, false}, @@ -2261,20 +2295,12 @@ static suffixinfo_t suffix[3][6] = {"negz", false, false, false} }, { - {"px", false, false, false}, - {"nx", false, false, false}, - {"py", false, false, false}, - {"ny", false, false, false}, - {"pz", false, false, false}, - {"nz", false, false, false} - }, - { - {"ft", true, false, true}, - {"bk", false, true, true}, - {"lf", true, true, false}, - {"rt", false, false, false}, - {"up", false, false, false}, - {"dn", false, false, false} + {"rt", true, false, true}, + {"lf", false, true, true}, + {"ft", true, true, false}, + {"bk", false, false, false}, + {"up", true, false, true}, + {"dn", true, false, true} } }; @@ -2290,30 +2316,39 @@ rtexture_t *R_Shadow_LoadCubemap(const char *basename) cubemapsize = 0; cubemappixels = NULL; cubemaptexture = NULL; + // keep trying different suffix groups (posx, px, rt) until one loads for (j = 0;j < 3 && !cubemappixels;j++) { + // load the 6 images in the suffix group for (i = 0;i < 6;i++) { + // generate an image name based on the base and and suffix snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix); + // load it if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize))) { + // an image loaded, make sure width and height are equal if (image_width == image_height) { + // if this is the first image to load successfully, allocate the cubemap memory if (!cubemappixels && image_width >= 1) { cubemapsize = image_width; - // note this clears to black, so unavailable sizes are black + // note this clears to black, so unavailable sides are black cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4); } + // copy the image with any flipping needed by the suffix (px and posx types don't need flipping) if (cubemappixels) Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_rgba, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder); } else Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height); + // free the image Mem_Free(image_rgba); } } } + // if a cubemap loaded, upload it if (cubemappixels) { if (!r_shadow_filters_texturepool) @@ -2352,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) { @@ -2378,22 +2417,18 @@ 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); - if (r_shadow_staticworldlights.integer) - R_RTLight_Compile(&light->rtlight); } void R_Shadow_FreeWorldLight(dlight_t *light) { dlight_t **lightpointer; + R_RTLight_Uncompile(&light->rtlight); for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next); if (*lightpointer != light) Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n"); *lightpointer = light->next; - R_RTLight_Uncompile(&light->rtlight); Mem_Free(light); } @@ -2414,8 +2449,6 @@ void R_Shadow_SelectLight(dlight_t *light) r_shadow_selectedlight->selected = true; } -rtexture_t *lighttextures[5]; - void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2) { float scale = r_editlights_cursorgrid.value * 0.5f; @@ -2539,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++; } @@ -2629,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++; } @@ -2639,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) @@ -2656,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; @@ -2687,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)) @@ -2784,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); } } @@ -2850,13 +2924,24 @@ void R_Shadow_EditLights_Clear_f(void) void R_Shadow_EditLights_Reload_f(void) { - r_shadow_reloadlights = true; + if (!cl.worldmodel) + return; + strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname)); + R_Shadow_ClearWorldLights(); + R_Shadow_LoadWorldLights(); + if (r_shadow_worldlightchain == NULL) + { + R_Shadow_LoadLightsFile(); + if (r_shadow_worldlightchain == NULL) + R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(); + } } void R_Shadow_EditLights_Save_f(void) { - if (cl.worldmodel) - R_Shadow_SaveWorldLights(); + if (!cl.worldmodel) + return; + R_Shadow_SaveWorldLights(); } void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void) @@ -2885,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) @@ -3102,20 +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(); + } } -extern int con_vislines; 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; @@ -3139,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) @@ -3156,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) @@ -3224,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); @@ -3240,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); }