- changed the output to be one lump using a compressed rgb16f format with 3d floors support

This commit is contained in:
Magnus Norddahl 2018-11-02 22:21:32 +01:00
parent 5e21857b4a
commit 5399e988c7
16 changed files with 3658 additions and 1468 deletions

View File

@ -152,6 +152,7 @@ set( SOURCES
src/lightmap/wad.cpp
src/lightmap/worker.cpp
src/lightmap/collision.cpp
src/lightmap/halffloat.cpp
src/lightmap/kexlib/binfile.cpp
src/lightmap/kexlib/kstring.cpp
src/lightmap/kexlib/memheap.cpp
@ -194,6 +195,7 @@ set( HEADERS
src/lightmap/wad.h
src/lightmap/worker.h
src/lightmap/collision.h
src/lightmap/halffloat.h
src/lightmap/kexlib/array.h
src/lightmap/kexlib/binfile.h
src/lightmap/kexlib/kstring.h

View File

@ -40,6 +40,8 @@ struct MapSideDef
WORD sector;
};
struct IntLineDef;
struct IntSideDef
{
// the first 5 values are only used for binary format maps
@ -51,6 +53,8 @@ struct IntSideDef
int sector;
IntLineDef *line;
TArray<UDMFKey> props;
};
@ -248,12 +252,6 @@ struct FloatVertex
float y;
};
struct leaf_t
{
FloatVertex vertex;
MapSegGLEx *seg;
};
struct lightDef_t
{
int doomednum;
@ -291,9 +289,6 @@ struct thingLight_t
struct surfaceLightDef
{
int tag;
float outerCone;
float innerCone;
float falloff;
float distance;
float intensity;
bool bIgnoreFloor;
@ -362,23 +357,7 @@ struct FLevel
TArray<int> MeshSurfaces;
std::unique_ptr<TriangleMeshShape> CollisionMesh;
leaf_t *leafs = nullptr;
uint8_t *mapPVS = nullptr;
bool *bSkySectors = nullptr;
bool *bSSectsVisibleToSky = nullptr;
int numLeafs = 0;
int *segLeafLookup = nullptr;
int *ssLeafLookup = nullptr;
int *ssLeafCount = nullptr;
kexBBox *ssLeafBounds = nullptr;
kexBBox *nodeBounds = nullptr;
surface_t **segSurfaces[3] = { nullptr, nullptr, nullptr };
surface_t **leafSurfaces[2] = { nullptr, nullptr };
TArray<thingLight_t*> thingLights;
TArray<kexLightSurface*> lightSurfaces;
@ -389,20 +368,13 @@ struct FLevel
const kexVec3 &GetSunColor() const;
const kexVec3 &GetSunDirection() const;
IntSideDef *GetSideDef(const MapSegGLEx *seg);
IntSector *GetFrontSector(const MapSegGLEx *seg);
IntSector *GetBackSector(const MapSegGLEx *seg);
IntSector *GetFrontSector(const IntSideDef *side);
IntSector *GetBackSector(const IntSideDef *side);
IntSector *GetSectorFromSubSector(const MapSubsectorEx *sub);
MapSubsectorEx *PointInSubSector(const int x, const int y);
bool PointInsideSubSector(const float x, const float y, const MapSubsectorEx *sub);
bool LineIntersectSubSector(const kexVec3 &start, const kexVec3 &end, const MapSubsectorEx *sub, kexVec2 &out);
FloatVertex GetSegVertex(int index);
bool CheckPVS(MapSubsectorEx *s1, MapSubsectorEx *s2);
private:
void BuildNodeBounds();
void BuildLeafs();
void BuildPVS();
void CheckSkySectors();
};

View File

@ -822,11 +822,10 @@ void FProcessor::Write (FWadWriter &out)
out.CopyLump (Wad, Wad.FindMapLump ("BEHAVIOR", Lump));
out.CopyLump (Wad, Wad.FindMapLump ("SCRIPTS", Lump));
}
if (LightmapsBuilt)
/*if (LightmapsBuilt)
{
LMBuilder.AddLightGridLump(out);
LMBuilder.AddLightmapLumps(out);
}
LMBuilder.AddLightmapLump(out);
}*/
if (Level.GLNodes != NULL && !compressGL)
{
char glname[9];

View File

@ -789,7 +789,8 @@ void FProcessor::WriteUDMF(FWadWriter &out)
const char *lumpname = Wad.LumpName(i);
if (stricmp(lumpname, "ZNODES") &&
stricmp(lumpname, "BLOCKMAP") &&
stricmp(lumpname, "REJECT"))
stricmp(lumpname, "REJECT") &&
stricmp(lumpname, "LIGHTMAP"))
{
out.CopyLump(Wad, i);
}
@ -797,8 +798,7 @@ void FProcessor::WriteUDMF(FWadWriter &out)
if (LightmapsBuilt)
{
LMBuilder.AddLightGridLump(out);
LMBuilder.AddLightmapLumps(out);
LMBuilder.AddLightmapLump(out);
}
out.CreateLabel("ENDMAP");

3381
src/lightmap/halffloat.cpp Normal file

File diff suppressed because it is too large Load Diff

68
src/lightmap/halffloat.h Normal file
View File

