From 5f36b86013018c5a7b76b069952c0ef94d87d3f9 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 4 Jan 2018 17:58:11 +0100 Subject: [PATCH] - Add dynamic spot lights --- src/g_shared/a_dynlight.cpp | 7 ++- src/g_shared/a_dynlight.h | 9 ++-- src/g_shared/a_dynlightdata.cpp | 59 +++++++++++++++++++++- src/gl/dynlights/gl_dynlight1.cpp | 29 ++++++++++- src/scripting/thingdef_data.cpp | 1 + wadsrc/static/shaders/glsl/main.fp | 34 ++++++++++--- wadsrc/static/zscript/shared/dynlights.txt | 8 ++- 7 files changed, 134 insertions(+), 13 deletions(-) diff --git a/src/g_shared/a_dynlight.cpp b/src/g_shared/a_dynlight.cpp index 0cad5e9ba..1858a9a92 100644 --- a/src/g_shared/a_dynlight.cpp +++ b/src/g_shared/a_dynlight.cpp @@ -114,6 +114,9 @@ DEFINE_CLASS_PROPERTY(type, S, DynamicLight) //========================================================================== IMPLEMENT_CLASS(ADynamicLight, false, false) +DEFINE_FIELD(ADynamicLight, SpotInnerAngle) +DEFINE_FIELD(ADynamicLight, SpotOuterAngle) + static FRandom randLight; //========================================================================== @@ -134,7 +137,9 @@ void ADynamicLight::Serialize(FSerializer &arc) arc("lightflags", lightflags, def->lightflags) ("lighttype", lighttype, def->lighttype) ("tickcount", m_tickCount, def->m_tickCount) - ("currentradius", m_currentRadius, def->m_currentRadius); + ("currentradius", m_currentRadius, def->m_currentRadius) + ("spotinnerangle", SpotInnerAngle, def->SpotInnerAngle) + ("spotouterangle", SpotOuterAngle, def->SpotOuterAngle); if (lighttype == PulseLight) arc("lastupdate", m_lastUpdate, def->m_lastUpdate) diff --git a/src/g_shared/a_dynlight.h b/src/g_shared/a_dynlight.h index 5446ba8cf..b659507d1 100644 --- a/src/g_shared/a_dynlight.h +++ b/src/g_shared/a_dynlight.h @@ -28,7 +28,8 @@ enum LightFlag LF_DONTLIGHTSELF = 4, LF_ATTENUATE = 8, LF_NOSHADOWMAP = 16, - LF_DONTLIGHTACTORS = 32 + LF_DONTLIGHTACTORS = 32, + LF_SPOT = 64 }; typedef TFlags LightFlags; @@ -42,7 +43,7 @@ enum ELightType FlickerLight, RandomFlickerLight, SectorLight, - SpotLight, + DummyLight, ColorPulseLight, ColorFlickerLight, RandomColorFlickerLight @@ -100,6 +101,7 @@ public: bool IsActive() const { return !(flags2&MF2_DORMANT); } bool IsSubtractive() { return !!(lightflags & LF_SUBTRACTIVE); } bool IsAdditive() { return !!(lightflags & LF_ADDITIVE); } + bool IsSpot() { return !!(lightflags & LF_SPOT); } FState *targetState; FLightNode * touching_sides; FLightNode * touching_subsectors; @@ -127,6 +129,7 @@ public: bool shadowmapped; int bufferindex; LightFlags lightflags; - + DAngle SpotInnerAngle = 10.0; + DAngle SpotOuterAngle = 25.0; }; diff --git a/src/g_shared/a_dynlightdata.cpp b/src/g_shared/a_dynlightdata.cpp index fcdbcd3d1..817e7a80b 100644 --- a/src/g_shared/a_dynlightdata.cpp +++ b/src/g_shared/a_dynlightdata.cpp @@ -128,6 +128,9 @@ public: void SetAttenuate(bool on) { m_attenuate = on; } void SetHalo(bool halo) { m_halo = halo; } void SetDontLightActors(bool on) { m_dontlightactors = on; } + void SetSpot(bool spot) { m_spot = spot; } + void SetSpotInnerAngle(double angle) { m_spotInnerAngle = angle; } + void SetSpotOuterAngle(double angle) { m_spotOuterAngle = angle; } void OrderIntensities() { @@ -151,6 +154,9 @@ protected: bool m_dontlightself = false; bool m_dontlightactors = false; bool m_swapped = false; + bool m_spot = false; + double m_spotInnerAngle = 10.0; + double m_spotOuterAngle = 25.0; }; TDeletingArray LightDefaults; @@ -183,6 +189,10 @@ void FLightDefaults::ApplyProperties(ADynamicLight * light) const if (m_additive) light->lightflags |= LF_ADDITIVE; if (m_dontlightself) light->lightflags |= LF_DONTLIGHTSELF; if (m_dontlightactors) light->lightflags |= LF_DONTLIGHTACTORS; + if (m_spot) + light->lightflags |= LF_SPOT; + light->SpotInnerAngle = m_spotInnerAngle; + light->SpotOuterAngle = m_spotOuterAngle; light->m_tickCount = 0; if (m_type == PulseLight) { @@ -233,7 +243,8 @@ static const char *LightTags[]= "dontlightself", "attenuate", "dontlightactors", - NULL + "spot", + nullptr }; @@ -255,6 +266,7 @@ enum { LIGHTTAG_DONTLIGHTSELF, LIGHTTAG_ATTENUATE, LIGHTTAG_DONTLIGHTACTORS, + LIGHTTAG_SPOT }; @@ -395,6 +407,15 @@ static void ParsePointLight(FScanner &sc) case LIGHTTAG_DONTLIGHTACTORS: defaults->SetDontLightActors(ParseInt(sc) != 0); break; + case LIGHTTAG_SPOT: + { + float innerAngle = ParseFloat(sc); + float outerAngle = ParseFloat(sc); + defaults->SetSpot(true); + defaults->SetSpotInnerAngle(innerAngle); + defaults->SetSpotOuterAngle(outerAngle); + } + break; default: sc.ScriptError("Unknown tag: %s\n", sc.String); } @@ -480,6 +501,15 @@ static void ParsePulseLight(FScanner &sc) case LIGHTTAG_DONTLIGHTACTORS: defaults->SetDontLightActors(ParseInt(sc) != 0); break; + case LIGHTTAG_SPOT: + { + float innerAngle = ParseFloat(sc); + float outerAngle = ParseFloat(sc); + defaults->SetSpot(true); + defaults->SetSpotInnerAngle(innerAngle); + defaults->SetSpotOuterAngle(outerAngle); + } + break; default: sc.ScriptError("Unknown tag: %s\n", sc.String); } @@ -567,6 +597,15 @@ void ParseFlickerLight(FScanner &sc) case LIGHTTAG_DONTLIGHTACTORS: defaults->SetDontLightActors(ParseInt(sc) != 0); break; + case LIGHTTAG_SPOT: + { + float innerAngle = ParseFloat(sc); + float outerAngle = ParseFloat(sc); + defaults->SetSpot(true); + defaults->SetSpotInnerAngle(innerAngle); + defaults->SetSpotOuterAngle(outerAngle); + } + break; default: sc.ScriptError("Unknown tag: %s\n", sc.String); } @@ -653,6 +692,15 @@ void ParseFlickerLight2(FScanner &sc) case LIGHTTAG_DONTLIGHTACTORS: defaults->SetDontLightActors(ParseInt(sc) != 0); break; + case LIGHTTAG_SPOT: + { + float innerAngle = ParseFloat(sc); + float outerAngle = ParseFloat(sc); + defaults->SetSpot(true); + defaults->SetSpotInnerAngle(innerAngle); + defaults->SetSpotOuterAngle(outerAngle); + } + break; default: sc.ScriptError("Unknown tag: %s\n", sc.String); } @@ -736,6 +784,15 @@ static void ParseSectorLight(FScanner &sc) case LIGHTTAG_DONTLIGHTACTORS: defaults->SetDontLightActors(ParseInt(sc) != 0); break; + case LIGHTTAG_SPOT: + { + float innerAngle = ParseFloat(sc); + float outerAngle = ParseFloat(sc); + defaults->SetSpot(true); + defaults->SetSpotInnerAngle(innerAngle); + defaults->SetSpotOuterAngle(outerAngle); + } + break; default: sc.ScriptError("Unknown tag: %s\n", sc.String); } diff --git a/src/gl/dynlights/gl_dynlight1.cpp b/src/gl/dynlights/gl_dynlight1.cpp index e42f89ac4..a9efdd880 100644 --- a/src/gl/dynlights/gl_dynlight1.cpp +++ b/src/gl/dynlights/gl_dynlight1.cpp @@ -128,7 +128,26 @@ void gl_AddLightToList(int group, ADynamicLight * light, FDynLightData &ldata) if (attenuate) shadowIndex = -shadowIndex; - float *data = &ldata.arrays[i][ldata.arrays[i].Reserve(8)]; + float lightType = 0.0f; + float spotInnerAngle = 0.0f; + float spotOuterAngle = 0.0f; + float spotDirX = 0.0f; + float spotDirY = 0.0f; + float spotDirZ = 0.0f; + if (light->IsSpot()) + { + lightType = 1.0f; + spotInnerAngle = light->SpotInnerAngle.Cos(); + 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(); + } + + float *data = &ldata.arrays[i][ldata.arrays[i].Reserve(16)]; data[0] = pos.X; data[1] = pos.Z; data[2] = pos.Y; @@ -137,5 +156,13 @@ void gl_AddLightToList(int group, ADynamicLight * light, FDynLightData &ldata) data[5] = g; data[6] = b; data[7] = shadowIndex; + data[8] = spotDirX; + data[9] = spotDirY; + data[10] = spotDirZ; + data[11] = lightType; + data[12] = spotInnerAngle; + data[13] = spotOuterAngle; + data[14] = 0.0f; // unused + data[15] = 0.0f; // unused } diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index c746c536d..09e28ba55 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -494,6 +494,7 @@ static FFlagDef DynLightFlagDefs[] = DEFINE_FLAG(LF, ATTENUATE, ADynamicLight, lightflags), DEFINE_FLAG(LF, NOSHADOWMAP, ADynamicLight, lightflags), DEFINE_FLAG(LF, DONTLIGHTACTORS, ADynamicLight, lightflags), + DEFINE_FLAG(LF, SPOT, ADynamicLight, lightflags), }; static FFlagDef PowerSpeedFlagDefs[] = diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 83cabbd0d..25a2c14d2 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -278,6 +278,13 @@ float pointLightAttenuation(vec4 lightpos, float lightcolorA) } } +float spotLightAttenuation(vec4 lightpos, vec3 spotdir, float lightCosInnerAngle, float lightCosOuterAngle) +{ + vec3 lightDirection = normalize(lightpos.xyz - pixelpos.xyz); + float cosDir = dot(lightDirection, spotdir); + return smoothstep(lightCosOuterAngle, lightCosInnerAngle, cosDir); +} + //=========================================================================== // // Calculate light @@ -348,23 +355,33 @@ vec4 getLightColor(float fogdist, float fogfactor) // // modulated lights // - for(int i=lightRange.x; i