- split map loading code from surface mesh code

This commit is contained in:
Magnus Norddahl 2018-11-09 08:42:37 +01:00
parent 73724c111c
commit 9a84d487dc
9 changed files with 438 additions and 383 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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());
} }

View file

@ -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);
}

View file

@ -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;

View file

@ -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)

View file

@ -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; }

View file

@ -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);
} }

View file

@ -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);
};