- decal utilities

This commit is contained in:
Christoph Oelckers 2022-06-20 15:28:20 +02:00
parent 30b81c0920
commit 352047cfca
2 changed files with 173 additions and 3 deletions

View file

@ -354,7 +354,21 @@ inline double SquareDist(double lx1, double ly1, double lx2, double ly2)
return dx * dx + dy * dy;
}
inline DVector2 NearestPointLine(double px, double py, const walltype* wal)
inline double PointDistOnLine(double px, double py, const walltype* wal)
{
double lx1 = wal->pos.X;
double ly1 = wal->pos.Y;
double lx2 = wal->point2Wall()->pos.X;
double ly2 = wal->point2Wall()->pos.Y;
double wall_length = SquareDist(lx1, ly1, lx2, ly2);
if (wall_length == 0) return 0.;
return ((px - lx1) * (lx2 - lx1) + (py - ly1) * (ly2 - ly1)) / wall_length;
}
inline DVector2 NearestPointOnLine(double px, double py, const walltype* wal)
{
double lx1 = wal->pos.X;
double ly1 = wal->pos.Y;

View file

@ -42,6 +42,162 @@
DCoreActor* wall_to_sprite_actors[8]; // gets updated each frame. Todo: Encapsulate this better without having to permanently store actors in the wall object.
static walltype* PrevColinearWall(walltype* nnwall)
{
const int maxangdelta = 1;
auto d = nnwall->delta();
int nwalang = getangle(d.X, d.Y);
walltype* best = nullptr;
auto sect = nnwall->sectorp();
// Check the chain of next walls.
auto nw = nnwall;
nnwall = nullptr;
vertexscan(nw, [&](walltype* nwal)
{
// We are only interested in walls from other sectors
if (nwal->sectorp() != sect)
{
nwal = nwal->lastWall();
if (!nwal || nwal->sectorp() == sect) return; // this can happen on malformed maps.
auto d = nwal->delta();
int walang = getangle(d.X, d.Y);
int deltaang = abs((((walang - nwalang) & 2047) << 21) >> 21);
if (deltaang >= -maxangdelta && deltaang <= maxangdelta)
{
best = nwal;
}
}
});
return best;
}
static walltype* NextColinearWall(walltype* nnwall)
{
const int maxangdelta = 1;
auto d = nnwall->delta();
int nwalang = getangle(d.X, d.Y);
walltype* best = nullptr;
auto sect = nnwall->sectorp();
// Check the chain of next walls.
auto nw = nnwall->point2Wall();
nnwall = nullptr;
vertexscan(nw, [&](walltype* nwal)
{
// We are only interested in walls from other sectors
if (nwal->sectorp() != sect)
{
auto d = nwal->delta();
int walang = getangle(d.X, d.Y);
int deltaang = abs((((walang - nwalang) & 2047) << 21) >> 21);
if (deltaang >= -maxangdelta && deltaang <= maxangdelta)
{
best = nwal;
}
}
});
return best;
}
//==========================================================================
//
//
//
//==========================================================================
static walltype* FindWallSpriteWall(tspritetype* tspr, int height, DVector2& outpos)
{
const double maxorthdist = 3 * maptoworld; // maximum orthogonal distance to be considered an attached sprite.
const double maxdistsq = maxorthdist * maxorthdist;
const int maxangdelta = 1;
walltype* best = nullptr;
auto sect = tspr->sectp;
float tx = tspr->pos.X * (float)inttoworld;
float ty = tspr->pos.Y * (float)inttoworld;
for(auto& wal : wallsofsector(sect))
{
// Intentionally include two sided walls. Even on them the sprite should be projected onto the wall for better results.
auto d = wal.delta();
int walang = getangle(d.X, d.Y);
int deltaang = abs((((walang - tspr->ang) & 2047) << 21) >> 21);
// angle of the sprite must either be the wall's normal or the negative wall's normal to be aligned.
if (deltaang >= 512 - maxangdelta && deltaang <= 512 + maxangdelta)
{
double wdist = SquareDistToWall(tx, ty, &wal, &outpos);
if (wdist <= maxdistsq)
{
return &wal;
}
}
if (d.X != 0 && d.Y != 0)
return nullptr;
}
// no wall was found where this sprite could be attached to.
// now check some adjacent walls to account for a type of mapping bug where wall sprites are badly placed
for(auto& wal : wallsofsector(sect))
{
// Intentionally include two sided walls. Even on them the sprite should be projected onto the wall for better results.
auto d = wal.delta();
int walang = getangle(d.X, d.Y);
int deltaang = abs((((walang - tspr->ang) & 2047) << 21) >> 21);
// angle of the sprite must either be the wall's normal or the negative wall's normal to be aligned.
if (deltaang >= 512 - maxangdelta && deltaang <= 512 + maxangdelta)
{
bool found = false;
// orthogonal lines do not check the actual position so that certain off-sector sprites get handled properly.
// In Wanton Destruction's airplane level there's such a sprite assigned to the wrong sector.
if (d.X == 0)
{
double newdist = fabs(tx - wal.pos.X);
found = (newdist < maxorthdist);
}
else if (d.Y == 0)
{
double newdist = fabs(ty - wal.pos.Y);
found = (newdist < maxorthdist);
}
if (found)
{
// Check the chain of next walls.
walltype *nnwall = &wal;
while (auto nwal = NextColinearWall(nnwall))
{
double wdist = SquareDistToWall(tx, ty, nwal, &outpos);
if (wdist <= maxdistsq)
return nwal;
else
nnwall = nwal;
}
// Check the chain of next walls.
nnwall = &wal;
while (auto nwal = PrevColinearWall(nnwall))
{
double wdist = SquareDistToWall(tx, ty, nwal, &outpos);
if (wdist <= maxdistsq)
return nwal;
else
nnwall = nwal;
}
}
}
}
return best;
}
//==========================================================================
//
//
@ -1175,8 +1331,8 @@ void HWWall::ProcessWallSprite(HWDrawInfo* di, tspritetype* spr, sectortype* sec
if (walldist)
{
// project the sprite right onto the wall.
auto v1 = NearestPointLine(glseg.x1, -glseg.y1, walldist);
auto v2 = NearestPointLine(glseg.x2, -glseg.y2, walldist);
auto v1 = NearestPointOnLine(glseg.x1, -glseg.y1, walldist);
auto v2 = NearestPointOnLine(glseg.x2, -glseg.y2, walldist);
glseg.x1 = v1.X;
glseg.y1 = -v1.Y;
glseg.x2 = v2.X;