diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 17b0808b1..9ef9a3814 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -888,6 +888,7 @@ set (PCH_SOURCES rendering/hwrenderer/hw_vertexbuilder.cpp rendering/hwrenderer/doom_aabbtree.cpp rendering/hwrenderer/doom_levelmesh.cpp + rendering/hwrenderer/doom_lightprobes.cpp rendering/hwrenderer/hw_models.cpp rendering/hwrenderer/hw_precache.cpp rendering/hwrenderer/scene/hw_lighting.cpp diff --git a/src/common/rendering/hwrenderer/data/hw_lightprobe.h b/src/common/rendering/hwrenderer/data/hw_lightprobe.h index 201d8691b..fbfaa9937 100644 --- a/src/common/rendering/hwrenderer/data/hw_lightprobe.h +++ b/src/common/rendering/hwrenderer/data/hw_lightprobe.h @@ -7,3 +7,8 @@ struct LightProbe FVector3 position; int index = 0; }; + +struct LightProbeTarget +{ + int index = 0; // parameter for renderstate.SetLightProbe +}; diff --git a/src/gamedata/r_defs.h b/src/gamedata/r_defs.h index b93ef24ff..b793757aa 100644 --- a/src/gamedata/r_defs.h +++ b/src/gamedata/r_defs.h @@ -44,6 +44,7 @@ #include "hwrenderer/data/buffers.h" #include "hwrenderer/data/hw_levelmesh.h" +#include "hwrenderer/data/hw_lightprobe.h" // Some more or less basic data types // we depend on. @@ -785,6 +786,8 @@ struct sector_t int healthceilinggroup; int health3dgroup; + LightProbeTarget lightProbe; // TODO split individual flats in the sector including 3d floors + // Member functions private: @@ -1295,6 +1298,7 @@ struct side_t int UDMFIndex; // needed to access custom UDMF fields which are stored in loading order. FLightNode * lighthead; // all dynamic lights that may affect this wall TArrayView LightmapTiles; // all lightmap tiles belonging to this sidedef + LightProbeTarget lightProbe; // TODO use different probe per each part (and 3D floors) seg_t **segs; // all segs belonging to this sidedef in ascending order. Used for precise rendering int numsegs; int sidenum; diff --git a/src/rendering/hwrenderer/doom_lightprobes.cpp b/src/rendering/hwrenderer/doom_lightprobes.cpp new file mode 100644 index 000000000..68fb08098 --- /dev/null +++ b/src/rendering/hwrenderer/doom_lightprobes.cpp @@ -0,0 +1,102 @@ +#include "c_dispatch.h" +#include "g_levellocals.h" + +static int FindClosestProbe(FVector3 pos) +{ + float bestDist = std::numeric_limits::max(); + int best = 0; + + for (int i = 0, size = level.lightProbes.size(); i < size; ++i) + { + const auto& probe = level.lightProbes[i]; + + const auto probeDist = (probe.position - pos).LengthSquared(); + + if (probeDist < bestDist) + { + best = i; + bestDist = probeDist; + } + } + + return best; +} + +static void RecalculateLightProbeTargets() +{ + for (int i = 0, size = level.sectors.size(); i < size; ++i) + { + auto& sector = level.sectors[i]; + const auto origin = FVector3(sector.centerspot.X, sector.centerspot.Y, float(sector.floorplane.ZatPoint(sector.centerspot) + 64.0)); + + sector.lightProbe.index = FindClosestProbe(origin); + } + + for (int i = 0, size = level.sides.size(); i < size; ++i) + { + auto& side = level.sides[i]; + + const auto sector = side.sector; + + if (!sector) // better safe than sorry + { + continue; + } + + const auto xy = side.linedef->v1->fPos() + side.linedef->delta * 0.5; + const auto origin = FVector3(xy.X, xy.Y, float(sector->floorplane.ZatPoint(sector->centerspot) + 64.0)); + + side.lightProbe.index = FindClosestProbe(origin); + } +} + +static void DumpLightProbeTargets() +{ + for (int i = 0, size = level.sectors.size(); i < size; ++i) + { + const auto& sector = level.sectors[i]; + Printf("Sector %d = %d\n", i, sector.lightProbe.index); + } + + for (int i = 0, size = level.sides.size(); i < size; ++i) + { + const auto& side = level.sides[i]; + Printf("Side %d = %d\n", i, side.lightProbe.index); + } +} + +static void DumpLightProbes() +{ + for (int i = 0, size = level.lightProbes.size(); i < size; ++i) + { + const auto& probe = level.lightProbes[i]; + Printf("Probe %d: (%.1f, %.1f, %.1f)\n", i, probe.position.X, probe.position.Y, probe.position.Z); + } +} + +static void AddLightProbe(FVector3 position) +{ + LightProbe probe; + probe.position = position; + probe.index = static_cast(level.lightProbes.size()); + level.lightProbes.Push(probe); +} + +CCMD(dumplightprobes) +{ + DumpLightProbes(); +} + +CCMD(dumplightprobetargets) +{ + DumpLightProbeTargets(); +} + +CCMD(addlightprobe) +{ + const auto pos = FVector3(players[0].mo->Pos().X, players[0].mo->Pos().Y, players[0].viewz); + AddLightProbe(pos); + RecalculateLightProbeTargets(); + + Printf("Spawned probe at %.1f, %.1f, %.1f\n", pos.X, pos.Y, pos.Z); +} \ No newline at end of file diff --git a/src/rendering/hwrenderer/scene/hw_flats.cpp b/src/rendering/hwrenderer/scene/hw_flats.cpp index 2d6ab4971..8edf6cc3b 100644 --- a/src/rendering/hwrenderer/scene/hw_flats.cpp +++ b/src/rendering/hwrenderer/scene/hw_flats.cpp @@ -330,6 +330,7 @@ void HWFlat::DrawFlat(HWFlatDispatcher *di, FRenderState &state, bool translucen int rel = getExtraLight(); state.SetNormal(plane.plane.Normal().X, plane.plane.Normal().Z, plane.plane.Normal().Y); + state.SetLightProbeIndex(sector->lightProbe.index); SetColor(state, di->Level, di->lightmode, lightlevel, rel, di->isFullbrightScene(), Colormap, alpha); SetFog(state, di->Level, di->lightmode, lightlevel, rel, di->isFullbrightScene(), &Colormap, false, di->di ? di->di->drawctx->portalState.inskybox : false); diff --git a/src/rendering/hwrenderer/scene/hw_walls.cpp b/src/rendering/hwrenderer/scene/hw_walls.cpp index aba705c67..6bf87564f 100644 --- a/src/rendering/hwrenderer/scene/hw_walls.cpp +++ b/src/rendering/hwrenderer/scene/hw_walls.cpp @@ -87,6 +87,7 @@ void HWWall::RenderWall(FRenderState &state, int textured) if (seg->sidedef->Flags & WALLF_DITHERTRANS) state.SetEffect(EFF_DITHERTRANS); assert(vertcount > 0); state.SetLightIndex(dynlightindex); + state.SetLightProbeIndex(seg->sidedef->lightProbe.index); state.Draw(DT_TriangleFan, vertindex, vertcount); vertexcount += vertcount; if (seg->sidedef->Flags & WALLF_DITHERTRANS)