mirror of
https://github.com/ZDoom/ZDRay.git
synced 2025-01-24 16:51:08 +00:00
- changed the output to be one lump using a compressed rgb16f format with 3d floors support
This commit is contained in:
parent
5e21857b4a
commit
5399e988c7
16 changed files with 3658 additions and 1468 deletions
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
3381
src/lightmap/halffloat.cpp
Normal file
File diff suppressed because it is too large
Load diff
68
src/lightmap/halffloat.h
Normal file
68
src/lightmap/halffloat.h
Normal 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]);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]))
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
227
src/main.cpp
227
src/main.cpp
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue