mirror of
https://github.com/ZDoom/ZDRay.git
synced 2025-01-24 16:51:08 +00:00
- split map loading code from surface mesh code
This commit is contained in:
parent
73724c111c
commit
9a84d487dc
9 changed files with 438 additions and 383 deletions
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
#include "framework/tarray.h"
|
#include "framework/tarray.h"
|
||||||
#include "math/mathlib.h"
|
#include "math/mathlib.h"
|
||||||
#include "lightmap/collision.h"
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#undef MIN
|
#undef MIN
|
||||||
#undef MAX
|
#undef MAX
|
||||||
|
@ -52,6 +51,7 @@ struct IntSideDef
|
||||||
char midtexture[8];
|
char midtexture[8];
|
||||||
|
|
||||||
int sector;
|
int sector;
|
||||||
|
int lightdef;
|
||||||
|
|
||||||
IntLineDef *line;
|
IntLineDef *line;
|
||||||
|
|
||||||
|
@ -112,8 +112,12 @@ struct IntSector
|
||||||
kexPlane ceilingplane;
|
kexPlane ceilingplane;
|
||||||
kexPlane floorplane;
|
kexPlane floorplane;
|
||||||
|
|
||||||
|
int floorlightdef;
|
||||||
|
int ceilinglightdef;
|
||||||
|
|
||||||
bool controlsector;
|
bool controlsector;
|
||||||
TArray<IntSector*> x3dfloors;
|
TArray<IntSector*> x3dfloors;
|
||||||
|
bool skySector;
|
||||||
|
|
||||||
TArray<UDMFKey> props;
|
TArray<UDMFKey> props;
|
||||||
};
|
};
|
||||||
|
@ -305,17 +309,6 @@ enum mapFlags_t
|
||||||
#define NO_SIDE_INDEX -1
|
#define NO_SIDE_INDEX -1
|
||||||
#define NO_LINE_INDEX 0xffffffff
|
#define NO_LINE_INDEX 0xffffffff
|
||||||
|
|
||||||
struct LevelTraceHit
|
|
||||||
{
|
|
||||||
kexVec3 start;
|
|
||||||
kexVec3 end;
|
|
||||||
float fraction;
|
|
||||||
|
|
||||||
surface_t *hitSurface;
|
|
||||||
int indices[3];
|
|
||||||
float b, c;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FLevel
|
struct FLevel
|
||||||
{
|
{
|
||||||
FLevel ();
|
FLevel ();
|
||||||
|
@ -359,23 +352,12 @@ struct FLevel
|
||||||
|
|
||||||
// Dlight helpers
|
// Dlight helpers
|
||||||
|
|
||||||
TArray<kexVec3> MeshVertices;
|
TArray<thingLight_t> ThingLights;
|
||||||
TArray<int> MeshUVIndex;
|
TArray<surfaceLightDef> SurfaceLights;
|
||||||
TArray<unsigned int> MeshElements;
|
|
||||||
TArray<int> MeshSurfaces;
|
|
||||||
std::unique_ptr<TriangleMeshShape> CollisionMesh;
|
|
||||||
|
|
||||||
std::vector<bool> bSkySectors;
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<thingLight_t>> thingLights;
|
|
||||||
std::vector<std::unique_ptr<kexLightSurface>> lightSurfaces;
|
|
||||||
|
|
||||||
void SetupDlight();
|
void SetupDlight();
|
||||||
void CreateLights();
|
void CreateLights();
|
||||||
|
|
||||||
LevelTraceHit Trace(const kexVec3 &startVec, const kexVec3 &endVec);
|
|
||||||
bool TraceAnyHit(const kexVec3 &startVec, const kexVec3 &endVec);
|
|
||||||
|
|
||||||
const kexVec3 &GetSunColor() const;
|
const kexVec3 &GetSunColor() const;
|
||||||
const kexVec3 &GetSunDirection() const;
|
const kexVec3 &GetSunDirection() const;
|
||||||
IntSector *GetFrontSector(const IntSideDef *side);
|
IntSector *GetFrontSector(const IntSideDef *side);
|
||||||
|
|
|
@ -622,7 +622,6 @@ void FProcessor::BuildLightmaps()
|
||||||
LMBuilder.textureHeight = LMDims;
|
LMBuilder.textureHeight = LMDims;
|
||||||
|
|
||||||
Level.SetupDlight();
|
Level.SetupDlight();
|
||||||
CreateSurfaces(Level);
|
|
||||||
Level.CreateLights();
|
Level.CreateLights();
|
||||||
|
|
||||||
LMBuilder.CreateLightmaps(Level);
|
LMBuilder.CreateLightmaps(Level);
|
||||||
|
|
|
@ -47,14 +47,47 @@ static const kexVec3 defaultSunDirection(0.45f, 0.3f, 0.9f);
|
||||||
void FLevel::SetupDlight()
|
void FLevel::SetupDlight()
|
||||||
{
|
{
|
||||||
CheckSkySectors();
|
CheckSkySectors();
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < Sectors.Size(); i++)
|
||||||
|
Sectors[i].controlsector = false;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < Sides.Size(); i++)
|
||||||
|
Sides[i].line = nullptr;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < Lines.Size(); i++)
|
||||||
|
{
|
||||||
|
IntLineDef *line = &Lines[i];
|
||||||
|
|
||||||
|
// Link sides to lines
|
||||||
|
if (line->sidenum[0] < Sides.Size())
|
||||||
|
Sides[line->sidenum[0]].line = line;
|
||||||
|
if (line->sidenum[1] < Sides.Size())
|
||||||
|
Sides[line->sidenum[1]].line = line;
|
||||||
|
|
||||||
|
if (line->special == 160) // Sector_Set3dFloor
|
||||||
|
{
|
||||||
|
int sectorTag = line->args[0];
|
||||||
|
int type = line->args[1];
|
||||||
|
//int opacity = line.args[3];
|
||||||
|
|
||||||
|
IntSector *controlsector = &Sectors[Sides[Lines[i].sidenum[0]].sector];
|
||||||
|
controlsector->controlsector = true;
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < Sectors.Size(); j++)
|
||||||
|
{
|
||||||
|
if (Sectors[j].data.tag == sectorTag)
|
||||||
|
{
|
||||||
|
Sectors[j].x3dfloors.Push(controlsector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FLevel::CheckSkySectors()
|
void FLevel::CheckSkySectors()
|
||||||
{
|
{
|
||||||
char name[9];
|
char name[9];
|
||||||
|
|
||||||
bSkySectors = std::vector<bool>(Sectors.Size()); // Most retarded way to resize ever, but Microsoft apparently broke std::vector<bool> in the latest update..
|
|
||||||
|
|
||||||
for (int i = 0; i < (int)Sectors.Size(); ++i)
|
for (int i = 0; i < (int)Sectors.Size(); ++i)
|
||||||
{
|
{
|
||||||
//if (mapDef && mapDef->sunIgnoreTag != 0 && Sectors[i].data.tag == mapDef->sunIgnoreTag)
|
//if (mapDef && mapDef->sunIgnoreTag != 0 && Sectors[i].data.tag == mapDef->sunIgnoreTag)
|
||||||
|
@ -65,7 +98,11 @@ void FLevel::CheckSkySectors()
|
||||||
|
|
||||||
if (!strncmp(name, "F_SKY001", 8) || !strncmp(name, "F_SKY1", 8) || !strncmp(name, "F_SKY", 8))
|
if (!strncmp(name, "F_SKY001", 8) || !strncmp(name, "F_SKY1", 8) || !strncmp(name, "F_SKY", 8))
|
||||||
{
|
{
|
||||||
bSkySectors[i] = true;
|
Sectors[i].skySector = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Sectors[i].skySector = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,175 +249,141 @@ void FLevel::CreateLights()
|
||||||
int x = thing->x >> FRACBITS;
|
int x = thing->x >> FRACBITS;
|
||||||
int y = thing->y >> FRACBITS;
|
int y = thing->y >> FRACBITS;
|
||||||
|
|
||||||
auto thingLight = std::make_unique<thingLight_t>();
|
thingLight_t thingLight;
|
||||||
|
thingLight.mapThing = thing;
|
||||||
|
thingLight.rgb.x = ((lightcolor >> 16) & 0xff) / 255.0f;
|
||||||
|
thingLight.rgb.y = ((lightcolor >> 8) & 0xff) / 255.0f;
|
||||||
|
thingLight.rgb.z = (lightcolor & 0xff) / 255.0f;
|
||||||
|
thingLight.intensity = lightintensity;
|
||||||
|
thingLight.innerAngleCos = std::max(innerAngleCos, outerAngleCos);
|
||||||
|
thingLight.outerAngleCos = outerAngleCos;
|
||||||
|
thingLight.radius = lightdistance;
|
||||||
|
thingLight.height = thing->height;
|
||||||
|
thingLight.bCeiling = false;
|
||||||
|
thingLight.ssect = PointInSubSector(x, y);
|
||||||
|
thingLight.sector = GetSectorFromSubSector(thingLight.ssect);
|
||||||
|
thingLight.origin.Set(x, y);
|
||||||
|
|
||||||
thingLight->mapThing = thing;
|
ThingLights.Push(thingLight);
|
||||||
thingLight->rgb.x = ((lightcolor >> 16) & 0xff) / 255.0f;
|
|
||||||
thingLight->rgb.y = ((lightcolor >> 8) & 0xff) / 255.0f;
|
|
||||||
thingLight->rgb.z = (lightcolor & 0xff) / 255.0f;
|
|
||||||
thingLight->intensity = lightintensity;
|
|
||||||
thingLight->innerAngleCos = std::max(innerAngleCos, outerAngleCos);
|
|
||||||
thingLight->outerAngleCos = outerAngleCos;
|
|
||||||
thingLight->radius = lightdistance;
|
|
||||||
thingLight->height = thing->height;
|
|
||||||
thingLight->bCeiling = false;
|
|
||||||
thingLight->ssect = PointInSubSector(x, y);
|
|
||||||
thingLight->sector = GetSectorFromSubSector(thingLight->ssect);
|
|
||||||
|
|
||||||
thingLight->origin.Set(x, y);
|
|
||||||
thingLights.push_back(std::move(thingLight));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Thing lights: %i\n", (int)thingLights.size());
|
printf("Thing lights: %i\n", (int)ThingLights.Size());
|
||||||
|
|
||||||
// add surface lights
|
// add surface lights
|
||||||
int numSurfLights = 0;
|
for (unsigned int i = 0; i < Sides.Size(); i++)
|
||||||
for (size_t j = 0; j < surfaces.size(); ++j)
|
|
||||||
{
|
{
|
||||||
surface_t *surface = surfaces[j].get();
|
IntSideDef *side = &Sides[i];
|
||||||
|
side->lightdef = -1;
|
||||||
|
|
||||||
if (surface->type >= ST_MIDDLESIDE && surface->type <= ST_LOWERSIDE)
|
IntLineDef *line = side->line;
|
||||||
|
if (line)
|
||||||
{
|
{
|
||||||
IntLineDef *line = Sides[surface->typeIndex].line;
|
uint32_t lightcolor = 0xffffff;
|
||||||
if (line)
|
float lightintensity = 1.0f;
|
||||||
|
float lightdistance = 0.0f;
|
||||||
|
|
||||||
|
for (unsigned int propIndex = 0; propIndex < line->props.Size(); propIndex++)
|
||||||
{
|
{
|
||||||
uint32_t lightcolor = 0xffffff;
|
const UDMFKey &key = line->props[propIndex];
|
||||||
float lightintensity = 1.0f;
|
if (!stricmp(key.key, "lightcolor"))
|
||||||
float lightdistance = 0.0f;
|
|
||||||
|
|
||||||
for (unsigned int propIndex = 0; propIndex < line->props.Size(); propIndex++)
|
|
||||||
{
|
{
|
||||||
const UDMFKey &key = line->props[propIndex];
|
lightcolor = atoi(key.value);
|
||||||
if (!stricmp(key.key, "lightcolor"))
|
|
||||||
{
|
|
||||||
lightcolor = atoi(key.value);
|
|
||||||
}
|
|
||||||
else if (!stricmp(key.key, "lightintensity"))
|
|
||||||
{
|
|
||||||
lightintensity = atof(key.value);
|
|
||||||
}
|
|
||||||
else if (!stricmp(key.key, "lightdistance"))
|
|
||||||
{
|
|
||||||
lightdistance = atof(key.value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if (!stricmp(key.key, "lightintensity"))
|
||||||
if (lightdistance > 0.0f && lightintensity > 0.0f && lightcolor != 0)
|
|
||||||
{
|
{
|
||||||
surfaceLightDef desc;
|
lightintensity = atof(key.value);
|
||||||
desc.intensity = lightintensity;
|
}
|
||||||
desc.distance = lightdistance;
|
else if (!stricmp(key.key, "lightdistance"))
|
||||||
desc.rgb.x = ((lightcolor >> 16) & 0xff) / 255.0f;
|
{
|
||||||
desc.rgb.y = ((lightcolor >> 8) & 0xff) / 255.0f;
|
lightdistance = atof(key.value);
|
||||||
desc.rgb.z = (lightcolor & 0xff) / 255.0f;
|
|
||||||
|
|
||||||
auto lightSurface = std::make_unique<kexLightSurface>(desc, surface);
|
|
||||||
lightSurface->Subdivide(16);
|
|
||||||
//lightSurface->CreateCenterOrigin();
|
|
||||||
lightSurfaces.push_back(std::move(lightSurface));
|
|
||||||
numSurfLights++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (surface->type == ST_FLOOR || surface->type == ST_CEILING)
|
|
||||||
{
|
|
||||||
MapSubsectorEx *sub = &GLSubsectors[surface->typeIndex];
|
|
||||||
IntSector *sector = GetSectorFromSubSector(sub);
|
|
||||||
|
|
||||||
if (sector && surface->numVerts > 0)
|
if (lightdistance > 0.0f && lightintensity > 0.0f && lightcolor != 0)
|
||||||
{
|
{
|
||||||
uint32_t lightcolor = 0xffffff;
|
surfaceLightDef desc;
|
||||||
float lightintensity = 1.0f;
|
desc.intensity = lightintensity;
|
||||||
float lightdistance = 0.0f;
|
desc.distance = lightdistance;
|
||||||
|
desc.rgb.x = ((lightcolor >> 16) & 0xff) / 255.0f;
|
||||||
for (unsigned int propIndex = 0; propIndex < sector->props.Size(); propIndex++)
|
desc.rgb.y = ((lightcolor >> 8) & 0xff) / 255.0f;
|
||||||
{
|
desc.rgb.z = (lightcolor & 0xff) / 255.0f;
|
||||||
const UDMFKey &key = sector->props[propIndex];
|
side->lightdef = SurfaceLights.Push(desc);
|
||||||
if (surface->type == ST_FLOOR)
|
|
||||||
{
|
|
||||||
if (!stricmp(key.key, "lightcolorfloor"))
|
|
||||||
{
|
|
||||||
lightcolor = atoi(key.value);
|
|
||||||
}
|
|
||||||
else if (!stricmp(key.key, "lightintensityfloor"))
|
|
||||||
{
|
|
||||||
lightintensity = atof(key.value);
|
|
||||||
}
|
|
||||||
else if (!stricmp(key.key, "lightdistancefloor"))
|
|
||||||
{
|
|
||||||
lightdistance = atof(key.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!stricmp(key.key, "lightcolorceiling"))
|
|
||||||
{
|
|
||||||
lightcolor = atoi(key.value);
|
|
||||||
}
|
|
||||||
else if (!stricmp(key.key, "lightintensityceiling"))
|
|
||||||
{
|
|
||||||
lightintensity = atof(key.value);
|
|
||||||
}
|
|
||||||
else if (!stricmp(key.key, "lightdistanceceiling"))
|
|
||||||
{
|
|
||||||
lightdistance = atof(key.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lightdistance > 0.0f && lightintensity > 0.0f && lightcolor != 0)
|
|
||||||
{
|
|
||||||
surfaceLightDef desc;
|
|
||||||
desc.intensity = lightintensity;
|
|
||||||
desc.distance = lightdistance;
|
|
||||||
desc.rgb.x = ((lightcolor >> 16) & 0xff) / 255.0f;
|
|
||||||
desc.rgb.y = ((lightcolor >> 8) & 0xff) / 255.0f;
|
|
||||||
desc.rgb.z = (lightcolor & 0xff) / 255.0f;
|
|
||||||
|
|
||||||
auto lightSurface = std::make_unique<kexLightSurface>(desc, surface);
|
|
||||||
lightSurface->Subdivide(16);
|
|
||||||
lightSurfaces.push_back(std::move(lightSurface));
|
|
||||||
numSurfLights++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Surface lights: %i\n", numSurfLights);
|
for (unsigned int i = 0; i < Sectors.Size(); i++)
|
||||||
}
|
|
||||||
|
|
||||||
LevelTraceHit FLevel::Trace(const kexVec3 &startVec, const kexVec3 &endVec)
|
|
||||||
{
|
|
||||||
TraceHit hit = TriangleMeshShape::find_first_hit(CollisionMesh.get(), startVec, endVec);
|
|
||||||
|
|
||||||
LevelTraceHit trace;
|
|
||||||
trace.start = startVec;
|
|
||||||
trace.end = endVec;
|
|
||||||
trace.fraction = hit.fraction;
|
|
||||||
if (trace.fraction < 1.0f)
|
|
||||||
{
|
{
|
||||||
int elementIdx = hit.triangle * 3;
|
IntSector *sector = &Sectors[i];
|
||||||
trace.hitSurface = surfaces[MeshSurfaces[hit.triangle]].get();
|
|
||||||
trace.indices[0] = MeshUVIndex[MeshElements[elementIdx]];
|
|
||||||
trace.indices[1] = MeshUVIndex[MeshElements[elementIdx + 1]];
|
|
||||||
trace.indices[2] = MeshUVIndex[MeshElements[elementIdx + 2]];
|
|
||||||
trace.b = hit.b;
|
|
||||||
trace.c = hit.c;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
trace.hitSurface = nullptr;
|
|
||||||
trace.indices[0] = 0;
|
|
||||||
trace.indices[1] = 0;
|
|
||||||
trace.indices[2] = 0;
|
|
||||||
trace.b = 0.0f;
|
|
||||||
trace.c = 0.0f;
|
|
||||||
}
|
|
||||||
return trace;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FLevel::TraceAnyHit(const kexVec3 &startVec, const kexVec3 &endVec)
|
sector->floorlightdef = -1;
|
||||||
{
|
sector->ceilinglightdef = -1;
|
||||||
return TriangleMeshShape::find_any_hit(CollisionMesh.get(), startVec, endVec);
|
|
||||||
|
uint32_t lightcolor = 0xffffff;
|
||||||
|
float lightintensity = 1.0f;
|
||||||
|
float lightdistance = 0.0f;
|
||||||
|
|
||||||
|
for (unsigned int propIndex = 0; propIndex < sector->props.Size(); propIndex++)
|
||||||
|
{
|
||||||
|
const UDMFKey &key = sector->props[propIndex];
|
||||||
|
if (!stricmp(key.key, "lightcolorfloor"))
|
||||||
|
{
|
||||||
|
lightcolor = atoi(key.value);
|
||||||
|
}
|
||||||
|
else if (!stricmp(key.key, "lightintensityfloor"))
|
||||||
|
{
|
||||||
|
lightintensity = atof(key.value);
|
||||||
|
}
|
||||||
|
else if (!stricmp(key.key, "lightdistancefloor"))
|
||||||
|
{
|
||||||
|
lightdistance = atof(key.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lightdistance > 0.0f && lightintensity > 0.0f && lightcolor != 0)
|
||||||
|
{
|
||||||
|
surfaceLightDef desc;
|
||||||
|
desc.intensity = lightintensity;
|
||||||
|
desc.distance = lightdistance;
|
||||||
|
desc.rgb.x = ((lightcolor >> 16) & 0xff) / 255.0f;
|
||||||
|
desc.rgb.y = ((lightcolor >> 8) & 0xff) / 255.0f;
|
||||||
|
desc.rgb.z = (lightcolor & 0xff) / 255.0f;
|
||||||
|
sector->floorlightdef = SurfaceLights.Push(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
lightcolor = 0xffffff;
|
||||||
|
lightintensity = 1.0f;
|
||||||
|
lightdistance = 0.0f;
|
||||||
|
|
||||||
|
for (unsigned int propIndex = 0; propIndex < sector->props.Size(); propIndex++)
|
||||||
|
{
|
||||||
|
const UDMFKey &key = sector->props[propIndex];
|
||||||
|
if (!stricmp(key.key, "lightcolorceiling"))
|
||||||
|
{
|
||||||
|
lightcolor = atoi(key.value);
|
||||||
|
}
|
||||||
|
else if (!stricmp(key.key, "lightintensityceiling"))
|
||||||
|
{
|
||||||
|
lightintensity = atof(key.value);
|
||||||
|
}
|
||||||
|
else if (!stricmp(key.key, "lightdistanceceiling"))
|
||||||
|
{
|
||||||
|
lightdistance = atof(key.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lightdistance > 0.0f && lightintensity > 0.0f && lightcolor != 0)
|
||||||
|
{
|
||||||
|
surfaceLightDef desc;
|
||||||
|
desc.intensity = lightintensity;
|
||||||
|
desc.distance = lightdistance;
|
||||||
|
desc.rgb.x = ((lightcolor >> 16) & 0xff) / 255.0f;
|
||||||
|
desc.rgb.y = ((lightcolor >> 8) & 0xff) / 255.0f;
|
||||||
|
desc.rgb.z = (lightcolor & 0xff) / 255.0f;
|
||||||
|
sector->ceilinglightdef = SurfaceLights.Push(desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Surface lights: %i\n", (int)SurfaceLights.Size());
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,7 +171,7 @@ bool kexLightmapBuilder::EmitFromCeiling(const surface_t *surface, const kexVec3
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LevelTraceHit trace = map->Trace(origin, origin + (map->GetSunDirection() * 32768.0f));
|
LevelTraceHit trace = mesh->Trace(origin, origin + (map->GetSunDirection() * 32768.0f));
|
||||||
|
|
||||||
if (trace.fraction == 1.0f)
|
if (trace.fraction == 1.0f)
|
||||||
{
|
{
|
||||||
|
@ -216,9 +216,9 @@ kexVec3 kexLightmapBuilder::LightTexelSample(const kexVec3 &origin, surface_t *s
|
||||||
kexVec3 color(0.0f, 0.0f, 0.0f);
|
kexVec3 color(0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
// check all thing lights
|
// check all thing lights
|
||||||
for (size_t i = 0; i < map->thingLights.size(); i++)
|
for (unsigned int i = 0; i < map->ThingLights.Size(); i++)
|
||||||
{
|
{
|
||||||
thingLight_t *tl = map->thingLights[i].get();
|
thingLight_t *tl = &map->ThingLights[i];
|
||||||
|
|
||||||
float originZ;
|
float originZ;
|
||||||
if (!tl->bCeiling)
|
if (!tl->bCeiling)
|
||||||
|
@ -265,7 +265,7 @@ kexVec3 kexLightmapBuilder::LightTexelSample(const kexVec3 &origin, surface_t *s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (map->TraceAnyHit(lightOrigin, origin))
|
if (mesh->TraceAnyHit(lightOrigin, origin))
|
||||||
{
|
{
|
||||||
// this light is occluded by something
|
// this light is occluded by something
|
||||||
continue;
|
continue;
|
||||||
|
@ -291,11 +291,11 @@ kexVec3 kexLightmapBuilder::LightTexelSample(const kexVec3 &origin, surface_t *s
|
||||||
}
|
}
|
||||||
|
|
||||||
// trace against surface lights
|
// trace against surface lights
|
||||||
for (size_t i = 0; i < map->lightSurfaces.size(); ++i)
|
for (size_t i = 0; i < lightSurfaces.size(); ++i)
|
||||||
{
|
{
|
||||||
kexLightSurface *surfaceLight = map->lightSurfaces[i].get();
|
kexLightSurface *surfaceLight = lightSurfaces[i].get();
|
||||||
|
|
||||||
float attenuation = surfaceLight->TraceSurface(map, surface, origin);
|
float attenuation = surfaceLight->TraceSurface(mesh.get(), surface, origin);
|
||||||
if (attenuation > 0.0f)
|
if (attenuation > 0.0f)
|
||||||
{
|
{
|
||||||
color += surfaceLight->GetRGB() * surfaceLight->Intensity() * attenuation;
|
color += surfaceLight->GetRGB() * surfaceLight->Intensity() * attenuation;
|
||||||
|
@ -601,7 +601,7 @@ void kexLightmapBuilder::TraceIndirectLight(surface_t *surface)
|
||||||
if (NdotL > 0.0f)
|
if (NdotL > 0.0f)
|
||||||
{
|
{
|
||||||
tracedTexels++;
|
tracedTexels++;
|
||||||
LevelTraceHit hit = map->Trace(pos, pos + L * 1000.0f);
|
LevelTraceHit hit = mesh->Trace(pos, pos + L * 1000.0f);
|
||||||
if (hit.fraction < 1.0f)
|
if (hit.fraction < 1.0f)
|
||||||
{
|
{
|
||||||
kexVec3 surfaceLight;
|
kexVec3 surfaceLight;
|
||||||
|
@ -653,12 +653,12 @@ void kexLightmapBuilder::TraceIndirectLight(surface_t *surface)
|
||||||
|
|
||||||
void kexLightmapBuilder::LightSurface(const int surfid)
|
void kexLightmapBuilder::LightSurface(const int surfid)
|
||||||
{
|
{
|
||||||
BuildSurfaceParams(surfaces[surfid].get());
|
BuildSurfaceParams(mesh->surfaces[surfid].get());
|
||||||
TraceSurface(surfaces[surfid].get());
|
TraceSurface(mesh->surfaces[surfid].get());
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
|
|
||||||
int numsurfs = surfaces.size();
|
int numsurfs = mesh->surfaces.size();
|
||||||
int lastproc = processed * 100 / numsurfs;
|
int lastproc = processed * 100 / numsurfs;
|
||||||
processed++;
|
processed++;
|
||||||
int curproc = processed * 100 / numsurfs;
|
int curproc = processed * 100 / numsurfs;
|
||||||
|
@ -671,9 +671,9 @@ void kexLightmapBuilder::LightSurface(const int surfid)
|
||||||
|
|
||||||
void kexLightmapBuilder::LightIndirect(const int surfid)
|
void kexLightmapBuilder::LightIndirect(const int surfid)
|
||||||
{
|
{
|
||||||
TraceIndirectLight(surfaces[surfid].get());
|
TraceIndirectLight(mesh->surfaces[surfid].get());
|
||||||
|
|
||||||
int numsurfs = surfaces.size();
|
int numsurfs = mesh->surfaces.size();
|
||||||
int lastproc = processed * 100 / numsurfs;
|
int lastproc = processed * 100 / numsurfs;
|
||||||
processed++;
|
processed++;
|
||||||
int curproc = processed * 100 / numsurfs;
|
int curproc = processed * 100 / numsurfs;
|
||||||
|
@ -684,9 +684,52 @@ void kexLightmapBuilder::LightIndirect(const int surfid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void kexLightmapBuilder::CreateLightSurfaces()
|
||||||
|
{
|
||||||
|
for (size_t j = 0; j < mesh->surfaces.size(); ++j)
|
||||||
|
{
|
||||||
|
surface_t *surface = mesh->surfaces[j].get();
|
||||||
|
|
||||||
|
if (surface->type >= ST_MIDDLESIDE && surface->type <= ST_LOWERSIDE)
|
||||||
|
{
|
||||||
|
int lightdefidx = map->Sides[surface->typeIndex].lightdef;
|
||||||
|
if (lightdefidx != -1)
|
||||||
|
{
|
||||||
|
auto lightSurface = std::make_unique<kexLightSurface>(map->SurfaceLights[lightdefidx], surface);
|
||||||
|
lightSurface->Subdivide(16);
|
||||||
|
lightSurfaces.push_back(std::move(lightSurface));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (surface->type == ST_FLOOR || surface->type == ST_CEILING)
|
||||||
|
{
|
||||||
|
MapSubsectorEx *sub = &map->GLSubsectors[surface->typeIndex];
|
||||||
|
IntSector *sector = map->GetSectorFromSubSector(sub);
|
||||||
|
|
||||||
|
if (sector && surface->numVerts > 0)
|
||||||
|
{
|
||||||
|
if (sector->floorlightdef != -1 && surface->type == ST_FLOOR)
|
||||||
|
{
|
||||||
|
auto lightSurface = std::make_unique<kexLightSurface>(map->SurfaceLights[sector->floorlightdef], surface);
|
||||||
|
lightSurface->Subdivide(16);
|
||||||
|
lightSurfaces.push_back(std::move(lightSurface));
|
||||||
|
}
|
||||||
|
else if (sector->ceilinglightdef != -1 && surface->type == ST_CEILING)
|
||||||
|
{
|
||||||
|
auto lightSurface = std::make_unique<kexLightSurface>(map->SurfaceLights[sector->ceilinglightdef], surface);
|
||||||
|
lightSurface->Subdivide(16);
|
||||||
|
lightSurfaces.push_back(std::move(lightSurface));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void kexLightmapBuilder::CreateLightmaps(FLevel &doomMap)
|
void kexLightmapBuilder::CreateLightmaps(FLevel &doomMap)
|
||||||
{
|
{
|
||||||
map = &doomMap;
|
map = &doomMap;
|
||||||
|
mesh = std::make_unique<LevelMesh>(doomMap);
|
||||||
|
|
||||||
|
CreateLightSurfaces();
|
||||||
|
|
||||||
printf("-------------- Tracing cells ---------------\n");
|
printf("-------------- Tracing cells ---------------\n");
|
||||||
|
|
||||||
|
@ -704,7 +747,7 @@ void kexLightmapBuilder::CreateLightmaps(FLevel &doomMap)
|
||||||
|
|
||||||
tracedTexels = 0;
|
tracedTexels = 0;
|
||||||
processed = 0;
|
processed = 0;
|
||||||
kexWorker::RunJob(surfaces.size(), [=](int id) {
|
kexWorker::RunJob(mesh->surfaces.size(), [=](int id) {
|
||||||
LightSurface(id);
|
LightSurface(id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -716,7 +759,7 @@ void kexLightmapBuilder::CreateLightmaps(FLevel &doomMap)
|
||||||
|
|
||||||
tracedTexels = 0;
|
tracedTexels = 0;
|
||||||
processed = 0;
|
processed = 0;
|
||||||
kexWorker::RunJob(surfaces.size(), [=](int id) {
|
kexWorker::RunJob(mesh->surfaces.size(), [=](int id) {
|
||||||
LightIndirect(id);
|
LightIndirect(id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -736,7 +779,7 @@ void kexLightmapBuilder::CreateLightmaps(FLevel &doomMap)
|
||||||
|
|
||||||
void kexLightmapBuilder::SetupLightCellGrid()
|
void kexLightmapBuilder::SetupLightCellGrid()
|
||||||
{
|
{
|
||||||
kexBBox worldBBox = map->CollisionMesh->get_bbox();
|
kexBBox worldBBox = mesh->CollisionMesh->get_bbox();
|
||||||
float blockWorldSize = LIGHTCELL_BLOCK_SIZE * LIGHTCELL_SIZE;
|
float blockWorldSize = LIGHTCELL_BLOCK_SIZE * LIGHTCELL_SIZE;
|
||||||
grid.x = static_cast<int>(std::floor(worldBBox.min.x / blockWorldSize));
|
grid.x = static_cast<int>(std::floor(worldBBox.min.x / blockWorldSize));
|
||||||
grid.y = static_cast<int>(std::floor(worldBBox.min.y / blockWorldSize));
|
grid.y = static_cast<int>(std::floor(worldBBox.min.y / blockWorldSize));
|
||||||
|
@ -845,15 +888,16 @@ void kexLightmapBuilder::LightBlock(int id)
|
||||||
float remaining = (float)processed / (float)numblocks;
|
float remaining = (float)processed / (float)numblocks;
|
||||||
printf("%i%c cells done\r", (int)(remaining * 100.0f), '%');
|
printf("%i%c cells done\r", (int)(remaining * 100.0f), '%');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void kexLightmapBuilder::AddLightmapLump(FWadWriter &wadFile)
|
void kexLightmapBuilder::AddLightmapLump(FWadWriter &wadFile)
|
||||||
{
|
{
|
||||||
|
const auto &surfaces = mesh->surfaces;
|
||||||
|
|
||||||
// Calculate size of lump
|
// Calculate size of lump
|
||||||
int numTexCoords = 0;
|
int numTexCoords = 0;
|
||||||
int numSurfaces = 0;
|
int numSurfaces = 0;
|
||||||
for (size_t i = 0; i < surfaces.size(); i++)
|
for (size_t i = 0; i < mesh->surfaces.size(); i++)
|
||||||
{
|
{
|
||||||
if (surfaces[i]->lightmapNum != -1)
|
if (surfaces[i]->lightmapNum != -1)
|
||||||
{
|
{
|
||||||
|
@ -1018,78 +1062,3 @@ void kexLightmapBuilder::WriteTexturesToTGA()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void kexLightmapBuilder::WriteMeshToOBJ()
|
|
||||||
{
|
|
||||||
FILE *f = fopen("mesh.obj", "w");
|
|
||||||
|
|
||||||
std::map<int, std::vector<surface_t*>> sortedSurfs;
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < surfaces.size(); i++)
|
|
||||||
sortedSurfs[surfaces[i]->lightmapNum].push_back(surfaces[i].get());
|
|
||||||
|
|
||||||
for (const auto &it : sortedSurfs)
|
|
||||||
{
|
|
||||||
for (const auto &s : it.second)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < s->numVerts; j++)
|
|
||||||
{
|
|
||||||
fprintf(f, "v %f %f %f\n", s->verts[j].x, s->verts[j].z + 100.0f, s->verts[j].y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &it : sortedSurfs)
|
|
||||||
{
|
|
||||||
for (const auto &s : it.second)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < s->numVerts; j++)
|
|
||||||
{
|
|
||||||
fprintf(f, "vt %f %f\n", s->lightmapCoords[j * 2], s->lightmapCoords[j * 2 + 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int voffset = 1;
|
|
||||||
for (const auto &it : sortedSurfs)
|
|
||||||
{
|
|
||||||
int lightmapNum = it.first;
|
|
||||||
|
|
||||||
if (lightmapNum != -1)
|
|
||||||
fprintf(f, "usemtl lightmap_%02d\n", lightmapNum);
|
|
||||||
else
|
|
||||||
fprintf(f, "usemtl black\n");
|
|
||||||
|
|
||||||
for (const auto &s : it.second)
|
|
||||||
{
|
|
||||||
switch (s->type)
|
|
||||||
{
|
|
||||||
case ST_FLOOR:
|
|
||||||
for (int j = 2; j < s->numVerts; j++)
|
|
||||||
{
|
|
||||||
fprintf(f, "f %d/%d %d/%d %d/%d\n", voffset + j, voffset + j, voffset + j - 1, voffset + j - 1, voffset, voffset);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ST_CEILING:
|
|
||||||
for (int j = 2; j < s->numVerts; j++)
|
|
||||||
{
|
|
||||||
fprintf(f, "f %d/%d %d/%d %d/%d\n", voffset, voffset, voffset + j - 1, voffset + j - 1, voffset + j, voffset + j);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
for (int j = 2; j < s->numVerts; j++)
|
|
||||||
{
|
|
||||||
if (j % 2 == 0)
|
|
||||||
fprintf(f, "f %d/%d %d/%d %d/%d\n", voffset + j - 2, voffset + j - 2, voffset + j - 1, voffset + j - 1, voffset + j, voffset + j);
|
|
||||||
else
|
|
||||||
fprintf(f, "f %d/%d %d/%d %d/%d\n", voffset + j, voffset + j, voffset + j - 1, voffset + j - 1, voffset + j - 2, voffset + j - 2);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
voffset += s->numVerts;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#define LIGHTCELL_BLOCK_SIZE 16
|
#define LIGHTCELL_BLOCK_SIZE 16
|
||||||
|
|
||||||
class FWadWriter;
|
class FWadWriter;
|
||||||
|
class kexLightSurface;
|
||||||
|
|
||||||
class LightCellBlock
|
class LightCellBlock
|
||||||
{
|
{
|
||||||
|
@ -62,7 +63,6 @@ public:
|
||||||
|
|
||||||
void CreateLightmaps(FLevel &doomMap);
|
void CreateLightmaps(FLevel &doomMap);
|
||||||
//void WriteTexturesToTGA();
|
//void WriteTexturesToTGA();
|
||||||
void WriteMeshToOBJ();
|
|
||||||
void AddLightmapLump(FWadWriter &wadFile);
|
void AddLightmapLump(FWadWriter &wadFile);
|
||||||
|
|
||||||
int samples = 16;
|
int samples = 16;
|
||||||
|
@ -85,7 +85,11 @@ private:
|
||||||
void LightSurface(const int surfid);
|
void LightSurface(const int surfid);
|
||||||
void LightIndirect(const int surfid);
|
void LightIndirect(const int surfid);
|
||||||
|
|
||||||
|
void CreateLightSurfaces();
|
||||||
|
|
||||||
|
std::unique_ptr<LevelMesh> mesh;
|
||||||
FLevel *map;
|
FLevel *map;
|
||||||
|
std::vector<std::unique_ptr<kexLightSurface>> lightSurfaces;
|
||||||
std::vector<std::vector<uint16_t>> textures;
|
std::vector<std::vector<uint16_t>> textures;
|
||||||
std::vector<uint16_t> indirectoutput;
|
std::vector<uint16_t> indirectoutput;
|
||||||
std::vector<std::vector<int>> allocBlocks;
|
std::vector<std::vector<int>> allocBlocks;
|
||||||
|
|
|
@ -241,7 +241,7 @@ void kexLightSurface::Subdivide(const float divide)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float kexLightSurface::TraceSurface(FLevel *map, const surface_t *fragmentSurface, const kexVec3 &fragmentPos)
|
float kexLightSurface::TraceSurface(LevelMesh *mesh, const surface_t *fragmentSurface, const kexVec3 &fragmentPos)
|
||||||
{
|
{
|
||||||
if (fragmentSurface == surface)
|
if (fragmentSurface == surface)
|
||||||
return 1.0f; // light surface will always be fullbright
|
return 1.0f; // light surface will always be fullbright
|
||||||
|
@ -286,7 +286,7 @@ float kexLightSurface::TraceSurface(FLevel *map, const surface_t *fragmentSurfac
|
||||||
|
|
||||||
// trace the origin to the center of the light surface. nudge by the normals in
|
// trace the origin to the center of the light surface. nudge by the normals in
|
||||||
// case the start/end points are directly on or inside the surface
|
// case the start/end points are directly on or inside the surface
|
||||||
if (map->TraceAnyHit(lightPos + lightSurfaceNormal, fragmentPos + fragmentNormal))
|
if (mesh->TraceAnyHit(lightPos + lightSurfaceNormal, fragmentPos + fragmentNormal))
|
||||||
continue; // something is obstructing it
|
continue; // something is obstructing it
|
||||||
|
|
||||||
if (d < closestDistance)
|
if (d < closestDistance)
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
~kexLightSurface();
|
~kexLightSurface();
|
||||||
|
|
||||||
void Subdivide(const float divide);
|
void Subdivide(const float divide);
|
||||||
float TraceSurface(FLevel *doomMap, const surface_t *surface, const kexVec3 &origin);
|
float TraceSurface(LevelMesh *map, const surface_t *surface, const kexVec3 &origin);
|
||||||
|
|
||||||
const float Distance() const { return distance; }
|
const float Distance() const { return distance; }
|
||||||
const float Intensity() const { return intensity; }
|
const float Intensity() const { return intensity; }
|
||||||
|
|
|
@ -24,24 +24,83 @@
|
||||||
// 3. This notice may not be removed or altered from any source
|
// 3. This notice may not be removed or altered from any source
|
||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// DESCRIPTION: Prepares geometry from map structures
|
|
||||||
//
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#include "math/mathlib.h"
|
#include "math/mathlib.h"
|
||||||
#include "level/level.h"
|
#include "level/level.h"
|
||||||
#include "surfaces.h"
|
#include "surfaces.h"
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(disable: 4267) // warning C4267: 'argument': conversion from 'size_t' to 'int', possible loss of data
|
#pragma warning(disable: 4267) // warning C4267: 'argument': conversion from 'size_t' to 'int', possible loss of data
|
||||||
#pragma warning(disable: 4244) // warning C4244: '=': conversion from '__int64' to 'int', possible loss of data
|
#pragma warning(disable: 4244) // warning C4244: '=': conversion from '__int64' to 'int', possible loss of data
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::vector<std::unique_ptr<surface_t>> surfaces;
|
LevelMesh::LevelMesh(FLevel &doomMap)
|
||||||
|
{
|
||||||
|
printf("------------- Building side surfaces -------------\n");
|
||||||
|
|
||||||
static void CreateSideSurfaces(FLevel &doomMap, IntSideDef *side)
|
for (unsigned int i = 0; i < doomMap.Sides.Size(); i++)
|
||||||
|
{
|
||||||
|
CreateSideSurfaces(doomMap, &doomMap.Sides[i]);
|
||||||
|
printf("sides: %i / %i\r", i + 1, doomMap.Sides.Size());
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\nSide surfaces: %i\n", (int)surfaces.size());
|
||||||
|
|
||||||
|
CreateSubsectorSurfaces(doomMap);
|
||||||
|
|
||||||
|
printf("Surfaces total: %i\n\n", (int)surfaces.size());
|
||||||
|
|
||||||
|
printf("Building collision mesh..\n\n");
|
||||||
|
|
||||||
|
for (size_t i = 0; i < surfaces.size(); i++)
|
||||||
|
{
|
||||||
|
const auto &s = surfaces[i];
|
||||||
|
int numVerts = s->numVerts;
|
||||||
|
unsigned int pos = MeshVertices.Size();
|
||||||
|
|
||||||
|
for (int j = 0; j < numVerts; j++)
|
||||||
|
{
|
||||||
|
MeshVertices.Push(s->verts[j]);
|
||||||
|
MeshUVIndex.Push(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->type == ST_FLOOR || s->type == ST_CEILING)
|
||||||
|
{
|
||||||
|
for (int j = 2; j < numVerts; j++)
|
||||||
|
{
|
||||||
|
if (!IsDegenerate(s->verts[0], s->verts[j - 1], s->verts[j]))
|
||||||
|
{
|
||||||
|
MeshElements.Push(pos);
|
||||||
|
MeshElements.Push(pos + j - 1);
|
||||||
|
MeshElements.Push(pos + j);
|
||||||
|
MeshSurfaces.Push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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]))
|
||||||
|
{
|
||||||
|
MeshElements.Push(pos + 0);
|
||||||
|
MeshElements.Push(pos + 1);
|
||||||
|
MeshElements.Push(pos + 2);
|
||||||
|
MeshSurfaces.Push(i);
|
||||||
|
}
|
||||||
|
if (!IsDegenerate(s->verts[1], s->verts[2], s->verts[3]))
|
||||||
|
{
|
||||||
|
MeshElements.Push(pos + 1);
|
||||||
|
MeshElements.Push(pos + 2);
|
||||||
|
MeshElements.Push(pos + 3);
|
||||||
|
MeshSurfaces.Push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CollisionMesh = std::make_unique<TriangleMeshShape>(&MeshVertices[0], MeshVertices.Size(), &MeshElements[0], MeshElements.Size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelMesh::CreateSideSurfaces(FLevel &doomMap, IntSideDef *side)
|
||||||
{
|
{
|
||||||
IntSector *front;
|
IntSector *front;
|
||||||
IntSector *back;
|
IntSector *back;
|
||||||
|
@ -151,10 +210,8 @@ static void CreateSideSurfaces(FLevel &doomMap, IntSideDef *side)
|
||||||
if (v1Top > v1TopBack || v2Top > v2TopBack)
|
if (v1Top > v1TopBack || v2Top > v2TopBack)
|
||||||
{
|
{
|
||||||
bool bSky = false;
|
bool bSky = false;
|
||||||
int frontidx = front - &doomMap.Sectors[0];
|
|
||||||
int backidx = back - &doomMap.Sectors[0];
|
|
||||||
|
|
||||||
if (doomMap.bSkySectors[frontidx] && doomMap.bSkySectors[backidx])
|
if (front->skySector && back->skySector)
|
||||||
{
|
{
|
||||||
if (front->data.ceilingheight != back->data.ceilingheight && side->toptexture[0] == '-')
|
if (front->data.ceilingheight != back->data.ceilingheight && side->toptexture[0] == '-')
|
||||||
{
|
{
|
||||||
|
@ -218,7 +275,7 @@ static void CreateSideSurfaces(FLevel &doomMap, IntSideDef *side)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CreateFloorSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector *sector, int typeIndex, bool is3DFloor)
|
void LevelMesh::CreateFloorSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector *sector, int typeIndex, bool is3DFloor)
|
||||||
{
|
{
|
||||||
auto surf = std::make_unique<surface_t>();
|
auto surf = std::make_unique<surface_t>();
|
||||||
surf->numVerts = sub->numlines;
|
surf->numVerts = sub->numlines;
|
||||||
|
@ -250,16 +307,12 @@ static void CreateFloorSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector *
|
||||||
surfaces.push_back(std::move(surf));
|
surfaces.push_back(std::move(surf));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CreateCeilingSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector *sector, int typeIndex, bool is3DFloor)
|
void LevelMesh::CreateCeilingSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector *sector, int typeIndex, bool is3DFloor)
|
||||||
{
|
{
|
||||||
auto surf = std::make_unique<surface_t>();
|
auto surf = std::make_unique<surface_t>();
|
||||||
surf->numVerts = sub->numlines;
|
surf->numVerts = sub->numlines;
|
||||||
surf->verts.resize(surf->numVerts);
|
surf->verts.resize(surf->numVerts);
|
||||||
|
surf->bSky = sector->skySector;
|
||||||
if (doomMap.bSkySectors[sector - &doomMap.Sectors[0]])
|
|
||||||
{
|
|
||||||
surf->bSky = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is3DFloor)
|
if (!is3DFloor)
|
||||||
{
|
{
|
||||||
|
@ -287,7 +340,7 @@ static void CreateCeilingSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector
|
||||||
surfaces.push_back(std::move(surf));
|
surfaces.push_back(std::move(surf));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CreateSubsectorSurfaces(FLevel &doomMap)
|
void LevelMesh::CreateSubsectorSurfaces(FLevel &doomMap)
|
||||||
{
|
{
|
||||||
printf("------------- Building subsector surfaces -------------\n");
|
printf("------------- Building subsector surfaces -------------\n");
|
||||||
|
|
||||||
|
@ -319,7 +372,42 @@ static void CreateSubsectorSurfaces(FLevel &doomMap)
|
||||||
printf("\nLeaf surfaces: %i\n", (int)surfaces.size() - doomMap.NumGLSubsectors);
|
printf("\nLeaf surfaces: %i\n", (int)surfaces.size() - doomMap.NumGLSubsectors);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsDegenerate(const kexVec3 &v0, const kexVec3 &v1, const kexVec3 &v2)
|
LevelTraceHit LevelMesh::Trace(const kexVec3 &startVec, const kexVec3 &endVec)
|
||||||
|
{
|
||||||
|
TraceHit hit = TriangleMeshShape::find_first_hit(CollisionMesh.get(), startVec, endVec);
|
||||||
|
|
||||||
|
LevelTraceHit trace;
|
||||||
|
trace.start = startVec;
|
||||||
|
trace.end = endVec;
|
||||||
|
trace.fraction = hit.fraction;
|
||||||
|
if (trace.fraction < 1.0f)
|
||||||
|
{
|
||||||
|
int elementIdx = hit.triangle * 3;
|
||||||
|
trace.hitSurface = surfaces[MeshSurfaces[hit.triangle]].get();
|
||||||
|
trace.indices[0] = MeshUVIndex[MeshElements[elementIdx]];
|
||||||
|
trace.indices[1] = MeshUVIndex[MeshElements[elementIdx + 1]];
|
||||||
|
trace.indices[2] = MeshUVIndex[MeshElements[elementIdx + 2]];
|
||||||
|
trace.b = hit.b;
|
||||||
|
trace.c = hit.c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trace.hitSurface = nullptr;
|
||||||
|
trace.indices[0] = 0;
|
||||||
|
trace.indices[1] = 0;
|
||||||
|
trace.indices[2] = 0;
|
||||||
|
trace.b = 0.0f;
|
||||||
|
trace.c = 0.0f;
|
||||||
|
}
|
||||||
|
return trace;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LevelMesh::TraceAnyHit(const kexVec3 &startVec, const kexVec3 &endVec)
|
||||||
|
{
|
||||||
|
return TriangleMeshShape::find_any_hit(CollisionMesh.get(), startVec, endVec);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LevelMesh::IsDegenerate(const kexVec3 &v0, const kexVec3 &v1, const kexVec3 &v2)
|
||||||
{
|
{
|
||||||
// A degenerate triangle has a zero cross product for two of its sides.
|
// A degenerate triangle has a zero cross product for two of its sides.
|
||||||
float ax = v1.x - v0.x;
|
float ax = v1.x - v0.x;
|
||||||
|
@ -335,104 +423,77 @@ static bool IsDegenerate(const kexVec3 &v0, const kexVec3 &v1, const kexVec3 &v2
|
||||||
return crosslengthsqr <= 1.e-6f;
|
return crosslengthsqr <= 1.e-6f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateSurfaces(FLevel &doomMap)
|
void LevelMesh::WriteMeshToOBJ()
|
||||||
{
|
{
|
||||||
surfaces.clear();
|
FILE *f = fopen("mesh.obj", "w");
|
||||||
|
|
||||||
for (unsigned int i = 0; i < doomMap.Sectors.Size(); i++)
|
std::map<int, std::vector<surface_t*>> sortedSurfs;
|
||||||
doomMap.Sectors[i].controlsector = false;
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < doomMap.Sides.Size(); i++)
|
for (unsigned int i = 0; i < surfaces.size(); i++)
|
||||||
doomMap.Sides[i].line = nullptr;
|
sortedSurfs[surfaces[i]->lightmapNum].push_back(surfaces[i].get());
|
||||||
|
|
||||||
for (unsigned int i = 0; i < doomMap.Lines.Size(); i++)
|
for (const auto &it : sortedSurfs)
|
||||||
{
|
{
|
||||||
IntLineDef *line = &doomMap.Lines[i];
|
for (const auto &s : it.second)
|
||||||
|
|
||||||
// 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];
|
for (int j = 0; j < s->numVerts; j++)
|
||||||
int type = line->args[1];
|
|
||||||
//int opacity = line.args[3];
|
|
||||||
|
|
||||||
IntSector *controlsector = &doomMap.Sectors[doomMap.Sides[doomMap.Lines[i].sidenum[0]].sector];
|
|
||||||
controlsector->controlsector = true;
|
|
||||||
|
|
||||||
for (unsigned int j = 0; j < doomMap.Sectors.Size(); j++)
|
|
||||||
{
|
{
|
||||||
if (doomMap.Sectors[j].data.tag == sectorTag)
|
fprintf(f, "v %f %f %f\n", s->verts[j].x, s->verts[j].z + 100.0f, s->verts[j].y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &it : sortedSurfs)
|
||||||
|
{
|
||||||
|
for (const auto &s : it.second)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < s->numVerts; j++)
|
||||||
|
{
|
||||||
|
fprintf(f, "vt %f %f\n", s->lightmapCoords[j * 2], s->lightmapCoords[j * 2 + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int voffset = 1;
|
||||||
|
for (const auto &it : sortedSurfs)
|
||||||
|
{
|
||||||
|
int lightmapNum = it.first;
|
||||||
|
|
||||||
|
if (lightmapNum != -1)
|
||||||
|
fprintf(f, "usemtl lightmap_%02d\n", lightmapNum);
|
||||||
|
else
|
||||||
|
fprintf(f, "usemtl black\n");
|
||||||
|
|
||||||
|
for (const auto &s : it.second)
|
||||||
|
{
|
||||||
|
switch (s->type)
|
||||||
|
{
|
||||||
|
case ST_FLOOR:
|
||||||
|
for (int j = 2; j < s->numVerts; j++)
|
||||||
{
|
{
|
||||||
doomMap.Sectors[j].x3dfloors.Push(controlsector);
|
fprintf(f, "f %d/%d %d/%d %d/%d\n", voffset + j, voffset + j, voffset + j - 1, voffset + j - 1, voffset, voffset);
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
}
|
case ST_CEILING:
|
||||||
}
|
for (int j = 2; j < s->numVerts; j++)
|
||||||
|
|
||||||
printf("------------- Building side surfaces -------------\n");
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < doomMap.Sides.Size(); i++)
|
|
||||||
{
|
|
||||||
CreateSideSurfaces(doomMap, &doomMap.Sides[i]);
|
|
||||||
printf("sides: %i / %i\r", i + 1, doomMap.Sides.Size());
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\nSide surfaces: %i\n", (int)surfaces.size());
|
|
||||||
|
|
||||||
CreateSubsectorSurfaces(doomMap);
|
|
||||||
|
|
||||||
printf("Surfaces total: %i\n\n", (int)surfaces.size());
|
|
||||||
|
|
||||||
printf("Building collision mesh..\n\n");
|
|
||||||
|
|
||||||
for (size_t i = 0; i < surfaces.size(); i++)
|
|
||||||
{
|
|
||||||
const auto &s = surfaces[i];
|
|
||||||
int numVerts = s->numVerts;
|
|
||||||
unsigned int pos = doomMap.MeshVertices.Size();
|
|
||||||
|
|
||||||
for (int j = 0; j < numVerts; j++)
|
|
||||||
{
|
|
||||||
doomMap.MeshVertices.Push(s->verts[j]);
|
|
||||||
doomMap.MeshUVIndex.Push(j);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s->type == ST_FLOOR || s->type == ST_CEILING)
|
|
||||||
{
|
|
||||||
for (int j = 2; j < numVerts; j++)
|
|
||||||
{
|
|
||||||
if (!IsDegenerate(s->verts[0], s->verts[j - 1], s->verts[j]))
|
|
||||||
{
|
{
|
||||||
doomMap.MeshElements.Push(pos);
|
fprintf(f, "f %d/%d %d/%d %d/%d\n", voffset, voffset, voffset + j - 1, voffset + j - 1, voffset + j, voffset + j);
|
||||||
doomMap.MeshElements.Push(pos + j - 1);
|
|
||||||
doomMap.MeshElements.Push(pos + j);
|
|
||||||
doomMap.MeshSurfaces.Push(i);
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
for (int j = 2; j < s->numVerts; j++)
|
||||||
|
{
|
||||||
|
if (j % 2 == 0)
|
||||||
|
fprintf(f, "f %d/%d %d/%d %d/%d\n", voffset + j - 2, voffset + j - 2, voffset + j - 1, voffset + j - 1, voffset + j, voffset + j);
|
||||||
|
else
|
||||||
|
fprintf(f, "f %d/%d %d/%d %d/%d\n", voffset + j, voffset + j, voffset + j - 1, voffset + j - 1, voffset + j - 2, voffset + j - 2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (s->type == ST_MIDDLESIDE || s->type == ST_UPPERSIDE || s->type == ST_LOWERSIDE)
|
voffset += s->numVerts;
|
||||||
{
|
|
||||||
if (!IsDegenerate(s->verts[0], s->verts[1], s->verts[2]))
|
|
||||||
{
|
|
||||||
doomMap.MeshElements.Push(pos + 0);
|
|
||||||
doomMap.MeshElements.Push(pos + 1);
|
|
||||||
doomMap.MeshElements.Push(pos + 2);
|
|
||||||
doomMap.MeshSurfaces.Push(i);
|
|
||||||
}
|
|
||||||
if (!IsDegenerate(s->verts[1], s->verts[2], s->verts[3]))
|
|
||||||
{
|
|
||||||
doomMap.MeshElements.Push(pos + 1);
|
|
||||||
doomMap.MeshElements.Push(pos + 2);
|
|
||||||
doomMap.MeshElements.Push(pos + 3);
|
|
||||||
doomMap.MeshSurfaces.Push(i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doomMap.CollisionMesh = std::make_unique<TriangleMeshShape>(&doomMap.MeshVertices[0], doomMap.MeshVertices.Size(), &doomMap.MeshElements[0], doomMap.MeshElements.Size());
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,13 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "framework/tarray.h"
|
||||||
|
#include "lightmap/collision.h"
|
||||||
|
|
||||||
struct MapSubsectorEx;
|
struct MapSubsectorEx;
|
||||||
|
struct IntSector;
|
||||||
|
struct IntSideDef;
|
||||||
|
struct FLevel;
|
||||||
|
|
||||||
enum surfaceType_t
|
enum surfaceType_t
|
||||||
{
|
{
|
||||||
|
@ -45,8 +51,6 @@ enum surfaceType_t
|
||||||
// convert from fixed point(FRACUNIT) to floating point
|
// convert from fixed point(FRACUNIT) to floating point
|
||||||
#define F(x) (((float)(x))/65536.0f)
|
#define F(x) (((float)(x))/65536.0f)
|
||||||
|
|
||||||
struct IntSector;
|
|
||||||
|
|
||||||
struct surface_t
|
struct surface_t
|
||||||
{
|
{
|
||||||
kexPlane plane;
|
kexPlane plane;
|
||||||
|
@ -66,8 +70,41 @@ struct surface_t
|
||||||
bool bSky;
|
bool bSky;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::vector<std::unique_ptr<surface_t>> surfaces;
|
struct LevelTraceHit
|
||||||
|
{
|
||||||
|
kexVec3 start;
|
||||||
|
kexVec3 end;
|
||||||
|
float fraction;
|
||||||
|
|
||||||
struct FLevel;
|
surface_t *hitSurface;
|
||||||
|
int indices[3];
|
||||||
|
float b, c;
|
||||||
|
};
|
||||||
|
|
||||||
void CreateSurfaces(FLevel &doomMap);
|
class LevelMesh
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LevelMesh(FLevel &doomMap);
|
||||||
|
|
||||||
|
LevelTraceHit Trace(const kexVec3 &startVec, const kexVec3 &endVec);
|
||||||
|
bool TraceAnyHit(const kexVec3 &startVec, const kexVec3 &endVec);
|
||||||
|
|
||||||
|
void WriteMeshToOBJ();
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<surface_t>> surfaces;
|
||||||
|
|
||||||
|
TArray<kexVec3> MeshVertices;
|
||||||
|
TArray<int> MeshUVIndex;
|
||||||
|
TArray<unsigned int> MeshElements;
|
||||||
|
TArray<int> MeshSurfaces;
|
||||||
|
std::unique_ptr<TriangleMeshShape> CollisionMesh;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void CreateSubsectorSurfaces(FLevel &doomMap);
|
||||||
|
void CreateCeilingSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector *sector, int typeIndex, bool is3DFloor);
|
||||||
|
void CreateFloorSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector *sector, int typeIndex, bool is3DFloor);
|
||||||
|
|
||||||
|
void CreateSideSurfaces(FLevel &doomMap, IntSideDef *side);
|
||||||
|
|
||||||
|
static bool IsDegenerate(const kexVec3 &v0, const kexVec3 &v1, const kexVec3 &v2);
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in a new issue