diff --git a/src/level/doomdata.h b/src/level/doomdata.h index 693ed5e..849a709 100644 --- a/src/level/doomdata.h +++ b/src/level/doomdata.h @@ -153,11 +153,23 @@ struct IntSector struct { bool skyFloor, skyCeiling; }; }; - inline const char* GetTextureName(int plane) const { return plane != PLANE_FLOOR ? data.ceilingpic : data.floorpic; } - TArray props; TArray lines; + + // Utility functions + inline const char* GetTextureName(int plane) const { return plane != PLANE_FLOOR ? data.ceilingpic : data.floorpic; } + + inline bool HasTag(int sectorTag) const + { + if (tags.Size() <= 0 && sectorTag == 0) + return true; + for (auto tag : tags) + { + if (tag == sectorTag) return true; + } + return false; + } }; struct MapSubsector diff --git a/src/lightmap/gpuraytracer.cpp b/src/lightmap/gpuraytracer.cpp index 03567c0..21dc2dd 100644 --- a/src/lightmap/gpuraytracer.cpp +++ b/src/lightmap/gpuraytracer.cpp @@ -1015,7 +1015,7 @@ std::vector GPURaytracer::CreatePortalInfo() for (const auto& surface : mesh->surfaces) { - if (surface->portalDestinationIndex >= 0) + if (surface->portalIndex >= 0) { PortalInfo info; info.Transformation = mesh->portals[surface->portalIndex]->transformation; diff --git a/src/lightmap/levelmesh.cpp b/src/lightmap/levelmesh.cpp index bcdeb89..48573c0 100644 --- a/src/lightmap/levelmesh.cpp +++ b/src/lightmap/levelmesh.cpp @@ -510,6 +510,92 @@ int LevelMesh::CreateLinePortal(FLevel& doomMap, const IntLineDef& srcLine, cons return int(portals.size() - 1); } +int LevelMesh::CheckAndMakePortal(FLevel& doomMap, MapSubsectorEx* sub, IntSector* sector, int typeIndex, int plane) +{ + const auto& lines = doomMap.GetSectorFromSubSector(sub)->lines; + + for (const auto& line : lines) + { + if (line->special == Sector_SetPortal && line->args[0] && line->args[2] == plane && !line->args[3] && sector->HasTag(line->args[0])) + { + const IntLineDef* dstLine = nullptr; + + // Find the other portal line + for (const auto &targetLine : doomMap.Lines) + { + if (targetLine.special == Sector_SetPortal && targetLine.args[2] == plane && targetLine.args[3] && line->args[0] == targetLine.args[0]) + { + dstLine = &targetLine; + break; + } + } + + if (dstLine) + { + return CreatePlanePortal(doomMap, *line, *dstLine); + } + } + } + + return -1; +} + +int LevelMesh::CreatePlanePortal(FLevel& doomMap, const IntLineDef& srcLine, const IntLineDef& dstLine) +{ + auto portal = std::make_unique(); + + // Calculate portal transformation + { + FloatVertex srcV1 = doomMap.GetSegVertex(srcLine.v1); + FloatVertex srcV2 = doomMap.GetSegVertex(srcLine.v2); + FloatVertex dstV1 = doomMap.GetSegVertex(dstLine.v1); + FloatVertex dstV2 = doomMap.GetSegVertex(dstLine.v2); + + int alignment = srcLine.args[2]; + + double srcAZ = 0; + double srcBZ = 0; + double dstAZ = 0; + double dstBZ = 0; + + const auto* srcFront = srcLine.frontsector; + const auto* dstFront = dstLine.frontsector; + + if (alignment == 0) // floor + { + srcAZ = srcFront->floorplane.zAt(srcV1.x, srcV1.y); + srcBZ = srcFront->floorplane.zAt(srcV2.x, srcV2.y); + dstAZ = dstFront->ceilingplane.zAt(dstV1.x, dstV1.y); + dstBZ = dstFront->ceilingplane.zAt(dstV2.x, dstV2.y); + } + else // ceiling + { + srcAZ = srcFront->ceilingplane.zAt(srcV1.x, srcV1.y); + srcBZ = srcFront->ceilingplane.zAt(srcV2.x, srcV2.y); + dstAZ = dstFront->floorplane.zAt(dstV1.x, dstV1.y); + dstBZ = dstFront->floorplane.zAt(dstV2.x, dstV2.y); + } + + const vec3 vecSrcA = vec3(vec2(srcV1.x, srcV1.y), srcAZ); + const vec3 vecSrcB = vec3(vec2(srcV2.x, srcV2.y), srcAZ); + const vec3 vecDstA = vec3(vec2(dstV1.x, dstV1.y), dstAZ); + const vec3 vecDstB = vec3(vec2(dstV2.x, dstV2.y), dstBZ); + + // Translation + vec3 originSrc = (vecSrcB + vecSrcA) * 0.5f; + vec3 originDst = (vecDstB + vecDstA) * 0.5f; + + vec3 translation = originDst - originSrc; + + // printf("Portal translation: %.3f %.3f %.3f\n", translation.x, translation.y, translation.z); + + portal->transformation = mat4::translate(translation); + } + + portals.push_back(std::move(portal)); + return int(portals.size() - 1); +} + void LevelMesh::CreateSideSurfaces(FLevel &doomMap, IntSideDef *side) { IntSector *front; @@ -585,6 +671,8 @@ void LevelMesh::CreateSideSurfaces(FLevel &doomMap, IntSideDef *side) surf->portalDestinationIndex = destLineIndex; surf->portalIndex = CreateLinePortal(doomMap, *side->line, doomMap.Lines[destLineIndex]); + + surfaces.push_back(std::move(surf)); return; } else @@ -874,6 +962,7 @@ void LevelMesh::CreateFloorSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSect if (!is3DFloor) { surf->plane = sector->floorplane; + surf->portalIndex = CheckAndMakePortal(doomMap, sub, sector, typeIndex, PLANE_FLOOR); } else { @@ -912,6 +1001,7 @@ void LevelMesh::CreateCeilingSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSe if (!is3DFloor) { surf->plane = sector->ceilingplane; + surf->portalIndex = CheckAndMakePortal(doomMap, sub, sector, typeIndex, PLANE_CEILING); } else { diff --git a/src/lightmap/levelmesh.h b/src/lightmap/levelmesh.h index 3834a07..63fb0d2 100644 --- a/src/lightmap/levelmesh.h +++ b/src/lightmap/levelmesh.h @@ -160,5 +160,8 @@ private: static bool IsDegenerate(const vec3 &v0, const vec3 &v1, const vec3 &v2); + int CheckAndMakePortal(FLevel& doomMap, MapSubsectorEx* sub, IntSector* sector, int typeIndex, int plane); + int CreateLinePortal(FLevel &doomMap, const IntLineDef& srcLine, const IntLineDef& dstLine); + int CreatePlanePortal(FLevel &doomMap, const IntLineDef& srcLine, const IntLineDef& dstLine); };