- pushmove rewritten.

This commit is contained in:
Christoph Oelckers 2022-10-13 16:34:10 +02:00
parent 830ded6e87
commit 2190499d63
5 changed files with 86 additions and 162 deletions

View file

@ -639,8 +639,10 @@ CollisionBase clipmove_(vec3_t * const pos, int * const sectnum, int32_t xvect,
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
{
DVector2 v(vec.X* inttoworld, vec.Y* inttoworld);
clipupdatesector(v, sectnum, rad * inttoworld, clipsectormap);
DVector3 v(vec.X* inttoworld, vec.Y* inttoworld, 0);
sectortype* sect = &sector[*sectnum];
updatesectorneighbor(v, &sect, rad * inttoworld);
*sectnum = ::sectnum(sect);
}
pos->X = vec.X;
@ -697,93 +699,3 @@ CollisionBase clipmove_(vec3_t * const pos, int * const sectnum, int32_t xvect,
}
//
// pushmove
//
int pushmove_(vec3_t *const vect, int *const sectnum,
int32_t const walldist, int32_t const ceildist, int32_t const flordist, uint32_t const cliptype, bool clear /*= true*/)
{
int bad;
const int32_t dawalclipmask = (cliptype&65535);
// const int32_t dasprclipmask = (cliptype >> 16);
if (*sectnum < 0)
return -1;
int32_t k = 32;
int dir = 1;
do
{
int32_t clipsectcnt = 0;
bad = 0;
if (clear)
{
if (enginecompatibility_mode != ENGINECOMPATIBILITY_NONE && *sectnum < 0)
return 0;
clipsectorlist[0] = *sectnum;
clipsectnum = 1;
clipsectormap.Zero();
clipsectormap.Set(*sectnum);
}
do
{
const walltype* wal;
int32_t startwall, endwall;
auto sec = &sector[clipsectorlist[clipsectcnt]];
if (dir > 0)
startwall = sec->wallptr, endwall = startwall + sec->wallnum;
else
endwall = sec->wallptr, startwall = endwall + sec->wallnum - 1;
int i;
for (i=startwall, wal=&wall[startwall]; i!=endwall; i+=dir, wal+=dir)
if (IsCloseToWall(DVector2(vect->X * inttoworld, vect->Y * inttoworld), &wall[i], (walldist-4) * inttoworld) == EClose::InFront)
{
int j = 0;
if (wal->nextsector < 0 || wal->cstat & EWallFlags::FromInt(dawalclipmask)) j = 1;
else
{
auto pvect = NearestPointOnWall(vect->X * inttoworld, vect->Y * inttoworld, wal);
vec2_t closest = { int(pvect.X * worldtoint), int(pvect.Y * worldtoint) };
j = cliptestsector(clipsectorlist[clipsectcnt], wal->nextsector, flordist, ceildist, closest, vect->Z);
}
if (j != 0)
{
DAngle jj = wal->delta().Angle();
int32_t dx = -int(jj.Sin() * 8);
int32_t dy = int(jj.Cos() * 8);
int bad2 = 16;
do
{
vect->X = (vect->X) + dx; vect->Y = (vect->Y) + dy;
bad2--; if (bad2 == 0) break;
} while (IsCloseToWall(DVector2(vect->X * inttoworld, vect->Y * inttoworld), &wall[i], (walldist - 4) * inttoworld) != EClose::Outside);
bad = -1;
k--; if (k <= 0) return bad;
DVector2 v(vect->vec2.X * inttoworld, vect->vec2.Y * inttoworld);
clipupdatesector(v, sectnum, walldist * inttoworld, clipsectormap);
if (*sectnum < 0) return -1;
}
else if (!clipsectormap[wal->nextsector])
addclipsect(wal->nextsector);
}
clipsectcnt++;
} while (clipsectcnt < clipsectnum);
dir = -dir;
} while (bad != 0);
return bad;
}

View file

@ -447,19 +447,6 @@ inline int clipmove(DVector3& pos, sectortype** const sect, const DVector2& mvec
return result.type;
}
inline int pushmove(DVector3& pos, sectortype** const sect, double const walldist, double const ceildist, double const flordist,
uint32_t const cliptype, bool clear = true)
{
auto vect = vec3_t(int(pos.X * worldtoint), int(pos.Y * worldtoint), int(pos.Z * zworldtoint));
int sectno = *sect ? sector.IndexOf(*sect) : -1;
int res = pushmove_(&vect, &sectno, int(walldist * worldtoint), int(ceildist * zworldtoint), int(flordist * zworldtoint), cliptype, clear);
pos = { vect.X * inttoworld, vect.Y * inttoworld, vect.Z * zinttoworld };
*sect = sectno == -1 ? nullptr : &sector[sectno];
return res;
}
tspritetype* renderAddTsprite(tspriteArray& tsprites, DCoreActor* actor);
inline PClassActor* PClass::FindActor(FName name)
{

View file

@ -1177,6 +1177,84 @@ void neartag(const DVector3& pos, sectortype* startsect, DAngle angle, HitInfoBa
}
}
//==========================================================================
//
//
//
//==========================================================================
bool checkOpening(const DVector3& pos, const sectortype* sec, const sectortype* nextsec, double ceilingdist, double floordist)
{
double c1, c2, f1, f2;
calcSlope(sec, pos.X, pos.Y, &c1, &f1);
calcSlope(nextsec, pos.X, pos.Y, &c2, &f2);
return ((f2 < f1 - 1 && (nextsec->floorstat & CSTAT_SECTOR_SKY) == 0 && pos.Z >= f2 - (floordist - zmaptoworld)) ||
(c2 > c1 + 1 && (nextsec->ceilingstat & CSTAT_SECTOR_SKY) == 0 && pos.Z <= c2 + (ceilingdist - zmaptoworld)));
}
//==========================================================================
//
//
//
//==========================================================================
int pushmove(DVector3& pos, sectortype** pSect, double walldist, double ceildist, double floordist, unsigned cliptype)
{
auto wallflags = EWallFlags::FromInt(cliptype & 65535);
int maxhitwalls = 0;
bool pushed = true;
for(int direction = 1; pushed; direction = -direction)
{
pushed = false;
if (*pSect == nullptr)
return -1;
BFSSectorSearch search(*pSect);
while (auto sec = search.GetNext())
{
// this must go both forward and backward so we cannot use wallsofsector. Pity
for (int i = 0; i < sec->wallnum; i++)
{
auto wal = direction > 0 ? sec->firstWall() + i : sec->lastWall() - i;
if (IsCloseToWall(pos.XY(), wal, walldist - 0.25) == EClose::InFront)
{
bool blocked = false;
if (!wal->twoSided() || wal->cstat & wallflags) blocked = true;
else
{
auto pvect = NearestPointOnWall(pos.X, pos.Y, wal);
blocked = checkOpening(DVector3(pvect, pos.Z), sec, wal->nextSector(), ceildist, floordist);
}
if (blocked)
{
auto dv = wal->delta().Rotated90CCW().Unit() * 0.5;
for (int t = 0; t < 16; t++)
{
pos += dv;
if (IsCloseToWall(pos, wal, (walldist - 0.25)) == EClose::Outside) break;
}
pushed = true;
updatesector(pos, pSect);
if (++maxhitwalls >= 32) return -1;
if (*pSect == nullptr) return -1;
}
else
search.Add(wal->nextSector());
}
}
}
if (!pushed) return 0;
}
return -1;
}
//==========================================================================
//
//

View file

@ -264,6 +264,9 @@ bool checkRangeOfWallSprite(DCoreActor* itActor, const DVector3& pos, double max
bool checkRangeOfFloorSprite(DCoreActor* itActor, const DVector3& pos, double maxdist, double& theZ);
void getzrange(const DVector3& pos, sectortype* sect, double* ceilz, CollisionBase& ceilhit, double* florz, CollisionBase& florhit, double walldist, uint32_t cliptype);
int pushmove(DVector3& pos, sectortype** pSect, double walldist, double ceildist, double flordist, unsigned cliptype);
tspritetype* renderAddTsprite(tspriteArray& tsprites, DCoreActor* actor);

View file

@ -61,7 +61,7 @@ void DoUpdateSector(double x, double y, double z, int* sectnum, double maxDistan
for (auto& wal : wallsofsector(lsect))
{
if (wal.twoSided() && !search.Check(wal.nextsector) && (iter == 0 || SquareDistToSector(x, y, wal.nextSector()) <= maxDistSq))
if (wal.twoSided() && !search.Check(wal.nextsector) && (iter == 0 || SquareDistToWall(x, y, &wal) <= maxDistSq))
search.Add(wal.nextsector);
}
iter++;
@ -118,59 +118,3 @@ inline void updatesector(int x_, int y_, int* sectnum)
DoUpdateSector(x, y, 0, sectnum, MAXUPDATESECTORDIST, inside0);
}
// clipmove uses this. It's really just two loops nearly identical to DoUpdateSector with different checking conditions.
inline void clipupdatesector(const DVector2& pos, int* const sectnum, double walldist, BitArray& sectormap)
{
assert(*sectnum >= 0);
sectortype* sect = &sector[*sectnum];
if (inside(pos.X, pos.Y, sect))
return;
double sdist = SquareDistToSector(pos.X, pos.Y, sect);
double wd = (walldist + 8);
wd *= wd;
if (sdist > wd)
{
wd = 2048 * 2048;
}
{
BFSSearch search(sector.Size(), *sectnum);
for (unsigned secnum; (secnum = search.GetNext()) != BFSSearch::EOL;)
{
if (inside(pos.X, pos.Y, &sector[secnum]))
{
*sectnum = secnum;
return;
}
for (auto& wal : wallsofsector(secnum))
{
if (wal.twoSided() && sectormap[wal.nextsector])
search.Add(wal.nextsector);
}
}
}
{
BFSSearch search(sector.Size(), *sectnum);
for (unsigned secnum; (secnum = search.GetNext()) != BFSSearch::EOL;)
{
if (inside(pos.X, pos.Y, &sector[secnum]))
{
*sectnum = secnum;
return;
}
for (auto& wal : wallsofsector(secnum))
{
if (wal.twoSided() && SquareDistToWall(pos.X, pos.Y, &wal) < wd)
search.Add(wal.nextsector);
}
}
}
*sectnum = -1;
}