mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-02-17 01:31:25 +00:00
Add ZDRay light intensity support
This commit is contained in:
parent
5a91e8573e
commit
98403698cd
4 changed files with 135 additions and 66 deletions
|
@ -56,7 +56,6 @@ struct LevelMeshSurface
|
|||
// Required for internal lightmapper:
|
||||
//
|
||||
|
||||
// int portalDestinationIndex = -1; // line or sector index
|
||||
int portalIndex = 0;
|
||||
int sectorGroup = 0;
|
||||
|
||||
|
@ -83,8 +82,7 @@ struct LevelMeshSurface
|
|||
TArray<FVector2> uvs;
|
||||
|
||||
// Touching light sources
|
||||
std::vector<LevelMeshLight*> LightList;
|
||||
std::vector<LevelMeshLight> LightListBuffer;
|
||||
std::vector<const LevelMeshLight*> LightList;
|
||||
|
||||
// Lightmapper has a lot of additional padding around the borders
|
||||
int lightmapperAtlasPage = -1;
|
||||
|
|
|
@ -144,7 +144,7 @@ void VkLightmap::RenderAtlasImage(size_t pageIndex)
|
|||
vertices.Pos += vertexCount;
|
||||
|
||||
LightInfo* lightinfo = &lights.Lights[firstLight];
|
||||
for (LevelMeshLight* light : surface->LightList)
|
||||
for (const LevelMeshLight* light : surface->LightList)
|
||||
{
|
||||
lightinfo->Origin = light->Origin;
|
||||
lightinfo->RelativeOrigin = light->RelativeOrigin;
|
||||
|
|
|
@ -174,19 +174,138 @@ void DoomLevelMesh::CreatePortals()
|
|||
}
|
||||
}
|
||||
|
||||
void DoomLevelMesh::UpdateLightLists()
|
||||
void DoomLevelMesh::PropagateLight(const LevelMeshLight* light, std::set<LevelMeshPortal, RecursivePortalComparator>& touchedPortals, int lightPropagationRecursiveDepth)
|
||||
{
|
||||
for (auto& surface : Surfaces)
|
||||
if (++lightPropagationRecursiveDepth > 32) // TODO is this too much?
|
||||
{
|
||||
if (surface.Type == ST_FLOOR || surface.Type == ST_CEILING)
|
||||
return;
|
||||
}
|
||||
|
||||
SphereShape sphere;
|
||||
sphere.center = FVector3(light->RelativeOrigin);
|
||||
sphere.radius = light->Radius;
|
||||
std::set<LevelMeshPortal, RecursivePortalComparator> portalsToErase;
|
||||
for (int triangleIndex : TriangleMeshShape::find_all_hits(Collision.get(), &sphere))
|
||||
{
|
||||
auto& surface = Surfaces[MeshSurfaceIndexes[triangleIndex]];
|
||||
|
||||
// TODO skip any surface which isn't physically connected to the sector group in which the light resides
|
||||
//if (light-> == surface.sectorGroup)
|
||||
{
|
||||
CreateLightList(&surface, surface.Subsector->section->lighthead, surface.Subsector->sector->PortalGroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateLightList(&surface, surface.Side->lighthead, surface.Side->sector->PortalGroup);
|
||||
if (surface.portalIndex >= 0)
|
||||
{
|
||||
auto& portal = Portals[surface.portalIndex];
|
||||
|
||||
if (touchedPortals.insert(portal).second)
|
||||
{
|
||||
auto newLight = std::make_unique<LevelMeshLight>(*light);
|
||||
auto fakeLight = newLight.get();
|
||||
Lights.push_back(std::move(newLight));
|
||||
|
||||
fakeLight->RelativeOrigin = portal.TransformPosition(light->RelativeOrigin);
|
||||
//fakeLight->sectorGroup = portal->targetSectorGroup;
|
||||
|
||||
PropagateLight(fakeLight, touchedPortals, lightPropagationRecursiveDepth);
|
||||
portalsToErase.insert(portal);
|
||||
}
|
||||
}
|
||||
|
||||
// Add light to the list if it isn't already there
|
||||
// TODO in order for this to work the light list be fed from global light buffer? Or just somehow de-duplicate portals?
|
||||
bool found = false;
|
||||
for (const LevelMeshLight* light2 : surface.LightList)
|
||||
{
|
||||
if (light2 == light)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
surface.LightList.push_back(light);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& portal : portalsToErase)
|
||||
{
|
||||
touchedPortals.erase(portal); // Dear me: I wonder what was the reason for all of this.
|
||||
}
|
||||
}
|
||||
|
||||
void DoomLevelMesh::CreateLightList()
|
||||
{
|
||||
std::set<FDynamicLight*> lightList; // bit silly ain't it?
|
||||
|
||||
Lights.clear();
|
||||
for (auto& surface : Surfaces)
|
||||
{
|
||||
surface.LightList.clear();
|
||||
|
||||
if (surface.Type == ST_FLOOR || surface.Type == ST_CEILING)
|
||||
{
|
||||
auto node = surface.Subsector->section->lighthead;
|
||||
|
||||
while (node)
|
||||
{
|
||||
FDynamicLight* light = node->lightsource;
|
||||
|
||||
if (light->Trace())
|
||||
{
|
||||
if (lightList.insert(light).second)
|
||||
{
|
||||
DVector3 pos = light->Pos; //light->PosRelative(portalgroup);
|
||||
|
||||
LevelMeshLight meshlight;
|
||||
meshlight.Origin = { (float)pos.X, (float)pos.Y, (float)pos.Z };
|
||||
meshlight.RelativeOrigin = meshlight.Origin;
|
||||
meshlight.Radius = (float)light->GetRadius();
|
||||
meshlight.Intensity = light->target->Alpha;
|
||||
if (light->IsSpot())
|
||||
{
|
||||
meshlight.InnerAngleCos = (float)light->pSpotInnerAngle->Cos();
|
||||
meshlight.OuterAngleCos = (float)light->pSpotOuterAngle->Cos();
|
||||
|
||||
DAngle negPitch = -*light->pPitch;
|
||||
DAngle Angle = light->target->Angles.Yaw;
|
||||
double xzLen = negPitch.Cos();
|
||||
meshlight.SpotDir.X = float(-Angle.Cos() * xzLen);
|
||||
meshlight.SpotDir.Y = float(-negPitch.Sin());
|
||||
meshlight.SpotDir.Z = float(-Angle.Sin() * xzLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
meshlight.InnerAngleCos = -1.0f;
|
||||
meshlight.OuterAngleCos = -1.0f;
|
||||
meshlight.SpotDir.X = 0.0f;
|
||||
meshlight.SpotDir.Y = 0.0f;
|
||||
meshlight.SpotDir.Z = 0.0f;
|
||||
}
|
||||
meshlight.Color.X = light->GetRed() * (1.0f / 255.0f);
|
||||
meshlight.Color.Y = light->GetGreen() * (1.0f / 255.0f);
|
||||
meshlight.Color.Z = light->GetBlue() * (1.0f / 255.0f);
|
||||
|
||||
Lights.push_back(std::make_unique<LevelMeshLight>(meshlight));
|
||||
}
|
||||
}
|
||||
|
||||
node = node->nextLight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::set<LevelMeshPortal, RecursivePortalComparator> touchedPortals;
|
||||
touchedPortals.insert(Portals[0]);
|
||||
|
||||
for (int i = 0, count = Lights.size(); i < count; ++i) // The array expands as the lights are duplicated/propagated
|
||||
{
|
||||
PropagateLight(Lights[i].get(), touchedPortals, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void DoomLevelMesh::UpdateLightLists()
|
||||
{
|
||||
CreateLightList(); // full recreation
|
||||
}
|
||||
|
||||
void DoomLevelMesh::BindLightmapSurfacesToGeometry(FLevelLocals& doomMap)
|
||||
|
@ -296,58 +415,6 @@ void DoomLevelMesh::SetSideLightmap(DoomLevelMeshSurface* surface)
|
|||
}
|
||||
}
|
||||
|
||||
void DoomLevelMesh::CreateLightList(DoomLevelMeshSurface* surface, FLightNode* node, int portalgroup)
|
||||
{
|
||||
surface->LightListBuffer.clear();
|
||||
surface->LightList.clear();
|
||||
|
||||
while (node)
|
||||
{
|
||||
FDynamicLight* light = node->lightsource;
|
||||
|
||||
if (light->Trace())
|
||||
{
|
||||
DVector3 pos = light->PosRelative(portalgroup);
|
||||
|
||||
LevelMeshLight meshlight;
|
||||
meshlight.Origin = { (float)pos.X, (float)pos.Y, (float)pos.Z };
|
||||
meshlight.RelativeOrigin = meshlight.Origin; // ?? what is the difference between this and Origin?
|
||||
meshlight.Radius = (float)light->GetRadius();
|
||||
meshlight.Intensity = light->target->Alpha;
|
||||
if (light->IsSpot())
|
||||
{
|
||||
meshlight.InnerAngleCos = (float)light->pSpotInnerAngle->Cos();
|
||||
meshlight.OuterAngleCos = (float)light->pSpotOuterAngle->Cos();
|
||||
|
||||
DAngle negPitch = -*light->pPitch;
|
||||
DAngle Angle = light->target->Angles.Yaw;
|
||||
double xzLen = negPitch.Cos();
|
||||
meshlight.SpotDir.X = float(-Angle.Cos() * xzLen);
|
||||
meshlight.SpotDir.Y = float(-negPitch.Sin());
|
||||
meshlight.SpotDir.Z = float(-Angle.Sin() * xzLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
meshlight.InnerAngleCos = -1.0f;
|
||||
meshlight.OuterAngleCos = -1.0f;
|
||||
meshlight.SpotDir.X = 0.0f;
|
||||
meshlight.SpotDir.Y = 0.0f;
|
||||
meshlight.SpotDir.Z = 0.0f;
|
||||
}
|
||||
meshlight.Color.X = light->GetRed() * (1.0f / 255.0f);
|
||||
meshlight.Color.Y = light->GetGreen() * (1.0f / 255.0f);
|
||||
meshlight.Color.Z = light->GetBlue() * (1.0f / 255.0f);
|
||||
|
||||
surface->LightListBuffer.push_back(meshlight);
|
||||
}
|
||||
|
||||
node = node->nextLight;
|
||||
}
|
||||
|
||||
for (auto& silly : surface->LightListBuffer)
|
||||
surface->LightList.push_back(&silly);
|
||||
}
|
||||
|
||||
void DoomLevelMesh::CreateSideSurfaces(FLevelLocals &doomMap, side_t *side)
|
||||
{
|
||||
sector_t *front;
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "bounds.h"
|
||||
#include <dp_rect_pack.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
typedef dp::rect_pack::RectPacker<int> RectPacker;
|
||||
|
||||
struct FLevelLocals;
|
||||
|
@ -43,7 +45,7 @@ public:
|
|||
int GetSurfaceCount() override { return Surfaces.Size(); }
|
||||
|
||||
TArray<DoomLevelMeshSurface> Surfaces;
|
||||
|
||||
std::vector<std::unique_ptr<LevelMeshLight>> Lights;
|
||||
TArray<FVector2> LightmapUvs;
|
||||
|
||||
static_assert(alignof(FVector2) == alignof(float[2]) && sizeof(FVector2) == sizeof(float) * 2);
|
||||
|
@ -63,7 +65,9 @@ private:
|
|||
void SetSubsectorLightmap(DoomLevelMeshSurface* surface);
|
||||
void SetSideLightmap(DoomLevelMeshSurface* surface);
|
||||
|
||||
void CreateLightList(DoomLevelMeshSurface* surface, FLightNode* lighthead, int portalgroup);
|
||||
void PropagateLight(const LevelMeshLight* light, std::set<LevelMeshPortal, RecursivePortalComparator>& touchedPortals, int lightPropagationRecursiveDepth);
|
||||
void CreateLightList();
|
||||
|
||||
|
||||
static bool IsTopSideSky(sector_t* frontsector, sector_t* backsector, side_t* side);
|
||||
static bool IsTopSideVisible(side_t* side);
|
||||
|
|
Loading…
Reference in a new issue