diff --git a/source/core/gamefuncs.cpp b/source/core/gamefuncs.cpp index f20c933cc..c2270460c 100644 --- a/source/core/gamefuncs.cpp +++ b/source/core/gamefuncs.cpp @@ -492,6 +492,33 @@ void dragpoint(walltype* startwall, const DVector2& pos) }); } +//========================================================================== +// +// +// +//========================================================================== + +int64_t checkforinside(double x, double y, const DVector2& pt1, const DVector2& pt2) +{ + // Perform the checks here in 48.16 fixed point. + // Doing it directly with floats and multiplications does not work reliably due to underflows. + // Unfortunately, due to the conversions, this is a bit slower. :( + int64_t xs = int64_t(0x10000 * (pt1.X - x)); + int64_t ys = int64_t(0x10000 * (pt1.Y - y)); + int64_t xe = int64_t(0x10000 * (pt2.X - x)); + int64_t ye = int64_t(0x10000 * (pt2.Y - y)); + + if ((ys ^ ye) < 0) + { + int64_t val; + + if ((xs ^ xe) >= 0) val = xs; + else val = ((xs * ye) - xe * ys) ^ ye; + return val; + } + return 0; +} + //========================================================================== // // @@ -505,23 +532,7 @@ int inside(double x, double y, const sectortype* sect) int64_t acc = 1; for (auto& wal : wallsofsector(sect)) { - // Perform the checks here in 48.16 fixed point. - // Doing it directly with floats and multiplications does not work reliably. - // Unfortunately, due to the conversions, this is a bit slower. :( - int64_t xs = int64_t(0x10000 * (wal.pos.X - x)); - int64_t ys = int64_t(0x10000 * (wal.pos.Y - y)); - auto wal2 = wal.point2Wall(); - int64_t xe = int64_t(0x10000 * (wal2->pos.X - x)); - int64_t ye = int64_t(0x10000 * (wal2->pos.Y - y)); - - if ((ys ^ ye) < 0) - { - int64_t val; - - if ((xs ^ xe) >= 0) val = xs; - else val = ((xs * ye) - xe * ys) ^ ye; - acc ^= val; - } + acc ^= checkforinside(x, y, wal.pos, wal.point2Wall()->pos); } return acc < 0; } @@ -540,25 +551,9 @@ int insidePoly(double x, double y, const DVector2* points, int count) for (int i = 0; i < count; i++) { int j = (i + 1) % count; - // Perform the checks here in 48.16 fixed point. - // Doing it directly with floats and multiplications does not work reliably. - // Unfortunately, due to the conversions, this is a bit slower. :( - int64_t xs = int64_t(0x10000 * (points[i].X - x)); - int64_t ys = int64_t(0x10000 * (points[i].Y - y)); - int64_t xe = int64_t(0x10000 * (points[j].X - x)); - int64_t ye = int64_t(0x10000 * (points[j].Y - y)); - - if ((ys ^ ye) < 0) - { - int64_t val; - - if ((xs ^ xe) >= 0) val = xs; - else val = ((xs * ye) - xe * ys) ^ ye; - acc ^= val; - } + acc ^= checkforinside(x, y, points[i], points[j]); } - return acc < 0; - + return acc < 0; } //========================================================================== diff --git a/source/core/rendering/hw_sections.cpp b/source/core/rendering/hw_sections.cpp index 72ca158b8..3934dfc25 100644 --- a/source/core/rendering/hw_sections.cpp +++ b/source/core/rendering/hw_sections.cpp @@ -288,45 +288,24 @@ static void CollectLoops(TArray& sectors) // // checks if a point is within a given section // -// Completely redone based on outside information. -// The math in here is based on this article: https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html -// Copyright (c) 1970-2003, Wm. Randolph Franklin , licensed under BSD 3-clause -// but was transformed to avoid the division it contained and to properly pick the vertices of Build walls. -// -// (not used in-game because it is not 100% identical to Build's original check and causing issues in SW.) -// //========================================================================== +static TArray points; static int insideLoop(int vertex, TArray& loop) { - auto pt = wall[vertex].wall_int_pos(); + points.Resize(loop.Size() - 1); + for (unsigned ii = 0; ii < loop.Size() - 1; ii++) + { + points[ii] = wall[loop[ii]].pos; + } + + // to reliably detect walls where vertices lie directly on outer walls, we must test the wall's center as well. + // SW: Wanton Destrcution's $bath.map, sector 601 is an example for that. + DVector2 pts[] = { wall[vertex].pos, wall[vertex].center() }; for (int i = 0; i < 2; i++) { - // to reliably detect walls where vertices lie directly on outer walls, we must test the wall's center as well. - // SW: Wanton Destrcution's $bath.map, sector 601 is an example for that. - if (i == 1) pt += wall[vertex].int_delta() / 2; - bool c = false; - for (unsigned ii = 0; ii < loop.Size() - 1; ii++) - { - auto& wal = wall[loop[ii]]; - const auto pt1 = wal.wall_int_pos(); - const auto pt2 = wal.point2Wall()->wall_int_pos(); - - if ((pt1.Y >pt.Y) != (pt2.Y > pt.Y)) // skip if both are on the same side. - { - // use 64 bit values to avoid overflows in the multiplications below. - int64_t deltatx = int64_t(pt.X) - pt1.X; - int64_t deltaty = int64_t(pt.Y) - pt1.Y; - int64_t deltax = int64_t(pt2.X) - pt1.X; - int64_t deltay = int64_t(pt2.Y) - pt1.Y; - //if (x < deltax * (deltaty) / deltay + pt1.x) - // reformatted to avoid the division - for nagative deltay the sign needs to be flipped to give the correct result. - int64_t result = ((deltay * deltatx - deltax * deltaty) ^ deltay); - if (result < 0) - c = !c; - } - } - if (i == 1 || c == 1) return int(c); + int isinside = insidePoly(pts[i].X, pts[i].Y, points.Data(), points.Size()); + if (isinside == 1) return 1; } return -1; } @@ -504,7 +483,7 @@ static void GroupData(TArray& collect, TArray& if (!tossit) // Have we created our dumping section yet? If no, do so now and print a warning. { tossit = true; - Printf("Potential problem at sector %d with %d loops\n", i, sectloops.Size()); + //Printf("Potential problem at sector %d with %d loops\n", i, sectloops.Size()); bugged.Insert(i, true); builder.sections.Reserve(1); builder.sections.Last().bugged = ESectionFlag::Dumped; // this will most likely require use of the node builder to triangulate anyway.