diff --git a/src/gl/dynlights/a_dynlight.cpp b/src/gl/dynlights/a_dynlight.cpp index 93000e83a..e7d41aa22 100644 --- a/src/gl/dynlights/a_dynlight.cpp +++ b/src/gl/dynlights/a_dynlight.cpp @@ -45,6 +45,7 @@ #include "templates.h" #include "doomdata.h" #include "r_utility.h" +#include "portal.h" #include "gl/renderer/gl_renderer.h" @@ -508,25 +509,25 @@ static FLightNode * DeleteLightNode(FLightNode * node) // //========================================================================== -float ADynamicLight::DistToSeg(seg_t *seg) +float ADynamicLight::DistToSeg(const fixedvec3 &pos, seg_t *seg) { - float u, px, py; + float u, px, py; - float seg_dx = FIXED2FLOAT(seg->v2->x - seg->v1->x); - float seg_dy = FIXED2FLOAT(seg->v2->y - seg->v1->y); - float seg_length_sq = seg_dx * seg_dx + seg_dy * seg_dy; + float seg_dx = FIXED2FLOAT(seg->v2->x - seg->v1->x); + float seg_dy = FIXED2FLOAT(seg->v2->y - seg->v1->y); + float seg_length_sq = seg_dx * seg_dx + seg_dy * seg_dy; - u = ( FIXED2FLOAT(X() - seg->v1->x) * seg_dx + FIXED2FLOAT(Y() - seg->v1->y) * seg_dy) / seg_length_sq; - if (u < 0.f) u = 0.f; // clamp the test point to the line segment - if (u > 1.f) u = 1.f; + u = (FIXED2FLOAT(pos.x - seg->v1->x) * seg_dx + FIXED2FLOAT(pos.y - seg->v1->y) * seg_dy) / seg_length_sq; + if (u < 0.f) u = 0.f; // clamp the test point to the line segment + if (u > 1.f) u = 1.f; - px = FIXED2FLOAT(seg->v1->x) + (u * seg_dx); - py = FIXED2FLOAT(seg->v1->y) + (u * seg_dy); + px = FIXED2FLOAT(seg->v1->x) + (u * seg_dx); + py = FIXED2FLOAT(seg->v1->y) + (u * seg_dy); - px -= FIXED2FLOAT(X()); - py -= FIXED2FLOAT(Y()); + px -= FIXED2FLOAT(pos.x); + py -= FIXED2FLOAT(pos.y); - return (px*px) + (py*py); + return (px*px) + (py*py); } @@ -537,7 +538,7 @@ float ADynamicLight::DistToSeg(seg_t *seg) // //========================================================================== -void ADynamicLight::CollectWithinRadius(subsector_t *subSec, float radius) +void ADynamicLight::CollectWithinRadius(const fixedvec3 &pos, subsector_t *subSec, float radius) { if (!subSec) return; @@ -557,12 +558,28 @@ void ADynamicLight::CollectWithinRadius(subsector_t *subSec, float radius) if (seg->sidedef && seg->linedef && seg->linedef->validcount!=::validcount) { // light is in front of the seg - if (DMulScale32 (Y()-seg->v1->y, seg->v2->x-seg->v1->x, seg->v1->x-X(), seg->v2->y-seg->v1->y) <=0) + if (DMulScale32(pos.y - seg->v1->y, seg->v2->x - seg->v1->x, seg->v1->x - pos.x, seg->v2->y - seg->v1->y) <= 0) { - seg->linedef->validcount=validcount; + seg->linedef->validcount = validcount; touching_sides = AddLightNode(&seg->sidedef->lighthead, seg->sidedef, this, touching_sides); } } + if (seg->linedef) + { + FLinePortal *port = seg->linedef->getPortal(); + if (port && port->mType == PORTT_LINKED) + { + if (DistToSeg(pos, seg) <= radius) + { + line_t *other = port->mDestination; + if (other->validcount != ::validcount) + { + subsector_t *othersub = R_PointInSubsector(other->v1->x + other->dx / 2, other->v1->y + other->dy / 2); + if (othersub->validcount != ::validcount) CollectWithinRadius(PosRelative(other), othersub, radius); + } + } + } + } seg_t *partner = seg->PartnerSeg; if (partner) @@ -571,13 +588,35 @@ void ADynamicLight::CollectWithinRadius(subsector_t *subSec, float radius) if (sub != NULL && sub->validcount!=::validcount) { // check distance from x/y to seg and if within radius add opposing subsector (lather/rinse/repeat) - if (DistToSeg(seg) <= radius) + if (DistToSeg(pos, seg) <= radius) { - CollectWithinRadius(sub, radius); + CollectWithinRadius(pos, sub, radius); } } } } + if (subSec->sector->PortalIsLinked(sector_t::ceiling)) + { + line_t *other = subSec->firstline->linedef; + AActor *sb = subSec->sector->SkyBoxes[sector_t::ceiling]; + if (sb->threshold < Z() + radius) + { + fixedvec2 refpos = { other->v1->x + other->dx / 2 + sb->scaleX, other->v1->y + other->dy / 2 + sb->scaleY }; + subsector_t *othersub = R_PointInSubsector(refpos.x, refpos.y); + if (othersub->validcount != ::validcount) CollectWithinRadius(PosRelative(othersub->sector), othersub, radius); + } + } + if (subSec->sector->PortalIsLinked(sector_t::floor)) + { + line_t *other = subSec->firstline->linedef; + AActor *sb = subSec->sector->SkyBoxes[sector_t::floor]; + if (sb->threshold > Z() - radius) + { + fixedvec2 refpos = { other->v1->x + other->dx / 2 + sb->scaleX, other->v1->y + other->dy / 2 + sb->scaleY }; + subsector_t *othersub = R_PointInSubsector(refpos.x, refpos.y); + if (othersub->validcount != ::validcount) CollectWithinRadius(PosRelative(othersub->sector), othersub, radius); + } + } } //========================================================================== @@ -614,12 +653,10 @@ void ADynamicLight::LinkLight() { // passing in radius*radius allows us to do a distance check without any calls to sqrtf subsector_t * subSec = R_PointInSubsector(X(), Y()); - if (subSec) - { - float fradius = FIXED2FLOAT(radius); - ::validcount++; - CollectWithinRadius(subSec, fradius*fradius); - } + float fradius = FIXED2FLOAT(radius); + ::validcount++; + CollectWithinRadius(Pos(), subSec, fradius*fradius); + } // Now delete any nodes that won't be used. These are the ones where diff --git a/src/gl/dynlights/gl_dynlight.h b/src/gl/dynlights/gl_dynlight.h index c78a0c927..3e263c895 100644 --- a/src/gl/dynlights/gl_dynlight.h +++ b/src/gl/dynlights/gl_dynlight.h @@ -99,8 +99,8 @@ public: FLightNode * touching_sector; private: - float DistToSeg(seg_t *seg); - void CollectWithinRadius(subsector_t *subSec, float radius); + float DistToSeg(const fixedvec3 &pos, seg_t *seg); + void CollectWithinRadius(const fixedvec3 &pos, subsector_t *subSec, float radius); protected: fixed_t m_offX, m_offY, m_offZ; @@ -184,7 +184,7 @@ struct FDynLightData -bool gl_GetLight(Plane & p, ADynamicLight * light, bool checkside, bool forceadditive, FDynLightData &data); +bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, bool forceadditive, FDynLightData &data); void gl_UploadLights(FDynLightData &data); diff --git a/src/gl/dynlights/gl_dynlight1.cpp b/src/gl/dynlights/gl_dynlight1.cpp index 864a9f3ce..b57882dcf 100644 --- a/src/gl/dynlights/gl_dynlight1.cpp +++ b/src/gl/dynlights/gl_dynlight1.cpp @@ -85,14 +85,15 @@ CUSTOM_CVAR (Bool, gl_lights_additive, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG // Sets up the parameters to render one dynamic light onto one plane // //========================================================================== -bool gl_GetLight(Plane & p, ADynamicLight * light, bool checkside, bool forceadditive, FDynLightData &ldata) +bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, bool forceadditive, FDynLightData &ldata) { Vector fn, pos; int i = 0; - float x = FIXED2FLOAT(light->X()); - float y = FIXED2FLOAT(light->Y()); - float z = FIXED2FLOAT(light->Z()); + fixedvec3 lpos = light->PosRelative(group); + float x = FIXED2FLOAT(lpos.x); + float y = FIXED2FLOAT(lpos.y); + float z = FIXED2FLOAT(lpos.z); float dist = fabsf(p.DistToPoint(x, z, y)); float radius = (light->GetRadius() * gl_lights_size); diff --git a/src/gl/scene/gl_flats.cpp b/src/gl/scene/gl_flats.cpp index c6ca9df96..7b8209eb3 100644 --- a/src/gl/scene/gl_flats.cpp +++ b/src/gl/scene/gl_flats.cpp @@ -150,7 +150,7 @@ void GLFlat::SetupSubsectorLights(int pass, subsector_t * sub, int *dli) } p.Set(plane.plane); - gl_GetLight(p, light, false, false, lightdata); + gl_GetLight(sub->sector->PortalGroup, p, light, false, false, lightdata); node = node->nextLight; } diff --git a/src/gl/scene/gl_walls_draw.cpp b/src/gl/scene/gl_walls_draw.cpp index 02a48c706..2b2e5bc6f 100644 --- a/src/gl/scene/gl_walls_draw.cpp +++ b/src/gl/scene/gl_walls_draw.cpp @@ -155,7 +155,7 @@ void GLWall::SetupLights() } if (outcnt[0]!=4 && outcnt[1]!=4 && outcnt[2]!=4 && outcnt[3]!=4) { - gl_GetLight(p, node->lightsource, true, false, lightdata); + gl_GetLight(seg->frontsector->PortalGroup, p, node->lightsource, true, false, lightdata); } } }