- Include all lights touching a model actor's render radius

This commit is contained in:
Magnus Norddahl 2017-08-01 00:43:58 +02:00
parent 65d5f4ae18
commit aaa00cbcb9
6 changed files with 110 additions and 30 deletions

View file

@ -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);

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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<typename Callback>
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<typename Callback>
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<ADynamicLight*> 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);

View file

@ -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

View file

@ -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);
}