mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-11 15:22:16 +00:00
- Include all lights touching a model actor's render radius
This commit is contained in:
parent
65d5f4ae18
commit
aaa00cbcb9
6 changed files with 110 additions and 30 deletions
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue