diff --git a/src/g_level.cpp b/src/g_level.cpp index 6139e1c04..09bf8400f 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -2282,27 +2282,3 @@ void FLevelLocals::SetMusic() { S_ChangeMusic(Music, musicorder); } - -void FLevelLocals::GetLightProbeLight(float x, float y, float z, float* out) -{ - out[0] = out[1] = out[2] = 0.f; - - // To do: Pretty stupid algorithm. Use something better once we confirmed this looks alright. - - float lastdist = 0.0f; - for (unsigned int i = 0; i < LightProbes.Size(); i++) - { - const LightProbe& probe = LightProbes[i]; - float dx = probe.X - x; - float dy = probe.Y - y; - float dz = probe.Z - z; - float dist = dx * dx + dy * dy + dz * dz; - if (i == 0 || dist < lastdist) - { - out[0] = probe.Red; - out[1] = probe.Green; - out[2] = probe.Blue; - lastdist = dist; - } - } -} diff --git a/src/g_levellocals.h b/src/g_levellocals.h index a6e6fe9f2..b3aaea6c1 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -429,8 +429,6 @@ public: void SetMusic(); - void GetLightProbeLight(float x, float y, float z, float* out); - TArray vertexes; TArray sectors; TArray extsectors; // container for non-trivial sector information. sector_t must be trivially copyable for *_fakeflat to work as intended. diff --git a/src/gamedata/r_defs.h b/src/gamedata/r_defs.h index d78f774a0..5a5579fdb 100644 --- a/src/gamedata/r_defs.h +++ b/src/gamedata/r_defs.h @@ -59,6 +59,7 @@ class AActor; struct FSection; struct FLevelLocals; struct LightmapSurface; +struct LightProbe; const uint16_t NO_INDEX = 0xffffu; const uint32_t NO_SIDE = 0xffffffffu; @@ -1621,6 +1622,8 @@ struct subsector_t FPortalCoverage portalcoverage[2]; LightmapSurface *lightmap[2]; + LightProbe* firstprobe; + uint32_t numprobes; }; diff --git a/src/maploader/maploader.cpp b/src/maploader/maploader.cpp index f8e7004e0..1daa818e5 100644 --- a/src/maploader/maploader.cpp +++ b/src/maploader/maploader.cpp @@ -3335,19 +3335,27 @@ void MapLoader::LoadLightmap(MapData *map) int version = fr.ReadInt32(); if (version != 0) + { + Printf(PRINT_HIGH, "LoadLightmap: unsupported lightmap lump version\n"); return; + } uint16_t textureSize = fr.ReadUInt16(); uint16_t numTextures = fr.ReadUInt16(); uint32_t numSurfaces = fr.ReadUInt32(); uint32_t numTexCoords = fr.ReadUInt32(); uint32_t numLightProbes = fr.ReadUInt32(); + uint32_t numSubsectors = fr.ReadUInt32(); uint32_t numTexBytes = numTextures * textureSize * textureSize * 3 * 2; if (numSurfaces == 0 || numTexCoords == 0 || numTexBytes == 0) return; - Level->LMTexCoords.Resize(numTexCoords * 2); + if (numSubsectors != Level->subsectors.Size()) + { + Printf(PRINT_HIGH, "LoadLightmap: subsector count for level doesn't match\n"); + return; + } if (numLightProbes > 0) { @@ -3355,6 +3363,29 @@ void MapLoader::LoadLightmap(MapData *map) fr.Read(&Level->LightProbes[0], sizeof(LightProbe) * numLightProbes); } + if (Level->subsectors.Size() > 0) + { + TArray counts; + counts.Resize(Level->subsectors.Size()); + fr.Read(&counts[0], sizeof(uint32_t) * Level->subsectors.Size()); + + unsigned int startIndex = 0; + for (unsigned int i = 0; i < Level->subsectors.Size(); i++) + { + unsigned int count = counts[i]; + if (startIndex + count > Level->LightProbes.Size()) + { + Printf(PRINT_HIGH, "LoadLightmap: invalid light probe data\n"); + break; + } + Level->subsectors[i].firstprobe = &Level->LightProbes[startIndex]; + Level->subsectors[i].numprobes = count; + startIndex += count; + } + } + + Level->LMTexCoords.Resize(numTexCoords * 2); + // Allocate room for all surfaces unsigned int allSurfaces = 0; diff --git a/src/rendering/hwrenderer/scene/hw_drawstructs.h b/src/rendering/hwrenderer/scene/hw_drawstructs.h index eac6b8424..cf6c53027 100644 --- a/src/rendering/hwrenderer/scene/hw_drawstructs.h +++ b/src/rendering/hwrenderer/scene/hw_drawstructs.h @@ -433,6 +433,7 @@ inline float Dist2(float x1,float y1,float x2,float y2) bool hw_SetPlaneTextureRotation(const HWSectorPlane * secplane, FGameTexture * gltexture, VSMatrix &mat); void hw_GetDynModelLight(AActor *self, FDynLightData &modellightdata); +LightProbe* FindLightProbe(FLevelLocals* level, float x, float y, float z); extern const float LARGE_VALUE; diff --git a/src/rendering/hwrenderer/scene/hw_spritelight.cpp b/src/rendering/hwrenderer/scene/hw_spritelight.cpp index 2b93c912e..206ff07d2 100644 --- a/src/rendering/hwrenderer/scene/hw_spritelight.cpp +++ b/src/rendering/hwrenderer/scene/hw_spritelight.cpp @@ -45,6 +45,50 @@ T smoothstep(const T edge0, const T edge1, const T x) return t * t * (3.0 - 2.0 * t); } +LightProbe* FindLightProbe(FLevelLocals* level, float x, float y, float z) +{ + LightProbe* foundprobe = nullptr; + if (level->LightProbes.Size() > 0) + { +#if 1 + float radiusSquared = 32.0f * 32.0f; + float lastdist = 0.0f; + BSPWalkCircle(level, x, y, radiusSquared, [&](subsector_t* subsector) // Iterate through all subsectors potentially touched by actor + { + for (uint32_t i = 0; i < subsector->numprobes; i++) + { + LightProbe* probe = subsector->firstprobe + i; + float dx = probe->X - x; + float dy = probe->Y - y; + float dz = probe->Z - z; + float dist = dx * dx + dy * dy + dz * dz; + if (!foundprobe || dist < lastdist) + { + foundprobe = probe; + lastdist = dist; + } + } + }); +#else + float lastdist = 0.0f; + for (unsigned int i = 0; i < level->LightProbes.Size(); i++) + { + LightProbe *probe = &level->LightProbes[i]; + float dx = probe->X - x; + float dy = probe->Y - y; + float dz = probe->Z - z; + float dist = dx * dx + dy * dy + dz * dz; + if (i == 0 || dist < lastdist) + { + foundprobe = probe; + lastdist = dist; + } + } +#endif + } + return foundprobe; +} + //========================================================================== // // Sets a single light value from all dynamic lights affecting the specified location @@ -57,7 +101,15 @@ void HWDrawInfo::GetDynSpriteLight(AActor *self, float x, float y, float z, FLig float frac, lr, lg, lb; float radius; - Level->GetLightProbeLight(x, y, z, out); + out[0] = out[1] = out[2] = 0.f; + + LightProbe* probe = FindLightProbe(Level, x, y, z); + if (probe) + { + out[0] = probe->Red; + out[1] = probe->Green; + out[2] = probe->Blue; + } // Go through both light lists while (node) diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index d53e9ee1e..f7e41cbc8 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -172,6 +172,12 @@ void HWSprite::DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent) di->GetDynSpriteLight(gl_light_sprites ? actor : nullptr, gl_light_particles ? particle : nullptr, out); state.SetDynLight(out[0], out[1], out[2]); } + else if (di->Level->LightProbes.Size() > 0) + { + LightProbe* probe = FindLightProbe(di->Level, actor->X(), actor->Y(), actor->Center()); + if (probe) + state.SetDynLight(probe->Red, probe->Green, probe->Blue); + } } sector_t *cursec = actor ? actor->Sector : particle ? particle->subsector->sector : nullptr; if (cursec != nullptr) diff --git a/src/rendering/hwrenderer/scene/hw_weapon.cpp b/src/rendering/hwrenderer/scene/hw_weapon.cpp index f90ff4fd9..e95512f0f 100644 --- a/src/rendering/hwrenderer/scene/hw_weapon.cpp +++ b/src/rendering/hwrenderer/scene/hw_weapon.cpp @@ -641,6 +641,14 @@ void HWDrawInfo::PreparePlayerSprites(sector_t * viewsector, area_t in_area) { hw_GetDynModelLight(playermo, lightdata); hudsprite.lightindex = screen->mLights->UploadLights(lightdata); + + LightProbe* probe = FindLightProbe(playermo->Level, playermo->X(), playermo->Y(), playermo->Center()); + if (probe) + { + hudsprite.dynrgb[0] = probe->Red; + hudsprite.dynrgb[1] = probe->Green; + hudsprite.dynrgb[2] = probe->Blue; + } } }