diff --git a/src/level/doomdata.h b/src/level/doomdata.h index c548edb..a198199 100644 --- a/src/level/doomdata.h +++ b/src/level/doomdata.h @@ -3,7 +3,6 @@ #include "framework/tarray.h" #include "math/mathlib.h" -#include "lightmap/collision.h" #include #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 x3dfloors; + bool skySector; TArray 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 MeshVertices; - TArray MeshUVIndex; - TArray MeshElements; - TArray MeshSurfaces; - std::unique_ptr CollisionMesh; - - std::vector bSkySectors; - - std::vector> thingLights; - std::vector> lightSurfaces; + TArray ThingLights; + TArray 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); diff --git a/src/level/level.cpp b/src/level/level.cpp index e897817..7a7978b 100644 --- a/src/level/level.cpp +++ b/src/level/level.cpp @@ -622,7 +622,6 @@ void FProcessor::BuildLightmaps() LMBuilder.textureHeight = LMDims; Level.SetupDlight(); - CreateSurfaces(Level); Level.CreateLights(); LMBuilder.CreateLightmaps(Level); diff --git a/src/level/level_light.cpp b/src/level/level_light.cpp index e17f3c1..024e023 100644 --- a/src/level/level_light.cpp +++ b/src/level/level_light.cpp @@ -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(Sectors.Size()); // Most retarded way to resize ever, but Microsoft apparently broke std::vector 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; + 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(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(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()); } diff --git a/src/lightmap/lightmap.cpp b/src/lightmap/lightmap.cpp index 25182a2..076cdd6 100644 --- a/src/lightmap/lightmap.cpp +++ b/src/lightmap/lightmap.cpp @@ -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 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(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(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(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(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(std::floor(worldBBox.min.x / blockWorldSize)); grid.y = static_cast(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> 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); -} diff --git a/src/lightmap/lightmap.h b/src/lightmap/lightmap.h index b04a935..ba0bbfc 100644 --- a/src/lightmap/lightmap.h +++ b/src/lightmap/lightmap.h @@ -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 mesh; FLevel *map; + std::vector> lightSurfaces; std::vector> textures; std::vector indirectoutput; std::vector> allocBlocks; diff --git a/src/lightmap/lightsurface.cpp b/src/lightmap/lightsurface.cpp index 356ffcd..5fc8438 100644 --- a/src/lightmap/lightsurface.cpp +++ b/src/lightmap/lightsurface.cpp @@ -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) diff --git a/src/lightmap/lightsurface.h b/src/lightmap/lightsurface.h index ae7c803..bedda55 100644 --- a/src/lightmap/lightsurface.h +++ b/src/lightmap/lightsurface.h @@ -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; } diff --git a/src/lightmap/surfaces.cpp b/src/lightmap/surfaces.cpp index 5606061..f4d5e86 100644 --- a/src/lightmap/surfaces.cpp +++ b/src/lightmap/surfaces.cpp @@ -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 #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> 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(&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(); 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(); 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> 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(&doomMap.MeshVertices[0], doomMap.MeshVertices.Size(), &doomMap.MeshElements[0], doomMap.MeshElements.Size()); + fclose(f); } diff --git a/src/lightmap/surfaces.h b/src/lightmap/surfaces.h index f539604..641ad2c 100644 --- a/src/lightmap/surfaces.h +++ b/src/lightmap/surfaces.h @@ -30,7 +30,13 @@ #include #include +#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> 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> surfaces; + + TArray MeshVertices; + TArray MeshUVIndex; + TArray MeshElements; + TArray MeshSurfaces; + std::unique_ptr 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); +};