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); + } } //============================================================================