- 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 "math/mathlib.h"
#include "lightmap/collision.h"
#include <memory>
#undef MIN
#undef MAX
@ -52,6 +51,7 @@ struct IntSideDef
char midtexture[8];
int sector;
int lightdef;
IntLineDef *line;
@ -112,8 +112,12 @@ struct IntSector
kexPlane ceilingplane;
kexPlane floorplane;
int floorlightdef;
int ceilinglightdef;
bool controlsector;
TArray<IntSector*> x3dfloors;
bool skySector;
TArray<UDMFKey> props;
};
@ -305,17 +309,6 @@ enum mapFlags_t
#define NO_SIDE_INDEX -1
#define NO_LINE_INDEX 0xffffffff
struct LevelTraceHit
{
kexVec3 start;
kexVec3 end;
float fraction;
surface_t *hitSurface;
int indices[3];
float b, c;
};
struct FLevel
{
FLevel ();
@ -359,23 +352,12 @@ struct FLevel
// Dlight helpers
TArray<kexVec3> MeshVertices;
TArray<int> MeshUVIndex;
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;
TArray<thingLight_t> ThingLights;
TArray<surfaceLightDef> SurfaceLights;
void SetupDlight();
void CreateLights();
LevelTraceHit Trace(const kexVec3 &startVec, const kexVec3 &endVec);
bool TraceAnyHit(const kexVec3 &startVec, const kexVec3 &endVec);
const kexVec3 &GetSunColor() const;
const kexVec3 &GetSunDirection() const;
IntSector *GetFrontSector(const IntSideDef *side);

View file

@ -622,7 +622,6 @@ void FProcessor::BuildLightmaps()
LMBuilder.textureHeight = LMDims;
Level.SetupDlight();
CreateSurfaces(Level);
Level.CreateLights();
LMBuilder.CreateLightmaps(Level);

View file

@ -47,14 +47,47 @@ static const kexVec3 defaultSunDirection(0.45f, 0.3f, 0.9f);
void FLevel::SetupDlight()
{
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()
{
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)
{
//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))
{
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 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;
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));
ThingLights.Push(thingLight);
}
}
printf("Thing lights: %i\n", (int)thingLights.size());
printf("Thing lights: %i\n", (int)ThingLights.Size());
// add surface lights
int numSurfLights = 0;
for (size_t j = 0; j < surfaces.size(); ++j)
for (unsigned int i = 0; i < Sides.Size(); i++)
{
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;
if (line)
uint32_t lightcolor = 0xffffff;
float lightintensity = 1.0f;
float lightdistance = 0.0f;
for (unsigned int propIndex = 0; propIndex < line->props.Size(); propIndex++)
{
uint32_t lightcolor = 0xffffff;
float lightintensity = 1.0f;
float lightdistance = 0.0f;
for (unsigned int propIndex = 0; propIndex < line->props.Size(); propIndex++)
const UDMFKey &key = line->props[propIndex];
if (!stricmp(key.key, "lightcolor"))
{
const UDMFKey &key = line->props[propIndex];
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);
}
lightcolor = atoi(key.value);
}
if (lightdistance > 0.0f && lightintensity > 0.0f && lightcolor != 0)
else if (!stricmp(key.key, "lightintensity"))
{
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);
//lightSurface->CreateCenterOrigin();
lightSurfaces.push_back(std::move(lightSurface));
numSurfLights++;
lightintensity = atof(key.value);
}
else if (!stricmp(key.key, "lightdistance"))
{
lightdistance = atof(key.value);
}
}
}
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;
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 (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++;
}
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;
side->lightdef = SurfaceLights.Push(desc);
}
}
}
printf("Surface lights: %i\n", numSurfLights);
}
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)
for (unsigned int i = 0; i < Sectors.Size(); i++)
{
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;
}
IntSector *sector = &Sectors[i];
bool FLevel::TraceAnyHit(const kexVec3 &startVec, const kexVec3 &endVec)
{
return TriangleMeshShape::find_any_hit(CollisionMesh.get(), startVec, endVec);
sector->floorlightdef = -1;
sector->ceilinglightdef = -1;
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;
}
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)
{
@ -216,9 +216,9 @@ kexVec3 kexLightmapBuilder::LightTexelSample(const kexVec3 &origin, surface_t *s
kexVec3 color(0.0f, 0.0f, 0.0f);
// 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;
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
continue;
@ -291,11 +291,11 @@ kexVec3 kexLightmapBuilder::LightTexelSample(const kexVec3 &origin, surface_t *s
}
// 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)
{
color += surfaceLight->GetRGB() * surfaceLight->Intensity() * attenuation;
@ -601,7 +601,7 @@ void kexLightmapBuilder::TraceIndirectLight(surface_t *surface)
if (NdotL > 0.0f)
{
tracedTexels++;
LevelTraceHit hit = map->Trace(pos, pos + L * 1000.0f);
LevelTraceHit hit = mesh->Trace(pos, pos + L * 1000.0f);
if (hit.fraction < 1.0f)
{
kexVec3 surfaceLight;
@ -653,12 +653,12 @@ void kexLightmapBuilder::TraceIndirectLight(surface_t *surface)
void kexLightmapBuilder::LightSurface(const int surfid)
{
BuildSurfaceParams(surfaces[surfid].get());
TraceSurface(surfaces[surfid].get());
BuildSurfaceParams(mesh->surfaces[surfid].get());
TraceSurface(mesh->surfaces[surfid].get());
std::unique_lock<std::mutex> lock(mutex);
int numsurfs = surfaces.size();
int numsurfs = mesh->surfaces.size();
int lastproc = processed * 100 / numsurfs;
processed++;
int curproc = processed * 100 / numsurfs;
@ -671,9 +671,9 @@ void kexLightmapBuilder::LightSurface(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;
processed++;
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)
{
map = &doomMap;
mesh = std::make_unique<LevelMesh>(doomMap);
CreateLightSurfaces();
printf("-------------- Tracing cells ---------------\n");
@ -704,7 +747,7 @@ void kexLightmapBuilder::CreateLightmaps(FLevel &doomMap)
tracedTexels = 0;
processed = 0;
kexWorker::RunJob(surfaces.size(), [=](int id) {
kexWorker::RunJob(mesh->surfaces.size(), [=](int id) {
LightSurface(id);
});
@ -716,7 +759,7 @@ void kexLightmapBuilder::CreateLightmaps(FLevel &doomMap)
tracedTexels = 0;
processed = 0;
kexWorker::RunJob(surfaces.size(), [=](int id) {
kexWorker::RunJob(mesh->surfaces.size(), [=](int id) {
LightIndirect(id);
});
@ -736,7 +779,7 @@ void kexLightmapBuilder::CreateLightmaps(FLevel &doomMap)
void kexLightmapBuilder::SetupLightCellGrid()
{
kexBBox worldBBox = map->CollisionMesh->get_bbox();
kexBBox worldBBox = mesh->CollisionMesh->get_bbox();
float blockWorldSize = LIGHTCELL_BLOCK_SIZE * LIGHTCELL_SIZE;
grid.x = static_cast<int>(std::floor(worldBBox.min.x / 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;
printf("%i%c cells done\r", (int)(remaining * 100.0f), '%');
}
}
void kexLightmapBuilder::AddLightmapLump(FWadWriter &wadFile)
{
const auto &surfaces = mesh->surfaces;
// Calculate size of lump
int numTexCoords = 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)
{
@ -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
class FWadWriter;
class kexLightSurface;
class LightCellBlock
{
@ -62,7 +63,6 @@ public:
void CreateLightmaps(FLevel &doomMap);
//void WriteTexturesToTGA();
void WriteMeshToOBJ();
void AddLightmapLump(FWadWriter &wadFile);
int samples = 16;
@ -85,7 +85,11 @@ private:
void LightSurface(const int surfid);
void LightIndirect(const int surfid);
void CreateLightSurfaces();
std::unique_ptr<LevelMesh> mesh;
FLevel *map;
std::vector<std::unique_ptr<kexLightSurface>> lightSurfaces;
std::vector<std::vector<uint16_t>> textures;
std::vector<uint16_t> indirectoutput;
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)
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
// 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
if (d < closestDistance)

View file

@ -39,7 +39,7 @@ public:
~kexLightSurface();
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 Intensity() const { return intensity; }

View file

@ -24,24 +24,83 @@
// 3. This notice may not be removed or altered from any source
// distribution.
//
//-----------------------------------------------------------------------------
//
// DESCRIPTION: Prepares geometry from map structures
//
//-----------------------------------------------------------------------------
#include "math/mathlib.h"
#include "level/level.h"
#include "surfaces.h"
#include <map>
#ifdef _MSC_VER
#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
#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 *back;
@ -151,10 +210,8 @@ static void CreateSideSurfaces(FLevel &doomMap, IntSideDef *side)
if (v1Top > v1TopBack || v2Top > v2TopBack)
{
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] == '-')
{
@ -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>();
surf->numVerts = sub->numlines;
@ -250,16 +307,12 @@ static void CreateFloorSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector *
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>();
surf->numVerts = sub->numlines;
surf->verts.resize(surf->numVerts);
if (doomMap.bSkySectors[sector - &doomMap.Sectors[0]])
{
surf->bSky = true;
}
surf->bSky = sector->skySector;
if (!is3DFloor)
{
@ -287,7 +340,7 @@ static void CreateCeilingSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector
surfaces.push_back(std::move(surf));
}
static void CreateSubsectorSurfaces(FLevel &doomMap)
void LevelMesh::CreateSubsectorSurfaces(FLevel &doomMap)
{
printf("------------- Building subsector surfaces -------------\n");
@ -319,7 +372,42 @@ static void CreateSubsectorSurfaces(FLevel &doomMap)
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.
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;
}
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++)
doomMap.Sectors[i].controlsector = false;
std::map<int, std::vector<surface_t*>> sortedSurfs;
for (unsigned int i = 0; i < doomMap.Sides.Size(); i++)
doomMap.Sides[i].line = nullptr;
for (unsigned int i = 0; i < surfaces.size(); i++)
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];
// 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
for (const auto &s : it.second)
{
int sectorTag = line->args[0];
int type = line->args[1];
//int opacity = line.args[3];
IntSector *controlsector = &doomMap.Sectors[doomMap.Sides[doomMap.Lines[i].sidenum[0]].sector];
controlsector->controlsector = true;
for (unsigned int j = 0; j < doomMap.Sectors.Size(); j++)
for (int j = 0; j < s->numVerts; 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);
}
}
}
}
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]))
break;
case ST_CEILING:
for (int j = 2; j < s->numVerts; j++)
{
doomMap.MeshElements.Push(pos);
doomMap.MeshElements.Push(pos + j - 1);
doomMap.MeshElements.Push(pos + j);
doomMap.MeshSurfaces.Push(i);
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;
}
}
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]))
{
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);
}
voffset += s->numVerts;
}
}
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 <memory>
#include "framework/tarray.h"
#include "lightmap/collision.h"
struct MapSubsectorEx;
struct IntSector;
struct IntSideDef;
struct FLevel;
enum surfaceType_t
{
@ -45,8 +51,6 @@ enum surfaceType_t
// convert from fixed point(FRACUNIT) to floating point
#define F(x) (((float)(x))/65536.0f)
struct IntSector;
struct surface_t
{
kexPlane plane;
@ -66,8 +70,41 @@ struct surface_t
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);
};