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/wad.cpp
|
||||||
src/lightmap/worker.cpp
|
src/lightmap/worker.cpp
|
||||||
src/lightmap/collision.cpp
|
src/lightmap/collision.cpp
|
||||||
|
src/lightmap/halffloat.cpp
|
||||||
src/lightmap/kexlib/binfile.cpp
|
src/lightmap/kexlib/binfile.cpp
|
||||||
src/lightmap/kexlib/kstring.cpp
|
src/lightmap/kexlib/kstring.cpp
|
||||||
src/lightmap/kexlib/memheap.cpp
|
src/lightmap/kexlib/memheap.cpp
|
||||||
|
@ -194,6 +195,7 @@ set( HEADERS
|
||||||
src/lightmap/wad.h
|
src/lightmap/wad.h
|
||||||
src/lightmap/worker.h
|
src/lightmap/worker.h
|
||||||
src/lightmap/collision.h
|
src/lightmap/collision.h
|
||||||
|
src/lightmap/halffloat.h
|
||||||
src/lightmap/kexlib/array.h
|
src/lightmap/kexlib/array.h
|
||||||
src/lightmap/kexlib/binfile.h
|
src/lightmap/kexlib/binfile.h
|
||||||
src/lightmap/kexlib/kstring.h
|
src/lightmap/kexlib/kstring.h
|
||||||
|
|
|
@ -40,6 +40,8 @@ struct MapSideDef
|
||||||
WORD sector;
|
WORD sector;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct IntLineDef;
|
||||||
|
|
||||||
struct IntSideDef
|
struct IntSideDef
|
||||||
{
|
{
|
||||||
// the first 5 values are only used for binary format maps
|
// the first 5 values are only used for binary format maps
|
||||||
|
@ -51,6 +53,8 @@ struct IntSideDef
|
||||||
|
|
||||||
int sector;
|
int sector;
|
||||||
|
|
||||||
|
IntLineDef *line;
|
||||||
|
|
||||||
TArray<UDMFKey> props;
|
TArray<UDMFKey> props;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -248,12 +252,6 @@ struct FloatVertex
|
||||||
float y;
|
float y;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct leaf_t
|
|
||||||
{
|
|
||||||
FloatVertex vertex;
|
|
||||||
MapSegGLEx *seg;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lightDef_t
|
struct lightDef_t
|
||||||
{
|
{
|
||||||
int doomednum;
|
int doomednum;
|
||||||
|
@ -291,9 +289,6 @@ struct thingLight_t
|
||||||
struct surfaceLightDef
|
struct surfaceLightDef
|
||||||
{
|
{
|
||||||
int tag;
|
int tag;
|
||||||
float outerCone;
|
|
||||||
float innerCone;
|
|
||||||
float falloff;
|
|
||||||
float distance;
|
float distance;
|
||||||
float intensity;
|
float intensity;
|
||||||
bool bIgnoreFloor;
|
bool bIgnoreFloor;
|
||||||
|
@ -362,23 +357,7 @@ struct FLevel
|
||||||
TArray<int> MeshSurfaces;
|
TArray<int> MeshSurfaces;
|
||||||
std::unique_ptr<TriangleMeshShape> CollisionMesh;
|
std::unique_ptr<TriangleMeshShape> CollisionMesh;
|
||||||
|
|
||||||
leaf_t *leafs = nullptr;
|
|
||||||
uint8_t *mapPVS = nullptr;
|
|
||||||
|
|
||||||
bool *bSkySectors = 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<thingLight_t*> thingLights;
|
||||||
TArray<kexLightSurface*> lightSurfaces;
|
TArray<kexLightSurface*> lightSurfaces;
|
||||||
|
@ -389,20 +368,13 @@ struct FLevel
|
||||||
|
|
||||||
const kexVec3 &GetSunColor() const;
|
const kexVec3 &GetSunColor() const;
|
||||||
const kexVec3 &GetSunDirection() const;
|
const kexVec3 &GetSunDirection() const;
|
||||||
IntSideDef *GetSideDef(const MapSegGLEx *seg);
|
IntSector *GetFrontSector(const IntSideDef *side);
|
||||||
IntSector *GetFrontSector(const MapSegGLEx *seg);
|
IntSector *GetBackSector(const IntSideDef *side);
|
||||||
IntSector *GetBackSector(const MapSegGLEx *seg);
|
|
||||||
IntSector *GetSectorFromSubSector(const MapSubsectorEx *sub);
|
IntSector *GetSectorFromSubSector(const MapSubsectorEx *sub);
|
||||||
MapSubsectorEx *PointInSubSector(const int x, const int y);
|
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);
|
FloatVertex GetSegVertex(int index);
|
||||||
bool CheckPVS(MapSubsectorEx *s1, MapSubsectorEx *s2);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void BuildNodeBounds();
|
|
||||||
void BuildLeafs();
|
|
||||||
void BuildPVS();
|
|
||||||
void CheckSkySectors();
|
void CheckSkySectors();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -822,11 +822,10 @@ void FProcessor::Write (FWadWriter &out)
|
||||||
out.CopyLump (Wad, Wad.FindMapLump ("BEHAVIOR", Lump));
|
out.CopyLump (Wad, Wad.FindMapLump ("BEHAVIOR", Lump));
|
||||||
out.CopyLump (Wad, Wad.FindMapLump ("SCRIPTS", Lump));
|
out.CopyLump (Wad, Wad.FindMapLump ("SCRIPTS", Lump));
|
||||||
}
|
}
|
||||||
if (LightmapsBuilt)
|
/*if (LightmapsBuilt)
|
||||||
{
|
{
|
||||||
LMBuilder.AddLightGridLump(out);
|
LMBuilder.AddLightmapLump(out);
|
||||||
LMBuilder.AddLightmapLumps(out);
|
}*/
|
||||||
}
|
|
||||||
if (Level.GLNodes != NULL && !compressGL)
|
if (Level.GLNodes != NULL && !compressGL)
|
||||||
{
|
{
|
||||||
char glname[9];
|
char glname[9];
|
||||||
|
|
|
@ -789,7 +789,8 @@ void FProcessor::WriteUDMF(FWadWriter &out)
|
||||||
const char *lumpname = Wad.LumpName(i);
|
const char *lumpname = Wad.LumpName(i);
|
||||||
if (stricmp(lumpname, "ZNODES") &&
|
if (stricmp(lumpname, "ZNODES") &&
|
||||||
stricmp(lumpname, "BLOCKMAP") &&
|
stricmp(lumpname, "BLOCKMAP") &&
|
||||||
stricmp(lumpname, "REJECT"))
|
stricmp(lumpname, "REJECT") &&
|
||||||
|
stricmp(lumpname, "LIGHTMAP"))
|
||||||
{
|
{
|
||||||
out.CopyLump(Wad, i);
|
out.CopyLump(Wad, i);
|
||||||
}
|
}
|
||||||
|
@ -797,8 +798,7 @@ void FProcessor::WriteUDMF(FWadWriter &out)
|
||||||
|
|
||||||
if (LightmapsBuilt)
|
if (LightmapsBuilt)
|
||||||
{
|
{
|
||||||
LMBuilder.AddLightGridLump(out);
|
LMBuilder.AddLightmapLump(out);
|
||||||
LMBuilder.AddLightmapLumps(out);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out.CreateLabel("ENDMAP");
|
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 "kexlib/binfile.h"
|
||||||
#include "wad.h"
|
#include "wad.h"
|
||||||
#include "framework/templates.h"
|
#include "framework/templates.h"
|
||||||
|
#include "halffloat.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -60,7 +61,6 @@ kexLightmapBuilder::kexLightmapBuilder()
|
||||||
this->extraSamples = 2;
|
this->extraSamples = 2;
|
||||||
this->ambience = 0.0f;
|
this->ambience = 0.0f;
|
||||||
this->tracedTexels = 0;
|
this->tracedTexels = 0;
|
||||||
this->gridMap = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -86,7 +86,7 @@ void kexLightmapBuilder::NewTexture()
|
||||||
|
|
||||||
memset(allocBlocks[numTextures-1], 0, sizeof(int) * textureWidth);
|
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);
|
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)
|
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
|
// plane is not even facing the sunlight
|
||||||
return false;
|
return false;
|
||||||
|
@ -222,11 +222,14 @@ bool kexLightmapBuilder::EmitFromCeiling(kexTrace &trace, const surface_t *surfa
|
||||||
|
|
||||||
if(trace.hitSurface->bSky == false)
|
if(trace.hitSurface->bSky == false)
|
||||||
{
|
{
|
||||||
|
if (trace.hitSurface->type == ST_CEILING)
|
||||||
|
return false;
|
||||||
|
|
||||||
// not a ceiling/sky surface
|
// not a ceiling/sky surface
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
color += map->GetSunColor() * dist;
|
color += map->GetSunColor() * attenuation;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -260,12 +263,6 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori
|
||||||
{
|
{
|
||||||
thingLight_t *tl = map->thingLights[i];
|
thingLight_t *tl = map->thingLights[i];
|
||||||
|
|
||||||
// try to early out if PVS data exists
|
|
||||||
if(!map->CheckPVS(surface->subSector, tl->ssect))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
float originZ;
|
float originZ;
|
||||||
if (!tl->bCeiling)
|
if (!tl->bCeiling)
|
||||||
originZ = tl->sector->floorplane.zAt(tl->origin.x, tl->origin.y) + tl->height;
|
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++;
|
tracedTexels++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(surface->type != ST_CEILING && map->bSSectsVisibleToSky[surface->subSector - map->GLSubsectors])
|
if(surface->type != ST_CEILING)
|
||||||
{
|
{
|
||||||
// see if it's exposed to sunlight
|
// see if it's exposed to sunlight
|
||||||
if(EmitFromCeiling(trace, surface, origin, plane.Normal(), color))
|
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];
|
kexLightSurface *surfaceLight = map->lightSurfaces[i];
|
||||||
|
|
||||||
// try to early out if PVS data exists
|
|
||||||
if(!map->CheckPVS(surface->subSector, surfaceLight->Surface()->subSector))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
float attenuation;
|
float attenuation;
|
||||||
if(surfaceLight->TraceSurface(map, trace, surface, origin, &attenuation))
|
if(surfaceLight->TraceSurface(map, trace, surface, origin, &attenuation))
|
||||||
{
|
{
|
||||||
|
@ -484,7 +475,7 @@ void kexLightmapBuilder::TraceSurface(surface_t *surface)
|
||||||
int i;
|
int i;
|
||||||
int j;
|
int j;
|
||||||
kexTrace trace;
|
kexTrace trace;
|
||||||
byte *currentTexture;
|
uint16_t *currentTexture;
|
||||||
bool bShouldLookupTexture = false;
|
bool bShouldLookupTexture = false;
|
||||||
|
|
||||||
trace.Init(*map);
|
trace.Init(*map);
|
||||||
|
@ -599,9 +590,9 @@ void kexLightmapBuilder::TraceSurface(surface_t *surface)
|
||||||
int offs = (((textureWidth * (i + surface->lightmapOffs[1])) + surface->lightmapOffs[0]) * 3);
|
int offs = (((textureWidth * (i + surface->lightmapOffs[1])) + surface->lightmapOffs[0]) * 3);
|
||||||
|
|
||||||
// convert RGB to bytes
|
// convert RGB to bytes
|
||||||
currentTexture[offs + j * 3 + 0] = (uint32_t)(colorSamples[i * 1024 + j].x * 255 + 0.5f);
|
currentTexture[offs + j * 3 + 0] = floatToHalf(colorSamples[i * 1024 + j].x);
|
||||||
currentTexture[offs + j * 3 + 1] = (uint32_t)(colorSamples[i * 1024 + j].y * 255 + 0.5f);
|
currentTexture[offs + j * 3 + 1] = floatToHalf(colorSamples[i * 1024 + j].y);
|
||||||
currentTexture[offs + j * 3 + 2] = (uint32_t)(colorSamples[i * 1024 + j].z * 255 + 0.5f);
|
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)
|
void kexLightmapBuilder::CreateLightmaps(FLevel &doomMap)
|
||||||
{
|
{
|
||||||
map = &doomMap;
|
map = &doomMap;
|
||||||
|
|
||||||
printf("------------- Building light grid -------------\n");
|
|
||||||
CreateLightGrid();
|
|
||||||
|
|
||||||
printf("------------- Tracing surfaces -------------\n");
|
printf("------------- Tracing surfaces -------------\n");
|
||||||
|
|
||||||
processed = 0;
|
processed = 0;
|
||||||
|
@ -867,262 +641,119 @@ void kexLightmapBuilder::CreateLightmaps(FLevel &doomMap)
|
||||||
printf("Texels traced: %i \n\n", tracedTexels);
|
printf("Texels traced: %i \n\n", tracedTexels);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
void kexLightmapBuilder::AddLightmapLump(FWadWriter &wadFile)
|
||||||
// kexLightmapBuilder::CreateLightGrid
|
|
||||||
//
|
|
||||||
|
|
||||||
void kexLightmapBuilder::CreateLightGrid()
|
|
||||||
{
|
{
|
||||||
int count;
|
// Calculate size of lump
|
||||||
int numNodes;
|
int numTexCoords = 0;
|
||||||
kexVec3 mins, maxs;
|
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
|
// Setup buffer
|
||||||
numNodes = map->NumGLNodes-1;
|
std::vector<uint8_t> buffer(lumpSize);
|
||||||
if(numNodes < 0)
|
kexBinFile lumpFile;
|
||||||
{
|
lumpFile.SetBuffer(buffer.data());
|
||||||
numNodes = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
// Write surfaces
|
||||||
for(int i = 0; i < 3; ++i)
|
int coordOffsets = 0;
|
||||||
{
|
for (unsigned int i = 0; i < surfaces.Length(); i++)
|
||||||
mins[i] = gridSize[i] * kexMath::Floor(worldGrid.min[i] / gridSize[i]);
|
{
|
||||||
maxs[i] = gridSize[i] * kexMath::Ceil(worldGrid.max[i] / gridSize[i]);
|
if (surfaces[i]->lightmapNum == -1)
|
||||||
gridBlock[i] = (maxs[i] - mins[i]) / gridSize[i] + 1;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
worldGrid.min = mins;
|
lumpFile.Write32(surfaces[i]->type);
|
||||||
worldGrid.max = maxs;
|
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);
|
// Write texture coordinates
|
||||||
gridBound.max = (gridSize * 0.5f);
|
for (unsigned int i = 0; i < surfaces.Length(); i++)
|
||||||
|
{
|
||||||
|
if (surfaces[i]->lightmapNum == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
// get the total number of grid cells
|
int count = surfaces[i]->numVerts;
|
||||||
count = (int)(gridBlock.x * gridBlock.y * gridBlock.z);
|
if (surfaces[i]->type == ST_FLOOR)
|
||||||
numLightGrids = count;
|
{
|
||||||
|
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
|
lumpFile.WriteFloat(surfaces[i]->lightmapCoords[0]);
|
||||||
gridMap = (gridMap_t*)Mem_Calloc(sizeof(gridMap_t) * count, hb_static);
|
lumpFile.WriteFloat(surfaces[i]->lightmapCoords[1]);
|
||||||
gridSectors = (MapSubsectorEx**)Mem_Calloc(sizeof(MapSubsectorEx*) *
|
|
||||||
(int)(gridBlock.x * gridBlock.y), hb_static);
|
|
||||||
|
|
||||||
// process all grid cells
|
lumpFile.WriteFloat(surfaces[i]->lightmapCoords[4]);
|
||||||
processed = 0;
|
lumpFile.WriteFloat(surfaces[i]->lightmapCoords[5]);
|
||||||
kexWorker::RunJob(count, [=](int id) {
|
|
||||||
LightGrid(id);
|
|
||||||
});
|
|
||||||
|
|
||||||
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()
|
void kexLightmapBuilder::WriteTexturesToTGA()
|
||||||
{
|
{
|
||||||
kexBinFile file;
|
kexBinFile file;
|
||||||
|
|
|
@ -43,14 +43,11 @@ public:
|
||||||
|
|
||||||
void BuildSurfaceParams(surface_t *surface);
|
void BuildSurfaceParams(surface_t *surface);
|
||||||
void TraceSurface(surface_t *surface);
|
void TraceSurface(surface_t *surface);
|
||||||
void CreateLightGrid();
|
|
||||||
void CreateLightmaps(FLevel &doomMap);
|
void CreateLightmaps(FLevel &doomMap);
|
||||||
void LightSurface(const int surfid);
|
void LightSurface(const int surfid);
|
||||||
void LightGrid(const int gridid);
|
|
||||||
void WriteTexturesToTGA();
|
void WriteTexturesToTGA();
|
||||||
void WriteMeshToOBJ();
|
void WriteMeshToOBJ();
|
||||||
void AddLightGridLump(FWadWriter &wadFile);
|
void AddLightmapLump(FWadWriter &wadFile);
|
||||||
void AddLightmapLumps(FWadWriter &wadFile);
|
|
||||||
|
|
||||||
int samples;
|
int samples;
|
||||||
float ambience;
|
float ambience;
|
||||||
|
@ -64,30 +61,16 @@ private:
|
||||||
bool MakeRoomForBlock(const int width, const int height, int *x, int *y, int *num);
|
bool MakeRoomForBlock(const int width, const int height, int *x, int *y, int *num);
|
||||||
kexBBox GetBoundsFromSurface(const surface_t *surface);
|
kexBBox GetBoundsFromSurface(const surface_t *surface);
|
||||||
kexVec3 LightTexelSample(kexTrace &trace, const kexVec3 &origin, 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);
|
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 ExportTexelsToObjFile(FILE *f, const kexVec3 &org, int indices);
|
||||||
void WriteBlock(FILE *f, const int i, const kexVec3 &org, int indices, kexBBox &box);
|
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;
|
FLevel *map;
|
||||||
kexArray<byte*> textures;
|
kexArray<uint16_t*> textures;
|
||||||
int **allocBlocks;
|
int **allocBlocks;
|
||||||
int numTextures;
|
int numTextures;
|
||||||
int extraSamples;
|
int extraSamples;
|
||||||
int tracedTexels;
|
int tracedTexels;
|
||||||
int numLightGrids;
|
|
||||||
gridMap_t *gridMap;
|
|
||||||
MapSubsectorEx **gridSectors;
|
|
||||||
kexBBox worldGrid;
|
|
||||||
kexBBox gridBound;
|
|
||||||
kexVec3 gridBlock;
|
|
||||||
|
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
int processed = 0;
|
int processed = 0;
|
||||||
|
|
|
@ -62,9 +62,6 @@ void kexLightSurface::Init(const surfaceLightDef &lightSurfaceDef,
|
||||||
const bool bWall,
|
const bool bWall,
|
||||||
const bool bNoCenterPoint)
|
const bool bNoCenterPoint)
|
||||||
{
|
{
|
||||||
this->outerCone = lightSurfaceDef.outerCone;
|
|
||||||
this->innerCone = lightSurfaceDef.innerCone;
|
|
||||||
this->falloff = lightSurfaceDef.falloff;
|
|
||||||
this->intensity = lightSurfaceDef.intensity;
|
this->intensity = lightSurfaceDef.intensity;
|
||||||
this->distance = lightSurfaceDef.distance;
|
this->distance = lightSurfaceDef.distance;
|
||||||
this->rgb = lightSurfaceDef.rgb;
|
this->rgb = lightSurfaceDef.rgb;
|
||||||
|
@ -292,9 +289,6 @@ bool kexLightSurface::TraceSurface(FLevel *doomMap, kexTrace &trace, const surfa
|
||||||
{
|
{
|
||||||
kexVec3 normal;
|
kexVec3 normal;
|
||||||
kexVec3 lnormal;
|
kexVec3 lnormal;
|
||||||
kexVec3 center;
|
|
||||||
bool bInside;
|
|
||||||
float angle;
|
|
||||||
float curDist;
|
float curDist;
|
||||||
|
|
||||||
*dist = -M_INFINITY;
|
*dist = -M_INFINITY;
|
||||||
|
@ -306,29 +300,6 @@ bool kexLightSurface::TraceSurface(FLevel *doomMap, kexTrace &trace, const surfa
|
||||||
return true;
|
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();
|
lnormal = surface->plane.Normal();
|
||||||
|
|
||||||
if(surf)
|
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
|
// that we have to trace each one... which could really blow up the compile time
|
||||||
for(unsigned int i = 0; i < origins.Length(); ++i)
|
for(unsigned int i = 0; i < origins.Length(); ++i)
|
||||||
{
|
{
|
||||||
center = origins[i];
|
kexVec3 center = origins[i];
|
||||||
|
|
||||||
if(!bWall && origin.z > center.z)
|
if(!bWall && origin.z > center.z)
|
||||||
{
|
{
|
||||||
|
@ -360,7 +331,7 @@ bool kexLightSurface::TraceSurface(FLevel *doomMap, kexTrace &trace, const surfa
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(bWall)
|
/*if(bWall)
|
||||||
{
|
{
|
||||||
angle = (origin - center).ToVec2().Normalize().Dot(lnormal.ToVec2());
|
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);
|
angle = dir.Dot(lnormal);
|
||||||
|
}*/
|
||||||
if(angle > innerCone)
|
|
||||||
{
|
|
||||||
angle = innerCone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!bInside && angle < outerCone)
|
|
||||||
{
|
|
||||||
// out of the cone range
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(bWall)
|
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)
|
if(curDist > *dist)
|
||||||
{
|
{
|
||||||
*dist = curDist;
|
*dist = curDist;
|
||||||
|
|
|
@ -44,9 +44,6 @@ public:
|
||||||
void CreateCenterOrigin();
|
void CreateCenterOrigin();
|
||||||
bool TraceSurface(FLevel *doomMap, kexTrace &trace, const surface_t *surface, const kexVec3 &origin, float *dist);
|
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 Distance() const { return distance; }
|
||||||
const float Intensity() const { return intensity; }
|
const float Intensity() const { return intensity; }
|
||||||
const kexVec3 GetRGB() const { return rgb; }
|
const kexVec3 GetRGB() const { return rgb; }
|
||||||
|
@ -59,9 +56,6 @@ private:
|
||||||
bool SubdivideRecursion(vertexBatch_t &surfPoints, float divide, kexArray<vertexBatch_t*> &points);
|
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);
|
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 distance;
|
||||||
float intensity;
|
float intensity;
|
||||||
kexVec3 rgb;
|
kexVec3 rgb;
|
||||||
|
|
|
@ -40,119 +40,14 @@ static const kexVec3 defaultSunDirection(0.45f, 0.3f, 0.9f);
|
||||||
|
|
||||||
void FLevel::SetupDlight()
|
void FLevel::SetupDlight()
|
||||||
{
|
{
|
||||||
BuildNodeBounds();
|
|
||||||
BuildLeafs();
|
|
||||||
BuildPVS();
|
|
||||||
CheckSkySectors();
|
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()
|
void FLevel::CheckSkySectors()
|
||||||
{
|
{
|
||||||
char name[9];
|
char name[9];
|
||||||
|
|
||||||
bSkySectors = (bool*)Mem_Calloc(sizeof(bool) * Sectors.Size(), hb_static);
|
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)
|
for (int i = 0; i < (int)Sectors.Size(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -167,27 +62,6 @@ void FLevel::CheckSkySectors()
|
||||||
bSkySectors[i] = true;
|
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
|
const kexVec3 &FLevel::GetSunColor() const
|
||||||
|
@ -200,65 +74,41 @@ const kexVec3 &FLevel::GetSunDirection() const
|
||||||
return defaultSunDirection;
|
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];
|
return &Sectors[side->sector];
|
||||||
}
|
}
|
||||||
|
|
||||||
IntSector *FLevel::GetBackSector(const MapSegGLEx *seg)
|
IntSector *FLevel::GetBackSector(const IntSideDef *side)
|
||||||
{
|
{
|
||||||
if (seg->linedef == NO_LINE_INDEX)
|
IntLineDef *line = side->line;
|
||||||
{
|
if (!(line->flags & ML_TWOSIDED))
|
||||||
// skip minisegs
|
return nullptr;
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
if (sidenum == NO_SIDE_INDEX)
|
||||||
{
|
return nullptr;
|
||||||
IntSideDef *backSide = &Sides[line->sidenum[seg->side ^ 1]];
|
|
||||||
return &Sectors[backSide->sector];
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
return GetFrontSector(&Sides[sidenum]);
|
||||||
}
|
}
|
||||||
|
|
||||||
IntSector *FLevel::GetSectorFromSubSector(const MapSubsectorEx *sub)
|
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++)
|
for (int i = 0; i < (int)sub->numlines; i++)
|
||||||
{
|
{
|
||||||
MapSegGLEx *seg = &GLSegs[sub->firstline + i];
|
MapSegGLEx *seg = &GLSegs[sub->firstline + i];
|
||||||
if (seg->side != NO_SIDE_INDEX)
|
if (seg->side != NO_SIDE_INDEX)
|
||||||
{
|
{
|
||||||
sector = GetFrontSector(seg);
|
IntLineDef *line = &Lines[seg->linedef];
|
||||||
break;
|
return GetFrontSector(&Sides[line->sidenum[seg->side]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
return sector;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MapSubsectorEx *FLevel::PointInSubSector(const int x, const int y)
|
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];
|
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)
|
FloatVertex FLevel::GetSegVertex(int index)
|
||||||
{
|
{
|
||||||
if (index & 0x8000)
|
if (index & 0x8000)
|
||||||
|
@ -420,19 +163,6 @@ FloatVertex FLevel::GetSegVertex(int index)
|
||||||
return v;
|
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()
|
void FLevel::CreateLights()
|
||||||
{
|
{
|
||||||
thingLight_t *thingLight;
|
thingLight_t *thingLight;
|
||||||
|
@ -514,12 +244,9 @@ void FLevel::CreateLights()
|
||||||
{
|
{
|
||||||
surface_t *surface = surfaces[j];
|
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;
|
IntLineDef *line = Sides[surface->typeIndex].line;
|
||||||
if (GLSegs[surface->typeIndex].linedef != NO_LINE_INDEX)
|
|
||||||
line = &Lines[GLSegs[surface->typeIndex].linedef];
|
|
||||||
|
|
||||||
if (line)
|
if (line)
|
||||||
{
|
{
|
||||||
uint32_t lightcolor = 0xffffff;
|
uint32_t lightcolor = 0xffffff;
|
||||||
|
@ -547,9 +274,6 @@ void FLevel::CreateLights()
|
||||||
{
|
{
|
||||||
surfaceLightDef desc;
|
surfaceLightDef desc;
|
||||||
desc.tag = 0;
|
desc.tag = 0;
|
||||||
desc.outerCone = 0.0f;
|
|
||||||
desc.innerCone = 0.0f;
|
|
||||||
desc.falloff = 1.0f;
|
|
||||||
desc.intensity = lightintensity;
|
desc.intensity = lightintensity;
|
||||||
desc.distance = lightdistance;
|
desc.distance = lightdistance;
|
||||||
desc.bIgnoreCeiling = false;
|
desc.bIgnoreCeiling = false;
|
||||||
|
@ -569,7 +293,7 @@ void FLevel::CreateLights()
|
||||||
}
|
}
|
||||||
else if (surface->type == ST_FLOOR || surface->type == ST_CEILING)
|
else if (surface->type == ST_FLOOR || surface->type == ST_CEILING)
|
||||||
{
|
{
|
||||||
MapSubsectorEx *sub = surface->subSector;
|
MapSubsectorEx *sub = &GLSubsectors[surface->typeIndex];
|
||||||
IntSector *sector = GetSectorFromSubSector(sub);
|
IntSector *sector = GetSectorFromSubSector(sub);
|
||||||
|
|
||||||
if (sector && surface->numVerts > 0)
|
if (sector && surface->numVerts > 0)
|
||||||
|
@ -617,9 +341,6 @@ void FLevel::CreateLights()
|
||||||
{
|
{
|
||||||
surfaceLightDef desc;
|
surfaceLightDef desc;
|
||||||
desc.tag = 0;
|
desc.tag = 0;
|
||||||
desc.outerCone = 0.0f;
|
|
||||||
desc.innerCone = 0.0f;
|
|
||||||
desc.falloff = 1.0f;
|
|
||||||
desc.intensity = lightintensity;
|
desc.intensity = lightintensity;
|
||||||
desc.distance = lightdistance;
|
desc.distance = lightdistance;
|
||||||
desc.bIgnoreCeiling = false;
|
desc.bIgnoreCeiling = false;
|
||||||
|
|
|
@ -36,27 +36,26 @@
|
||||||
|
|
||||||
kexArray<surface_t*> surfaces;
|
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;
|
surface_t *surf;
|
||||||
IntSector *front;
|
IntSector *front;
|
||||||
IntSector *back;
|
IntSector *back;
|
||||||
|
|
||||||
if(seg->linedef == NO_LINE_INDEX)
|
front = doomMap.GetFrontSector(side);
|
||||||
{
|
back = doomMap.GetBackSector(side);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
side = doomMap.GetSideDef(seg);
|
|
||||||
front = doomMap.GetFrontSector(seg);
|
|
||||||
back = doomMap.GetBackSector(seg);
|
|
||||||
|
|
||||||
if (front->controlsector)
|
if (front->controlsector)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
FloatVertex v1 = doomMap.GetSegVertex(seg->v1);
|
FloatVertex v1 = doomMap.GetSegVertex(side->line->v1);
|
||||||
FloatVertex v2 = doomMap.GetSegVertex(seg->v2);
|
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 v1Top = front->ceilingplane.zAt(v1.x, v1.y);
|
||||||
float v1Bottom = front->floorplane.zAt(v1.x, v1.y);
|
float v1Bottom = front->floorplane.zAt(v1.x, v1.y);
|
||||||
float v2Top = front->ceilingplane.zAt(v2.x, v2.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.SetNormal(surf->verts[0], surf->verts[1], surf->verts[2]);
|
||||||
surf->plane.SetDistance(surf->verts[0]);
|
surf->plane.SetDistance(surf->verts[0]);
|
||||||
surf->type = ST_LOWERSEG;
|
surf->type = ST_LOWERSIDE;
|
||||||
surf->typeIndex = seg - doomMap.GLSegs;
|
surf->typeIndex = side - &doomMap.Sides[0];
|
||||||
surf->subSector = &doomMap.GLSubsectors[doomMap.segLeafLookup[seg - doomMap.GLSegs]];
|
|
||||||
|
|
||||||
doomMap.segSurfaces[1][surf->typeIndex] = surf;
|
|
||||||
surf->data = (MapSegGLEx*)seg;
|
|
||||||
|
|
||||||
surfaces.Push(surf);
|
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.SetNormal(surf->verts[0], surf->verts[1], surf->verts[2]);
|
||||||
surf->plane.SetDistance(surf->verts[0]);
|
surf->plane.SetDistance(surf->verts[0]);
|
||||||
surf->type = ST_UPPERSEG;
|
surf->type = ST_UPPERSIDE;
|
||||||
surf->typeIndex = seg - doomMap.GLSegs;
|
surf->typeIndex = side - &doomMap.Sides[0];
|
||||||
surf->bSky = bSky;
|
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);
|
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.SetNormal(surf->verts[0], surf->verts[1], surf->verts[2]);
|
||||||
surf->plane.SetDistance(surf->verts[0]);
|
surf->plane.SetDistance(surf->verts[0]);
|
||||||
surf->type = ST_MIDDLESEG;
|
surf->type = ST_MIDDLESIDE;
|
||||||
surf->typeIndex = seg - doomMap.GLSegs;
|
surf->typeIndex = side - &doomMap.Sides[0];
|
||||||
surf->subSector = &doomMap.GLSubsectors[doomMap.segLeafLookup[seg - doomMap.GLSegs]];
|
|
||||||
|
|
||||||
doomMap.segSurfaces[0][surf->typeIndex] = surf;
|
|
||||||
surf->data = (MapSegGLEx*)seg;
|
|
||||||
|
|
||||||
surfaces.Push(surf);
|
surfaces.Push(surf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Surface_AllocateFromLeaf
|
|
||||||
//
|
|
||||||
// Plane normals should almost always be known
|
|
||||||
// unless slopes are involved....
|
|
||||||
//
|
|
||||||
|
|
||||||
static void Surface_AllocateFromLeaf(FLevel &doomMap)
|
static void Surface_AllocateFromLeaf(FLevel &doomMap)
|
||||||
{
|
{
|
||||||
surface_t *surf;
|
surface_t *surf;
|
||||||
leaf_t *leaf;
|
|
||||||
IntSector *sector = NULL;
|
IntSector *sector = NULL;
|
||||||
int i;
|
int i;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
printf("------------- Building leaf surfaces -------------\n");
|
printf("------------- Building subsector 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);
|
|
||||||
|
|
||||||
for(i = 0; i < doomMap.NumGLSubsectors; i++)
|
for(i = 0; i < doomMap.NumGLSubsectors; i++)
|
||||||
{
|
{
|
||||||
printf("subsectors: %i / %i\r", i+1, doomMap.NumGLSubsectors);
|
printf("subsectors: %i / %i\r", i+1, doomMap.NumGLSubsectors);
|
||||||
|
|
||||||
if(doomMap.ssLeafCount[i] < 3)
|
MapSubsectorEx *sub = &doomMap.GLSubsectors[i];
|
||||||
|
|
||||||
|
if(sub->numlines < 3)
|
||||||
{
|
{
|
||||||
continue;
|
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
|
// I will be NOT surprised if some users tries to do something stupid with
|
||||||
// sector hacks
|
// sector hacks
|
||||||
|
@ -228,17 +206,17 @@ static void Surface_AllocateFromLeaf(FLevel &doomMap)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
surf = (surface_t*)Mem_Calloc(sizeof(surface_t), hb_static);
|
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->verts = (kexVec3*)Mem_Calloc(sizeof(kexVec3) * surf->numVerts, hb_static);
|
||||||
surf->subSector = &doomMap.GLSubsectors[i];
|
|
||||||
|
|
||||||
// floor verts
|
// floor verts
|
||||||
for(j = 0; j < surf->numVerts; j++)
|
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].x = v1.x;
|
||||||
surf->verts[j].y = leaf->vertex.y;
|
surf->verts[j].y = v1.y;
|
||||||
surf->verts[j].z = sector->floorplane.zAt(surf->verts[j].x, surf->verts[j].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->type = ST_FLOOR;
|
||||||
surf->typeIndex = i;
|
surf->typeIndex = i;
|
||||||
|
|
||||||
doomMap.leafSurfaces[0][i] = surf;
|
|
||||||
surf->data = (IntSector*)sector;
|
|
||||||
|
|
||||||
surfaces.Push(surf);
|
surfaces.Push(surf);
|
||||||
|
|
||||||
surf = (surface_t*)Mem_Calloc(sizeof(surface_t), hb_static);
|
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->verts = (kexVec3*)Mem_Calloc(sizeof(kexVec3) * surf->numVerts, hb_static);
|
||||||
surf->subSector = &doomMap.GLSubsectors[i];
|
|
||||||
|
|
||||||
if(doomMap.bSkySectors[sector-&doomMap.Sectors[0]])
|
if(doomMap.bSkySectors[sector-&doomMap.Sectors[0]])
|
||||||
{
|
{
|
||||||
|
@ -264,10 +238,11 @@ static void Surface_AllocateFromLeaf(FLevel &doomMap)
|
||||||
// ceiling verts
|
// ceiling verts
|
||||||
for(j = 0; j < surf->numVerts; j++)
|
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].x = v1.x;
|
||||||
surf->verts[j].y = leaf->vertex.y;
|
surf->verts[j].y = v1.y;
|
||||||
surf->verts[j].z = sector->ceilingplane.zAt(surf->verts[j].x, surf->verts[j].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->type = ST_CEILING;
|
||||||
surf->typeIndex = i;
|
surf->typeIndex = i;
|
||||||
|
|
||||||
doomMap.leafSurfaces[1][i] = surf;
|
|
||||||
surf->data = (IntSector*)sector;
|
|
||||||
|
|
||||||
surfaces.Push(surf);
|
surfaces.Push(surf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,20 +278,26 @@ void Surface_AllocateFromMap(FLevel &doomMap)
|
||||||
Mem_Free(surfaces[i]);
|
Mem_Free(surfaces[i]);
|
||||||
surfaces = {};
|
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++)
|
for (unsigned int i = 0; i < doomMap.Sectors.Size(); i++)
|
||||||
doomMap.Sectors[i].controlsector = false;
|
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++)
|
for (unsigned int i = 0; i < doomMap.Lines.Size(); i++)
|
||||||
{
|
{
|
||||||
const auto &line = doomMap.Lines[i];
|
IntLineDef *line = &doomMap.Lines[i];
|
||||||
if (line.special == 160) // Sector_Set3dFloor
|
|
||||||
|
// 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 sectorTag = line->args[0];
|
||||||
int type = line.args[1];
|
int type = line->args[1];
|
||||||
//int opacity = line.args[3];
|
//int opacity = line.args[3];
|
||||||
|
|
||||||
IntSector *controlsector = &doomMap.Sectors[doomMap.Sides[doomMap.Lines[i].sidenum[0]].sector];
|
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");
|
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]);
|
Surface_AllocateFromSide(doomMap, &doomMap.Sides[i]);
|
||||||
printf("segs: %i / %i\r", i+1, doomMap.NumGLSegs);
|
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);
|
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]))
|
if (!IsDegenerate(s->verts[0], s->verts[1], s->verts[2]))
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,9 +32,9 @@ struct MapSubsectorEx;
|
||||||
enum surfaceType_t
|
enum surfaceType_t
|
||||||
{
|
{
|
||||||
ST_UNKNOWN = 0,
|
ST_UNKNOWN = 0,
|
||||||
ST_MIDDLESEG,
|
ST_MIDDLESIDE,
|
||||||
ST_UPPERSEG,
|
ST_UPPERSIDE,
|
||||||
ST_LOWERSEG,
|
ST_LOWERSIDE,
|
||||||
ST_CEILING,
|
ST_CEILING,
|
||||||
ST_FLOOR
|
ST_FLOOR
|
||||||
};
|
};
|
||||||
|
@ -59,9 +59,9 @@ struct surface_t
|
||||||
float *lightmapCoords;
|
float *lightmapCoords;
|
||||||
surfaceType_t type;
|
surfaceType_t type;
|
||||||
int typeIndex;
|
int typeIndex;
|
||||||
void *data;
|
//void *data;
|
||||||
bool bSky;
|
bool bSky;
|
||||||
MapSubsectorEx *subSector;
|
//MapSubsectorEx *subSector;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern kexArray<surface_t*> surfaces;
|
extern kexArray<surface_t*> surfaces;
|
||||||
|
|
|
@ -35,36 +35,11 @@
|
||||||
#include "mapdata.h"
|
#include "mapdata.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
//
|
|
||||||
// kexTrace::kexTrace
|
|
||||||
//
|
|
||||||
|
|
||||||
kexTrace::kexTrace()
|
|
||||||
{
|
|
||||||
this->map = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// kexTrace::~kexTrace
|
|
||||||
//
|
|
||||||
|
|
||||||
kexTrace::~kexTrace()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// kexTrace::Init
|
|
||||||
//
|
|
||||||
|
|
||||||
void kexTrace::Init(FLevel &doomMap)
|
void kexTrace::Init(FLevel &doomMap)
|
||||||
{
|
{
|
||||||
map = &doomMap;
|
map = &doomMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// kexTrace::Trace
|
|
||||||
//
|
|
||||||
|
|
||||||
void kexTrace::Trace(const kexVec3 &startVec, const kexVec3 &endVec)
|
void kexTrace::Trace(const kexVec3 &startVec, const kexVec3 &endVec)
|
||||||
{
|
{
|
||||||
start = startVec;
|
start = startVec;
|
||||||
|
@ -76,223 +51,4 @@ void kexTrace::Trace(const kexVec3 &startVec, const kexVec3 &endVec)
|
||||||
hitSurface = surfaces[hit.surface];
|
hitSurface = surfaces[hit.surface];
|
||||||
else
|
else
|
||||||
hitSurface = nullptr;
|
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
|
class kexTrace
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
kexTrace();
|
|
||||||
~kexTrace();
|
|
||||||
|
|
||||||
void Init(FLevel &doomMap);
|
void Init(FLevel &doomMap);
|
||||||
void Trace(const kexVec3 &startVec, const kexVec3 &endVec);
|
void Trace(const kexVec3 &startVec, const kexVec3 &endVec);
|
||||||
|
|
||||||
|
@ -44,15 +41,5 @@ public:
|
||||||
float fraction;
|
float fraction;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FLevel *map;
|
FLevel *map = nullptr;
|
||||||
|
|
||||||
#if 0
|
|
||||||
kexVec3 dir;
|
|
||||||
kexVec3 hitNormal;
|
|
||||||
kexVec3 hitVector;
|
|
||||||
|
|
||||||
void TraceBSPNode(int num);
|
|
||||||
void TraceSubSector(int num);
|
|
||||||
void TraceSurface(surface_t *surface);
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
227
src/main.cpp
227
src/main.cpp
|
@ -763,230 +763,3 @@ const int64_t GetSeconds()
|
||||||
{
|
{
|
||||||
return time(0);
|
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