From ec258c9588a6bbeabf8768188dbb8f8260ff069d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 3 Mar 2016 13:07:11 +0100 Subject: [PATCH] - redid P_ClipLineToPortal with revised visibility rules: * any line completely parallel to the portal is rejected * any line with one end on the same straight line than the portal is solely decided by the other vertex. * any line with both ends behind the portal cannot be visible inside, so there's no need to check for an intersection with the view range. * due to the above P_IntersectLines could be removed as it was redundant. * for any line that does intersect with the portal straight, do a reverse check: If both ends of the portal lie on the other side of the line than the viewpoint, the line is between viewpoint and portal and needs to be rejected. This fixes nearly all the phantom wall glitches in the demo map. --- src/portal.cpp | 98 +++++++++++++++++++------------------------------- 1 file changed, 37 insertions(+), 61 deletions(-) diff --git a/src/portal.cpp b/src/portal.cpp index f9c3cec2a..49a1592a3 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -468,47 +468,6 @@ void P_ClearPortals() } -//============================================================================ -// -// Calculate the intersection between two lines. -// [ZZ] lots of floats here to avoid overflowing a lot -// -//============================================================================ - -bool P_IntersectLines(fixed_t o1x, fixed_t o1y, fixed_t p1x, fixed_t p1y, - fixed_t o2x, fixed_t o2y, fixed_t p2x, fixed_t p2y, - fixed_t& rx, fixed_t& ry) -{ - double xx = FIXED2DBL(o2x) - FIXED2DBL(o1x); - double xy = FIXED2DBL(o2y) - FIXED2DBL(o1y); - - double d1x = FIXED2DBL(p1x) - FIXED2DBL(o1x); - double d1y = FIXED2DBL(p1y) - FIXED2DBL(o1y); - - if (d1x > d1y) - { - d1y = d1y / d1x * 32767.0f; - d1x = 32767.0; - } - else - { - d1x = d1x / d1y * 32767.0f; - d1y = 32767.0; - } - - double d2x = FIXED2DBL(p2x) - FIXED2DBL(o2x); - double d2y = FIXED2DBL(p2y) - FIXED2DBL(o2y); - - double cross = d1x*d2y - d1y*d2x; - if (fabs(cross) < 1e-8) - return false; - - double t1 = (xx * d2y - xy * d2x)/cross; - rx = o1x + FLOAT2FIXED(d1x * t1); - ry = o1y + FLOAT2FIXED(d1y * t1); - return true; -} - inline int P_PointOnLineSideExplicit (fixed_t x, fixed_t y, fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2) { return DMulScale32 (y-y1, x2-x1, x1-x, y2-y1) > 0; @@ -517,35 +476,52 @@ inline int P_PointOnLineSideExplicit (fixed_t x, fixed_t y, fixed_t x1, fixed_t //============================================================================ // // check if this line is between portal and the viewer. clip away if it is. -// (this may need some fixing) // //============================================================================ +inline int P_GetLineSide(fixed_t x, fixed_t y, const line_t *line) +{ + return DMulScale32(y - line->v1->y, line->dx, line->v1->x - x, line->dy); +} + bool P_ClipLineToPortal(line_t* line, line_t* portal, fixed_t viewx, fixed_t viewy, bool partial, bool samebehind) { - bool behind1 = !!P_PointOnLineSidePrecise(line->v1->x, line->v1->y, portal); - bool behind2 = !!P_PointOnLineSidePrecise(line->v2->x, line->v2->y, portal); + int behind1 = P_GetLineSide(line->v1->x, line->v1->y, portal); + int behind2 = P_GetLineSide(line->v2->x, line->v2->y, portal); - // [ZZ] update 16.12.2014: if a vertex equals to one of portal's vertices, it's treated as being behind the portal. - // this is required in order to clip away diagonal lines around the portal (example: 1-sided triangle shape with a mirror on it's side) - if ((line->v1->x == portal->v1->x && line->v1->y == portal->v1->y) || - (line->v1->x == portal->v2->x && line->v1->y == portal->v2->y)) - behind1 = samebehind; - if ((line->v2->x == portal->v1->x && line->v2->y == portal->v1->y) || - (line->v2->x == portal->v2->x && line->v2->y == portal->v2->y)) - behind2 = samebehind; - - if (behind1 && behind2) + if (behind1 == 0 && behind2 == 0) { - // line is behind the portal plane. now check if it's in front of two view plane borders (i.e. if it will get in the way of rendering) - fixed_t dummyx, dummyy; - bool infront1 = P_IntersectLines(line->v1->x, line->v1->y, line->v2->x, line->v2->y, viewx, viewy, portal->v1->x, portal->v1->y, dummyx, dummyy); - bool infront2 = P_IntersectLines(line->v1->x, line->v1->y, line->v2->x, line->v2->y, viewx, viewy, portal->v2->x, portal->v2->y, dummyx, dummyy); - if (infront1 && infront2) - return true; + // The line is parallel to the portal and cannot possibly be visible. + return true; } + // If one point lies on the same straight line than the portal, the other vertex will determine sidedness alone. + else if (behind2 == 0) behind2 = behind1; + else if (behind1 == 0) behind1 = behind2; - return false; + if (behind1 > 0 && behind2 > 0) + { + // The line is behind the portal, i.e. between viewer and portal line, and must be rejected + return true; + } + else if (behind1 < 0 && behind2 < 0) + { + // The line is in front of the portal, i.e. the portal is between viewer and line. This line must not be rejected + return false; + } + else + { + // The line intersects with the portal straight, so we need to do another check to see how both ends of the portal lie in relation to the viewer. + int viewside = P_PointOnLineSidePrecise(viewx, viewy, line); + int p1side = P_GetLineSide(portal->v1->x, portal->v1->y, line); + int p2side = P_GetLineSide(portal->v2->x, portal->v2->y, line); + // Do the same handling of points on the portal straight than above. + if (p1side == 0) p1side = p2side; + else if (p2side == 0) p2side = p1side; + p1side = p1side > 0; + p2side = p2side > 0; + // If the portal is on the other side of the line than the viewpoint, there is no possibility to see this line inside the portal. + return (p1side == p2side && viewside != p1side); + } } //============================================================================