diff --git a/src/gl/dynlights/gl_dynlight1.cpp b/src/gl/dynlights/gl_dynlight1.cpp index c41290740..42f1c27cf 100644 --- a/src/gl/dynlights/gl_dynlight1.cpp +++ b/src/gl/dynlights/gl_dynlight1.cpp @@ -141,10 +141,10 @@ void gl_AddLightToList(int group, ADynamicLight * light, FDynLightData &ldata) spotOuterAngle = light->SpotOuterAngle.Cos(); DAngle negPitch = -light->Angles.Pitch; - float xyLen = negPitch.Cos(); - spotDirX = -light->Angles.Yaw.Cos() * xyLen; - spotDirY = -light->Angles.Yaw.Sin() * xyLen; - spotDirZ = -negPitch.Sin(); + double xzLen = negPitch.Cos(); + spotDirX = -light->Angles.Yaw.Cos() * xzLen; + spotDirY = -negPitch.Sin(); + spotDirZ = -light->Angles.Yaw.Sin() * xzLen; } float *data = &ldata.arrays[i][ldata.arrays[i].Reserve(16)]; diff --git a/src/gl/scene/gl_spritelight.cpp b/src/gl/scene/gl_spritelight.cpp index 2d2e65b76..bde9f1450 100644 --- a/src/gl/scene/gl_spritelight.cpp +++ b/src/gl/scene/gl_spritelight.cpp @@ -49,6 +49,13 @@ FDynLightData modellightdata; int modellightindex = -1; +template +T smoothstep(const T edge0, const T edge1, const T x) +{ + auto t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); + return t * t * (3.0 - 2.0 * t); +} + //========================================================================== // // Sets a single light value from all dynamic lights affecting the specified location @@ -70,6 +77,7 @@ void gl_SetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t * if (light->visibletoplayer && !(light->flags2&MF2_DORMANT) && (!(light->lightflags&LF_DONTLIGHTSELF) || light->target != self) && !(light->lightflags&LF_DONTLIGHTACTORS)) { float dist; + FVector3 L; // This is a performance critical section of code where we cannot afford to let the compiler decide whether to inline the function or not. // This will do the calculations explicitly rather than calling one of AActor's utility functions. @@ -80,14 +88,15 @@ void gl_SetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t * if (fromgroup == togroup || fromgroup == 0 || togroup == 0) goto direct; DVector2 offset = Displacements.getOffset(fromgroup, togroup); - dist = FVector3(x - light->X() - offset.X, y - light->Y() - offset.Y, z - light->Z()).LengthSquared(); + L = FVector3(x - light->X() - offset.X, y - light->Y() - offset.Y, z - light->Z()); } else { direct: - dist = FVector3(x - light->X(), y - light->Y(), z - light->Z()).LengthSquared(); + L = FVector3(x - light->X(), y - light->Y(), z - light->Z()); } + dist = L.LengthSquared(); radius = light->GetRadius(); if (dist < radius * radius) @@ -96,6 +105,17 @@ void gl_SetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t * frac = 1.0f - (dist / radius); + if (light->IsSpot()) + { + DAngle negPitch = -light->Angles.Pitch; + double xzLen = negPitch.Cos(); + double spotDirX = -light->Angles.Yaw.Cos() * xzLen; + double spotDirY = -negPitch.Sin(); + double spotDirZ = -light->Angles.Yaw.Sin() * xzLen; + double cosDir = L.X * spotDirX + L.Y * spotDirY + L.Z * spotDirZ; + frac *= (float)smoothstep(light->SpotOuterAngle.Cos(), light->SpotInnerAngle.Cos(), cosDir); + } + if (frac > 0 && GLRenderer->mShadowMap.ShadowTest(light, { x, y, z })) { lr = light->GetRed() / 255.0f;