From 9b8252e2daab1908d231d790600c63b4f3704cb0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 22 Oct 2022 23:12:29 +0200 Subject: [PATCH] - reimplemented the wall collision check for clipmove. --- source/build/src/clip.cpp | 53 +++++++++++++++++--------------- source/common/utility/geometry.h | 8 +++++ source/core/gamefuncs.cpp | 32 +++++++++++++++++++ source/core/gamefuncs.h | 17 ++++++++++ 4 files changed, 85 insertions(+), 25 deletions(-) diff --git a/source/build/src/clip.cpp b/source/build/src/clip.cpp index 9abcbd157..dc06a47e8 100644 --- a/source/build/src/clip.cpp +++ b/source/build/src/clip.cpp @@ -221,8 +221,6 @@ CollisionBase clipmove_(vec3_t * const pos, int * const sectnum, int32_t xvect, if ((xvect|yvect) == 0 || *sectnum < 0) return b; - DCoreActor* curspr=NULL; // non-NULL when handling sprite with sector-like clipping - int const initialsectnum = *sectnum; int32_t const dawalclipmask = (cliptype & 65535); // CLIPMASK0 = 0x00010001 (in desperate need of getting fixed!) @@ -237,6 +235,16 @@ CollisionBase clipmove_(vec3_t * const pos, int * const sectnum, int32_t xvect, int32_t const rad = ksqrt((int64_t)diff.X * diff.X + (int64_t)diff.Y * diff.Y) + MAXCLIPDIST + walldist + 8; vec2_t const clipMin = { cent.X - rad, cent.Y - rad }; vec2_t const clipMax = { cent.X + rad, cent.Y + rad }; + + MoveClipper clip; + + clip.moveDelta = { (xvect >> 14) * inttoworld, (yvect >> 14) * inttoworld }; // beware of excess precision here! + clip.rect.min = { clipMin.X * inttoworld, clipMin.Y * inttoworld }; + clip.rect.max = { clipMax.X * inttoworld, clipMax.Y * inttoworld }; + clip.wallflags = EWallFlags::FromInt(dawalclipmask); + clip.ceilingdist = ceildist * zinttoworld; + clip.floordist = flordist * zinttoworld; + clip.walldist = walldist * inttoworld; int clipsectcnt = 0; int clipspritecnt = 0; @@ -255,33 +263,44 @@ CollisionBase clipmove_(vec3_t * const pos, int * const sectnum, int32_t xvect, do { int const dasect = clipsectorlist[clipsectcnt++]; - //if (curspr) - // Printf("sprite %d/%d: sect %d/%d (%d)\n", clipspritecnt,clipspritenum, clipsectcnt,clipsectnum,dasect); - + ////////// Walls ////////// auto const sec = §or[dasect]; for (auto& wal : sec->walls) { + clip.pos = { pos->X * inttoworld, pos->Y * inttoworld, pos->Z * zinttoworld}; + + int clipyou2 = checkClipWall(clip, &wal); + auto const wal2 = wal.point2Wall(); vec2_t p1 = wal.wall_int_pos(); vec2_t p2 = wal2->wall_int_pos(); if ((p1.X < clipMin.X && p2.X < clipMin.X) || (p1.X > clipMax.X && p2.X > clipMax.X) || (p1.Y < clipMin.Y && p2.Y < clipMin.Y) || (p1.Y > clipMax.Y && p2.Y > clipMax.Y)) + { + assert(clipyou2 != 1); continue; + } vec2_t d = { p2.X-p1.X, p2.Y-p1.Y }; if (d.X * (pos->Y-p1.Y) < (pos->X-p1.X) * d.Y) - continue; //If wall's not facing you + { + assert(clipyou2 != 1); + continue; + } vec2_t const r = { (d.Y > 0) ? clipMax.X : clipMin.X, (d.X > 0) ? clipMin.Y : clipMax.Y }; vec2_t v = { d.X * (r.Y - p1.Y), d.Y * (r.X - p1.X) }; if (v.X >= v.Y) + { + assert(clipyou2 != 1); continue; + } int clipyou = 0; @@ -297,31 +316,14 @@ CollisionBase clipmove_(vec3_t * const pos, int * const sectnum, int32_t xvect, ceildist * zinttoworld, flordist * zinttoworld, enginecompatibility_mode == ENGINECOMPATIBILITY_NONE); v.X = int(ipos.X * worldtoint); v.Y = int(ipos.Y * worldtoint); - } - // We're not interested in any sector reached by portal traversal that we're "inside" of. - if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE && !curspr && dasect != initialsectnum - && inside(pos->X * inttoworld, pos->Y * inttoworld, sec) == 1) - { - bool found = false; - for (auto& wwal : sec->walls) - { - if (wwal.nextsector == initialsectnum) - { - found = true; - break; - } - } - if (!found) - break; - } + assert(clipyou == clipyou2); if (clipyou) { CollisionBase objtype; - if (curspr) objtype.setSprite(curspr); - else objtype.setWall(&wal); + objtype.setWall(&wal); //Add 2 boxes at endpoints int32_t bsz = walldist; if (diff.X < 0) bsz = -bsz; @@ -331,6 +333,7 @@ CollisionBase clipmove_(vec3_t * const pos, int * const sectnum, int32_t xvect, addclipline(p1.X+bsz, p1.Y-bsz, p1.X-bsz, p1.Y-bsz, objtype, false); addclipline(p2.X+bsz, p2.Y-bsz, p2.X-bsz, p2.Y-bsz, objtype, false); + vec2_t v; v.X = walldist; if (d.Y > 0) v.X = -v.X; v.Y = walldist; if (d.X < 0) v.Y = -v.Y; diff --git a/source/common/utility/geometry.h b/source/common/utility/geometry.h index 3a7bb8d9c..6e22cb031 100644 --- a/source/common/utility/geometry.h +++ b/source/common/utility/geometry.h @@ -232,3 +232,11 @@ inline bool BoxInRange(const DVector2& boxtl, const DVector2& boxbr, const DVect boxtl.Y < max(start.Y, end.Y) && boxbr.Y > min(start.Y, end.Y); } + +inline bool BoxInRange2(const DVector2& boxtl, const DVector2& boxbr, const DVector2& start, const DVector2& end) +{ + return boxtl.X <= max(start.X, end.X) && + boxbr.X >= min(start.X, end.X) && + boxtl.Y <= max(start.Y, end.Y) && + boxbr.Y >= min(start.Y, end.Y); +} diff --git a/source/core/gamefuncs.cpp b/source/core/gamefuncs.cpp index af5b231f5..b71280983 100644 --- a/source/core/gamefuncs.cpp +++ b/source/core/gamefuncs.cpp @@ -1230,6 +1230,38 @@ int pushmove(DVector3& pos, sectortype** pSect, double walldist, double ceildist // //========================================================================== +int checkClipWall(const MoveClipper& clip, walltype* wal) +{ + auto wal2 = wal->point2Wall(); + auto waldelta = wal->delta(); + + // out of reach? + if (!BoxInRange2(clip.rect.min, clip.rect.max, wal->pos, wal2->pos)) return -1; + + // facing back side? + if (PointOnLineSide(clip.pos.XY(), wal) > 0) return -1; + + // do we touch it? + if (BoxOnLineSide(clip.rect.min, clip.rect.max, wal->pos, waldelta) != -1) return -1; + + if (!wal->twoSided() || (wal->cstat & clip.wallflags)) + return 1; + else + { + DVector2 intersect; + double factor = InterceptLineSegments(clip.pos.X, clip.pos.Y, clip.moveDelta.X, clip.moveDelta.Y, wal->pos.X, wal->pos.Y, waldelta.X, waldelta.Y); + if (factor < 0) intersect = clip.pos.XY(); + else intersect = clip.pos.XY() + clip.moveDelta * factor; + return checkOpening(intersect, clip.pos.Z, wal->sectorp(), wal->nextSector(), clip.ceilingdist, clip.floordist); + } +} + +//========================================================================== +// +// +// +//========================================================================== + int FindBestSector(const DVector3& pos) { int bestnum = -1; diff --git a/source/core/gamefuncs.h b/source/core/gamefuncs.h index 8b0190f5a..4f9e51183 100644 --- a/source/core/gamefuncs.h +++ b/source/core/gamefuncs.h @@ -234,8 +234,25 @@ inline int pushmove(DVector2& pos, double z, sectortype** pSect, double walldist pos = vect.XY(); return result; } +struct ClipRect +{ + DVector2 min; + DVector2 max; +}; +struct MoveClipper +{ + DVector3 pos; + DVector2 pest; + DVector2 moveDelta; + ClipRect rect; + EWallFlags wallflags; + double ceilingdist; + double floordist; + double walldist; +}; +int checkClipWall(const MoveClipper& clip, walltype* wal); int FindBestSector(const DVector3& pos);