From aaa00cbcb9c493d62500df5a8652929fc2c58942 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 1 Aug 2017 00:43:58 +0200 Subject: [PATCH] - Include all lights touching a model actor's render radius --- src/gl/dynlights/gl_dynlight.h | 3 +- src/gl/dynlights/gl_dynlight1.cpp | 40 +++++++++----- src/gl/scene/gl_sprite.cpp | 2 +- src/gl/scene/gl_spritelight.cpp | 91 +++++++++++++++++++++++++++---- src/gl/scene/gl_wall.h | 2 +- src/gl/scene/gl_weapon.cpp | 2 +- 6 files changed, 110 insertions(+), 30 deletions(-) diff --git a/src/gl/dynlights/gl_dynlight.h b/src/gl/dynlights/gl_dynlight.h index 3eb19ee39..a85814b6b 100644 --- a/src/gl/dynlights/gl_dynlight.h +++ b/src/gl/dynlights/gl_dynlight.h @@ -58,7 +58,8 @@ struct FDynLightData -bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, FDynLightData &data, bool planecheck = true, bool hudmodel = false); +bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, FDynLightData &data); +void gl_AddLightToList(int group, ADynamicLight * light, FDynLightData &ldata, bool hudmodel); void gl_UploadLights(FDynLightData &data); diff --git a/src/gl/dynlights/gl_dynlight1.cpp b/src/gl/dynlights/gl_dynlight1.cpp index 13443c26a..92a503c8d 100644 --- a/src/gl/dynlights/gl_dynlight1.cpp +++ b/src/gl/dynlights/gl_dynlight1.cpp @@ -63,24 +63,35 @@ CVAR(Int, gl_attenuate, -1, 0); // This is mainly a debug option. // Sets up the parameters to render one dynamic light onto one plane // //========================================================================== -bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, FDynLightData &ldata, bool planecheck, bool hudmodel) +bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, FDynLightData &ldata) +{ + DVector3 pos = light->PosRelative(group); + float radius = (light->GetRadius()); + + float dist = fabsf(p.DistToPoint(pos.X, pos.Z, pos.Y)); + + if (radius <= 0.f) return false; + if (dist > radius) return false; + if (checkside && gl_lights_checkside && p.PointOnSide(pos.X, pos.Z, pos.Y)) + { + return false; + } + + gl_AddLightToList(group, light, ldata, false); + return true; +} + +//========================================================================== +// +// Add one dynamic light to the light data list +// +//========================================================================== +void gl_AddLightToList(int group, ADynamicLight * light, FDynLightData &ldata, bool hudmodel) { int i = 0; DVector3 pos = light->PosRelative(group); - float radius = (light->GetRadius()); - - if (planecheck) - { - float dist = fabsf(p.DistToPoint(pos.X, pos.Z, pos.Y)); - - if (radius <= 0.f) return false; - if (dist > radius) return false; - if (checkside && gl_lights_checkside && p.PointOnSide(pos.X, pos.Z, pos.Y)) - { - return false; - } - } + float radius = light->GetRadius(); if (hudmodel) { @@ -151,6 +162,5 @@ bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, FD data[5] = g; data[6] = b; data[7] = shadowIndex; - return true; } diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index d42eea5ee..e7e82a569 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -327,7 +327,7 @@ void GLSprite::Draw(int pass) if (gl_lights && GLRenderer->mLightCount && mDrawer->FixedColormap == CM_DEFAULT && !fullbright) { if (modelframe && !particle) - gl_SetDynModelLight(gl_light_sprites ? actor : NULL, actor->X(), actor->Y(), actor->Center(), actor->subsector); + gl_SetDynModelLight(gl_light_sprites ? actor : NULL, false); else gl_SetDynSpriteLight(gl_light_sprites ? actor : NULL, gl_light_particles ? particle : NULL); } diff --git a/src/gl/scene/gl_spritelight.cpp b/src/gl/scene/gl_spritelight.cpp index 7a30015f8..fa4318535 100644 --- a/src/gl/scene/gl_spritelight.cpp +++ b/src/gl/scene/gl_spritelight.cpp @@ -32,6 +32,7 @@ #include "vectors.h" #include "gl/gl_functions.h" #include "g_level.h" +#include "g_levellocals.h" #include "gl/system/gl_cvars.h" #include "gl/renderer/gl_renderer.h" @@ -132,23 +133,91 @@ void gl_SetDynSpriteLight(AActor *thing, particle_t *particle) } } -void gl_SetDynModelLight(AActor *self, float x, float y, float z, subsector_t * subsec, bool hudmodel) +// Check if circle potentially intersects with node AABB +static bool CheckBBoxCircle(float *bbox, float x, float y, float radiusSquared) { - Plane p; - p.Set(subsec->sector->ceilingplane); // Is this correct? + float centerX = (bbox[BOXRIGHT] + bbox[BOXLEFT]) * 0.5f; + float centerY = (bbox[BOXBOTTOM] + bbox[BOXTOP]) * 0.5f; + float extentX = (bbox[BOXRIGHT] - bbox[BOXLEFT]) * 0.5f; + float extentY = (bbox[BOXBOTTOM] - bbox[BOXTOP]) * 0.5f; + float aabbRadiusSquared = extentX * extentX + extentY * extentY; + x -= centerX; + y -= centerY; + float dist = x * x + y * y; + return dist <= radiusSquared + aabbRadiusSquared; +} +template +void BSPNodeWalkCircle(void *node, float x, float y, float radiusSquared, Callback &callback) +{ + while (!((size_t)node & 1)) + { + node_t *bsp = (node_t *)node; + + if (CheckBBoxCircle(bsp->bbox[0], x, y, radiusSquared)) + BSPNodeWalkCircle(bsp->children[0], x, y, radiusSquared, callback); + + if (!CheckBBoxCircle(bsp->bbox[1], x, y, radiusSquared)) + return; + + node = bsp->children[1]; + } + + subsector_t *sub = (subsector_t *)((uint8_t *)node - 1); + callback(sub); +} + +template +void BSPWalkCircle(float x, float y, float radiusSquared, Callback &callback) +{ + if (level.nodes.Size() == 0) + callback(&level.subsectors[0]); + else + BSPNodeWalkCircle(level.HeadNode(), x, y, radiusSquared, callback); +} + +void gl_SetDynModelLight(AActor *self, bool hudmodel) +{ modellightdata.Clear(); - // Go through both light lists - FLightNode * node = subsec->lighthead; - while (node) + if (self) { - ADynamicLight *light = node->lightsource; - if (light->visibletoplayer && !(light->flags2&MF2_DORMANT) && (!(light->lightflags&LF_DONTLIGHTSELF) || light->target != self) && !(light->lightflags&LF_DONTLIGHTACTORS)) + static std::vector addedLights; // static so that we build up a reserve (memory allocations stop) + + addedLights.clear(); + + float x = self->X(); + float y = self->Y(); + float z = self->Center(); + float radiusSquared = self->renderradius * self->renderradius; + + BSPWalkCircle(x, y, radiusSquared, [&](subsector_t *subsector) // Iterate through all subsectors potentially touched by actor { - gl_GetLight(subsec->sector->PortalGroup, p, node->lightsource, false, modellightdata, false, hudmodel); - } - node = node->nextLight; + FLightNode * node = subsector->lighthead; + while (node) // check all lights touching a subsector + { + ADynamicLight *light = node->lightsource; + if (light->visibletoplayer && !(light->flags2&MF2_DORMANT) && (!(light->lightflags&LF_DONTLIGHTSELF) || light->target != self) && !(light->lightflags&LF_DONTLIGHTACTORS)) + { + int group = subsector->sector->PortalGroup; + DVector3 pos = light->PosRelative(group); + float radius = light->GetRadius(); + double dx = pos.X - x; + double dy = pos.Y - y; + double dz = pos.Z - z; + double distSquared = dx * dx + dy * dy + dz * dz; + if (distSquared < radiusSquared + radius * radius) // Light and actor touches + { + if (std::find(addedLights.begin(), addedLights.end(), light) == addedLights.end()) // Check if we already added this light from a different subsector + { + gl_AddLightToList(group, light, modellightdata, hudmodel); + addedLights.push_back(light); + } + } + } + node = node->nextLight; + } + }); } gl_RenderState.SetDynLight(0, 0, 0); diff --git a/src/gl/scene/gl_wall.h b/src/gl/scene/gl_wall.h index 9298a4703..47cf5654c 100644 --- a/src/gl/scene/gl_wall.h +++ b/src/gl/scene/gl_wall.h @@ -422,6 +422,6 @@ inline float Dist2(float x1,float y1,float x2,float y2) void gl_SetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t *subsec); void gl_SetDynSpriteLight(AActor *actor, particle_t *particle); -void gl_SetDynModelLight(AActor *self, float x, float y, float z, subsector_t * subsec, bool hudmodel = false); +void gl_SetDynModelLight(AActor *self, bool hudmodel); #endif diff --git a/src/gl/scene/gl_weapon.cpp b/src/gl/scene/gl_weapon.cpp index 36990944e..548078bed 100644 --- a/src/gl/scene/gl_weapon.cpp +++ b/src/gl/scene/gl_weapon.cpp @@ -422,7 +422,7 @@ void GLSceneDrawer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep) { FSpriteModelFrame *smf = gl_FindModelFrame(playermo->player->ReadyWeapon->GetClass(), psp->GetState()->sprite, psp->GetState()->GetFrame(), false); if (smf) - gl_SetDynModelLight(playermo, playermo->X(), playermo->Y(), playermo->Center(), playermo->subsector, true); + gl_SetDynModelLight(playermo, true); else gl_SetDynSpriteLight(playermo, NULL); }