@ -0,0 +1,68 @@
/*
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
** Note: Some of the libraries UICore may link to may have additional
** requirements or restrictions.
**
** Based on the paper "Fast Half Float Conversions" by Jeroen van der Zijp.
*/
#pragma once
namespace HalfFloatTables
{
extern unsigned int mantissa_table[2048];
extern unsigned int exponent_table[64];
extern unsigned short offset_table[64];
extern unsigned short base_table[512];
extern unsigned char shift_table[512];
};
/// Convert half-float to float. Only works for 'normal' half-float values
inline float halfToFloatSimple(unsigned short hf)
{
unsigned int float_value = ((hf & 0x8000) << 16) | (((hf & 0x7c00) + 0x1C000) << 13) | ((hf & 0x03FF) << 13);
void *ptr = static_cast<void*>(&float_value);
return *static_cast<float*>(ptr);
}
/// Convert float to half-float. Only works for 'normal' half-float values
inline unsigned short floatToHalfSimple(float float_value)
{
void *ptr = static_cast<void*>(&float_value);
unsigned int f = *static_cast<unsigned int*>(ptr);
return ((f >> 16) & 0x8000) | ((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00) | ((f >> 13) & 0x03ff);
}
/// Convert half-float to float
inline float halfToFloat(unsigned short hf)
{
using namespace HalfFloatTables;
unsigned int float_value = mantissa_table[offset_table[hf >> 10] + (hf & 0x3ff)] + exponent_table[hf >> 10];
void *ptr = static_cast<void*>(&float_value);
return *static_cast<float*>(ptr);
}
/// Convert float to half-float
inline unsigned short floatToHalf(float float_value)
{
using namespace HalfFloatTables;
void *ptr = static_cast<void*>(&float_value);
unsigned int f = *static_cast<unsigned int*>(ptr);
return base_table[(f >> 23) & 0x1ff] + ((f & 0x007fffff) >> shift_table[(f >> 23) & 0x1ff]);
}

View File

@ -39,6 +39,7 @@
#include "kexlib/binfile.h"
#include "wad.h"
#include "framework/templates.h"
#include "halffloat.h"
#include <map>
#include <vector>
@ -60,7 +61,6 @@ kexLightmapBuilder::kexLightmapBuilder()
this->extraSamples = 2;
this->ambience = 0.0f;
this->tracedTexels = 0;
this->gridMap = NULL;
}
//
@ -86,7 +86,7 @@ void kexLightmapBuilder::NewTexture()
memset(allocBlocks[numTextures-1], 0, sizeof(int) * textureWidth);
byte *texture = (byte*)Mem_Calloc((textureWidth * textureHeight) * 3, hb_static);
uint16_t *texture = (uint16_t*)Mem_Calloc((textureWidth * textureHeight) * 3 * 2, hb_static);
textures.Push(texture);
}
@ -203,9 +203,9 @@ kexBBox kexLightmapBuilder::GetBoundsFromSurface(const surface_t *surface)
bool kexLightmapBuilder::EmitFromCeiling(kexTrace &trace, const surface_t *surface, const kexVec3 &origin, const kexVec3 &normal, kexVec3 &color)
{
float dist = normal.Dot(map->GetSunDirection());
float attenuation = normal.Dot(map->GetSunDirection());
if(dist <= 0)
if(attenuation <= 0)
{
// plane is not even facing the sunlight
return false;
@ -222,11 +222,14 @@ bool kexLightmapBuilder::EmitFromCeiling(kexTrace &trace, const surface_t *surfa
if(trace.hitSurface->bSky == false)
{
if (trace.hitSurface->type == ST_CEILING)
return false;
// not a ceiling/sky surface
return false;
}
color += map->GetSunColor() * dist;
color += map->GetSunColor() * attenuation;
return true;
}
@ -260,12 +263,6 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori
{
thingLight_t *tl = map->thingLights[i];
// try to early out if PVS data exists
if(!map->CheckPVS(surface->subSector, tl->ssect))
{
continue;
}
float originZ;
if (!tl->bCeiling)
originZ = tl->sector->floorplane.zAt(tl->origin.x, tl->origin.y) + tl->height;
@ -330,7 +327,7 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori
tracedTexels++;
}
if(surface->type != ST_CEILING && map->bSSectsVisibleToSky[surface->subSector - map->GLSubsectors])
if(surface->type != ST_CEILING)
{
// see if it's exposed to sunlight
if(EmitFromCeiling(trace, surface, origin, plane.Normal(), color))
@ -342,12 +339,6 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori
{
kexLightSurface *surfaceLight = map->lightSurfaces[i];
// try to early out if PVS data exists
if(!map->CheckPVS(surface->subSector, surfaceLight->Surface()->subSector))
{
continue;
}
float attenuation;
if(surfaceLight->TraceSurface(map, trace, surface, origin, &attenuation))
{
@ -484,7 +475,7 @@ void kexLightmapBuilder::TraceSurface(surface_t *surface)
int i;
int j;
kexTrace trace;
byte *currentTexture;
uint16_t *currentTexture;
bool bShouldLookupTexture = false;
trace.Init(*map);
@ -599,9 +590,9 @@ void kexLightmapBuilder::TraceSurface(surface_t *surface)
int offs = (((textureWidth * (i + surface->lightmapOffs[1])) + surface->lightmapOffs[0]) * 3);
// convert RGB to bytes
currentTexture[offs + j * 3 + 0] = (uint32_t)(colorSamples[i * 1024 + j].x * 255 + 0.5f);
currentTexture[offs + j * 3 + 1] = (uint32_t)(colorSamples[i * 1024 + j].y * 255 + 0.5f);
currentTexture[offs + j * 3 + 2] = (uint32_t)(colorSamples[i * 1024 + j].z * 255 + 0.5f);
currentTexture[offs + j * 3 + 0] = floatToHalf(colorSamples[i * 1024 + j].x);
currentTexture[offs + j * 3 + 1] = floatToHalf(colorSamples[i * 1024 + j].y);
currentTexture[offs + j * 3 + 2] = floatToHalf(colorSamples[i * 1024 + j].z);
}
}
}
@ -636,227 +627,10 @@ void kexLightmapBuilder::LightSurface(const int surfid)
}
}
//
// kexLightmapBuilder::LightCellSample
//
// Traces a line from the cell's origin to the sunlight direction
// and against all nearby thing lights
//
kexVec3 kexLightmapBuilder::LightCellSample(const int gridid, kexTrace &trace, const kexVec3 &origin, const MapSubsectorEx *sub)
{
kexVec3 color;
kexVec3 dir;
IntSector *mapSector;
float intensity;
float radius;
float dist;
float colorAdd;
thingLight_t *tl;
kexVec3 lightOrigin;
bool bInSkySector;
kexVec3 org;
mapSector = map->GetSectorFromSubSector(sub);
bInSkySector = map->bSkySectors[mapSector - &map->Sectors[0]];
trace.Trace(origin, origin + (map->GetSunDirection() * 32768));
// did we traced a ceiling surface with a sky texture?
if(trace.fraction != 1 && trace.hitSurface != NULL)
{
if(trace.hitSurface->bSky && origin.z + gridSize[2] > mapSector->data.floorheight)
{
color = map->GetSunColor();
// this cell is inside a sector with a sky texture and is also exposed to sunlight.
// mark this cell as a sun type. cells of this type will simply sample the
// sector's light level
gridMap[gridid].sunShadow = 2;
return color;
}
// if this cell is inside a sector with a sky texture but is NOT exposed to sunlight, then
// mark this cell as a sun shade type. cells of this type will halve the sector's light level
if(bInSkySector)
{
gridMap[gridid].sunShadow = 1;
}
}
// if the cell is technically inside a sector with a sky but is not actually on an actual surface
// then this cell is considered occluded
else if(bInSkySector && !map->PointInsideSubSector(origin.x, origin.y, sub))
{
gridMap[gridid].sunShadow = 1;
}
// trace against all thing lights
for(unsigned int i = 0; i < map->thingLights.Size(); i++)
{
tl = map->thingLights[i];
lightOrigin.Set(tl->origin.x,
tl->origin.y,
!tl->bCeiling ?
(float)tl->sector->data.floorheight + 16 :
(float)tl->sector->data.ceilingheight - 16);
radius = tl->radius;
intensity = tl->intensity * 4;
if(intensity < 1.0f)
{
intensity = 1.0f;
}
if(origin.DistanceSq(lightOrigin) > (radius*radius))
{
// not within range
continue;
}
trace.Trace(origin, lightOrigin);
if(trace.fraction != 1)
{
// something is occluding it
continue;
}
dir = (lightOrigin - origin);
dist = dir.Unit();
dir.Normalize();
colorAdd = (radius / (dist * dist)) * intensity;
kexMath::Clamp(colorAdd, 0, 1);
// accumulate results
color = color.Lerp(tl->rgb, colorAdd);
kexMath::Clamp(color, 0, 1);
}
org = origin;
// if the cell is sticking out from the ground then at least
// clamp the origin to the ground level so it can at least
// have a chance to be sampled by the light
if(origin.z + gridSize[2] > mapSector->data.floorheight)
{
org.z = (float)mapSector->data.floorheight + 2;
}
// trace against all light surfaces
for(unsigned int i = 0; i < map->lightSurfaces.Size(); ++i)
{
kexLightSurface *surfaceLight = map->lightSurfaces[i];
if(surfaceLight->TraceSurface(map, trace, NULL, org, &dist))
{
dist = (dist * (surfaceLight->Intensity() * 0.5f)) * 0.5f;
kexMath::Clamp(dist, 0, 1);
// accumulate results
color = color.Lerp(surfaceLight->GetRGB(), dist);
kexMath::Clamp(color, 0, 1);
}
}
return color;
}
//
// kexLightmapBuilder::LightGrid
//
void kexLightmapBuilder::LightGrid(const int gridid)
{
float remaining;
int x, y, z;
int mod;
int secnum;
bool bInRange;
int gx = (int)gridBlock.x;
int gy = (int)gridBlock.y;
kexTrace trace;
MapSubsectorEx *ss;
// convert grid id to xyz coordinates
mod = gridid;
z = mod / (gx * gy);
mod -= z * (gx * gy);
y = mod / gx;
mod -= y * gx;
x = mod;
// get world-coordinates
kexVec3 org(worldGrid.min[0] + x * gridSize[0],
worldGrid.min[1] + y * gridSize[1],
worldGrid.min[2] + z * gridSize[2]);
ss = NULL;
secnum = ((int)gridBlock.x * y) + x;
// determine what sector this cell is in
if(gridSectors[secnum] == NULL)
{
ss = map->PointInSubSector((int)org.x, (int)org.y);
gridSectors[secnum] = ss;
}
else
{
ss = gridSectors[secnum];
}
trace.Init(*map);
kexBBox bounds = gridBound + org;
bInRange = false;
// is this cell even inside the world?
for(int i = 0; i < map->NumGLSubsectors; ++i)
{
if(bounds.IntersectingBox(map->ssLeafBounds[i]))
{
bInRange = true;
break;
}
}
if(bInRange)
{
// mark grid cell and accumulate color results
gridMap[gridid].marked = 1;
gridMap[gridid].color += LightCellSample(gridid, trace, org, ss);
kexMath::Clamp(gridMap[gridid].color, 0, 1);
}
std::unique_lock<std::mutex> lock(mutex);
int lastproc = processed * 100 / numLightGrids;
processed++;
int curproc = processed * 100 / numLightGrids;
if (lastproc != curproc || processed == 1)
{
remaining = (float)processed / (float)numLightGrids;
printf("%i%c cells done\r", (int)(remaining * 100.0f), '%');
}
}
//
// kexLightmapBuilder::CreateLightmaps
//
void kexLightmapBuilder::CreateLightmaps(FLevel &doomMap)
{
map = &doomMap;
printf("------------- Building light grid -------------\n");
CreateLightGrid();
printf("------------- Tracing surfaces -------------\n");
processed = 0;
@ -867,262 +641,119 @@ void kexLightmapBuilder::CreateLightmaps(FLevel &doomMap)
printf("Texels traced: %i \n\n", tracedTexels);
}
//
// kexLightmapBuilder::CreateLightGrid
//
void kexLightmapBuilder::CreateLightGrid()
void kexLightmapBuilder::AddLightmapLump(FWadWriter &wadFile)
{
int count;
int numNodes;
kexVec3 mins, maxs;
// Calculate size of lump
int numTexCoords = 0;
int numSurfaces = 0;
for (unsigned int i = 0; i < surfaces.Length(); i++)
{
if (surfaces[i]->lightmapNum != -1)
{
numTexCoords += surfaces[i]->numVerts;
numSurfaces++;
}
}
int version = 0;
int headerSize = 3 * sizeof(uint32_t) + 2 * sizeof(uint16_t);
int surfacesSize = surfaces.Length() * 5 * sizeof(uint32_t);
int texCoordsSize = numTexCoords * 2 * sizeof(float);
int texDataSize = textures.Length() * textureWidth * textureHeight * 3 * 2;
int lumpSize = headerSize + surfacesSize + texCoordsSize + texDataSize;
// get the bounding box of the root BSP node
numNodes = map->NumGLNodes-1;
if(numNodes < 0)
{
numNodes = 0;
}
// Setup buffer
std::vector<uint8_t> buffer(lumpSize);
kexBinFile lumpFile;
lumpFile.SetBuffer(buffer.data());
worldGrid = map->nodeBounds[numNodes];
// Write header
lumpFile.Write32(version);
lumpFile.Write16(textureWidth);
lumpFile.Write16(textures.Length());
lumpFile.Write32(numSurfaces);
lumpFile.Write32(numTexCoords);
// determine the size of the grid block
for(int i = 0; i < 3; ++i)
{
mins[i] = gridSize[i] * kexMath::Floor(worldGrid.min[i] / gridSize[i]);
maxs[i] = gridSize[i] * kexMath::Ceil(worldGrid.max[i] / gridSize[i]);
gridBlock[i] = (maxs[i] - mins[i]) / gridSize[i] + 1;
}
// Write surfaces
int coordOffsets = 0;
for (unsigned int i = 0; i < surfaces.Length(); i++)
{
if (surfaces[i]->lightmapNum == -1)
continue;
worldGrid.min = mins;
worldGrid.max = maxs;
lumpFile.Write32(surfaces[i]->type);
lumpFile.Write32(surfaces[i]->typeIndex);
lumpFile.Write32(0xffffffff/*surfaces[i]->controlSector*/);
lumpFile.Write32(surfaces[i]->lightmapNum);
lumpFile.Write32(coordOffsets);
coordOffsets += surfaces[i]->numVerts;
}
gridBound.min = -(gridSize * 0.5f);
gridBound.max = (gridSize * 0.5f);
// Write texture coordinates
for (unsigned int i = 0; i < surfaces.Length(); i++)
{
if (surfaces[i]->lightmapNum == -1)
continue;
// get the total number of grid cells
count = (int)(gridBlock.x * gridBlock.y * gridBlock.z);
numLightGrids = count;
int count = surfaces[i]->numVerts;
if (surfaces[i]->type == ST_FLOOR)
{
for (int j = count - 1; j >= 0; j--)
{
lumpFile.WriteFloat(surfaces[i]->lightmapCoords[j * 2]);
lumpFile.WriteFloat(surfaces[i]->lightmapCoords[j * 2 + 1]);
}
}
else if (surfaces[i]->type == ST_CEILING)
{
for (int j = 0; j < count; j++)
{
lumpFile.WriteFloat(surfaces[i]->lightmapCoords[j * 2]);
lumpFile.WriteFloat(surfaces[i]->lightmapCoords[j * 2 + 1]);
}
}
else
{
// zdray uses triangle strip internally, lump/gzd uses triangle fan
// allocate data
gridMap = (gridMap_t*)Mem_Calloc(sizeof(gridMap_t) * count, hb_static);
gridSectors = (MapSubsectorEx**)Mem_Calloc(sizeof(MapSubsectorEx*) *
(int)(gridBlock.x * gridBlock.y), hb_static);
lumpFile.WriteFloat(surfaces[i]->lightmapCoords[0]);
lumpFile.WriteFloat(surfaces[i]->lightmapCoords[1]);
// process all grid cells
processed = 0;
kexWorker::RunJob(count, [=](int id) {
LightGrid(id);
});
lumpFile.WriteFloat(surfaces[i]->lightmapCoords[4]);
lumpFile.WriteFloat(surfaces[i]->lightmapCoords[5]);
printf("\nGrid cells: %i\n\n", count);
lumpFile.WriteFloat(surfaces[i]->lightmapCoords[6]);
lumpFile.WriteFloat(surfaces[i]->lightmapCoords[7]);
lumpFile.WriteFloat(surfaces[i]->lightmapCoords[2]);
lumpFile.WriteFloat(surfaces[i]->lightmapCoords[3]);
}
}
// Write lightmap textures
for (unsigned int i = 0; i < textures.Length(); i++)
{
unsigned int count = (textureWidth * textureHeight) * 3;
for (unsigned int j = 0; j < count; j++)
{
lumpFile.Write16(textures[i][j]);
}
}
#if 0
// Apply compression predictor
uint8_t *texBytes = lumpFile.BufferAt() - texDataSize;
for (int i = texDataSize - 1; i > 0; i--)
{
texBytes[i] -= texBytes[i - 1];
}
#endif
// Compress and store in lump
ZLibOut zout(wadFile);
wadFile.StartWritingLump("LIGHTMAP");
zout.Write(buffer.data(), lumpFile.BufferAt() - lumpFile.Buffer());
}
//
// kexLightmapBuilder::AddLightGridLump
//
void kexLightmapBuilder::AddLightGridLump(FWadWriter &wadFile)
{
kexBinFile lumpFile;
int lumpSize = 0;
int bit;
int bitmask;
byte *data;
lumpSize = 28 + numLightGrids;
for(int i = 0; i < numLightGrids; ++i)
{
if(gridMap[i].marked)
{
lumpSize += 4;
}
}
lumpSize += 512; // add some extra slop
data = (byte*)Mem_Calloc(lumpSize, hb_static);
lumpFile.SetBuffer(data);
lumpFile.Write32(numLightGrids);
lumpFile.Write16((short)worldGrid.min[0]);
lumpFile.Write16((short)worldGrid.min[1]);
lumpFile.Write16((short)worldGrid.min[2]);
lumpFile.Write16((short)worldGrid.max[0]);
lumpFile.Write16((short)worldGrid.max[1]);
lumpFile.Write16((short)worldGrid.max[2]);
lumpFile.Write16((short)gridSize.x);
lumpFile.Write16((short)gridSize.y);
lumpFile.Write16((short)gridSize.z);
lumpFile.Write16((short)gridBlock.x);
lumpFile.Write16((short)gridBlock.y);
lumpFile.Write16((short)gridBlock.z);
bit = 0;
bitmask = 0;
for(int i = 0; i < numLightGrids; ++i)
{
#if 0
bit |= (gridMap[i].marked << bitmask);
if(++bitmask == 8)
{
lumpFile.Write8(bit);
bit = 0;
bitmask = 0;
}
#else
lumpFile.Write8(gridMap[i].marked);
#endif
}
#if 0
if(bit)
{
lumpFile.Write8(bit);
}
#endif
for(int i = 0; i < numLightGrids; ++i)
{
if(gridMap[i].marked)
{
lumpFile.Write8((byte)(gridMap[i].color[0] * 255.0f));
lumpFile.Write8((byte)(gridMap[i].color[1] * 255.0f));
lumpFile.Write8((byte)(gridMap[i].color[2] * 255.0f));
}
}
bit = 0;
bitmask = 0;
for(int i = 0; i < numLightGrids; ++i)
{
if(gridMap[i].marked)
{
#if 0
bit |= (gridMap[i].sunShadow << bitmask);
bitmask += 2;
if(bitmask >= 8)
{
lumpFile.Write8(bit);
bit = 0;
bitmask = 0;
}
#else
lumpFile.Write8(gridMap[i].sunShadow);
#endif
}
}
#if 0
if(bit)
{
lumpFile.Write8(bit);
}
#endif
wadFile.WriteLump("LM_CELLS", data, lumpFile.BufferAt() - lumpFile.Buffer());
}
//
// kexLightmapBuilder::CreateLightmapLump
//
void kexLightmapBuilder::AddLightmapLumps(FWadWriter &wadFile)
{
int lumpSize = 0;
unsigned int i;
byte *data, *surfs, *txcrd, *lmaps;
int offs;
int size;
int j;
int coordOffsets;
kexBinFile lumpFile;
// try to guess the actual lump size
lumpSize += ((textureWidth * textureHeight) * 3) * textures.Length();
lumpSize += (12 * surfaces.Length());
lumpSize += sizeof(kexVec3);
lumpSize += 2048; // add some extra slop
for(i = 0; i < surfaces.Length(); i++)
{
lumpSize += (surfaces[i]->numVerts * 2) * sizeof(float);
}
data = (byte*)Mem_Calloc(lumpSize, hb_static);
lumpFile.SetBuffer(data);
lumpFile.WriteVector(map->GetSunDirection());
wadFile.WriteLump("LM_SUN", data, sizeof(kexVec3));
offs = lumpFile.BufferAt() - lumpFile.Buffer();
surfs = data + offs;
coordOffsets = 0;
size = 0;
// begin writing LM_SURFS lump
for(i = 0; i < surfaces.Length(); i++)
{
lumpFile.Write16(surfaces[i]->type);
lumpFile.Write16(surfaces[i]->typeIndex);
lumpFile.Write16(surfaces[i]->lightmapNum);
lumpFile.Write16(surfaces[i]->numVerts * 2);
lumpFile.Write32(coordOffsets);
size += 12;
coordOffsets += (surfaces[i]->numVerts * 2);
}
offs = lumpFile.BufferAt() - lumpFile.Buffer();
wadFile.WriteLump("LM_SURFS", data, size);
txcrd = data + offs;
size = 0;
// begin writing LM_TXCRD lump
for(i = 0; i < surfaces.Length(); i++)
{
for(j = 0; j < surfaces[i]->numVerts * 2; j++)
{
lumpFile.WriteFloat(surfaces[i]->lightmapCoords[j]);
size += 4;
}
}
offs = (lumpFile.BufferAt() - lumpFile.Buffer()) - offs;
wadFile.WriteLump("LM_TXCRD", txcrd, size);
lmaps = txcrd + offs;
// begin writing LM_LMAPS lump
lumpFile.Write32(textures.Length());
lumpFile.Write32(textureWidth);
lumpFile.Write32(textureHeight);
size = 12;
for(i = 0; i < textures.Length(); i++)
{
for(j = 0; j < (textureWidth * textureHeight) * 3; j++)
{
lumpFile.Write8(textures[i][j]);
size++;
}
}
offs = (lumpFile.BufferAt() - lumpFile.Buffer()) - offs;
wadFile.WriteLump("LM_LMAPS", lmaps, size);
}
//
// kexLightmapBuilder::WriteTexturesToTGA
//
void kexLightmapBuilder::WriteTexturesToTGA()
{
kexBinFile file;

View File

@ -43,14 +43,11 @@ public:
void BuildSurfaceParams(surface_t *surface);
void TraceSurface(surface_t *surface);
void CreateLightGrid();
void CreateLightmaps(FLevel &doomMap);
void LightSurface(const int surfid);
void LightGrid(const int gridid);
void WriteTexturesToTGA();
void WriteMeshToOBJ();
void AddLightGridLump(FWadWriter &wadFile);
void AddLightmapLumps(FWadWriter &wadFile);
void AddLightmapLump(FWadWriter &wadFile);
int samples;
float ambience;
@ -64,30 +61,16 @@ private:
bool MakeRoomForBlock(const int width, const int height, int *x, int *y, int *num);
kexBBox GetBoundsFromSurface(const surface_t *surface);
kexVec3 LightTexelSample(kexTrace &trace, const kexVec3 &origin, surface_t *surface);
kexVec3 LightCellSample(const int gridid, kexTrace &trace, const kexVec3 &origin, const MapSubsectorEx *sub);
bool EmitFromCeiling(kexTrace &trace, const surface_t *surface, const kexVec3 &origin, const kexVec3 &normal, kexVec3 &color);
void ExportTexelsToObjFile(FILE *f, const kexVec3 &org, int indices);
void WriteBlock(FILE *f, const int i, const kexVec3 &org, int indices, kexBBox &box);
struct gridMap_t
{
byte marked;
byte sunShadow;
kexVec3 color;
};
FLevel *map;
kexArray<byte*> textures;
kexArray<uint16_t*> textures;
int **allocBlocks;
int numTextures;
int extraSamples;
int tracedTexels;
int numLightGrids;
gridMap_t *gridMap;
MapSubsectorEx **gridSectors;
kexBBox worldGrid;
kexBBox gridBound;
kexVec3 gridBlock;
std::mutex mutex;
int processed = 0;

View File

@ -62,9 +62,6 @@ void kexLightSurface::Init(const surfaceLightDef &lightSurfaceDef,
const bool bWall,
const bool bNoCenterPoint)
{
this->outerCone = lightSurfaceDef.outerCone;
this->innerCone = lightSurfaceDef.innerCone;
this->falloff = lightSurfaceDef.falloff;
this->intensity = lightSurfaceDef.intensity;
this->distance = lightSurfaceDef.distance;
this->rgb = lightSurfaceDef.rgb;
@ -292,9 +289,6 @@ bool kexLightSurface::TraceSurface(FLevel *doomMap, kexTrace &trace, const surfa
{
kexVec3 normal;
kexVec3 lnormal;
kexVec3 center;
bool bInside;
float angle;
float curDist;
*dist = -M_INFINITY;
@ -306,29 +300,6 @@ bool kexLightSurface::TraceSurface(FLevel *doomMap, kexTrace &trace, const surfa
return true;
}
bInside = false;
// nudge the origin around to see if it's actually in the subsector
float nudges[4] = { -2, 2, -4, 4 };
for(int x = 0; x < 4; x++)
{
for(int y = 0; y < 4; y++)
{
if(doomMap->PointInsideSubSector(origin.x + nudges[x],
origin.y + nudges[y], surface->subSector))
{
bInside = true;
break;
}
}
if(bInside)
{
break;
}
}
lnormal = surface->plane.Normal();
if(surf)
@ -350,7 +321,7 @@ bool kexLightSurface::TraceSurface(FLevel *doomMap, kexTrace &trace, const surfa
// that we have to trace each one... which could really blow up the compile time
for(unsigned int i = 0; i < origins.Length(); ++i)
{
center = origins[i];
kexVec3 center = origins[i];
if(!bWall && origin.z > center.z)
{
@ -360,7 +331,7 @@ bool kexLightSurface::TraceSurface(FLevel *doomMap, kexTrace &trace, const surfa
continue;
}
if(bWall)
/*if(bWall)
{
angle = (origin - center).ToVec2().Normalize().Dot(lnormal.ToVec2());
}
@ -378,18 +349,7 @@ bool kexLightSurface::TraceSurface(FLevel *doomMap, kexTrace &trace, const surfa
}
angle = dir.Dot(lnormal);
if(angle > innerCone)
{
angle = innerCone;
}
}
if(!bInside && angle < outerCone)
{
// out of the cone range
continue;
}
}*/
if(bWall)
{
@ -430,21 +390,6 @@ bool kexLightSurface::TraceSurface(FLevel *doomMap, kexTrace &trace, const surfa
}
}
// determine how much to fade out
if(angle < innerCone)
{
float div = (innerCone - outerCone);
if(div != 0)
{
curDist *= ((angle - outerCone) / div);
}
else
{
curDist *= angle;
}
}
if(curDist > *dist)
{
*dist = curDist;

View File

@ -44,9 +44,6 @@ public:
void CreateCenterOrigin();
bool TraceSurface(FLevel *doomMap, kexTrace &trace, const surface_t *surface, const kexVec3 &origin, float *dist);
const float OuterCone() const { return outerCone; }
const float InnerCone() const { return innerCone; }
const float FallOff() const { return falloff; }
const float Distance() const { return distance; }
const float Intensity() const { return intensity; }
const kexVec3 GetRGB() const { return rgb; }
@ -59,9 +56,6 @@ private:
bool SubdivideRecursion(vertexBatch_t &surfPoints, float divide, kexArray<vertexBatch_t*> &points);
void Clip(vertexBatch_t &points, const kexVec3 &normal, float dist, vertexBatch_t *frontPoints, vertexBatch_t *backPoints);
float outerCone;
float innerCone;
float falloff;
float distance;
float intensity;
kexVec3 rgb;

View File

@ -40,119 +40,14 @@ static const kexVec3 defaultSunDirection(0.45f, 0.3f, 0.9f);
void FLevel::SetupDlight()
{
BuildNodeBounds();
BuildLeafs();
BuildPVS();
CheckSkySectors();
}
void FLevel::BuildNodeBounds()
{
int i;
int j;
kexVec3 point;
float high = -M_INFINITY;
float low = M_INFINITY;
nodeBounds = (kexBBox*)Mem_Calloc(sizeof(kexBBox) * NumGLNodes, hb_static);
for (i = 0; i < (int)Sectors.Size(); ++i)
{
if (Sectors[i].data.ceilingheight > high)
{
high = Sectors[i].data.ceilingheight;
}
if (Sectors[i].data.floorheight < low)
{
low = Sectors[i].data.floorheight;
}
}
for (i = 0; i < NumGLNodes; ++i)
{
nodeBounds[i].Clear();
for (j = 0; j < 2; ++j)
{
point.Set(GLNodes[i].bbox[j][BOXLEFT], GLNodes[i].bbox[j][BOXBOTTOM], low);
nodeBounds[i].AddPoint(point);
point.Set(GLNodes[i].bbox[j][BOXRIGHT], GLNodes[i].bbox[j][BOXTOP], high);
nodeBounds[i].AddPoint(point);
}
}
}
void FLevel::BuildLeafs()
{
MapSubsectorEx *ss;
leaf_t *lf;
int i;
int j;
kexVec3 point;
IntSector *sector;
int count;
leafs = (leaf_t*)Mem_Calloc(sizeof(leaf_t*) * NumGLSegs * 2, hb_static);
numLeafs = NumGLSubsectors;
ss = GLSubsectors;
segLeafLookup = (int*)Mem_Calloc(sizeof(int) * NumGLSegs, hb_static);
ssLeafLookup = (int*)Mem_Calloc(sizeof(int) * NumGLSubsectors, hb_static);
ssLeafCount = (int*)Mem_Calloc(sizeof(int) * NumGLSubsectors, hb_static);
ssLeafBounds = (kexBBox*)Mem_Calloc(sizeof(kexBBox) * NumGLSubsectors, hb_static);
count = 0;
for (i = 0; i < NumGLSubsectors; ++i, ++ss)
{
ssLeafCount[i] = ss->numlines;
ssLeafLookup[i] = ss->firstline;
ssLeafBounds[i].Clear();
sector = GetSectorFromSubSector(ss);
if (ss->numlines)
{
for (j = 0; j < (int)ss->numlines; ++j)
{
MapSegGLEx *seg = &GLSegs[ss->firstline + j];
lf = &leafs[count++];
segLeafLookup[ss->firstline + j] = i;
lf->vertex = GetSegVertex(seg->v1);
lf->seg = seg;
point.Set(lf->vertex.x, lf->vertex.y, sector->data.floorheight);
ssLeafBounds[i].AddPoint(point);
point.z = sector->data.ceilingheight;
ssLeafBounds[i].AddPoint(point);
}
}
}
}
void FLevel::BuildPVS()
{
// don't do anything if already loaded
if (mapPVS != NULL)
{
return;
}
int len = ((NumGLSubsectors + 7) / 8) * NumGLSubsectors;
mapPVS = (byte*)Mem_Malloc(len, hb_static);
memset(mapPVS, 0xff, len);
}
void FLevel::CheckSkySectors()
{
char name[9];
bSkySectors = (bool*)Mem_Calloc(sizeof(bool) * Sectors.Size(), hb_static);
bSSectsVisibleToSky = (bool*)Mem_Calloc(sizeof(bool) * NumGLSubsectors, hb_static);
for (int i = 0; i < (int)Sectors.Size(); ++i)
{
@ -167,27 +62,6 @@ void FLevel::CheckSkySectors()
bSkySectors[i] = true;
}
}
// try to early out by quickly checking which subsector can potentially
// see a sky sector
for (int i = 0; i < NumGLSubsectors; ++i)
{
for (int j = 0; j < NumGLSubsectors; ++j)
{
IntSector *sec = GetSectorFromSubSector(&GLSubsectors[j]);
if (bSkySectors[sec - &Sectors[0]] == false)
{
continue;
}
if (CheckPVS(&GLSubsectors[i], &GLSubsectors[j]))
{
bSSectsVisibleToSky[i] = true;
break;
}
}
}
}
const kexVec3 &FLevel::GetSunColor() const
@ -200,65 +74,41 @@ const kexVec3 &FLevel::GetSunDirection() const
return defaultSunDirection;
}
IntSideDef *FLevel::GetSideDef(const MapSegGLEx *seg)
IntSector *FLevel::GetFrontSector(const IntSideDef *side)
{
if (seg->linedef == NO_LINE_INDEX)
{
// skip minisegs
return NULL;
}
IntLineDef *line = &Lines[seg->linedef];
return &Sides[line->sidenum[seg->side]];
}
IntSector *FLevel::GetFrontSector(const MapSegGLEx *seg)
{
IntSideDef *side = GetSideDef(seg);
if (side == NULL)
{
return NULL;
}
return &Sectors[side->sector];
}
IntSector *FLevel::GetBackSector(const MapSegGLEx *seg)
IntSector *FLevel::GetBackSector(const IntSideDef *side)
{
if (seg->linedef == NO_LINE_INDEX)
{
// skip minisegs
return NULL;
}
IntLineDef *line = side->line;
if (!(line->flags & ML_TWOSIDED))
return nullptr;
IntLineDef *line = &Lines[seg->linedef];
int sidenum = (ptrdiff_t)(side - &Sides[0]);
if (line->sidenum[0] == sidenum)
sidenum = line->sidenum[1];
else
sidenum = line->sidenum[0];
if ((line->flags & ML_TWOSIDED) && line->sidenum[seg->side ^ 1] != 0xffffffff)
{
IntSideDef *backSide = &Sides[line->sidenum[seg->side ^ 1]];
return &Sectors[backSide->sector];
}
if (sidenum == NO_SIDE_INDEX)
return nullptr;
return NULL;
return GetFrontSector(&Sides[sidenum]);
}
IntSector *FLevel::GetSectorFromSubSector(const MapSubsectorEx *sub)
{
IntSector *sector = NULL;
// try to find a sector that the subsector belongs to
for (int i = 0; i < (int)sub->numlines; i++)
{
MapSegGLEx *seg = &GLSegs[sub->firstline + i];
if (seg->side != NO_SIDE_INDEX)
{
sector = GetFrontSector(seg);
break;
IntLineDef *line = &Lines[seg->linedef];
return GetFrontSector(&Sides[line->sidenum[seg->side]]);
}
}
return sector;
return nullptr;
}
MapSubsectorEx *FLevel::PointInSubSector(const int x, const int y)
@ -300,113 +150,6 @@ MapSubsectorEx *FLevel::PointInSubSector(const int x, const int y)
return &GLSubsectors[nodenum & ~NFX_SUBSECTOR];
}
bool FLevel::PointInsideSubSector(const float x, const float y, const MapSubsectorEx *sub)
{
surface_t *surf;
int i;
kexVec2 p(x, y);
kexVec2 dp1, dp2;
kexVec2 pt1, pt2;
surf = leafSurfaces[0][sub - GLSubsectors];
if (!surf)
return false;
// check to see if the point is inside the subsector leaf
for (i = 0; i < surf->numVerts; i++)
{
pt1 = surf->verts[i].ToVec2();
pt2 = surf->verts[(i + 1) % surf->numVerts].ToVec2();
dp1 = pt1 - p;
dp2 = pt2 - p;
if (dp1.CrossScalar(dp2) < 0)
{
continue;
}
// this point is outside the subsector leaf
return false;
}
return true;
}
bool FLevel::LineIntersectSubSector(const kexVec3 &start, const kexVec3 &end, const MapSubsectorEx *sub, kexVec2 &out)
{
surface_t *surf;
kexVec2 p1, p2;
kexVec2 s1, s2;
kexVec2 pt;
kexVec2 v;
float d, u;
float newX;
float ab;
int i;
surf = leafSurfaces[0][sub - GLSubsectors];
p1 = start.ToVec2();
p2 = end.ToVec2();
for (i = 0; i < surf->numVerts; i++)
{
s1 = surf->verts[i].ToVec2();
s2 = surf->verts[(i + 1) % surf->numVerts].ToVec2();
if ((p1 == p2) || (s1 == s2))
{
// zero length
continue;
}
if ((p1 == s1) || (p2 == s1) || (p1 == s2) || (p2 == s2))
{
// shares end point
continue;
}
// translate to origin
pt = p2 - p1;
s1 -= p1;
s2 -= p1;
// normalize
u = pt.UnitSq();
d = kexMath::InvSqrt(u);
v = (pt * d);
// rotate points s1 and s2 so they're on the positive x axis
newX = s1.Dot(v);
s1.y = s1.CrossScalar(v);
s1.x = newX;
newX = s2.Dot(v);
s2.y = s2.CrossScalar(v);
s2.x = newX;
if ((s1.y < 0 && s2.y < 0) || (s1.y >= 0 && s2.y >= 0))
{
// s1 and s2 didn't cross
continue;
}
ab = s2.x + (s1.x - s2.x) * s2.y / (s2.y - s1.y);
if (ab < 0 || ab >(u * d))
{
// s1 and s2 crosses but outside of points p1 and p2
continue;
}
// intersected
out = p1 + (v * ab);
return true;
}
return false;
}
FloatVertex FLevel::GetSegVertex(int index)
{
if (index & 0x8000)
@ -420,19 +163,6 @@ FloatVertex FLevel::GetSegVertex(int index)
return v;
}
bool FLevel::CheckPVS(MapSubsectorEx *s1, MapSubsectorEx *s2)
{
uint8_t *vis;
int n1, n2;
n1 = s1 - GLSubsectors;
n2 = s2 - GLSubsectors;
vis = &mapPVS[(((NumGLSubsectors + 7) / 8) * n1)];
return ((vis[n2 >> 3] & (1 << (n2 & 7))) != 0);
}
void FLevel::CreateLights()
{
thingLight_t *thingLight;
@ -514,12 +244,9 @@ void FLevel::CreateLights()
{
surface_t *surface = surfaces[j];
if (surface->type >= ST_MIDDLESEG && surface->type <= ST_LOWERSEG)
if (surface->type >= ST_MIDDLESIDE && surface->type <= ST_LOWERSIDE)
{
IntLineDef *line = nullptr;
if (GLSegs[surface->typeIndex].linedef != NO_LINE_INDEX)
line = &Lines[GLSegs[surface->typeIndex].linedef];
IntLineDef *line = Sides[surface->typeIndex].line;
if (line)
{
uint32_t lightcolor = 0xffffff;
@ -547,9 +274,6 @@ void FLevel::CreateLights()
{
surfaceLightDef desc;
desc.tag = 0;
desc.outerCone = 0.0f;
desc.innerCone = 0.0f;
desc.falloff = 1.0f;
desc.intensity = lightintensity;
desc.distance = lightdistance;
desc.bIgnoreCeiling = false;
@ -569,7 +293,7 @@ void FLevel::CreateLights()
}
else if (surface->type == ST_FLOOR || surface->type == ST_CEILING)
{
MapSubsectorEx *sub = surface->subSector;
MapSubsectorEx *sub = &GLSubsectors[surface->typeIndex];
IntSector *sector = GetSectorFromSubSector(sub);
if (sector && surface->numVerts > 0)
@ -617,9 +341,6 @@ void FLevel::CreateLights()
{
surfaceLightDef desc;
desc.tag = 0;
desc.outerCone = 0.0f;
desc.innerCone = 0.0f;
desc.falloff = 1.0f;
desc.intensity = lightintensity;
desc.distance = lightdistance;
desc.bIgnoreCeiling = false;

View File

@ -36,27 +36,26 @@
kexArray<surface_t*> surfaces;
static void Surface_AllocateFromSeg(FLevel &doomMap, MapSegGLEx *seg)
static void Surface_AllocateFromSide(FLevel &doomMap, IntSideDef *side)
{
IntSideDef *side;
surface_t *surf;
IntSector *front;
IntSector *back;
if(seg->linedef == NO_LINE_INDEX)
{
return;
}
side = doomMap.GetSideDef(seg);
front = doomMap.GetFrontSector(seg);
back = doomMap.GetBackSector(seg);
front = doomMap.GetFrontSector(side);
back = doomMap.GetBackSector(side);
if (front->controlsector)
return;
FloatVertex v1 = doomMap.GetSegVertex(seg->v1);
FloatVertex v2 = doomMap.GetSegVertex(seg->v2);
FloatVertex v1 = doomMap.GetSegVertex(side->line->v1);
FloatVertex v2 = doomMap.GetSegVertex(side->line->v2);
if (side->line->sidenum[0] != (ptrdiff_t)(side - &doomMap.Sides[0]))
{
std::swap(v1, v2);
}
float v1Top = front->ceilingplane.zAt(v1.x, v1.y);
float v1Bottom = front->floorplane.zAt(v1.x, v1.y);
float v2Top = front->ceilingplane.zAt(v2.x, v2.y);
@ -94,12 +93,8 @@ static void Surface_AllocateFromSeg(FLevel &doomMap, MapSegGLEx *seg)
surf->plane.SetNormal(surf->verts[0], surf->verts[1], surf->verts[2]);
surf->plane.SetDistance(surf->verts[0]);
surf->type = ST_LOWERSEG;
surf->typeIndex = seg - doomMap.GLSegs;
surf->subSector = &doomMap.GLSubsectors[doomMap.segLeafLookup[seg - doomMap.GLSegs]];
doomMap.segSurfaces[1][surf->typeIndex] = surf;
surf->data = (MapSegGLEx*)seg;
surf->type = ST_LOWERSIDE;
surf->typeIndex = side - &doomMap.Sides[0];
surfaces.Push(surf);
}
@ -140,13 +135,9 @@ static void Surface_AllocateFromSeg(FLevel &doomMap, MapSegGLEx *seg)
surf->plane.SetNormal(surf->verts[0], surf->verts[1], surf->verts[2]);
surf->plane.SetDistance(surf->verts[0]);
surf->type = ST_UPPERSEG;
surf->typeIndex = seg - doomMap.GLSegs;
surf->type = ST_UPPERSIDE;
surf->typeIndex = side - &doomMap.Sides[0];
surf->bSky = bSky;
surf->subSector = &doomMap.GLSubsectors[doomMap.segLeafLookup[seg - doomMap.GLSegs]];
doomMap.segSurfaces[2][surf->typeIndex] = surf;
surf->data = (MapSegGLEx*)seg;
surfaces.Push(surf);
}
@ -174,47 +165,34 @@ static void Surface_AllocateFromSeg(FLevel &doomMap, MapSegGLEx *seg)
surf->plane.SetNormal(surf->verts[0], surf->verts[1], surf->verts[2]);
surf->plane.SetDistance(surf->verts[0]);
surf->type = ST_MIDDLESEG;
surf->typeIndex = seg - doomMap.GLSegs;
surf->subSector = &doomMap.GLSubsectors[doomMap.segLeafLookup[seg - doomMap.GLSegs]];
doomMap.segSurfaces[0][surf->typeIndex] = surf;
surf->data = (MapSegGLEx*)seg;
surf->type = ST_MIDDLESIDE;
surf->typeIndex = side - &doomMap.Sides[0];
surfaces.Push(surf);
}
}
//
// Surface_AllocateFromLeaf
//
// Plane normals should almost always be known
// unless slopes are involved....
//
static void Surface_AllocateFromLeaf(FLevel &doomMap)
{
surface_t *surf;
leaf_t *leaf;
IntSector *sector = NULL;
int i;
int j;
printf("------------- Building leaf surfaces -------------\n");
doomMap.leafSurfaces[0] = (surface_t**)Mem_Calloc(sizeof(surface_t*) * doomMap.NumGLSubsectors, hb_static);
doomMap.leafSurfaces[1] = (surface_t**)Mem_Calloc(sizeof(surface_t*) * doomMap.NumGLSubsectors, hb_static);
printf("------------- Building subsector surfaces -------------\n");
for(i = 0; i < doomMap.NumGLSubsectors; i++)
{
printf("subsectors: %i / %i\r", i+1, doomMap.NumGLSubsectors);
if(doomMap.ssLeafCount[i] < 3)
MapSubsectorEx *sub = &doomMap.GLSubsectors[i];
if(sub->numlines < 3)
{
continue;
}
sector = doomMap.GetSectorFromSubSector(&doomMap.GLSubsectors[i]);
sector = doomMap.GetSectorFromSubSector(sub);
// I will be NOT surprised if some users tries to do something stupid with
// sector hacks
@ -228,17 +206,17 @@ static void Surface_AllocateFromLeaf(FLevel &doomMap)
continue;
surf = (surface_t*)Mem_Calloc(sizeof(surface_t), hb_static);
surf->numVerts = doomMap.ssLeafCount[i];
surf->numVerts = sub->numlines;
surf->verts = (kexVec3*)Mem_Calloc(sizeof(kexVec3) * surf->numVerts, hb_static);
surf->subSector = &doomMap.GLSubsectors[i];
// floor verts
for(j = 0; j < surf->numVerts; j++)
{
leaf = &doomMap.leafs[doomMap.ssLeafLookup[i] + (surf->numVerts - 1) - j];
MapSegGLEx *seg = &doomMap.GLSegs[sub->firstline + (surf->numVerts - 1) - j];
FloatVertex v1 = doomMap.GetSegVertex(seg->v1);
surf->verts[j].x = leaf->vertex.x;
surf->verts[j].y = leaf->vertex.y;
surf->verts[j].x = v1.x;
surf->verts[j].y = v1.y;
surf->verts[j].z = sector->floorplane.zAt(surf->verts[j].x, surf->verts[j].y);
}
@ -246,15 +224,11 @@ static void Surface_AllocateFromLeaf(FLevel &doomMap)
surf->type = ST_FLOOR;
surf->typeIndex = i;
doomMap.leafSurfaces[0][i] = surf;
surf->data = (IntSector*)sector;
surfaces.Push(surf);
surf = (surface_t*)Mem_Calloc(sizeof(surface_t), hb_static);
surf->numVerts = doomMap.ssLeafCount[i];
surf->numVerts = sub->numlines;
surf->verts = (kexVec3*)Mem_Calloc(sizeof(kexVec3) * surf->numVerts, hb_static);
surf->subSector = &doomMap.GLSubsectors[i];
if(doomMap.bSkySectors[sector-&doomMap.Sectors[0]])
{
@ -264,10 +238,11 @@ static void Surface_AllocateFromLeaf(FLevel &doomMap)
// ceiling verts
for(j = 0; j < surf->numVerts; j++)
{
leaf = &doomMap.leafs[doomMap.ssLeafLookup[i] + j];
MapSegGLEx *seg = &doomMap.GLSegs[sub->firstline + j];
FloatVertex v1 = doomMap.GetSegVertex(seg->v1);
surf->verts[j].x = leaf->vertex.x;
surf->verts[j].y = leaf->vertex.y;
surf->verts[j].x = v1.x;
surf->verts[j].y = v1.y;
surf->verts[j].z = sector->ceilingplane.zAt(surf->verts[j].x, surf->verts[j].y);
}
@ -275,9 +250,6 @@ static void Surface_AllocateFromLeaf(FLevel &doomMap)
surf->type = ST_CEILING;
surf->typeIndex = i;
doomMap.leafSurfaces[1][i] = surf;
surf->data = (IntSector*)sector;
surfaces.Push(surf);
}
@ -306,20 +278,26 @@ void Surface_AllocateFromMap(FLevel &doomMap)
Mem_Free(surfaces[i]);
surfaces = {};
doomMap.segSurfaces[0] = (surface_t**)Mem_Calloc(sizeof(surface_t*) * doomMap.NumGLSegs, hb_static);
doomMap.segSurfaces[1] = (surface_t**)Mem_Calloc(sizeof(surface_t*) * doomMap.NumGLSegs, hb_static);
doomMap.segSurfaces[2] = (surface_t**)Mem_Calloc(sizeof(surface_t*) * doomMap.NumGLSegs, hb_static);
for (unsigned int i = 0; i < doomMap.Sectors.Size(); i++)
doomMap.Sectors[i].controlsector = false;
for (unsigned int i = 0; i < doomMap.Sides.Size(); i++)
doomMap.Sides[i].line = nullptr;
for (unsigned int i = 0; i < doomMap.Lines.Size(); i++)
{
const auto &line = doomMap.Lines[i];
if (line.special == 160) // Sector_Set3dFloor
IntLineDef *line = &doomMap.Lines[i];
// Link sides to lines
if (line->sidenum[0] < doomMap.Sides.Size())
doomMap.Sides[line->sidenum[0]].line = line;
if (line->sidenum[1] < doomMap.Sides.Size())
doomMap.Sides[line->sidenum[1]].line = line;
if (line->special == 160) // Sector_Set3dFloor
{
int sectorTag = line.args[0];
int type = line.args[1];
int sectorTag = line->args[0];
int type = line->args[1];
//int opacity = line.args[3];
IntSector *controlsector = &doomMap.Sectors[doomMap.Sides[doomMap.Lines[i].sidenum[0]].sector];
@ -337,13 +315,13 @@ void Surface_AllocateFromMap(FLevel &doomMap)
printf("------------- Building seg surfaces -------------\n");
for(int i = 0; i < doomMap.NumGLSegs; i++)
for(unsigned int i = 0; i < doomMap.Sides.Size(); i++)
{
Surface_AllocateFromSeg(doomMap, &doomMap.GLSegs[i]);
printf("segs: %i / %i\r", i+1, doomMap.NumGLSegs);
Surface_AllocateFromSide(doomMap, &doomMap.Sides[i]);
printf("sides: %i / %i\r", i+1, doomMap.Sides.Size());
}
printf("\nSeg surfaces: %i\n", surfaces.Length());
printf("\nSide surfaces: %i\n", surfaces.Length());
Surface_AllocateFromLeaf(doomMap);
@ -373,7 +351,7 @@ void Surface_AllocateFromMap(FLevel &doomMap)
}
}
}
else if (s->type == ST_MIDDLESEG || s->type == ST_UPPERSEG || s->type == ST_LOWERSEG)
else if (s->type == ST_MIDDLESIDE || s->type == ST_UPPERSIDE || s->type == ST_LOWERSIDE)
{
if (!IsDegenerate(s->verts[0], s->verts[1], s->verts[2]))
{

View File

@ -32,9 +32,9 @@ struct MapSubsectorEx;
enum surfaceType_t
{
ST_UNKNOWN = 0,
ST_MIDDLESEG,
ST_UPPERSEG,
ST_LOWERSEG,
ST_MIDDLESIDE,
ST_UPPERSIDE,
ST_LOWERSIDE,
ST_CEILING,
ST_FLOOR
};
@ -59,9 +59,9 @@ struct surface_t
float *lightmapCoords;
surfaceType_t type;
int typeIndex;
void *data;
//void *data;
bool bSky;
MapSubsectorEx *subSector;
//MapSubsectorEx *subSector;
};
extern kexArray<surface_t*> surfaces;

View File

@ -35,36 +35,11 @@
#include "mapdata.h"
#include "trace.h"
//
// kexTrace::kexTrace
//
kexTrace::kexTrace()
{
this->map = NULL;
}
//
// kexTrace::~kexTrace
//
kexTrace::~kexTrace()
{
}
//
// kexTrace::Init
//
void kexTrace::Init(FLevel &doomMap)
{
map = &doomMap;
}
//
// kexTrace::Trace
//
void kexTrace::Trace(const kexVec3 &startVec, const kexVec3 &endVec)
{
start = startVec;
@ -76,223 +51,4 @@ void kexTrace::Trace(const kexVec3 &startVec, const kexVec3 &endVec)
hitSurface = surfaces[hit.surface];
else
hitSurface = nullptr;
/*
dir = (end - start).Normalize();
hitNormal.Clear();
hitVector.Clear();
hitSurface = NULL;
fraction = 1;
if(map == NULL)
{
return;
}
TraceBSPNode(map->NumGLNodes - 1);
*/
}
#if 0
//
// kexTrace::TraceSurface
//
void kexTrace::TraceSurface(surface_t *surface)
{
kexPlane *plane;
kexVec3 hit;
kexVec3 edge1;
kexVec3 edge2;
kexVec3 normal;
float d1;
float d2;
float d;
float frac;
int i;
kexPluecker r;
if(surface == NULL)
{
return;
}
plane = &surface->plane;
d1 = plane->Distance(start) - plane->d;
d2 = plane->Distance(end) - plane->d;
if(d1 <= d2 || d1 < 0 || d2 > 0)
{
// trace is either completely in front or behind the plane
return;
}
frac = (d1 / (d1 - d2));
if(frac > 1 || frac < 0)
{
// not a valid contact
return;
}
if(frac >= fraction)
{
// farther than the current contact
return;
}
hit = start.Lerp(end, frac);
normal = plane->Normal();
r.SetRay(start, dir);
// segs are always made up of 4 vertices, so its safe to assume 4 edges here
if(surface->type >= ST_MIDDLESEG && surface->type <= ST_LOWERSEG)
{
kexPluecker p1;
kexPluecker p2;
kexPluecker p3;
kexPluecker p4;
byte sideBits = 0;
p1.SetLine(surface->verts[2], surface->verts[3]); // top edge
p2.SetLine(surface->verts[1], surface->verts[0]); // bottom edge
p3.SetLine(surface->verts[3], surface->verts[1]); // right edge
p4.SetLine(surface->verts[0], surface->verts[2]); // left edge
// this sucks so much..... I am surprised this even works at all
d = r.InnerProduct(p1)-0.001f;
sideBits |= (FLOATSIGNBIT(d) << 0);
d = r.InnerProduct(p2)-0.001f;
sideBits |= (FLOATSIGNBIT(d) << 1);
d = r.InnerProduct(p3)-0.001f;
sideBits |= (FLOATSIGNBIT(d) << 2);
d = r.InnerProduct(p4)-0.001f;
sideBits |= (FLOATSIGNBIT(d) << 3);
if(sideBits != 0xF)
{
return;
}
}
else if(surface->type == ST_FLOOR || surface->type == ST_CEILING)
{
kexPluecker p;
kexVec3 v1;
kexVec3 v2;
for(i = 0; i < surface->numVerts; i++)
{
v1 = surface->verts[i];
v2 = surface->verts[(i+1)%surface->numVerts];
p.SetLine(v2, v1);
if(r.InnerProduct(p) > 0.01f)
{
return;
}
}
}
hitNormal = normal;
hitVector = hit;
hitSurface = surface;
fraction = frac;
}
//
// kexTrace::TraceSubSector
//
void kexTrace::TraceSubSector(int num)
{
MapSubsectorEx *sub;
int i;
int j;
sub = &map->GLSubsectors[num];
if(!map->ssLeafBounds[num].LineIntersect(start, end))
{
return;
}
// test line segments
for(i = 0; i < (int)sub->numlines; i++)
{
int segnum = sub->firstline + i;
for(j = 0; j < 3; j++)
{
if(j == 0)
{
int linenum = map->GLSegs[segnum].linedef;
if(linenum != NO_LINE_INDEX && map->Lines[linenum].flags & (ML_TWOSIDED|ML_TRANSPARENT1|ML_TRANSPARENT2))
{
// don't trace transparent 2-sided lines
continue;
}
}
TraceSurface(map->segSurfaces[j][segnum]);
}
}
// test subsector leafs
for(j = 0; j < 2; j++)
{
TraceSurface(map->leafSurfaces[j][num]);
}
}
//
// kexTrace::TraceBSPNode
//
void kexTrace::TraceBSPNode(int num)
{
MapNodeEx *node;
kexVec3 dp1;
kexVec3 dp2;
float d;
byte side;
if(num & NFX_SUBSECTOR)
{
TraceSubSector(num & (~NFX_SUBSECTOR));
return;
}
if(!map->nodeBounds[num & (~NFX_SUBSECTOR)].LineIntersect(start, end))
{
return;
}
node = &map->GLNodes[num];
kexVec3 pt1(F(node->x), F(node->y), 0);
kexVec3 pt2(F(node->dx), F(node->dy), 0);
//kexVec3 pt1(F(node->x << 16), F(node->y << 16), 0);
//kexVec3 pt2(F(node->dx << 16), F(node->dy << 16), 0);
dp1 = pt1 - start;
dp2 = (pt2 + pt1) - start;
d = dp1.Cross(dp2).z;
side = FLOATSIGNBIT(d);
TraceBSPNode(node->children[side ^ 1]);
dp1 = pt1 - end;
dp2 = (pt2 + pt1) - end;
d = dp1.Cross(dp2).z;
// don't trace if both ends of the ray are on the same side
if(side != FLOATSIGNBIT(d))
{
TraceBSPNode(node->children[side]);
}
}
#endif

View File

@ -32,9 +32,6 @@ struct FLevel;
class kexTrace
{
public:
kexTrace();
~kexTrace();
void Init(FLevel &doomMap);
void Trace(const kexVec3 &startVec, const kexVec3 &endVec);
@ -44,15 +41,5 @@ public:
float fraction;
private:
FLevel *map;
#if 0
kexVec3 dir;
kexVec3 hitNormal;
kexVec3 hitVector;
void TraceBSPNode(int num);
void TraceSubSector(int num);
void TraceSurface(surface_t *surface);
#endif
FLevel *map = nullptr;
};

View File

@ -763,230 +763,3 @@ const int64_t GetSeconds()
{
return time(0);
}
#if 0 // Old dlight main function
int main(int argc, char **argv)
{
kexWadFile wadFile;
kexWadFile outWadFile;
FLevel doomMap;
lump_t *lmLump;
kexArray<int> ignoreLumps;
kexLightmapBuilder builder;
kexStr configFile("strife_sve.cfg");
bool bWriteTGA;
int map = 1;
int arg = 1;
printf("DLight (c) 2013-2014 Samuel Villarreal\n\n");
if (argc < 1 || argv[1] == NULL)
{
printf("Usage: dlight [options] [wadfile]\n");
printf("Use -help for list of options\n");
return 0;
}
basePath = argv[0];
basePath.StripFile();
bWriteTGA = false;
while (1)
{
if (!strcmp(argv[arg], "-help"))
{
printf("Options:\n");
printf("-help: displays all known options\n");
printf("-map: process lightmap for MAP##\n");
printf("-samples: set texel sampling size (lowest = higher quaility but\n");
printf(" slow compile time) must be in powers of two\n");
printf("-ambience: set global ambience value for lightmaps (0.0 - 1.0)\n");
printf("-size: lightmap texture dimentions for width and height\n");
printf(" must be in powers of two (1, 2, 4, 8, 16, etc)\n");
printf("-threads: set total number of threads (1 min, 128 max)\n");
printf("-config: specify a config file to parse (default: strife_sve.cfg)\n");
printf("-writetga: dumps lightmaps to targa (.TGA) files\n");
arg++;
return 0;
}
else if (!strcmp(argv[arg], "-map"))
{
if (argv[arg + 1] == NULL)
{
Error("Specify map number for -map\n");
return 1;
}
map = atoi(argv[++arg]);
arg++;
}
else if (!strcmp(argv[arg], "-samples"))
{
if (argv[arg + 1] == NULL)
{
Error("Specify value for -samples\n");
return 1;
}
builder.samples = atoi(argv[++arg]);
if (builder.samples <= 0)
{
builder.samples = 1;
}
if (builder.samples > 128)
{
builder.samples = 128;
}
builder.samples = kexMath::RoundPowerOfTwo(builder.samples);
arg++;
}
else if (!strcmp(argv[arg], "-ambience"))
{
if (argv[arg + 1] == NULL)
{
Error("Specify value for -ambience\n");
return 1;
}
builder.ambience = (float)atof(argv[++arg]);
if (builder.ambience < 0)
{
builder.ambience = 0;
}
if (builder.ambience > 1)
{
builder.ambience = 1;
}
}
else if (!strcmp(argv[arg], "-size"))
{
int lmDims;
if (argv[arg + 1] == NULL)
{
Error("Specify value for -size\n");
return 1;
}
lmDims = atoi(argv[++arg]);
if (lmDims <= 0)
{
lmDims = 1;
}
if (lmDims > LIGHTMAP_MAX_SIZE)
{
lmDims = LIGHTMAP_MAX_SIZE;
}
lmDims = kexMath::RoundPowerOfTwo(lmDims);
builder.textureWidth = lmDims;
builder.textureHeight = lmDims;
arg++;
}
else if (!strcmp(argv[arg], "-threads"))
{
kexWorker::maxWorkThreads = atoi(argv[++arg]);
kexMath::Clamp(kexWorker::maxWorkThreads, 1, MAX_THREADS);
arg++;
}
else if (!strcmp(argv[arg], "-config"))
{
configFile = argv[++arg];
arg++;
}
else if (!strcmp(argv[arg], "-writetga"))
{
bWriteTGA = true;
arg++;
}
else
{
break;
}
}
if (argv[arg] == NULL)
{
printf("Usage: dlight [options] [wadfile]\n");
return 0;
}
if (!wadFile.Open(argv[arg]))
{
return 1;
}
// concat the base path to light def file if there is none
if (configFile.IndexOf("\\") == -1 && configFile.IndexOf("/") == -1)
{
configFile = basePath + configFile;
}
int starttime = (int)GetSeconds();
printf("---------------- Parsing config file ----------------\n\n");
doomMap.ParseConfigFile(configFile.c_str());
printf("------------- Building level structures -------------\n\n");
wadFile.SetCurrentMap(map);
doomMap.BuildMapFromWad(wadFile);
printf("----------- Allocating surfaces from level ----------\n\n");
Surface_AllocateFromMap(doomMap);
printf("---------------- Allocating lights ----------------\n\n");
doomMap.CreateLights();
printf("---------------- Creating lightmaps ---------------\n\n");
builder.CreateLightmaps(doomMap);
doomMap.CleanupThingLights();
if (bWriteTGA)
{
builder.WriteTexturesToTGA();
}
printf("------------------ Rebuilding wad ----------------\n\n");
wadFile.CreateBackup();
lmLump = wadFile.GetLumpFromName(Va("LM_MAP%02d", wadFile.currentmap));
if (lmLump)
{
int lumpnum = lmLump - wadFile.lumps;
ignoreLumps.Push(lumpnum + ML_LM_LABEL);
ignoreLumps.Push(lumpnum + ML_LM_CELLS);
ignoreLumps.Push(lumpnum + ML_LM_SUN);
ignoreLumps.Push(lumpnum + ML_LM_SURFS);
ignoreLumps.Push(lumpnum + ML_LM_TXCRD);
ignoreLumps.Push(lumpnum + ML_LM_LMAPS);
}
outWadFile.InitForWrite();
outWadFile.CopyLumpsFromWadFile(wadFile, ignoreLumps);
outWadFile.AddLump(Va("LM_MAP%02d", wadFile.currentmap), 0, NULL);
builder.AddLightGridLump(outWadFile);
builder.AddLightmapLumps(outWadFile);
printf("------------- Writing %s -------------\n\n", wadFile.wadName.c_str());
outWadFile.Write(wadFile.wadName);
outWadFile.Close();
wadFile.Close();
printf("----------------- Shutting down -----------------\n\n");
Mem_Purge(hb_static);
int proctime = (int)GetSeconds() - starttime;
printf("\nBuild time: %d:%02d:%02d\n",
proctime / 3600, (proctime / 60) % 60, proctime % 60);
return 0;
}
#endif