From 823d8a2d16635f92223b991cb36ae0104fb6d88e Mon Sep 17 00:00:00 2001 From: havoc Date: Mon, 1 Mar 2004 01:58:02 +0000 Subject: [PATCH] cleaned up rtlight handling, merging most code between world rtlights and dlights (which now could conceivably be compiled if static) moved R_ShadowVolumeLighting to r_shadow.c added RENDER_LIGHT flag to entity_render_t to make rtlighting optional per entity git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@3939 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_main.c | 2 + cl_parse.c | 4 +- client.h | 114 ++++++- gl_models.c | 4 +- gl_rmain.c | 225 +------------ gl_rsurf.c | 50 +-- model_shared.h | 7 +- protocol.h | 1 + r_light.c | 127 +++----- r_light.h | 24 +- r_shadow.c | 856 ++++++++++++++++++++++++++++++------------------- r_shadow.h | 60 +--- render.h | 1 + todo | 18 +- 14 files changed, 752 insertions(+), 741 deletions(-) diff --git a/cl_main.c b/cl_main.c index e45180f0..768397e1 100644 --- a/cl_main.c +++ b/cl_main.c @@ -832,6 +832,8 @@ void CL_LinkNetworkEntity(entity_t *e) && !(e->render.flags & RENDER_VIEWMODEL) && ((e - cl_entities) != cl.viewentity || (!cl.intermission && cl.protocol != PROTOCOL_NEHAHRAMOVIE && !cl_noplayershadow.integer))) e->render.flags |= RENDER_SHADOW; + if (!(e->render.effects & EF_FULLBRIGHT)) + e->render.flags |= RENDER_LIGHT; // as soon as player is known we can call V_CalcRefDef if ((e - cl_entities) == cl.viewentity) V_CalcRefdef(); diff --git a/cl_parse.c b/cl_parse.c index 0a1d5ede..04879f66 100644 --- a/cl_parse.c +++ b/cl_parse.c @@ -447,9 +447,9 @@ void CL_ParseServerInfo (void) // entire entity array was cleared, so just fill in a few fields ent->state_current.active = true; ent->render.model = cl.worldmodel = cl.model_precache[1]; - //ent->render.scale = 1; + ent->render.scale = 1; // some of the renderer still relies on scale ent->render.alpha = 1; - ent->render.flags = RENDER_SHADOW; + ent->render.flags = RENDER_SHADOW | RENDER_LIGHT; Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, 0, 0, 0, 0, 0, 0, 1); Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix); CL_BoundingBoxForEntity(&ent->render); diff --git a/client.h b/client.h index b8d6c279..2e8349e1 100644 --- a/client.h +++ b/client.h @@ -70,30 +70,120 @@ typedef struct } beam_t; -typedef struct +typedef struct rtlight_s { - // location - vec3_t origin; - // stop lighting after this time - vec_t die; - // color of light - vec3_t color; - // brightness (not really radius anymore) - vec_t radius; - // drop this each second - vec_t decay; + // shadow volumes are done entirely in model space, so there are no matrices for dealing with them... they just use the origin + + // note that the world to light matrices are inversely scaled (divided) by lightradius + + // core properties + // matrix for transforming world coordinates to light filter coordinates + matrix4x4_t matrix_worldtolight; + // based on worldtolight this transforms -1 to +1 to 0 to 1 for purposes + // of attenuation texturing in full 3D (Z result often ignored) + matrix4x4_t matrix_worldtoattenuationxyz; + // this transforms only the Z to S, and T is always 0.5 + matrix4x4_t matrix_worldtoattenuationz; + // typically 1 1 1, can be lower (dim) or higher (overbright) + vec3_t color; + // size of the light (remove?) + vec_t radius; + // light filter + char cubemapname[64]; + // whether light should render shadows + int shadow; + // intensity of corona to render + vec_t corona; + // light style to monitor for brightness + int style; + + // generated properties + // used only for shadow volumes + vec3_t shadoworigin; + // culling + vec3_t cullmins; + vec3_t cullmaxs; + // culling + vec_t cullradius; + // squared cullradius + vec_t cullradius2; + + // lightmap renderer stuff (remove someday!) + // the size of the light + vec_t lightmap_cullradius; + // the size of the light, squared + vec_t lightmap_cullradius2; + // the brightness of the light + vec3_t lightmap_light; + // to avoid sudden brightness change at cullradius, subtract this + vec_t lightmap_subtract; + + // static light info + // true if this light should be compiled as a static light + int isstatic; + // true if this is a compiled world light, cleared if the light changes + int compiled; + // premade shadow volumes and lit surfaces to render for world entity + shadowmesh_t *static_meshchain_shadow; + shadowmesh_t *static_meshchain_light; + // used for visibility testing (more exact than bbox) + int static_numclusters; + int *static_clusterindices; +} +rtlight_t; + +typedef struct dlight_s +{ + // destroy light after this time + // (dlight only) + vec_t die; // the entity that owns this light (can be NULL) + // (dlight only) struct entity_render_s *ent; - // orientation/scaling/location + // location + // (worldlight: saved to .rtlights file) + vec3_t origin; + // worldlight orientation + // (worldlight only) + // (worldlight: saved to .rtlights file) + vec3_t angles; + // dlight orientation/scaling/location + // (dlight only) matrix4x4_t matrix; + // color of light + // (worldlight: saved to .rtlights file) + vec3_t color; // cubemap number to use on this light + // (dlight only) int cubemapnum; + // cubemap name to use on this light + // (worldlight only) + // (worldlight: saved to .rtlights file) + char cubemapname[64]; + // make light flash while selected + // (worldlight only) + int selected; + // brightness (not really radius anymore) + // (worldlight: saved to .rtlights file) + vec_t radius; + // drop radius this much each second + // (dlight only) + vec_t decay; // light style which controls intensity of this light + // (worldlight: saved to .rtlights file) int style; // cast shadows + // (worldlight: saved to .rtlights file) int shadow; // corona intensity + // (worldlight: saved to .rtlights file) vec_t corona; + // linked list of world lights + // (worldlight only) + struct dlight_s *next; + // embedded rtlight struct for renderer + // (renderer only) + rtlight_t rtlight; } dlight_t; diff --git a/gl_models.c b/gl_models.c index 8757229b..ca8bdb7d 100644 --- a/gl_models.c +++ b/gl_models.c @@ -378,7 +378,7 @@ void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, v if (layer->flags & ALIASLAYER_SPECULAR) { c_alias_polys += mesh->num_triangles; - R_Shadow_SpecularLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, aliasvert_vertex3f, aliasvert_svector3f, aliasvert_tvector3f, aliasvert_normal3f, mesh->data_texcoord2f, relativelightorigin, relativeeyeorigin, lightradius, lightcolor2, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, layer->texture, layer->nmap, lightcubemap); + R_Shadow_SpecularLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, aliasvert_vertex3f, aliasvert_svector3f, aliasvert_tvector3f, aliasvert_normal3f, mesh->data_texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, layer->texture, layer->nmap, lightcubemap); } else if (layer->flags & ALIASLAYER_DIFFUSE) { @@ -407,7 +407,7 @@ void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, v lightcolor2[2] *= bcolor[2] * (1.0f / 255.0f); } c_alias_polys += mesh->num_triangles; - R_Shadow_DiffuseLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, aliasvert_vertex3f, aliasvert_svector3f, aliasvert_tvector3f, aliasvert_normal3f, mesh->data_texcoord2f, relativelightorigin, lightradius, lightcolor2, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, layer->texture, layer->nmap, lightcubemap); + R_Shadow_DiffuseLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, aliasvert_vertex3f, aliasvert_svector3f, aliasvert_tvector3f, aliasvert_normal3f, mesh->data_texcoord2f, relativelightorigin, lightcolor2, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, layer->texture, layer->nmap, lightcubemap); } } } diff --git a/gl_rmain.c b/gl_rmain.c index 8e5ae27c..90536563 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // r_main.c #include "quakedef.h" +#include "r_shadow.h" // used for dlight push checking and other things int r_framecount; @@ -55,13 +56,11 @@ unsigned short d_lightstylevalue[256]; cvar_t r_drawentities = {0, "r_drawentities","1"}; cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"}; -cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"}; cvar_t r_speeds = {0, "r_speeds","0"}; cvar_t r_fullbright = {0, "r_fullbright","0"}; cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"}; cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1"}; cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"}; -cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"}; cvar_t r_drawcollisionbrushes = {0, "r_drawcollisionbrushes", "0"}; cvar_t gl_fogenable = {0, "gl_fogenable", "0"}; @@ -249,14 +248,12 @@ void GL_Main_Init(void) Cmd_AddCommand("timerefresh", R_TimeRefresh_f); Cvar_RegisterVariable(&r_drawentities); Cvar_RegisterVariable(&r_drawviewmodel); - Cvar_RegisterVariable(&r_shadow_staticworldlights); Cvar_RegisterVariable(&r_speeds); Cvar_RegisterVariable(&r_fullbrights); Cvar_RegisterVariable(&r_wateralpha); Cvar_RegisterVariable(&r_dynamic); Cvar_RegisterVariable(&r_fullbright); Cvar_RegisterVariable(&r_textureunits); - Cvar_RegisterVariable(&r_shadow_cull); Cvar_RegisterVariable(&r_lerpsprites); Cvar_RegisterVariable(&r_lerpmodels); Cvar_RegisterVariable(&r_waterscroll); @@ -407,8 +404,6 @@ int R_CullBox(const vec3_t mins, const vec3_t maxs) return false; } -#define VIS_CullBox(mins,maxs) (R_CullBox((mins), (maxs)) || (cl.worldmodel && cl.worldmodel->brush.BoxTouchingPVS && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, r_pvsbits, (mins), (maxs)))) - //================================================================================== static void R_MarkEntities (void) @@ -508,224 +503,6 @@ void R_DrawModels(void) } } -#include "r_shadow.h" - -int shadowframecount = 0; - -void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t lightorigin, float cullradius, float lightradius, vec3_t lightmins, vec3_t lightmaxs, vec3_t clipmins, vec3_t clipmaxs, int lightmarked) -{ - vec3_t relativelightorigin; - // rough checks - if ((ent->flags & RENDER_SHADOW) && ent->model && ent->model->DrawShadowVolume && !(r_shadow_cull.integer && (ent->maxs[0] < lightmins[0] || ent->mins[0] > lightmaxs[0] || ent->maxs[1] < lightmins[1] || ent->mins[1] > lightmaxs[1] || ent->maxs[2] < lightmins[2] || ent->mins[2] > lightmaxs[2]))) - { - Matrix4x4_Transform(&ent->inversematrix, lightorigin, relativelightorigin); - ent->model->DrawShadowVolume (ent, relativelightorigin, lightradius); - } -} - -void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light); - -void R_ShadowVolumeLighting(int visiblevolumes) -{ - int i; - entity_render_t *ent; - int lnum; - float f, lightradius, cullradius; - vec3_t relativelightorigin, relativeeyeorigin, lightcolor, clipmins, clipmaxs; - worldlight_t *wl; - rdlight_t *rd; - rmeshstate_t m; - rtexture_t *cubemaptexture; - matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz; - - if (visiblevolumes) - { - memset(&m, 0, sizeof(m)); - R_Mesh_State_Texture(&m); - - GL_BlendFunc(GL_ONE, GL_ONE); - GL_DepthMask(false); - GL_DepthTest(r_shadow_visiblevolumes.integer < 2); - qglDisable(GL_CULL_FACE); - GL_Color(0.0, 0.0125, 0.1, 1); - } - else - R_Shadow_Stage_Begin(); - shadowframecount++; - if (r_shadow_realtime_world.integer) - { - R_Shadow_LoadWorldLightsIfNeeded(); - for (lnum = 0, wl = r_shadow_worldlightchain;wl;wl = wl->next, lnum++) - { - if (d_lightstylevalue[wl->style] <= 0) - continue; - if (R_CullBox(wl->mins, wl->maxs)) - continue; - for (i = 0;i < wl->numclusters;i++) - if (CHECKPVSBIT(r_pvsbits, wl->clusterindices[i])) - break; - if (i == wl->numclusters) - continue; - if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer) - continue; - if (R_Shadow_ScissorForBBox(wl->mins, wl->maxs)) - continue; - - cullradius = wl->cullradius; - lightradius = wl->radius; - VectorCopy(wl->mins, clipmins); - VectorCopy(wl->maxs, clipmaxs); - - f = d_lightstylevalue[wl->style] * (1.0f / 256.0f); - VectorScale(wl->color, f, lightcolor); - if (wl->selected) - { - f = 2 + sin(realtime * M_PI * 4.0); - VectorScale(lightcolor, f, lightcolor); - } - - if (r_shadow_worldshadows.integer && wl->drawshadows && (gl_stencil || visiblevolumes)) - { - if (!visiblevolumes) - R_Shadow_Stage_ShadowVolumes(); - ent = &cl_entities[0].render; - if (r_shadow_staticworldlights.integer) - R_Shadow_DrawStaticWorldLight_Shadow(wl, &ent->matrix); - else - R_TestAndDrawShadowVolume(ent, wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true); - if (r_drawentities.integer) - for (i = 0;i < r_refdef.numentities;i++) - R_TestAndDrawShadowVolume(r_refdef.entities[i], wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true); - } - - if (!visiblevolumes) - { - if (r_shadow_worldshadows.integer && wl->drawshadows && gl_stencil) - R_Shadow_Stage_LightWithShadows(); - else - R_Shadow_Stage_LightWithoutShadows(); - - ent = &cl_entities[0].render; - if (ent->model && ent->model->DrawLight) - { - Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin); - Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin); - Matrix4x4_Concat(&matrix_modeltolight, &wl->matrix_worldtolight, &ent->matrix); - Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &wl->matrix_worldtoattenuationxyz, &ent->matrix); - Matrix4x4_Concat(&matrix_modeltoattenuationz, &wl->matrix_worldtoattenuationz, &ent->matrix); - if (r_shadow_staticworldlights.integer) - R_Shadow_DrawStaticWorldLight_Light(wl, &ent->matrix, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz); - else - ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, wl->cubemap); - } - if (r_drawentities.integer) - { - for (i = 0;i < r_refdef.numentities;i++) - { - ent = r_refdef.entities[i]; - if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight - && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs) - && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1) - { - Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin); - Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin); - Matrix4x4_Concat(&matrix_modeltolight, &wl->matrix_worldtolight, &ent->matrix); - Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &wl->matrix_worldtoattenuationxyz, &ent->matrix); - Matrix4x4_Concat(&matrix_modeltoattenuationz, &wl->matrix_worldtoattenuationz, &ent->matrix); - ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, wl->cubemap); - } - } - } - } - } - } - if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) - { - for (lnum = 0, rd = r_dlight;lnum < r_numdlights;lnum++, rd++) - { - lightradius = rd->radius; - clipmins[0] = rd->origin[0] - lightradius; - clipmins[1] = rd->origin[1] - lightradius; - clipmins[2] = rd->origin[2] - lightradius; - clipmaxs[0] = rd->origin[0] + lightradius; - clipmaxs[1] = rd->origin[1] + lightradius; - clipmaxs[2] = rd->origin[2] + lightradius; - if (VIS_CullBox(clipmins, clipmaxs) || R_Shadow_ScissorForBBox(clipmins, clipmaxs)) - continue; - - cullradius = RadiusFromBoundsAndOrigin(clipmins, clipmaxs, rd->origin); - VectorCopy(rd->color, lightcolor); - - if (rd->cubemapnum > 0) - cubemaptexture = R_Shadow_Cubemap(va("cubemaps/%i", rd->cubemapnum)); - else - cubemaptexture = NULL; - - if (r_shadow_dlightshadows.integer && rd->shadow && (gl_stencil || visiblevolumes)) - { - if (!visiblevolumes) - R_Shadow_Stage_ShadowVolumes(); - ent = &cl_entities[0].render; - R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false); - if (r_drawentities.integer) - { - for (i = 0;i < r_refdef.numentities;i++) - { - ent = r_refdef.entities[i]; - if (ent != rd->ent) - R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false); - } - } - } - - if (!visiblevolumes) - { - if (r_shadow_dlightshadows.integer && gl_stencil && rd->shadow) - R_Shadow_Stage_LightWithShadows(); - else - R_Shadow_Stage_LightWithoutShadows(); - - ent = &cl_entities[0].render; - if (ent->model && ent->model->DrawLight) - { - Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin); - Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin); - Matrix4x4_Concat(&matrix_modeltolight, &rd->matrix_worldtolight, &ent->matrix); - Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rd->matrix_worldtoattenuationxyz, &ent->matrix); - Matrix4x4_Concat(&matrix_modeltoattenuationz, &rd->matrix_worldtoattenuationz, &ent->matrix); - ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture); - } - if (r_drawentities.integer) - { - for (i = 0;i < r_refdef.numentities;i++) - { - ent = r_refdef.entities[i]; - if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight - && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs) - && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1) - { - Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin); - Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin); - Matrix4x4_Concat(&matrix_modeltolight, &rd->matrix_worldtolight, &ent->matrix); - Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rd->matrix_worldtoattenuationxyz, &ent->matrix); - Matrix4x4_Concat(&matrix_modeltoattenuationz, &rd->matrix_worldtoattenuationz, &ent->matrix); - ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture); - } - } - } - } - } - } - - if (visiblevolumes) - { - qglEnable(GL_CULL_FACE); - GL_Scissor(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height); - } - else - R_Shadow_Stage_End(); -} - static void R_SetFrustum(void) { // break apart the viewentity matrix into vectors for various purposes diff --git a/gl_rsurf.c b/gl_rsurf.c index 2ff69257..8b0fd081 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -46,6 +46,7 @@ static int R_IntAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surf) int sdtable[256], lnum, td, maxdist, maxdist2, maxdist3, i, s, t, smax, tmax, smax3, red, green, blue, lit, dist2, impacts, impactt, subtract, k; unsigned int *bl; float dist, impact[3], local[3]; + dlight_t *light; lit = false; @@ -53,17 +54,17 @@ static int R_IntAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surf) tmax = (surf->extents[1] >> 4) + 1; smax3 = smax * 3; - for (lnum = 0; lnum < r_numdlights; lnum++) + for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++) { if (!(surf->dlightbits[lnum >> 5] & (1 << (lnum & 31)))) continue; // not lit by this light - Matrix4x4_Transform(matrix, r_dlight[lnum].origin, local); + Matrix4x4_Transform(matrix, light->origin, local); dist = DotProduct (local, surf->plane->normal) - surf->plane->dist; // for comparisons to minimum acceptable light // compensate for LIGHTOFFSET - maxdist = (int) r_dlight[lnum].cullradius2 + LIGHTOFFSET; + maxdist = (int) light->rtlight.lightmap_cullradius2 + LIGHTOFFSET; dist2 = dist * dist; dist2 += LIGHTOFFSET; @@ -98,10 +99,10 @@ static int R_IntAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surf) maxdist3 = maxdist - dist2; // convert to 8.8 blocklights format - red = r_dlight[lnum].light[0] * (1.0f / 128.0f); - green = r_dlight[lnum].light[1] * (1.0f / 128.0f); - blue = r_dlight[lnum].light[2] * (1.0f / 128.0f); - subtract = (int) (r_dlight[lnum].subtract * 4194304.0f); + red = light->rtlight.lightmap_light[0] * (1.0f / 128.0f); + green = light->rtlight.lightmap_light[1] * (1.0f / 128.0f); + blue = light->rtlight.lightmap_light[2] * (1.0f / 128.0f); + subtract = (int) (light->rtlight.lightmap_subtract * 4194304.0f); bl = intblocklights; i = impactt; @@ -139,6 +140,7 @@ static int R_FloatAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surf) { int lnum, s, t, smax, tmax, smax3, lit, impacts, impactt; float sdtable[256], *bl, k, dist, dist2, maxdist, maxdist2, maxdist3, td1, td, red, green, blue, impact[3], local[3], subtract; + dlight_t *light; lit = false; @@ -146,17 +148,17 @@ static int R_FloatAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surf) tmax = (surf->extents[1] >> 4) + 1; smax3 = smax * 3; - for (lnum = 0; lnum < r_numdlights; lnum++) + for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++) { if (!(surf->dlightbits[lnum >> 5] & (1 << (lnum & 31)))) continue; // not lit by this light - Matrix4x4_Transform(matrix, r_dlight[lnum].origin, local); + Matrix4x4_Transform(matrix, light->origin, local); dist = DotProduct (local, surf->plane->normal) - surf->plane->dist; // for comparisons to minimum acceptable light // compensate for LIGHTOFFSET - maxdist = (int) r_dlight[lnum].cullradius2 + LIGHTOFFSET; + maxdist = (int) light->rtlight.lightmap_cullradius2 + LIGHTOFFSET; dist2 = dist * dist; dist2 += LIGHTOFFSET; @@ -191,10 +193,10 @@ static int R_FloatAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surf) maxdist3 = maxdist - dist2; // convert to 8.8 blocklights format - red = r_dlight[lnum].light[0]; - green = r_dlight[lnum].light[1]; - blue = r_dlight[lnum].light[2]; - subtract = r_dlight[lnum].subtract * 32768.0f; + red = light->rtlight.lightmap_light[0]; + green = light->rtlight.lightmap_light[1]; + blue = light->rtlight.lightmap_light[2]; + subtract = light->rtlight.lightmap_subtract * 32768.0f; bl = floatblocklights; td1 = impactt; @@ -684,21 +686,21 @@ static int RSurf_LightSeparate_Vertex3f_Color4f(const matrix4x4_t *matrix, const const float *v; float *c; int i, l, lit = false; - const rdlight_t *rd; + const dlight_t *light; vec3_t lightorigin; for (l = 0;l < r_numdlights;l++) { if (dlightbits[l >> 5] & (1 << (l & 31))) { - rd = &r_dlight[l]; - Matrix4x4_Transform(matrix, rd->origin, lightorigin); + light = &r_dlight[l]; + Matrix4x4_Transform(matrix, light->origin, lightorigin); for (i = 0, v = vert, c = color;i < numverts;i++, v += 3, c += 4) { f = VectorDistance2(v, lightorigin) + LIGHTOFFSET; - if (f < rd->cullradius2) + if (f < light->rtlight.lightmap_cullradius2) { - f = ((1.0f / f) - rd->subtract) * scale; - VectorMA(c, f, rd->light, c); + f = ((1.0f / f) - light->rtlight.lightmap_subtract) * scale; + VectorMA(c, f, light->rtlight.lightmap_light, c); lit = true; } } @@ -1877,8 +1879,8 @@ void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, v t = surf->texinfo->texture->currentframe; if (t->rendertype == SURFRENDER_OPAQUE && t->flags & SURF_SHADOWLIGHT) { - R_Shadow_DiffuseLighting(surf->mesh.num_vertices, surf->mesh.num_triangles, surf->mesh.data_element3i, surf->mesh.data_vertex3f, surf->mesh.data_svector3f, surf->mesh.data_tvector3f, surf->mesh.data_normal3f, surf->mesh.data_texcoordtexture2f, relativelightorigin, lightradius, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.base, t->skin.nmap, lightcubemap); - R_Shadow_SpecularLighting(surf->mesh.num_vertices, surf->mesh.num_triangles, surf->mesh.data_element3i, surf->mesh.data_vertex3f, surf->mesh.data_svector3f, surf->mesh.data_tvector3f, surf->mesh.data_normal3f, surf->mesh.data_texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.gloss, t->skin.nmap, lightcubemap); + R_Shadow_DiffuseLighting(surf->mesh.num_vertices, surf->mesh.num_triangles, surf->mesh.data_element3i, surf->mesh.data_vertex3f, surf->mesh.data_svector3f, surf->mesh.data_tvector3f, surf->mesh.data_normal3f, surf->mesh.data_texcoordtexture2f, relativelightorigin, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.base, t->skin.nmap, lightcubemap); + R_Shadow_SpecularLighting(surf->mesh.num_vertices, surf->mesh.num_triangles, surf->mesh.data_element3i, surf->mesh.data_vertex3f, surf->mesh.data_svector3f, surf->mesh.data_tvector3f, surf->mesh.data_normal3f, surf->mesh.data_texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.gloss, t->skin.nmap, lightcubemap); } } } @@ -2397,8 +2399,8 @@ void R_Q3BSP_DrawFaceLight(entity_render_t *ent, q3mface_t *face, vec3_t relativ { if ((face->texture->surfaceflags & Q3SURFACEFLAG_NODRAW) || !face->num_triangles) return; - R_Shadow_DiffuseLighting(face->num_vertices, face->num_triangles, face->data_element3i, face->data_vertex3f, face->data_svector3f, face->data_tvector3f, face->data_normal3f, face->data_texcoordtexture2f, relativelightorigin, lightradius, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, face->texture->skin.base, face->texture->skin.nmap, lightcubemap); - R_Shadow_SpecularLighting(face->num_vertices, face->num_triangles, face->data_element3i, face->data_vertex3f, face->data_svector3f, face->data_tvector3f, face->data_normal3f, face->data_texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, face->texture->skin.gloss, face->texture->skin.nmap, lightcubemap); + R_Shadow_DiffuseLighting(face->num_vertices, face->num_triangles, face->data_element3i, face->data_vertex3f, face->data_svector3f, face->data_tvector3f, face->data_normal3f, face->data_texcoordtexture2f, relativelightorigin, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, face->texture->skin.base, face->texture->skin.nmap, lightcubemap); + R_Shadow_SpecularLighting(face->num_vertices, face->num_triangles, face->data_element3i, face->data_vertex3f, face->data_svector3f, face->data_tvector3f, face->data_normal3f, face->data_texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, face->texture->skin.gloss, face->texture->skin.nmap, lightcubemap); } void R_Q3BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap) diff --git a/model_shared.h b/model_shared.h index 86339635..1cd9d5ba 100644 --- a/model_shared.h +++ b/model_shared.h @@ -47,15 +47,16 @@ animscene_t; typedef struct skinframe_s { + rtexture_t *stain; // inverse modulate with background (used for decals and such) + rtexture_t *merged; // original texture without glow rtexture_t *base; // original texture without pants/shirt/glow rtexture_t *pants; // pants only (in greyscale) rtexture_t *shirt; // shirt only (in greyscale) - rtexture_t *glow; // glow only (fullbrights) - rtexture_t *merged; // original texture without glow - rtexture_t *fog; // alpha of the base texture (if not opaque) rtexture_t *nmap; // normalmap (bumpmap for dot3) rtexture_t *gloss; // glossmap (for dot3) rtexture_t *detail; // detail texture (silly bumps for non-dot3) + rtexture_t *glow; // glow only (fullbrights) + rtexture_t *fog; // alpha of the base texture (if not opaque) } skinframe_t; diff --git a/protocol.h b/protocol.h index b57e4e6e..4d140b45 100644 --- a/protocol.h +++ b/protocol.h @@ -307,6 +307,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define RENDER_LOWPRECISION 16 // send as low precision coordinates to save bandwidth #define RENDER_COLORMAPPED 32 #define RENDER_SHADOW 64 // cast shadow +#define RENDER_LIGHT 128 // receive light typedef struct { diff --git a/r_light.c b/r_light.c index b3ec3a51..aafbbf19 100644 --- a/r_light.c +++ b/r_light.c @@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "cl_collision.h" #include "r_shadow.h" -rdlight_t r_dlight[MAX_DLIGHTS]; +dlight_t r_dlight[MAX_DLIGHTS]; int r_numdlights = 0; cvar_t r_modellights = {CVAR_SAVE, "r_modellights", "4"}; @@ -87,8 +87,6 @@ R_UpdateLights void R_UpdateLights(void) { int i, j, k; - dlight_t *cd; - rdlight_t *rd; // light animations // 'm' is normal light, 'a' is no light, 'z' is double bright @@ -114,36 +112,13 @@ void R_UpdateLights(void) for (i = 0;i < MAX_DLIGHTS;i++) { - cd = cl_dlights + i; - if (cd->radius <= 0) - continue; - rd = &r_dlight[r_numdlights++]; - VectorCopy(cd->origin, rd->origin); - VectorScale(cd->color, d_lightstylevalue[cd->style] * (1.0f / 256.0f), rd->color); - rd->radius = bound(0, cd->radius, 2048.0f); - VectorScale(rd->color, rd->radius * 64.0f, rd->light); -#if 0 - rd->cullradius2 = DotProduct(rd->light, rd->light) * (0.25f / (64.0f * 64.0f)) + 4096.0f; - // clamp radius to avoid overflowing division table in lightmap code - rd->cullradius2 = bound(0, rd->cullradius2, 2048.0f*2048.0f); - rd->cullradius = sqrt(rd->cullradius2); -#else - rd->cullradius = rd->radius; - rd->cullradius2 = rd->cullradius * rd->cullradius; -#endif - rd->subtract = 1.0f / rd->cullradius2; - rd->ent = cd->ent; - rd->cubemapnum = cd->cubemapnum; - rd->shadow = cd->shadow; - rd->corona = cd->corona; - - rd->matrix_lighttoworld = cd->matrix; - Matrix4x4_ConcatScale(&rd->matrix_lighttoworld, rd->cullradius); - Matrix4x4_Invert_Simple(&rd->matrix_worldtolight, &rd->matrix_lighttoworld); - Matrix4x4_Concat(&rd->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rd->matrix_worldtolight); - Matrix4x4_Concat(&rd->matrix_worldtoattenuationz, &matrix_attenuationz, &rd->matrix_worldtolight); - - c_dlights++; // count every dlight in use + if (cl_dlights[i].radius > 0) + { + R_RTLight_UpdateFromDLight(&cl_dlights[i].rtlight, &cl_dlights[i], false); + // FIXME: use pointer instead of copy + r_dlight[r_numdlights++] = cl_dlights[i]; + c_dlights++; // count every dlight in use + } } } @@ -151,37 +126,35 @@ void R_DrawCoronas(void) { int i, lnum; float cscale, scale, viewdist, dist; - rdlight_t *rd; - worldlight_t *wl; + dlight_t *light; if (!r_coronas.integer) return; R_Mesh_Matrix(&r_identitymatrix); viewdist = DotProduct(r_vieworigin, r_viewforward); if (r_shadow_realtime_world.integer) { - for (lnum = 0, wl = r_shadow_worldlightchain;wl;wl = wl->next, lnum++) + for (lnum = 0, light = r_shadow_worldlightchain;light;light = light->next, lnum++) { - if (wl->corona * r_coronas.value > 0 && (r_shadow_debuglight.integer < 0 || r_shadow_debuglight.integer == lnum) && (dist = (DotProduct(wl->origin, r_viewforward) - viewdist)) >= 24.0f && CL_TraceLine(wl->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1) + if (light->rtlight.corona * r_coronas.value > 0 && (r_shadow_debuglight.integer < 0 || r_shadow_debuglight.integer == lnum) && (dist = (DotProduct(light->rtlight.shadoworigin, r_viewforward) - viewdist)) >= 24.0f && CL_TraceLine(light->rtlight.shadoworigin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1) { - cscale = wl->corona * r_coronas.value * 0.25f; - scale = wl->radius * 0.25f; - R_DrawSprite(GL_ONE, GL_ONE, lightcorona, true, wl->origin, r_viewright, r_viewup, scale, -scale, -scale, scale, wl->color[0] * cscale, wl->color[1] * cscale, wl->color[2] * cscale, 1); + cscale = light->rtlight.corona * r_coronas.value * 0.25f; + scale = light->rtlight.radius * 0.25f; + R_DrawSprite(GL_ONE, GL_ONE, lightcorona, true, light->rtlight.shadoworigin, r_viewright, r_viewup, scale, -scale, -scale, scale, light->rtlight.color[0] * cscale, light->rtlight.color[1] * cscale, light->rtlight.color[2] * cscale, 1); } } } - for (i = 0;i < r_numdlights;i++) + for (i = 0, light = r_dlight;i < r_numdlights;i++, light++) { - rd = r_dlight + i; - if (rd->corona * r_coronas.value > 0 && (dist = (DotProduct(rd->origin, r_viewforward) - viewdist)) >= 24.0f && CL_TraceLine(rd->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1) + if (light->corona * r_coronas.value > 0 && (dist = (DotProduct(light->origin, r_viewforward) - viewdist)) >= 24.0f && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1) { - cscale = rd->corona * r_coronas.value * 0.25f; - scale = rd->radius * 0.25f; + cscale = light->corona * r_coronas.value * 0.25f; + scale = light->radius * 0.25f; if (gl_flashblend.integer) { cscale *= 4.0f; scale *= 2.0f; } - R_DrawSprite(GL_ONE, GL_ONE, lightcorona, true, rd->origin, r_viewright, r_viewup, scale, -scale, -scale, scale, rd->color[0] * cscale, rd->color[1] * cscale, rd->color[2] * cscale, 1); + R_DrawSprite(GL_ONE, GL_ONE, lightcorona, true, light->origin, r_viewright, r_viewup, scale, -scale, -scale, scale, light->color[0] * cscale, light->color[1] * cscale, light->color[2] * cscale, 1); } } } @@ -202,7 +175,7 @@ static qbyte lightpvs[(MAX_MAP_LEAFS+7)>>3]; R_MarkLights ============= */ -static void R_RecursiveMarkLights(entity_render_t *ent, vec3_t lightorigin, rdlight_t *rd, int bit, int bitindex, mnode_t *node, qbyte *pvs, int pvsbits) +static void R_RecursiveMarkLights(entity_render_t *ent, vec3_t lightorigin, dlight_t *light, int bit, int bitindex, mnode_t *node, qbyte *pvs, int pvsbits) { int i; mleaf_t *leaf; @@ -212,12 +185,12 @@ static void R_RecursiveMarkLights(entity_render_t *ent, vec3_t lightorigin, rdli while(node->contents >= 0) { dist = PlaneDiff(lightorigin, node->plane); - if (dist > rd->cullradius) + if (dist > light->rtlight.lightmap_cullradius) node = node->children[0]; else { - if (dist >= -rd->cullradius) - R_RecursiveMarkLights(ent, lightorigin, rd, bit, bitindex, node->children[0], pvs, pvsbits); + if (dist >= -light->rtlight.lightmap_cullradius) + R_RecursiveMarkLights(ent, lightorigin, light, bit, bitindex, node->children[0], pvs, pvsbits); node = node->children[1]; } } @@ -231,7 +204,7 @@ static void R_RecursiveMarkLights(entity_render_t *ent, vec3_t lightorigin, rdli float sdist, maxdist, dist2, impact[3]; msurface_t *surf; // mark the polygons - maxdist = rd->cullradius2; + maxdist = light->rtlight.lightmap_cullradius2; surfacepvsframes = ent->model->brushq1.surfacepvsframes; for (i = 0;i < leaf->nummarksurfaces;i++) { @@ -283,19 +256,19 @@ static void R_RecursiveMarkLights(entity_render_t *ent, vec3_t lightorigin, rdli void R_MarkLights(entity_render_t *ent) { int i, bit, bitindex; - rdlight_t *rd; + dlight_t *light; vec3_t lightorigin; if (!gl_flashblend.integer && r_dynamic.integer && ent->model && ent->model->brushq1.num_leafs) { - for (i = 0, rd = r_dlight;i < r_numdlights;i++, rd++) + for (i = 0, light = r_dlight;i < r_numdlights;i++, light++) { bit = 1 << (i & 31); bitindex = i >> 5; - Matrix4x4_Transform(&ent->inversematrix, rd->origin, lightorigin); + Matrix4x4_Transform(&ent->inversematrix, light->origin, lightorigin); lightpvsbytes = 0; if (r_vismarklights.integer && ent->model->brush.FatPVS) lightpvsbytes = ent->model->brush.FatPVS(ent->model, lightorigin, 0, lightpvs, sizeof(lightpvs)); - R_RecursiveMarkLights(ent, lightorigin, rd, bit, bitindex, ent->model->brushq1.nodes + ent->model->brushq1.hulls[0].firstclipnode, lightpvs, min(lightpvsbytes * 8, ent->model->brush.num_pvsclusters)); + R_RecursiveMarkLights(ent, lightorigin, light, bit, bitindex, ent->model->brushq1.nodes + ent->model->brushq1.hulls[0].firstclipnode, lightpvs, min(lightpvsbytes * 8, ent->model->brush.num_pvsclusters)); } } } @@ -348,17 +321,17 @@ void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffu { int i; float f, v[3]; - rdlight_t *rd; + dlight_t *light; // FIXME: this really should handle dlights as diffusecolor/diffusenormal somehow for (i = 0;i < r_numdlights;i++) { - rd = r_dlight + i; - VectorSubtract(p, rd->origin, v); + light = r_dlight + i; + VectorSubtract(p, light->origin, v); f = DotProduct(v, v); - if (f < rd->cullradius2 && CL_TraceLine(p, rd->origin, NULL, NULL, false, NULL, SUPERCONTENTS_SOLID) == 1) + if (f < light->rtlight.lightmap_cullradius2 && CL_TraceLine(p, light->origin, NULL, NULL, false, NULL, SUPERCONTENTS_SOLID) == 1) { - f = (1.0f / (f + LIGHTOFFSET)) - rd->subtract; - VectorMA(ambientcolor, f, rd->light, ambientcolor); + f = (1.0f / (f + LIGHTOFFSET)) - light->rtlight.lightmap_subtract; + VectorMA(ambientcolor, f, light->rtlight.lightmap_light, ambientcolor); } } } @@ -388,7 +361,7 @@ int R_LightModel(float *ambient4f, float *diffusecolor, float *diffusenormal, co float v[3], f, mscale, stylescale, intensity, ambientcolor[3], tempdiffusenormal[3]; nearlight_t *nl; mlight_t *sl; - rdlight_t *rd; + dlight_t *light; nearlights = 0; maxnearlights = r_modellights.integer; @@ -474,19 +447,19 @@ int R_LightModel(float *ambient4f, float *diffusecolor, float *diffusenormal, co { for (i = 0;i < r_numdlights;i++) { - rd = r_dlight + i; - VectorCopy(rd->origin, v); + light = r_dlight + i; + VectorCopy(light->origin, v); if (v[0] < ent->mins[0]) v[0] = ent->mins[0];if (v[0] > ent->maxs[0]) v[0] = ent->maxs[0]; if (v[1] < ent->mins[1]) v[1] = ent->mins[1];if (v[1] > ent->maxs[1]) v[1] = ent->maxs[1]; if (v[2] < ent->mins[2]) v[2] = ent->mins[2];if (v[2] > ent->maxs[2]) v[2] = ent->maxs[2]; - VectorSubtract (v, rd->origin, v); - if (DotProduct(v, v) < rd->cullradius2) + VectorSubtract (v, light->origin, v); + if (DotProduct(v, v) < light->rtlight.lightmap_cullradius2) { - if (CL_TraceLine(ent->origin, rd->origin, NULL, NULL, false, NULL, SUPERCONTENTS_SOLID) != 1) + if (CL_TraceLine(ent->origin, light->origin, NULL, NULL, false, NULL, SUPERCONTENTS_SOLID) != 1) continue; - VectorSubtract (ent->origin, rd->origin, v); - f = ((1.0f / (DotProduct(v, v) + LIGHTOFFSET)) - rd->subtract); - VectorScale(rd->light, f, ambientcolor); + VectorSubtract (ent->origin, light->origin, v); + f = ((1.0f / (DotProduct(v, v) + LIGHTOFFSET)) - light->rtlight.lightmap_subtract); + VectorScale(light->rtlight.lightmap_light, f, ambientcolor); intensity = DotProduct(ambientcolor, ambientcolor); if (f < 0) intensity *= -1.0f; @@ -517,14 +490,14 @@ int R_LightModel(float *ambient4f, float *diffusecolor, float *diffusenormal, co nl->intensity = intensity; // transform the light into the model's coordinate system if (worldcoords) - VectorCopy(rd->origin, nl->origin); + VectorCopy(light->origin, nl->origin); else { - Matrix4x4_Transform(&ent->inversematrix, rd->origin, nl->origin); + Matrix4x4_Transform(&ent->inversematrix, light->origin, nl->origin); /* Con_Printf("%i %s : %f %f %f : %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n" , rd - r_dlight, ent->model->name - , rd->origin[0], rd->origin[1], rd->origin[2] + , light->origin[0], light->origin[1], light->origin[2] , nl->origin[0], nl->origin[1], nl->origin[2] , ent->inversematrix.m[0][0], ent->inversematrix.m[0][1], ent->inversematrix.m[0][2], ent->inversematrix.m[0][3] , ent->inversematrix.m[1][0], ent->inversematrix.m[1][1], ent->inversematrix.m[1][2], ent->inversematrix.m[1][3] @@ -535,10 +508,10 @@ int R_LightModel(float *ambient4f, float *diffusecolor, float *diffusenormal, co // integrate mscale into falloff, for maximum speed nl->falloff = mscale; VectorCopy(ambientcolor, nl->ambientlight); - nl->light[0] = rd->light[0] * colorr * 4.0f; - nl->light[1] = rd->light[1] * colorg * 4.0f; - nl->light[2] = rd->light[2] * colorb * 4.0f; - nl->subtract = rd->subtract; + nl->light[0] = light->rtlight.lightmap_light[0] * colorr * 4.0f; + nl->light[1] = light->rtlight.lightmap_light[1] * colorg * 4.0f; + nl->light[2] = light->rtlight.lightmap_light[2] * colorb * 4.0f; + nl->subtract = light->rtlight.lightmap_subtract; nl->offset = LIGHTOFFSET; } } diff --git a/r_light.h b/r_light.h index 5c7c116b..5190e001 100644 --- a/r_light.h +++ b/r_light.h @@ -2,30 +2,8 @@ #ifndef R_LIGHT_H #define R_LIGHT_H -typedef struct -{ - vec3_t origin; - vec_t cullradius2; // only for culling comparisons, squared version - vec3_t light; // the brightness of the light - vec_t cullradius; // only for culling comparisons - vec_t subtract; // to avoid sudden brightness change at cullradius, subtract this - entity_render_t *ent; // owner of this light - - matrix4x4_t matrix_lighttoworld; - matrix4x4_t matrix_worldtolight; - matrix4x4_t matrix_worldtoattenuationxyz; - matrix4x4_t matrix_worldtoattenuationz; - - vec3_t color; - vec_t radius; - int cubemapnum; - int shadow; - vec_t corona; -} -rdlight_t; - extern int r_numdlights; -extern rdlight_t r_dlight[MAX_DLIGHTS]; +extern dlight_t r_dlight[MAX_DLIGHTS]; void R_UpdateLights(void); void R_MarkLights(entity_render_t *ent); diff --git a/r_shadow.c b/r_shadow.c index 8c083ece..5883fb8e 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -174,6 +174,8 @@ cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegener cvar_t r_shadow_worldshadows = {0, "r_shadow_worldshadows", "1"}; cvar_t r_shadow_dlightshadows = {CVAR_SAVE, "r_shadow_dlightshadows", "1"}; cvar_t r_shadow_showtris = {0, "r_shadow_showtris", "0"}; +cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"}; +cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"}; int c_rt_lights, c_rt_clears, c_rt_scissored; int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris; @@ -297,6 +299,8 @@ void R_Shadow_Init(void) Cvar_RegisterVariable(&r_shadow_worldshadows); Cvar_RegisterVariable(&r_shadow_dlightshadows); Cvar_RegisterVariable(&r_shadow_showtris); + Cvar_RegisterVariable(&r_shadow_staticworldlights); + Cvar_RegisterVariable(&r_shadow_cull); if (gamemode == GAME_TENEBRAE) { Cvar_SetValue("r_shadow_gloss", 2); @@ -1285,7 +1289,7 @@ void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out3f, int numverts, co } } -void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *relativelightorigin, float lightradius, const float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *lightcubemap) +void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *relativelightorigin, const float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *lightcubemap) { int renders; float color[3], color2[3]; @@ -1574,7 +1578,7 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element } } -void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *relativelightorigin, const float *relativeeyeorigin, float lightradius, const float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *glosstexture, rtexture_t *bumptexture, rtexture_t *lightcubemap) +void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *relativelightorigin, const float *relativeeyeorigin, const float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *glosstexture, rtexture_t *bumptexture, rtexture_t *lightcubemap) { int renders; float color[3], color2[3], colorscale; @@ -1786,264 +1790,70 @@ void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elemen } } -void R_Shadow_DrawStaticWorldLight_Shadow(worldlight_t *light, matrix4x4_t *matrix) -{ - R_Mesh_Matrix(matrix); - if (r_shadow_showtris.integer) - { - shadowmesh_t *mesh; - rmeshstate_t m; - int depthenabled = qglIsEnabled(GL_DEPTH_TEST); - int stencilenabled = qglIsEnabled(GL_STENCIL_TEST); - qglDisable(GL_DEPTH_TEST); - qglDisable(GL_STENCIL_TEST); - //qglDisable(GL_CULL_FACE); - qglColorMask(1,1,1,1); - memset(&m, 0, sizeof(m)); - R_Mesh_State_Texture(&m); - GL_Color(0,0.1,0,1); - GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); - for (mesh = light->meshchain_shadow;mesh;mesh = mesh->next) - { - GL_VertexPointer(mesh->vertex3f); - R_Mesh_Draw_ShowTris(mesh->numverts, mesh->numtriangles, mesh->element3i); - } - //qglEnable(GL_CULL_FACE); - if (depthenabled) - qglEnable(GL_DEPTH_TEST); - if (stencilenabled) - { - qglEnable(GL_STENCIL_TEST); - qglColorMask(0,0,0,0); - } - } - R_Shadow_RenderShadowMeshVolume(light->meshchain_shadow); -} - -void R_Shadow_DrawStaticWorldLight_Light(worldlight_t *light, matrix4x4_t *matrix, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz) -{ - shadowmesh_t *mesh; - R_Mesh_Matrix(matrix); - if (r_shadow_showtris.integer) - { - rmeshstate_t m; - int depthenabled = qglIsEnabled(GL_DEPTH_TEST); - int stencilenabled = qglIsEnabled(GL_STENCIL_TEST); - qglDisable(GL_DEPTH_TEST); - qglDisable(GL_STENCIL_TEST); - //qglDisable(GL_CULL_FACE); - memset(&m, 0, sizeof(m)); - R_Mesh_State_Texture(&m); - GL_Color(0.2,0,0,1); - GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); - for (mesh = light->meshchain_light;mesh;mesh = mesh->next) - { - GL_VertexPointer(mesh->vertex3f); - R_Mesh_Draw_ShowTris(mesh->numverts, mesh->numtriangles, mesh->element3i); - } - //qglEnable(GL_CULL_FACE); - if (depthenabled) - qglEnable(GL_DEPTH_TEST); - if (stencilenabled) - qglEnable(GL_STENCIL_TEST); - } - for (mesh = light->meshchain_light;mesh;mesh = mesh->next) - { - R_Shadow_DiffuseLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, lightradius, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, mesh->map_diffuse, mesh->map_normal, light->cubemap); - R_Shadow_SpecularLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, mesh->map_specular, mesh->map_normal, light->cubemap); - } -} - -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"}; -worldlight_t *r_shadow_worldlightchain; -worldlight_t *r_shadow_selectedlight; -vec3_t r_editlights_cursorlocation; - -static int lightpvsbytes; -static qbyte lightpvs[(MAX_MAP_LEAFS + 7)/ 8]; -static qbyte lightfullpvs[(MAX_MAP_LEAFS + 7)/ 8]; - -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; -} -suffixinfo_t; -static suffixinfo_t suffix[3][6] = -{ - { - {"posx", false, false, false}, - {"negx", false, false, false}, - {"posy", false, false, false}, - {"negy", false, false, false}, - {"posz", false, false, false}, - {"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} - } -}; - -static int componentorder[4] = {0, 1, 2, 3}; - -rtexture_t *R_Shadow_LoadCubemap(const char *basename) -{ - int i, j, cubemapsize; - qbyte *cubemappixels, *image_rgba; - rtexture_t *cubemaptexture; - char name[256]; - // must start 0 so the first loadimagepixels has no requested width/height - cubemapsize = 0; - cubemappixels = NULL; - cubemaptexture = NULL; - for (j = 0;j < 3 && !cubemappixels;j++) - { - for (i = 0;i < 6;i++) - { - snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix); - if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize))) - { - if (image_width == image_height) - { - if (!cubemappixels && image_width >= 1) - { - cubemapsize = image_width; - // note this clears to black, so unavailable sizes are black - cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4); - } - 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); - Mem_Free(image_rgba); - } - } - } - if (cubemappixels) - { - if (!r_shadow_filters_texturepool) - r_shadow_filters_texturepool = R_AllocTexturePool(); - cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL); - Mem_Free(cubemappixels); - } - else - { - Con_Printf("Failed to load Cubemap \"%s\", tried ", basename); - for (j = 0;j < 3;j++) - for (i = 0;i < 6;i++) - Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix); - Con_Printf(" and was unable to find any of them.\n"); - } - return cubemaptexture; -} - -rtexture_t *R_Shadow_Cubemap(const char *basename) -{ - int i; - for (i = 0;i < numcubemaps;i++) - if (!strcasecmp(cubemaps[i].basename, basename)) - return cubemaps[i].texture; - if (i >= MAX_CUBEMAPS) - return NULL; - numcubemaps++; - strcpy(cubemaps[i].basename, basename); - cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename); - return cubemaps[i].texture; -} - -void R_Shadow_FreeCubemaps(void) -{ - numcubemaps = 0; - R_FreeTexturePool(&r_shadow_filters_texturepool); +void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic) +{ + int j, k; + float scale; + R_RTLight_Uncompile(rtlight); + memset(rtlight, 0, sizeof(*rtlight)); + + VectorCopy(light->origin, rtlight->shadoworigin); + VectorCopy(light->color, rtlight->color); + rtlight->radius = light->radius; + rtlight->cullradius = rtlight->radius; + rtlight->cullradius2 = rtlight->cullradius * rtlight->cullradius; + rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->cullradius; + rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->cullradius; + rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->cullradius; + rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->cullradius; + rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->cullradius; + rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->cullradius; + rtlight->cubemapname[0] = 0; + if (light->cubemapname[0]) + strcpy(rtlight->cubemapname, light->cubemapname); + else if (light->cubemapnum > 0) + sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum); + rtlight->shadow = light->shadow; + rtlight->corona = light->corona; + rtlight->style = light->style; + rtlight->isstatic = isstatic; + Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix); + // ConcatScale won't work here because this needs to scale rotate and + // translate, not just rotate + scale = 1.0f / rtlight->radius; + for (k = 0;k < 3;k++) + for (j = 0;j < 4;j++) + rtlight->matrix_worldtolight.m[k][j] *= scale; + Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight); + Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight); + + rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f); + rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius; + VectorScale(rtlight->color, rtlight->radius * d_lightstylevalue[rtlight->style] * 0.25f, rtlight->lightmap_light); + rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2; } -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) +// compiles rtlight geometry +// (undone by R_FreeCompiledRTLight, which R_UpdateLight calls) +void R_RTLight_Compile(rtlight_t *rtlight) { int i, j, k, l, maxverts = 256, tris; float *vertex3f = NULL, mins[3], maxs[3]; - worldlight_t *e; shadowmesh_t *mesh, *castmesh = NULL; - - if (radius < 15 || DotProduct(color, color) < 0.03) - { - Con_Printf("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n"); - return; - } - - e = Mem_Alloc(r_shadow_mempool, sizeof(worldlight_t)); - VectorCopy(origin, e->origin); - VectorCopy(angles, e->angles); - VectorCopy(color, e->color); - e->radius = radius; - e->style = style; - if (e->style < 0 || e->style >= MAX_LIGHTSTYLES) - { - Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", e->style, MAX_LIGHTSTYLES); - e->style = 0; - } - e->drawshadows = shadowenable; - e->corona = corona; - - Matrix4x4_CreateFromQuakeEntity(&e->matrix_lighttoworld, e->origin[0], e->origin[1], e->origin[2], e->angles[0], e->angles[1], e->angles[2], e->radius); - Matrix4x4_Invert_Simple(&e->matrix_worldtolight, &e->matrix_lighttoworld); - Matrix4x4_Concat(&e->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &e->matrix_worldtolight); - Matrix4x4_Concat(&e->matrix_worldtoattenuationz, &matrix_attenuationz, &e->matrix_worldtolight); - - e->cullradius = e->radius; - for (k = 0;k < 3;k++) - { - mins[k] = e->origin[k] - e->radius; - maxs[k] = e->origin[k] + e->radius; - } - - e->next = r_shadow_worldlightchain; - r_shadow_worldlightchain = e; - if (cubemapname && cubemapname[0]) - { - e->cubemapname = Mem_Alloc(r_shadow_mempool, strlen(cubemapname) + 1); - strcpy(e->cubemapname, cubemapname); - e->cubemap = R_Shadow_Cubemap(e->cubemapname); - } - // FIXME: rewrite this to store ALL geometry into a cache in the light - if (e->drawshadows) + int lightpvsbytes; + qbyte lightpvs[(MAX_MAP_LEAFS + 7)/ 8]; + qbyte lightfullpvs[(MAX_MAP_LEAFS + 7)/ 8]; + + // compile the light + rtlight->compiled = true; + VectorCopy(rtlight->cullmins, mins); + VectorCopy(rtlight->cullmaxs, maxs); + if (rtlight->shadow) castmesh = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true); - e->meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true); + rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true); if (cl.worldmodel) { - lightpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, origin, 0, lightfullpvs, sizeof(lightfullpvs)); + lightpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, rtlight->shadoworigin, 0, lightfullpvs, sizeof(lightfullpvs)); memset(lightpvs, 0, lightpvsbytes); if (cl.worldmodel->brushq3.num_leafs) { @@ -2056,16 +1866,16 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra SETPVSBIT(lightpvs, leaf->clusterindex); // make a cluster list for fast visibility checking during rendering - for (i = 0, e->numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++) + for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++) if (CHECKPVSBIT(lightpvs, i)) - e->numclusters++; - e->clusterindices = Mem_Alloc(r_shadow_mempool, e->numclusters * sizeof(int)); - for (i = 0, e->numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++) + rtlight->static_numclusters++; + rtlight->static_clusterindices = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(int)); + for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++) if (CHECKPVSBIT(lightpvs, i)) - e->clusterindices[e->numclusters++] = i; + rtlight->static_clusterindices[rtlight->static_numclusters++] = i; - VectorCopy(e->origin, e->mins); - VectorCopy(e->origin, e->maxs); + VectorCopy(rtlight->shadoworigin, rtlight->cullmins); + VectorCopy(rtlight->shadoworigin, rtlight->cullmaxs); for (i = 0, face = cl.worldmodel->brushq3.data_thismodel->firstface;i < cl.worldmodel->brushq3.data_thismodel->numfaces;i++, face++) face->lighttemp_castshadow = false; for (i = 0, leaf = cl.worldmodel->brushq3.data_leafs;i < cl.worldmodel->brushq3.num_leafs;i++, leaf++) @@ -2074,8 +1884,8 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra { for (k = 0;k < 3;k++) { - if (e->mins[k] > leaf->mins[k]) e->mins[k] = leaf->mins[k]; - if (e->maxs[k] < leaf->maxs[k]) e->maxs[k] = leaf->maxs[k]; + if (rtlight->cullmins[k] > leaf->mins[k]) rtlight->cullmins[k] = leaf->mins[k]; + if (rtlight->cullmaxs[k] < leaf->maxs[k]) rtlight->cullmaxs[k] = leaf->maxs[k]; } for (j = 0;j < leaf->numleaffaces;j++) { @@ -2094,11 +1904,11 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra face->lighttemp_castshadow = false; if (!(face->texture->surfaceflags & (Q3SURFACEFLAG_NODRAW | Q3SURFACEFLAG_SKY))) { - if (e->drawshadows) + if (rtlight->shadow) if (!(face->texture->nativecontents & CONTENTSQ3_TRANSLUCENT)) Mod_ShadowMesh_AddMesh(r_shadow_mempool, castmesh, NULL, NULL, NULL, face->data_vertex3f, NULL, NULL, NULL, NULL, face->num_triangles, face->data_element3i); if (!(face->texture->surfaceflags & Q3SURFACEFLAG_SKY)) - Mod_ShadowMesh_AddMesh(r_shadow_mempool, e->meshchain_light, face->texture->skin.base, face->texture->skin.gloss, face->texture->skin.nmap, face->data_vertex3f, face->data_svector3f, face->data_tvector3f, face->data_normal3f, face->data_texcoordtexture2f, face->num_triangles, face->data_element3i); + Mod_ShadowMesh_AddMesh(r_shadow_mempool, rtlight->static_meshchain_light, face->texture->skin.base, face->texture->skin.gloss, face->texture->skin.nmap, face->data_vertex3f, face->data_svector3f, face->data_tvector3f, face->data_normal3f, face->data_texcoordtexture2f, face->num_triangles, face->data_element3i); } } } @@ -2107,9 +1917,9 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra { mleaf_t *leaf; msurface_t *surf; - VectorCopy(e->origin, e->mins); - VectorCopy(e->origin, e->maxs); - i = CL_PointQ1Contents(e->origin); + VectorCopy(rtlight->shadoworigin, rtlight->cullmins); + VectorCopy(rtlight->shadoworigin, rtlight->cullmaxs); + i = CL_PointQ1Contents(rtlight->shadoworigin); for (i = 0, surf = cl.worldmodel->brushq1.surfaces + cl.worldmodel->brushq1.firstmodelsurface;i < cl.worldmodel->brushq1.nummodelsurfaces;i++, surf++) surf->lighttemp_castshadow = false; @@ -2122,7 +1932,7 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra byteleafpvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.num_leafs); bytesurfacepvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.numsurfaces); - Portal_Visibility(cl.worldmodel, e->origin, byteleafpvs, bytesurfacepvs, NULL, 0, true, mins, maxs, e->mins, e->maxs); + Portal_Visibility(cl.worldmodel, rtlight->shadoworigin, byteleafpvs, bytesurfacepvs, NULL, 0, true, mins, maxs, rtlight->cullmins, rtlight->cullmaxs); // make a pvs that only includes things within the box for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++) @@ -2132,8 +1942,8 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra SETPVSBIT(lightpvs, leaf->clusterindex); for (k = 0;k < 3;k++) { - if (e->mins[k] > leaf->mins[k]) e->mins[k] = leaf->mins[k]; - if (e->maxs[k] < leaf->maxs[k]) e->maxs[k] = leaf->maxs[k]; + if (rtlight->cullmins[k] > leaf->mins[k]) rtlight->cullmins[k] = leaf->mins[k]; + if (rtlight->cullmaxs[k] < leaf->maxs[k]) rtlight->cullmaxs[k] = leaf->maxs[k]; } } } @@ -2146,13 +1956,13 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra Mem_Free(bytesurfacepvs); // make a cluster list for fast visibility checking during rendering - for (i = 0, e->numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++) + for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++) if (CHECKPVSBIT(lightpvs, i)) - e->numclusters++; - e->clusterindices = Mem_Alloc(r_shadow_mempool, e->numclusters * sizeof(int)); - for (i = 0, e->numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++) + rtlight->static_numclusters++; + rtlight->static_clusterindices = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(int)); + for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++) if (CHECKPVSBIT(lightpvs, i)) - e->clusterindices[e->numclusters++] = i; + rtlight->static_clusterindices[rtlight->static_numclusters++] = i; } else { @@ -2164,8 +1974,8 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra SETPVSBIT(lightpvs, leaf->clusterindex); for (k = 0;k < 3;k++) { - if (e->mins[k] > leaf->mins[k]) e->mins[k] = leaf->mins[k]; - if (e->maxs[k] < leaf->maxs[k]) e->maxs[k] = leaf->maxs[k]; + if (rtlight->cullmins[k] > leaf->mins[k]) rtlight->cullmins[k] = leaf->mins[k]; + if (rtlight->cullmaxs[k] < leaf->maxs[k]) rtlight->cullmaxs[k] = leaf->maxs[k]; } for (j = 0;j < leaf->nummarksurfaces;j++) { @@ -2182,13 +1992,13 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra SETPVSBIT(lightpvs, leaf->clusterindex); // make a cluster list for fast visibility checking during rendering - for (i = 0, e->numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++) + for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++) if (CHECKPVSBIT(lightpvs, i)) - e->numclusters++; - e->clusterindices = Mem_Alloc(r_shadow_mempool, e->numclusters * sizeof(int)); - for (i = 0, e->numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++) + rtlight->static_numclusters++; + rtlight->static_clusterindices = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(int)); + for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++) if (CHECKPVSBIT(lightpvs, i)) - e->clusterindices[e->numclusters++] = i; + rtlight->static_clusterindices[rtlight->static_numclusters++] = i; } // add surfaces to shadow casting mesh and light mesh @@ -2197,10 +2007,10 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra if (surf->lighttemp_castshadow) { surf->lighttemp_castshadow = false; - if (e->drawshadows && (surf->flags & SURF_SHADOWCAST)) + if (rtlight->shadow && (surf->flags & SURF_SHADOWCAST)) Mod_ShadowMesh_AddMesh(r_shadow_mempool, castmesh, NULL, NULL, NULL, surf->mesh.data_vertex3f, NULL, NULL, NULL, NULL, surf->mesh.num_triangles, surf->mesh.data_element3i); if (!(surf->flags & SURF_DRAWSKY)) - Mod_ShadowMesh_AddMesh(r_shadow_mempool, e->meshchain_light, surf->texinfo->texture->skin.base, surf->texinfo->texture->skin.gloss, surf->texinfo->texture->skin.nmap, surf->mesh.data_vertex3f, surf->mesh.data_svector3f, surf->mesh.data_tvector3f, surf->mesh.data_normal3f, surf->mesh.data_texcoordtexture2f, surf->mesh.num_triangles, surf->mesh.data_element3i); + Mod_ShadowMesh_AddMesh(r_shadow_mempool, rtlight->static_meshchain_light, surf->texinfo->texture->skin.base, surf->texinfo->texture->skin.gloss, surf->texinfo->texture->skin.nmap, surf->mesh.data_vertex3f, surf->mesh.data_svector3f, surf->mesh.data_tvector3f, surf->mesh.data_normal3f, surf->mesh.data_texcoordtexture2f, surf->mesh.num_triangles, surf->mesh.data_element3i); } } } @@ -2209,10 +2019,11 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra // limit box to light bounds (in case it grew larger) for (k = 0;k < 3;k++) { - if (e->mins[k] < e->origin[k] - e->radius) e->mins[k] = e->origin[k] - e->radius; - if (e->maxs[k] > e->origin[k] + e->radius) e->maxs[k] = e->origin[k] + e->radius; + if (rtlight->cullmins[k] < rtlight->shadoworigin[k] - rtlight->radius) rtlight->cullmins[k] = rtlight->shadoworigin[k] - rtlight->radius; + if (rtlight->cullmaxs[k] > rtlight->shadoworigin[k] + rtlight->radius) rtlight->cullmaxs[k] = rtlight->shadoworigin[k] + rtlight->radius; } - e->cullradius = RadiusFromBoundsAndOrigin(e->mins, e->maxs, e->origin); + rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin); + rtlight->cullradius = min(rtlight->cullradius, rtlight->radius); // cast shadow volume from castmesh castmesh = Mod_ShadowMesh_Finish(r_shadow_mempool, castmesh, false, true); @@ -2230,13 +2041,13 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra vertex3f = Mem_Alloc(r_shadow_mempool, maxverts * sizeof(float[3])); // now that we have the buffers big enough, construct and add // the shadow volume mesh - if (e->drawshadows) - e->meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true); + if (rtlight->shadow) + rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true); for (mesh = castmesh;mesh;mesh = mesh->next) { Mod_BuildTriangleNeighbors(mesh->neighbor3i, mesh->element3i, mesh->numtriangles); - if ((tris = R_Shadow_ConstructShadowVolume(castmesh->numverts, 0, castmesh->numtriangles, castmesh->element3i, castmesh->neighbor3i, castmesh->vertex3f, NULL, shadowelements, vertex3f, e->origin, r_shadow_projectdistance.value))) - Mod_ShadowMesh_AddMesh(r_shadow_mempool, e->meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, tris, shadowelements); + if ((tris = R_Shadow_ConstructShadowVolume(castmesh->numverts, 0, castmesh->numtriangles, castmesh->element3i, castmesh->neighbor3i, castmesh->vertex3f, NULL, shadowelements, vertex3f, rtlight->shadoworigin, r_shadow_projectdistance.value))) + Mod_ShadowMesh_AddMesh(r_shadow_mempool, rtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, tris, shadowelements); } Mem_Free(vertex3f); vertex3f = NULL; @@ -2245,33 +2056,437 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra Mod_ShadowMesh_Free(castmesh); } - e->meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, e->meshchain_shadow, false, false); - e->meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, e->meshchain_light, true, false); + rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false); + rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false); k = 0; - if (e->meshchain_shadow) - for (mesh = e->meshchain_shadow;mesh;mesh = mesh->next) + if (rtlight->static_meshchain_shadow) + for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next) k += mesh->numtriangles; l = 0; - if (e->meshchain_light) - for (mesh = e->meshchain_light;mesh;mesh = mesh->next) + if (rtlight->static_meshchain_light) + for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next) l += mesh->numtriangles; - Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles, %i light triangles\n", e->mins[0], e->mins[1], e->mins[2], e->maxs[0], e->maxs[1], e->maxs[2], k, l); + Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles, %i light triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], k, l); +} + +void R_RTLight_Uncompile(rtlight_t *rtlight) +{ + if (rtlight->compiled) + { + if (rtlight->static_meshchain_shadow) + Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow); + rtlight->static_meshchain_shadow = NULL; + if (rtlight->static_meshchain_light) + Mod_ShadowMesh_Free(rtlight->static_meshchain_light); + rtlight->static_meshchain_light = NULL; + if (rtlight->static_clusterindices) + Mem_Free(rtlight->static_clusterindices); + rtlight->static_clusterindices = NULL; + rtlight->static_numclusters = 0; + rtlight->compiled = false; + } +} + +int shadowframecount = 0; + +void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t shadoworigin, vec_t shadowradius, vec3_t cullmins, vec3_t cullmaxs) +{ + // rough checks + if ((BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) || !r_shadow_cull.integer) && (ent->flags & RENDER_SHADOW) && ent->model && ent->model->DrawShadowVolume) + { + vec3_t relativeshadoworigin; + Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativeshadoworigin); + ent->model->DrawShadowVolume (ent, relativeshadoworigin, shadowradius); + } +} + +void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light); + +void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes) +{ + int i, shadow; + entity_render_t *ent; + float f; + vec3_t relativelightorigin, relativeeyeorigin, lightcolor; + rtexture_t *cubemaptexture; + matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz; + + if (d_lightstylevalue[rtlight->style] <= 0) + return; + if (rtlight->compiled) + { + if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs)) + return; + for (i = 0;i < rtlight->static_numclusters;i++) + if (CHECKPVSBIT(r_pvsbits, rtlight->static_clusterindices[i])) + break; + if (i == rtlight->static_numclusters) + return; + } + else if (VIS_CullBox(rtlight->cullmins, rtlight->cullmaxs)) + return; + if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs)) + return; + + if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer) + R_RTLight_Compile(rtlight); + + f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f); + VectorScale(rtlight->color, f, lightcolor); + /* + if (rtlight->selected) + { + f = 2 + sin(realtime * M_PI * 4.0); + VectorScale(lightcolor, f, lightcolor); + } + */ + + if (rtlight->cubemapname[0]) + cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname); + else + cubemaptexture = NULL; + + shadow = rtlight->shadow && (rtlight->isstatic ? r_shadow_worldshadows.integer : r_shadow_dlightshadows.integer); + if (shadow && (gl_stencil || visiblevolumes)) + { + if (!visiblevolumes) + R_Shadow_Stage_ShadowVolumes(); + ent = &cl_entities[0].render; + if (r_shadow_staticworldlights.integer && rtlight->compiled) + { + R_Mesh_Matrix(&ent->matrix); + if (r_shadow_showtris.integer) + { + shadowmesh_t *mesh; + rmeshstate_t m; + int depthenabled = qglIsEnabled(GL_DEPTH_TEST); + int stencilenabled = qglIsEnabled(GL_STENCIL_TEST); + qglDisable(GL_DEPTH_TEST); + qglDisable(GL_STENCIL_TEST); + //qglDisable(GL_CULL_FACE); + qglColorMask(1,1,1,1); + memset(&m, 0, sizeof(m)); + R_Mesh_State_Texture(&m); + GL_Color(0,0.1,0,1); + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next) + { + GL_VertexPointer(mesh->vertex3f); + R_Mesh_Draw_ShowTris(mesh->numverts, mesh->numtriangles, mesh->element3i); + } + //qglEnable(GL_CULL_FACE); + if (depthenabled) + qglEnable(GL_DEPTH_TEST); + if (stencilenabled) + { + qglEnable(GL_STENCIL_TEST); + qglColorMask(0,0,0,0); + } + } + R_Shadow_RenderShadowMeshVolume(rtlight->static_meshchain_shadow); + } + else + R_TestAndDrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs); + if (r_drawentities.integer) + for (i = 0;i < r_refdef.numentities;i++) + if (r_refdef.entities[i]->flags & RENDER_SHADOW) + R_TestAndDrawShadowVolume(r_refdef.entities[i], rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs); + } + + if (!visiblevolumes) + { + if (shadow && gl_stencil) + R_Shadow_Stage_LightWithShadows(); + else + R_Shadow_Stage_LightWithoutShadows(); + + ent = &cl_entities[0].render; + if (ent->model && ent->model->DrawLight) + { + 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); + if (r_shadow_staticworldlights.integer && rtlight->compiled) + { + //R_Shadow_DrawStaticWorldLight_Light(rtlight, &ent->matrix, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture); + shadowmesh_t *mesh; + R_Mesh_Matrix(&ent->matrix); + if (r_shadow_showtris.integer) + { + rmeshstate_t m; + int depthenabled = qglIsEnabled(GL_DEPTH_TEST); + int stencilenabled = qglIsEnabled(GL_STENCIL_TEST); + qglDisable(GL_DEPTH_TEST); + qglDisable(GL_STENCIL_TEST); + //qglDisable(GL_CULL_FACE); + memset(&m, 0, sizeof(m)); + R_Mesh_State_Texture(&m); + GL_Color(0.2,0,0,1); + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next) + { + GL_VertexPointer(mesh->vertex3f); + R_Mesh_Draw_ShowTris(mesh->numverts, mesh->numtriangles, mesh->element3i); + } + //qglEnable(GL_CULL_FACE); + if (depthenabled) + qglEnable(GL_DEPTH_TEST); + if (stencilenabled) + qglEnable(GL_STENCIL_TEST); + } + for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next) + { + R_Shadow_DiffuseLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, mesh->map_normal, cubemaptexture); + R_Shadow_SpecularLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_specular, mesh->map_normal, cubemaptexture); + } + } + else + ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture); + } + if (r_drawentities.integer) + { + for (i = 0;i < r_refdef.numentities;i++) + { + ent = r_refdef.entities[i]; + if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight + && BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs) + && (ent->flags & RENDER_LIGHT)) + { + 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); + } + } + } + } +} + +void R_ShadowVolumeLighting(int visiblevolumes) +{ + int lnum; + dlight_t *light; + rmeshstate_t m; + + if (visiblevolumes) + { + memset(&m, 0, sizeof(m)); + R_Mesh_State_Texture(&m); + + GL_BlendFunc(GL_ONE, GL_ONE); + GL_DepthMask(false); + GL_DepthTest(r_shadow_visiblevolumes.integer < 2); + qglDisable(GL_CULL_FACE); + GL_Color(0.0, 0.0125, 0.1, 1); + } + 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) + if (lnum == r_shadow_debuglight.integer) + R_DrawRTLight(&light->rtlight, visiblevolumes); + } + else + 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) + for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++) + R_DrawRTLight(&light->rtlight, visiblevolumes); + + if (visiblevolumes) + { + qglEnable(GL_CULL_FACE); + GL_Scissor(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height); + } + else + R_Shadow_Stage_End(); } -void R_Shadow_FreeWorldLight(worldlight_t *light) +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 { - worldlight_t **lightpointer; + 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; +} +suffixinfo_t; +static suffixinfo_t suffix[3][6] = +{ + { + {"posx", false, false, false}, + {"negx", false, false, false}, + {"posy", false, false, false}, + {"negy", false, false, false}, + {"posz", false, false, false}, + {"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} + } +}; + +static int componentorder[4] = {0, 1, 2, 3}; + +rtexture_t *R_Shadow_LoadCubemap(const char *basename) +{ + int i, j, cubemapsize; + qbyte *cubemappixels, *image_rgba; + rtexture_t *cubemaptexture; + char name[256]; + // must start 0 so the first loadimagepixels has no requested width/height + cubemapsize = 0; + cubemappixels = NULL; + cubemaptexture = NULL; + for (j = 0;j < 3 && !cubemappixels;j++) + { + for (i = 0;i < 6;i++) + { + snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix); + if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize))) + { + if (image_width == image_height) + { + if (!cubemappixels && image_width >= 1) + { + cubemapsize = image_width; + // note this clears to black, so unavailable sizes are black + cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4); + } + 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); + Mem_Free(image_rgba); + } + } + } + if (cubemappixels) + { + if (!r_shadow_filters_texturepool) + r_shadow_filters_texturepool = R_AllocTexturePool(); + cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL); + Mem_Free(cubemappixels); + } + else + { + Con_Printf("Failed to load Cubemap \"%s\", tried ", basename); + for (j = 0;j < 3;j++) + for (i = 0;i < 6;i++) + Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix); + Con_Printf(" and was unable to find any of them.\n"); + } + return cubemaptexture; +} + +rtexture_t *R_Shadow_Cubemap(const char *basename) +{ + int i; + for (i = 0;i < numcubemaps;i++) + if (!strcasecmp(cubemaps[i].basename, basename)) + return cubemaps[i].texture; + if (i >= MAX_CUBEMAPS) + return NULL; + numcubemaps++; + strcpy(cubemaps[i].basename, basename); + cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename); + return cubemaps[i].texture; +} + +void R_Shadow_FreeCubemaps(void) +{ + numcubemaps = 0; + 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 *light; + + if (radius < 15 || DotProduct(color, color) < 0.03) + { + Con_Printf("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n"); + return; + } + + light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t)); + VectorCopy(origin, light->origin); + VectorCopy(angles, light->angles); + VectorCopy(color, light->color); + light->radius = radius; + light->style = style; + if (light->style < 0 || light->style >= MAX_LIGHTSTYLES) + { + Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES); + light->style = 0; + } + light->shadow = shadowenable; + light->corona = corona; + 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; 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; - if (light->cubemapname) - Mem_Free(light->cubemapname); - if (light->meshchain_shadow) - Mod_ShadowMesh_Free(light->meshchain_shadow); - if (light->meshchain_light) - Mod_ShadowMesh_Free(light->meshchain_light); + R_RTLight_Uncompile(&light->rtlight); Mem_Free(light); } @@ -2283,7 +2498,7 @@ void R_Shadow_ClearWorldLights(void) R_Shadow_FreeCubemaps(); } -void R_Shadow_SelectLight(worldlight_t *light) +void R_Shadow_SelectLight(dlight_t *light) { if (r_shadow_selectedlight) r_shadow_selectedlight->selected = false; @@ -2303,12 +2518,12 @@ void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2) void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2) { float intensity; - const worldlight_t *light; + const dlight_t *light; light = calldata1; intensity = 0.5; if (light->selected) intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0); - if (!light->meshchain_shadow) + if (!light->shadow) intensity *= 0.5f; R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[calldata2], false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5); } @@ -2317,7 +2532,7 @@ void R_Shadow_DrawLightSprites(void) { int i; cachepic_t *pic; - worldlight_t *light; + dlight_t *light; for (i = 0;i < 5;i++) { @@ -2334,7 +2549,7 @@ void R_Shadow_DrawLightSprites(void) void R_Shadow_SelectLightInView(void) { float bestrating, rating, temp[3]; - worldlight_t *best, *light; + dlight_t *best, *light; best = NULL; bestrating = 0; for (light = r_shadow_worldlightchain;light;light = light->next) @@ -2386,18 +2601,17 @@ void R_Shadow_LoadWorldLights(void) shadow = false; t++; } - a = sscanf(t, "%f %f %f %f %f %f %f %d %s %f %f %f %f", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname, &corona, &angles[0], &angles[1], &angles[2]); + a = sscanf(t, "%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname, &corona, &angles[0], &angles[1], &angles[2]); if (a < 13) - { - corona = 0; VectorClear(angles); - } + if (a < 10) + corona = 0; if (a < 9) cubemapname[0] = 0; *s = '\n'; if (a < 8) { - Con_Printf("found %d parameters on line %i, should be 8 or 9 parameters (origin[0] origin[1] origin[2] radius color[0] color[1] color[2] style cubemapname)\n", a, n + 1); + Con_Printf("found %d parameters on line %i, should be 8 or more parameters (origin[0] origin[1] origin[2] radius color[0] color[1] color[2] style \"cubemapname\" corona angles[0] angles[1] angles[2])\n", a, n + 1); break; } VectorScale(color, r_editlights_rtlightscolorscale.value, color); @@ -2414,7 +2628,7 @@ void R_Shadow_LoadWorldLights(void) void R_Shadow_SaveWorldLights(void) { - worldlight_t *light; + dlight_t *light; int bufchars, bufmaxchars; char *buf, *oldbuf; char name[MAX_QPATH]; @@ -2432,7 +2646,7 @@ 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\n", light->drawshadows ? "" : "!", 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->cubemapname : ""); + 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->cubemapname : "", light->corona, light->angles[0], light->angles[1], light->angles[2]); if (bufchars + (int) strlen(line) > bufmaxchars) { bufmaxchars = bufchars + strlen(line) + 2048; @@ -2765,7 +2979,7 @@ void R_Shadow_EditLights_Edit_f(void) strcpy(cubemapname, r_shadow_selectedlight->cubemapname); else cubemapname[0] = 0; - shadows = r_shadow_selectedlight->drawshadows; + shadows = r_shadow_selectedlight->shadow; corona = r_shadow_selectedlight->corona; if (!strcmp(Cmd_Argv(1), "origin")) { @@ -2950,7 +3164,7 @@ void R_Shadow_EditLights_Edit_f(void) Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius); Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona); Con_Printf("Style : %i\n", r_shadow_selectedlight->style); - Con_Printf("Shadows: %s\n", r_shadow_selectedlight->drawshadows ? "yes" : "no"); + Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no"); Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname); return; } @@ -2975,7 +3189,7 @@ void R_Shadow_EditLights_DrawSelectedLightProperties(void) sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; - sprintf(temp, "Shadows %s", r_shadow_selectedlight->drawshadows ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; + sprintf(temp, "Shadows %s", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; } @@ -2991,7 +3205,7 @@ void R_Shadow_EditLights_ToggleShadow_f(void) Con_Printf("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->drawshadows, r_shadow_selectedlight->cubemapname); + 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; } @@ -3008,7 +3222,7 @@ void R_Shadow_EditLights_ToggleCorona_f(void) Con_Printf("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->drawshadows, r_shadow_selectedlight->cubemapname); + 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; } diff --git a/r_shadow.h b/r_shadow.h index 4e1349a3..3af580fe 100644 --- a/r_shadow.h +++ b/r_shadow.h @@ -17,8 +17,8 @@ extern cvar_t r_shadow_dlightshadows; void R_Shadow_Init(void); void R_Shadow_Volume(int numverts, int numtris, const float *invertex3f, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance); -void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *elements, const float *vertices, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, float lightradius, const float *lightcolor, const matrix4x4_t *matrix_worldtolight, const matrix4x4_t *matrix_worldtoattenuationxyz, const matrix4x4_t *matrix_worldtoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *lightcubemap); -void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elements, const float *vertices, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, const float *relativeeyeorigin, float lightradius, const float *lightcolor, const matrix4x4_t *matrix_worldtolight, const matrix4x4_t *matrix_worldtoattenuationxyz, const matrix4x4_t *matrix_worldtoattenuationz, rtexture_t *glosstexture, rtexture_t *bumptexture, rtexture_t *lightcubemap); +void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *elements, const float *vertices, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, const float *lightcolor, const matrix4x4_t *matrix_worldtolight, const matrix4x4_t *matrix_worldtoattenuationxyz, const matrix4x4_t *matrix_worldtoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *lightcubemap); +void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elements, const float *vertices, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, const float *relativeeyeorigin, const float *lightcolor, const matrix4x4_t *matrix_worldtolight, const matrix4x4_t *matrix_worldtoattenuationxyz, const matrix4x4_t *matrix_worldtoattenuationz, rtexture_t *glosstexture, rtexture_t *bumptexture, rtexture_t *lightcubemap); void R_Shadow_ClearStencil(void); void R_Shadow_RenderShadowMeshVolume(shadowmesh_t *mesh); @@ -36,58 +36,14 @@ extern matrix4x4_t matrix_attenuationz; rtexture_t *R_Shadow_Cubemap(const char *basename); -typedef struct worldlight_s -{ - // saved properties - vec3_t origin; - vec3_t angles; - vec3_t color; - vec_t radius; - vec_t corona; - int drawshadows; - char *cubemapname; - - // shadow volumes are done entirely in model space, so there are no matrices for dealing with them... - - // note that the world to light matrices are inversely scaled (divided) by lightradius - - // matrix for transforming world coordinates to light filter coordinates - //matrix4x4_t matrix_worldtolight; - // based on worldtolight this transforms -1 to +1 to 0 to 1 for purposes - // of attenuation texturing in full 3D (z result often ignored) - //matrix4x4_t matrix_worldtoattenuationxyz; - // this transforms only the Z to S, and T is always 0.5 - //matrix4x4_t matrix_worldtoattenuationz; - - // generated properties - vec3_t mins; - vec3_t maxs; - vec_t cullradius; - struct worldlight_s *next; - rtexture_t *cubemap; - int style; - int selected; - - matrix4x4_t matrix_lighttoworld; - matrix4x4_t matrix_worldtolight; - matrix4x4_t matrix_worldtoattenuationxyz; - matrix4x4_t matrix_worldtoattenuationz; - - // premade shadow volumes and lit surfaces to render - shadowmesh_t *meshchain_shadow; - shadowmesh_t *meshchain_light; - - // used for visibility testing - int numclusters; - int *clusterindices; -} -worldlight_t; - -extern worldlight_t *r_shadow_worldlightchain; +extern dlight_t *r_shadow_worldlightchain; void R_Shadow_UpdateWorldLightSelection(void); -void R_Shadow_DrawStaticWorldLight_Shadow(worldlight_t *light, matrix4x4_t *matrix); -void R_Shadow_DrawStaticWorldLight_Light(worldlight_t *light, matrix4x4_t *matrix, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz); +void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic); +void R_RTLight_Compile(rtlight_t *rtlight); +void R_RTLight_Uncompile(rtlight_t *rtlight); + +void R_ShadowVolumeLighting(int visiblevolumes); #endif diff --git a/render.h b/render.h index a85e6604..9a28218f 100644 --- a/render.h +++ b/render.h @@ -127,6 +127,7 @@ void R_DrawExplosions(void); //#define PARANOID 1 int R_CullBox(const vec3_t mins, const vec3_t maxs); +#define VIS_CullBox(mins,maxs) (R_CullBox((mins), (maxs)) || (cl.worldmodel && cl.worldmodel->brush.BoxTouchingPVS && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, r_pvsbits, (mins), (maxs)))) extern qboolean fogenabled; extern vec3_t fogcolor; diff --git a/todo b/todo index e2846a52..bf15b682 100644 --- a/todo +++ b/todo @@ -34,6 +34,22 @@ -n darkplaces: segfault reading memory in windows when starting a new server from menu (yummyluv) -n darkplaces: server is starting before the "port" cvar is set by commandline and scripts? (yummyluv) -n darkplaces: typing ip in join game menu should show 'trying' and 'no response' after a while, or 'no network' if networking is not initialized (yummyluv) +d darkplaces: fixed SV_TouchAreaGrid to not crash if SV_IncreaseEdicts is called during a touch function, by making a list of edicts to touch and then running through the list afterward (KGB|romi) +d darkplaces: moved R_ShadowVolumeLighting to r_shadow.c +d darkplaces: added RENDER_LIGHT flag to entity_render_t to make rtlighting optional per entity +d darkplaces: cleaned up rtlight handling, merging most code between world rtlights and dlights +d darkplaces: safety checked lightmap access in Mod_Q1BSP_RecursiveLightPoint as one map Sajt uses was crashing (Sajt) +0 darkplaces: upgrade network protocol to send precise angles, and make EF_LOWPRECISION downgrade both origin and angles (Urre) +0 darkplaces: figure out why cubemap upload scaling crashes (Urre) +0 darkplaces: make screenshots save to screenshots/fniggium%04i.tga in GAME_FNIGGIUM (Sajt) +0 darkplaces: make screenshots save to screenshots directory (Sajt) +2 darkplaces: make corona occlusion testing use GL_ARB_occlusion_query instead of a CL_TraceLine (Riot) +d darkplaces: default a few cvars accordingly for GAME_TENEBRAE mode +d darkplaces: add skin and pflags support to light entity loader +0 darkplaces: add EF_NOSHADOW to make entities that never cast shadows (Urre) +2 darkplaces: fix fogging in realtime lighting mode, need to split the shaders into two stages, this will also fix decal bugs with fog (Electro, Mitchell) +0 darkplaces: fix cl_nodelta 1, it's halting updates (Tomaz) +0 darkplaces: player setup menu network speed is never applying to rate (Mitchell) d darkplaces: PF_traceline/PF_tracebox now work with world as the edict d darkplaces: make the static light built messages be developer prints (Tomaz) d dpmod: use Tomaz's ammo box models (Tomaz) @@ -279,7 +295,7 @@ d darkplaces: q1bsp trace bug: scrags frequently fly through ceilings - this nee 0 sv_user.qc: figure out why looking up/down slows movement and fix it (Vermeulen) 1 darkplaces: add DP_CLIENTCAMERA extension (.entity clientcamera; sets which entity the client views from) (Wazat for Battlemech, SeienAbunae) 1 darkplaces: add DP_EF_CLIENTLOCKANGLES extension (prevents client from turning view, takes angles from entity) (Wazat for Battlemech, SeienAbunae) -1 darkplaces: add DP_EF_PRECISEANGLES extension (sends short angles instead of byte) (Wazat for Battlemech, FrikaC, mashakos, RenegadeC) +1 darkplaces: add DP_EF_PRECISEANGLES extension (sends short angles instead of byte) (Wazat for Battlemech, FrikaC, mashakos, RenegadeC, Sajt) 1 darkplaces: add DP_QC_ENDFRAME extension/documentation and post it on wiki (tell Uffe, SeienAbunae) 1 darkplaces: add DP_SV_READCLIENTINPUT extension (.vector clientinput; works like .movement but for mouse or any other similar controllers) (Wazat for Battlemech, FrikaC, SeienAbunae) 1 darkplaces: add EndGame function (called on server shutdown or level change) (SeienAbunae, Nexuiz) -- 2.39.2