mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-04-23 03:10:58 +00:00
WIP BuildSurfaceParams from ZDRay
This commit is contained in:
parent
1849d31d7c
commit
005bae7348
4 changed files with 339 additions and 4 deletions
|
@ -3205,10 +3205,16 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
|
|||
SpawnThings(position);
|
||||
|
||||
// Load and link lightmaps - must be done after P_Spawn3DFloors (and SpawnThings? Potentially for baking static model actors?)
|
||||
#if 0
|
||||
if (!ForceNodeBuild)
|
||||
{
|
||||
LoadLightmap(map);
|
||||
}
|
||||
#endif
|
||||
Level->levelMesh = new DoomLevelMesh(*Level);
|
||||
InitLightmap(map);
|
||||
|
||||
screen->InitLightmap(Level->LMTextureSize, Level->LMTextureCount, Level->LMTextureData);
|
||||
|
||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
|
@ -3246,8 +3252,6 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
|
|||
CreateVBO(*screen->RenderState(0), Level->sectors);
|
||||
meshcache.Clear();
|
||||
|
||||
screen->InitLightmap(Level->LMTextureSize, Level->LMTextureCount, Level->LMTextureData);
|
||||
|
||||
for (auto &sec : Level->sectors)
|
||||
{
|
||||
P_Recalculate3DFloors(&sec);
|
||||
|
@ -3263,7 +3267,6 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
|
|||
Level->FinalizePortals(); // finalize line portals after polyobjects have been initialized. This info is needed for properly flagging them.
|
||||
|
||||
Level->aabbTree = new DoomLevelAABBTree(Level);
|
||||
Level->levelMesh = new DoomLevelMesh(*Level);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3324,15 +3327,141 @@ void MapLoader::SetSideLightmap(const LightmapSurface &surface)
|
|||
}
|
||||
}
|
||||
|
||||
void MapLoader::LoadLightmap(MapData *map)
|
||||
#include "halffloat.h"
|
||||
|
||||
void MapLoader::InitLightmap(MapData* map)
|
||||
{
|
||||
// We have to reset everything as FLevelLocals is recycled between maps
|
||||
Level->LMTexCoords.Reset();
|
||||
Level->LMSurfaces.Reset();
|
||||
Level->LMTextureData.Reset();
|
||||
|
||||
// Debug placeholder stuff
|
||||
{
|
||||
Level->LMTextureCount = 1;
|
||||
Level->LMTextureSize = 1024;
|
||||
|
||||
for (int i = 0; i < 1024; ++i) // avoid crashing lol
|
||||
{
|
||||
Level->LMTexCoords.Push(0);
|
||||
Level->LMTexCoords.Push(0);
|
||||
|
||||
Level->LMTexCoords.Push(1);
|
||||
Level->LMTexCoords.Push(0);
|
||||
|
||||
Level->LMTexCoords.Push(1);
|
||||
Level->LMTexCoords.Push(1);
|
||||
|
||||
Level->LMTexCoords.Push(0);
|
||||
Level->LMTexCoords.Push(1);
|
||||
}
|
||||
|
||||
auto constructDebugTexture = [&](TArray<uint16_t>& buffer, int width, int height) {
|
||||
uint16_t* ptr = buffer.Data();
|
||||
|
||||
for (int y = 0; y < height; ++y)
|
||||
{
|
||||
for (int x = 0; x < width; ++x)
|
||||
{
|
||||
*(ptr++) = floatToHalf(float(x) / width);
|
||||
*(ptr++) = floatToHalf(float(y) / height);
|
||||
*(ptr++) = floatToHalf((x + y) % 2 == 0 ? 1.0f : 0.0f);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int size = Level->LMTextureSize;
|
||||
int layers = 1;
|
||||
|
||||
Level->LMTextureData.Resize(size * size * 3 * layers);
|
||||
constructDebugTexture(Level->LMTextureData, size, size);
|
||||
}
|
||||
|
||||
for (auto& surface : Level->levelMesh->Surfaces)
|
||||
{
|
||||
Level->levelMesh->BuildSurfaceParams(Level->LMTextureSize, Level->LMTextureSize, surface);
|
||||
}
|
||||
|
||||
Level->LMTexCoords = Level->levelMesh->LightmapUvs;
|
||||
|
||||
|
||||
// Allocate room for all surfaces
|
||||
|
||||
unsigned int allSurfaces = 0;
|
||||
|
||||
for (unsigned int i = 0; i < Level->sides.Size(); i++)
|
||||
allSurfaces += 4 + Level->sides[i].sector->e->XFloor.ffloors.Size();
|
||||
|
||||
for (unsigned int i = 0; i < Level->subsectors.Size(); i++)
|
||||
allSurfaces += 2 + Level->subsectors[i].sector->e->XFloor.ffloors.Size() * 2;
|
||||
|
||||
Level->LMSurfaces.Resize(allSurfaces);
|
||||
memset(&Level->LMSurfaces[0], 0, sizeof(LightmapSurface) * allSurfaces);
|
||||
|
||||
// Link the surfaces to sectors, sides and their 3D floors
|
||||
|
||||
unsigned int offset = 0;
|
||||
for (unsigned int i = 0; i < Level->sides.Size(); i++)
|
||||
{
|
||||
auto& side = Level->sides[i];
|
||||
side.lightmap = &Level->LMSurfaces[offset];
|
||||
offset += 4 + side.sector->e->XFloor.ffloors.Size();
|
||||
}
|
||||
for (unsigned int i = 0; i < Level->subsectors.Size(); i++)
|
||||
{
|
||||
auto& subsector = Level->subsectors[i];
|
||||
unsigned int count = 1 + subsector.sector->e->XFloor.ffloors.Size();
|
||||
subsector.lightmap[0] = &Level->LMSurfaces[offset];
|
||||
subsector.lightmap[1] = &Level->LMSurfaces[offset + count];
|
||||
offset += count * 2;
|
||||
}
|
||||
|
||||
// Copy and build properties
|
||||
size_t index = 0;
|
||||
for (auto& surface : Level->levelMesh->Surfaces)
|
||||
{
|
||||
LightmapSurface l;
|
||||
//LightmapSurface& l = Level->LMSurfaces[index++];
|
||||
memset(&l, 0, sizeof(LightmapSurface));
|
||||
|
||||
l.ControlSector = surface.controlSector;
|
||||
l.Type = surface.type;
|
||||
l.LightmapNum = 0;
|
||||
|
||||
//l.TexCoords = &Level->LMTexCoords[0];
|
||||
//l.TexCoords = &Level->levelMesh->LightmapUvs[surface.startUvIndex];
|
||||
l.TexCoords = &Level->LMTexCoords[surface.startUvIndex];
|
||||
|
||||
if (surface.type == ST_FLOOR || surface.type == ST_CEILING)
|
||||
{
|
||||
l.Subsector = &Level->subsectors[surface.typeIndex];
|
||||
l.Subsector->firstline->sidedef->sector->HasLightmaps = true;
|
||||
SetSubsectorLightmap(l);
|
||||
}
|
||||
else
|
||||
{
|
||||
l.Side = &Level->sides[surface.typeIndex];
|
||||
SetSideLightmap(l);
|
||||
}
|
||||
|
||||
//Level->LMSurfaces.Push(l);
|
||||
|
||||
}
|
||||
|
||||
Printf("Generated custom lightmap data");
|
||||
}
|
||||
|
||||
#if 0
|
||||
void MapLoader::LoadLightmap(MapData *map)
|
||||
{
|
||||
Level->LMTexCoords.Reset();
|
||||
Level->LMSurfaces.Reset();
|
||||
Level->LMTextureData.Reset();
|
||||
Level->LMTextureCount = 0;
|
||||
Level->LMTextureSize = 0;
|
||||
|
||||
// We have to reset everything as FLevelLocals is recycled between maps
|
||||
|
||||
//if (!Args->CheckParm("-enablelightmaps"))
|
||||
// return; // this feature is still too early WIP to allow general access
|
||||
|
||||
|
@ -3459,3 +3588,4 @@ void MapLoader::LoadLightmap(MapData *map)
|
|||
data[i] += data[i - 1];
|
||||
#endif
|
||||
}
|
||||
#endif
|
|
@ -306,7 +306,11 @@ public:
|
|||
|
||||
void SetSubsectorLightmap(const LightmapSurface &surface);
|
||||
void SetSideLightmap(const LightmapSurface &surface);
|
||||
|
||||
#if 0
|
||||
void LoadLightmap(MapData *map);
|
||||
#endif
|
||||
void InitLightmap(MapData* map);
|
||||
|
||||
void LoadLevel(MapData *map, const char *lumpname, int position);
|
||||
|
||||
|
|
|
@ -463,3 +463,115 @@ void DoomLevelMesh::DumpMesh(const FString& filename) const
|
|||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void DoomLevelMesh::BuildSurfaceParams(int lightMapTextureWidth, int lightMapTextureHeight, Surface& surface)
|
||||
{
|
||||
secplane_t* plane;
|
||||
BBox bounds;
|
||||
FVector3 roundedSize;
|
||||
int i;
|
||||
PlaneAxis axis;
|
||||
FVector3 tOrigin;
|
||||
int width;
|
||||
int height;
|
||||
float d;
|
||||
|
||||
plane = &surface.plane;
|
||||
bounds = GetBoundsFromSurface(surface);
|
||||
//surface->bounds = bounds;
|
||||
|
||||
if (surface.sampleDimension <= 0)
|
||||
{
|
||||
surface.sampleDimension = 1; // TODO change?
|
||||
}
|
||||
|
||||
surface.sampleDimension = 1;
|
||||
//surface->sampleDimension = Math::RoundPowerOfTwo(surface->sampleDimension);
|
||||
|
||||
|
||||
// round off dimensions
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
bounds.min[i] = surface.sampleDimension * (floor(bounds.min[i] / surface.sampleDimension) - 1);
|
||||
bounds.max[i] = surface.sampleDimension * (ceil(bounds.max[i] / surface.sampleDimension) + 1);
|
||||
|
||||
roundedSize[i] = (bounds.max[i] - bounds.min[i]) / surface.sampleDimension;
|
||||
}
|
||||
|
||||
FVector3 tCoords[2] = { FVector3(0.0f, 0.0f, 0.0f), FVector3(0.0f, 0.0f, 0.0f) };
|
||||
|
||||
axis = BestAxis(*plane);
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case AXIS_YZ:
|
||||
width = (int)roundedSize.Y;
|
||||
height = (int)roundedSize.Z;
|
||||
tCoords[0].Y = 1.0f / surface.sampleDimension;
|
||||
tCoords[1].Z = 1.0f / surface.sampleDimension;
|
||||
break;
|
||||
|
||||
case AXIS_XZ:
|
||||
width = (int)roundedSize.X;
|
||||
height = (int)roundedSize.Z;
|
||||
tCoords[0].X = 1.0f / surface.sampleDimension;
|
||||
tCoords[1].Z = 1.0f / surface.sampleDimension;
|
||||
break;
|
||||
|
||||
case AXIS_XY:
|
||||
width = (int)roundedSize.X;
|
||||
height = (int)roundedSize.Y;
|
||||
tCoords[0].X = 1.0f / surface.sampleDimension;
|
||||
tCoords[1].Y = 1.0f / surface.sampleDimension;
|
||||
break;
|
||||
}
|
||||
|
||||
// clamp width
|
||||
if (width > lightMapTextureWidth - 2)
|
||||
{
|
||||
tCoords[0] *= ((float)(lightMapTextureWidth - 2) / (float)width);
|
||||
width = (lightMapTextureWidth - 2);
|
||||
}
|
||||
|
||||
// clamp height
|
||||
if (height > lightMapTextureHeight - 2)
|
||||
{
|
||||
tCoords[1] *= ((float)(lightMapTextureHeight - 2) / (float)height);
|
||||
height = (lightMapTextureHeight - 2);
|
||||
}
|
||||
|
||||
surface.translateWorldToLocal = bounds.min;
|
||||
surface.projLocalToU = tCoords[0];
|
||||
surface.projLocalToV = tCoords[1];
|
||||
|
||||
surface.startUvIndex = AllocUvs(surface.numVerts);
|
||||
auto uv = surface.startUvIndex;
|
||||
for (i = 0; i < surface.numVerts; i++)
|
||||
{
|
||||
FVector3 tDelta = MeshVertices[surface.startVertIndex + i] - surface.translateWorldToLocal;
|
||||
|
||||
LightmapUvs[uv++] = (tDelta | surface.projLocalToU);
|
||||
LightmapUvs[uv++] = (tDelta | surface.projLocalToV);
|
||||
}
|
||||
|
||||
|
||||
tOrigin = bounds.min;
|
||||
|
||||
// project tOrigin and tCoords so they lie on the plane
|
||||
d = float(((bounds.min | FVector3(plane->Normal())) - plane->D) / plane->Normal()[axis]); //d = (plane->PointToDist(bounds.min)) / plane->Normal()[axis];
|
||||
tOrigin[axis] -= d;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
tCoords[i].MakeUnit();
|
||||
d = (tCoords[i] | FVector3(plane->Normal())) / plane->Normal()[axis]; //d = dot(tCoords[i], plane->Normal()) / plane->Normal()[axis];
|
||||
tCoords[i][axis] -= d;
|
||||
}
|
||||
|
||||
surface.texWidth = width;
|
||||
surface.texHeight = height;
|
||||
//surface->texPixels.resize(width * height);
|
||||
surface.worldOrigin = tOrigin;
|
||||
surface.worldStepX = tCoords[0] * (float)surface.sampleDimension;
|
||||
surface.worldStepY = tCoords[1] * (float)surface.sampleDimension;
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
#include "tarray.h"
|
||||
#include "vectors.h"
|
||||
#include "r_defs.h"
|
||||
#include "bounds.h"
|
||||
|
||||
struct FLevelLocals;
|
||||
|
||||
|
@ -17,6 +18,28 @@ struct Surface
|
|||
secplane_t plane;
|
||||
sector_t *controlSector;
|
||||
bool bSky;
|
||||
|
||||
//
|
||||
// Required for internal lightmapper:
|
||||
|
||||
int sampleDimension = 0;
|
||||
|
||||
// Lightmap world coordinates for the texture
|
||||
FVector3 worldOrigin = { 0.f, 0.f, 0.f };
|
||||
FVector3 worldStepX = { 0.f, 0.f, 0.f };
|
||||
FVector3 worldStepY = { 0.f, 0.f, 0.f };
|
||||
|
||||
// Calculate world coordinates to UV coordinates
|
||||
FVector3 translateWorldToLocal = { 0.f, 0.f, 0.f };
|
||||
FVector3 projLocalToU = { 0.f, 0.f, 0.f };
|
||||
FVector3 projLocalToV = { 0.f, 0.f, 0.f };
|
||||
|
||||
// Output lightmap for the surface
|
||||
int texWidth = 0;
|
||||
int texHeight = 0;
|
||||
|
||||
// UV coordinates for the vertices
|
||||
int startUvIndex = -666;
|
||||
};
|
||||
|
||||
class DoomLevelMesh : public hwrenderer::LevelMesh
|
||||
|
@ -37,6 +60,7 @@ public:
|
|||
}
|
||||
|
||||
TArray<Surface> Surfaces;
|
||||
TArray<float> LightmapUvs;
|
||||
|
||||
void DumpMesh(const FString& filename) const;
|
||||
|
||||
|
@ -66,4 +90,69 @@ private:
|
|||
static FVector4 ToFVector4(const DVector4& v) { return FVector4((float)v.X, (float)v.Y, (float)v.Z, (float)v.W); }
|
||||
|
||||
static bool IsDegenerate(const FVector3 &v0, const FVector3 &v1, const FVector3 &v2);
|
||||
|
||||
// WIP internal lightmapper
|
||||
|
||||
BBox GetBoundsFromSurface(const Surface& surface) const
|
||||
{
|
||||
constexpr float M_INFINITY = 1e30; // TODO cleanup
|
||||
|
||||
FVector3 low(M_INFINITY, M_INFINITY, M_INFINITY);
|
||||
FVector3 hi(-M_INFINITY, -M_INFINITY, -M_INFINITY);
|
||||
|
||||
for (int i = int(surface.startVertIndex); i < int(surface.startVertIndex) + surface.numVerts; i++)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
if (MeshVertices[i][j] < low[j])
|
||||
{
|
||||
low[j] = MeshVertices[i][j];
|
||||
}
|
||||
if (MeshVertices[i][j] > hi[j])
|
||||
{
|
||||
hi[j] = MeshVertices[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BBox bounds;
|
||||
bounds.Clear();
|
||||
bounds.min = low;
|
||||
bounds.max = hi;
|
||||
return bounds;
|
||||
}
|
||||
|
||||
enum PlaneAxis
|
||||
{
|
||||
AXIS_YZ = 0,
|
||||
AXIS_XZ,
|
||||
AXIS_XY
|
||||
};
|
||||
|
||||
inline static PlaneAxis BestAxis(const secplane_t& p)
|
||||
{
|
||||
float na = fabs(float(p.Normal().X));
|
||||
float nb = fabs(float(p.Normal().Y));
|
||||
float nc = fabs(float(p.Normal().Z));
|
||||
|
||||
// figure out what axis the plane lies on
|
||||
if (na >= nb && na >= nc)
|
||||
{
|
||||
return AXIS_YZ;
|
||||
}
|
||||
else if (nb >= na && nb >= nc)
|
||||
{
|
||||
return AXIS_XZ;
|
||||
}
|
||||
|
||||
return AXIS_XY;
|
||||
}
|
||||
|
||||
int AllocUvs(int amount)
|
||||
{
|
||||
return LightmapUvs.Reserve(amount * 2);
|
||||
}
|
||||
|
||||
public:
|
||||
void BuildSurfaceParams(int lightMapTextureWidth, int lightMapTextureHeight, Surface& surface);
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue