diff --git a/src/g_shared/a_dynlight.cpp b/src/g_shared/a_dynlight.cpp index 4d26df186..95e87baf4 100644 --- a/src/g_shared/a_dynlight.cpp +++ b/src/g_shared/a_dynlight.cpp @@ -568,6 +568,7 @@ void ADynamicLight::CollectWithinRadius(const DVector3 &opos, subsector_t *subSe collected_ss.Push({ subSec, opos }); subSec->validcount = ::validcount; + bool hitonesidedback = false; for (unsigned i = 0; i < collected_ss.Size(); i++) { subSec = collected_ss[i].sub; @@ -596,6 +597,10 @@ void ADynamicLight::CollectWithinRadius(const DVector3 &opos, subsector_t *subSe seg->linedef->validcount = validcount; touching_sides = AddLightNode(&seg->sidedef->lighthead, seg->sidedef, this, touching_sides); } + else if (seg->linedef->sidedef[0] == seg->sidedef && seg->linedef->sidedef[1] == nullptr) + { + hitonesidedback = true; + } } if (seg->linedef) { @@ -657,6 +662,7 @@ void ADynamicLight::CollectWithinRadius(const DVector3 &opos, subsector_t *subSe } } } + shadowmapped = hitonesidedback && !(flags4 & MF4_NOSHADOWMAP); } //========================================================================== @@ -758,6 +764,7 @@ void ADynamicLight::UnlinkLight () while (touching_sides) touching_sides = DeleteLightNode(touching_sides); while (touching_subsectors) touching_subsectors = DeleteLightNode(touching_subsectors); while (touching_sector) touching_sector = DeleteLightNode(touching_sector); + shadowmapped = false; } void ADynamicLight::OnDestroy() @@ -771,7 +778,7 @@ CCMD(listlights) { int walls, sectors, subsecs; int allwalls=0, allsectors=0, allsubsecs = 0; - int i=0; + int i=0, shadowcount = 0; ADynamicLight * dl; TThinkerIterator it; @@ -780,11 +787,12 @@ CCMD(listlights) walls=0; sectors=0; subsecs = 0; - Printf("%s at (%f, %f, %f), color = 0x%02x%02x%02x, radius = %f %s", + Printf("%s at (%f, %f, %f), color = 0x%02x%02x%02x, radius = %f %s %s", dl->target? dl->target->GetClass()->TypeName.GetChars() : dl->GetClass()->TypeName.GetChars(), dl->X(), dl->Y(), dl->Z(), dl->args[LIGHT_RED], - dl->args[LIGHT_GREEN], dl->args[LIGHT_BLUE], dl->radius, (dl->flags4 & MF4_ATTENUATE)? "attenuated" : ""); + dl->args[LIGHT_GREEN], dl->args[LIGHT_BLUE], dl->radius, (dl->flags4 & MF4_ATTENUATE)? "attenuated" : "", dl->shadowmapped? "shadowmapped" : ""); i++; + shadowcount += dl->shadowmapped; if (dl->target) { @@ -824,7 +832,7 @@ CCMD(listlights) Printf("- %d walls, %d subsectors, %d sectors\n", walls, subsecs, sectors); } - Printf("%i dynamic lights, %d walls, %d subsectors, %d sectors\n\n\n", i, allwalls, allsubsecs, allsectors); + Printf("%i dynamic lights, %d shadowmapped, %d walls, %d subsectors, %d sectors\n\n\n", i, shadowcount, allwalls, allsubsecs, allsectors); } CCMD(listsublights) diff --git a/src/g_shared/a_dynlight.h b/src/g_shared/a_dynlight.h index 3e8de3ed8..1a1862957 100644 --- a/src/g_shared/a_dynlight.h +++ b/src/g_shared/a_dynlight.h @@ -21,11 +21,12 @@ enum LIGHT_SCALE = 3, }; -// This is as good as something new - and it can be set directly in the ActorInfo! +// This is as good as something new #define MF4_SUBTRACTIVE MF4_MISSILEEVENMORE #define MF4_ADDITIVE MF4_MISSILEMORE #define MF4_DONTLIGHTSELF MF4_SEESDAGGERS #define MF4_ATTENUATE MF4_INCOMBAT +#define MF4_NOSHADOWMAP MF4_STANDSTILL enum ELightType { @@ -117,6 +118,7 @@ public: uint8_t color2[3]; bool visibletoplayer; bool swapped; + bool shadowmapped; int bufferindex; diff --git a/src/gl/dynlights/gl_shadowmap.cpp b/src/gl/dynlights/gl_shadowmap.cpp index 80fc90113..0e997bb0e 100644 --- a/src/gl/dynlights/gl_shadowmap.cpp +++ b/src/gl/dynlights/gl_shadowmap.cpp @@ -116,35 +116,43 @@ bool FShadowMap::IsEnabled() const int FShadowMap::ShadowMapIndex(ADynamicLight *light) { if (IsEnabled()) - return mLightToShadowmap[light]; - else - return 1024; + { + auto val = mLightToShadowmap.CheckKey(light); + if (val != nullptr) return *val; + } + return 1024; } void FShadowMap::UploadLights() { - mLights.Clear(); + if (mLights.Size() != 1024 * 4) mLights.Resize(1024 * 4); + int lightindex = 0; mLightToShadowmap.Clear(mLightToShadowmap.CountUsed() * 2); // To do: allow clearing a TMap while building up a reserve + // Todo: this should go through the blockmap in a spiral pattern around the player so that closer lights are preferred. TThinkerIterator it(STAT_DLIGHT); - while (true) + while (auto light = it.Next()) { - ADynamicLight *light = it.Next(); - if (!light) break; + if (light->shadowmapped) + { + mLightToShadowmap[light] = lightindex >> 2; - mLightToShadowmap[light] = mLights.Size() / 4; + mLights[lightindex] = light->X(); + mLights[lightindex+1] = light->Y(); + mLights[lightindex+2] = light->Z(); + mLights[lightindex+3] = light->GetRadius(); + lightindex += 4; - mLights.Push(light->X()); - mLights.Push(light->Y()); - mLights.Push(light->Z()); - mLights.Push(light->GetRadius()); + if (lightindex == 1024*4) // Only 1024 lights for now + break; + } - if (mLights.Size() == 1024) // Only 1024 lights for now - break; } - while (mLights.Size() < 1024 * 4) - mLights.Push(0.0f); + for (; lightindex < 1024 * 4; lightindex++) + { + mLights[lightindex] = 0; + } if (mLightList == 0) glGenBuffers(1, (GLuint*)&mLightList); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 4bf8db837..32363abdc 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -60,6 +60,7 @@ #include "r_data/sprites.h" #include "serializer.h" #include "wi_stuff.h" +#include "a_dynlight.h" static TArray properties; static TArray AFTable; @@ -479,6 +480,16 @@ static FFlagDef PlayerPawnFlagDefs[] = DEFINE_FLAG(PPF, CROUCHABLEMORPH, APlayerPawn, PlayerFlags), }; +static FFlagDef DynLightFlagDefs[] = +{ + // PlayerPawn flags + DEFINE_FLAG(MF4, SUBTRACTIVE, ADynamicLight, flags4), + DEFINE_FLAG(MF4, ADDITIVE, ADynamicLight, flags4), + DEFINE_FLAG(MF4, DONTLIGHTSELF, ADynamicLight, flags4), + DEFINE_FLAG(MF4, ATTENUATE, ADynamicLight, flags4), + DEFINE_FLAG(MF4, NOSHADOWMAP, ADynamicLight, flags4), +}; + static FFlagDef PowerSpeedFlagDefs[] = { // PowerSpeed flags