- wall sprite WIP.

This commit is contained in:
Christoph Oelckers 2021-03-27 13:22:34 +01:00
parent 1dfb2672a8
commit d0f38d7362
10 changed files with 243 additions and 186 deletions

View File

@ -208,13 +208,26 @@ void PlanesAtPoint(const sectortype* sec, float dax, float day, float* pceilz, f
//
//==========================================================================
void GetWallSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out)
void GetWallSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out, bool render)
{
auto tex = tileGetTexture(spr->picnum);
int width, leftofs;
if (render && hw_hightile && TileFiles.tiledata[spr->picnum].h_xsize)
{
width = TileFiles.tiledata[spr->picnum].h_xsize * spr->xrepeat;
leftofs = (TileFiles.tiledata[spr->picnum].h_xoffs + spr->xoffset) * spr->xrepeat;
}
else
{
width = tex->GetTexelWidth() * spr->xrepeat;
leftofs = (tex->GetTexelLeftOffset() + spr->xoffset) * spr->xrepeat;
}
int x = bsin(spr->ang) * spr->xrepeat;
int y = -bcos(spr->ang) * spr->xrepeat;
int width = tileWidth(spr->picnum);
int xoff = tileLeftOffset(spr->picnum) + spr->xoffset;
int xoff = leftofs + spr->xoffset;
if (spr->cstat & CSTAT_SPRITE_XFLIP) xoff = -xoff;
int origin = (width >> 1) + xoff;
@ -235,19 +248,21 @@ void GetFlatSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out, bool
{
auto tex = tileGetTexture(spr->picnum);
int width, height;
int width, height, leftofs, topofs;
if (render && hw_hightile && TileFiles.tiledata[spr->picnum].h_xsize)
{
width = TileFiles.tiledata[spr->picnum].h_xsize * spr->xrepeat;
height = TileFiles.tiledata[spr->picnum].h_ysize * spr->yrepeat;
leftofs = (TileFiles.tiledata[spr->picnum].h_xoffs + spr->xoffset) * spr->xrepeat;
topofs = (TileFiles.tiledata[spr->picnum].h_yoffs + spr->yoffset) * spr->yrepeat;
}
else
{
width = tex->GetTexelWidth() * spr->xrepeat;
height = tex->GetTexelHeight() * spr->yrepeat;
leftofs = (tex->GetTexelLeftOffset() + spr->xoffset) * spr->xrepeat;
topofs = (tex->GetTexelTopOffset() + spr->yoffset) * spr->yrepeat;
}
int leftofs = (tex->GetTexelLeftOffset() + spr->xoffset) * spr->xrepeat;
int topofs = (tex->GetTexelTopOffset() + spr->yoffset) * spr->yrepeat;
if (spr->cstat & CSTAT_SPRITE_XFLIP) leftofs = -leftofs;
if (spr->cstat & CSTAT_SPRITE_YFLIP) topofs = -topofs;

View File

@ -10,7 +10,7 @@ bool calcChaseCamPos(int* px, int* py, int* pz, spritetype* pspr, short *psectnu
bool spriteIsModelOrVoxel(const spritetype* tspr);
void PlanesAtPoint(const sectortype* sec, float dax, float day, float* ceilz, float* florz);
void setWallSectors();
void GetWallSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out);
void GetWallSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out, bool render = false);
void GetFlatSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out, bool render = false);
void checkRotatedWalls();

View File

@ -346,8 +346,11 @@ void HWDrawInfo::DispatchSprites()
break;
case CSTAT_SPRITE_ALIGNMENT_WALL:
// wall sprite
{
HWWall wall;
wall.ProcessWallSprite(this, tspr, &sector[tspr->sectnum]);
break;
}
case CSTAT_SPRITE_ALIGNMENT_FLOOR:
{
@ -445,20 +448,32 @@ void HWDrawInfo::RenderScene(FRenderState &state)
// These lists must be drawn in two passes for color and depth to avoid depth fighting with overlapping entries
drawlists[GLDL_MASKEDFLATS].SortFlats(this);
//drawlists[GLDL_MASKEDWALLSV].SortWalls(this);
//drawlists[GLDL_MASKEDWALLSH].SortWalls(this);
drawlists[GLDL_MASKEDWALLSV].SortWallsVert(this);
drawlists[GLDL_MASKEDWALLSH].SortWallsHorz(this);
// these lists are only wall and floor sprites - often attached to walls and floors - so they need to be offset from the plane they may be attached to.
drawlists[GLDL_MASKEDWALLSS].DrawWalls(this, state, false);
// Each list must draw both its passes before the next one to ensure proper depth buffer contents.
state.SetDepthBias(-1, -128);
state.SetDepthMask(false);
drawlists[GLDL_MASKEDWALLSV].DrawWalls(this, state, false);
drawlists[GLDL_MASKEDWALLSH].DrawWalls(this, state, false);
drawlists[GLDL_MASKEDFLATS].DrawFlats(this, state, false);
state.SetDepthMask(true);
state.SetColorMask(false);
drawlists[GLDL_MASKEDWALLSV].DrawWalls(this, state, false);
state.SetColorMask(true);
state.SetDepthMask(false);
drawlists[GLDL_MASKEDWALLSH].DrawWalls(this, state, false);
state.SetDepthMask(true);
state.SetColorMask(false);
drawlists[GLDL_MASKEDWALLSH].DrawWalls(this, state, false);
state.SetColorMask(true);
state.SetDepthMask(false);
drawlists[GLDL_MASKEDFLATS].DrawFlats(this, state, false);
state.SetDepthMask(true);
state.SetColorMask(false);
drawlists[GLDL_MASKEDFLATS].DrawFlats(this, state, false);
state.SetColorMask(true);
state.ClearDepthBias();

View File

@ -76,7 +76,6 @@ enum DrawListType
GLDL_MASKEDWALLSV, // vertical wall sprites
GLDL_MASKEDWALLSH, // horizontal wall sprites. These two lists merely exist for easier sorting.
GLDL_MASKEDFLATS,
GLDL_MASKEDWALLSOFS,
GLDL_MODELS,
GLDL_TRANSLUCENT,

View File

@ -703,26 +703,104 @@ void HWDrawList::Sort(HWDrawInfo *di)
//==========================================================================
//
// Sorting the drawitems first by texture and then by light level
//
//
//==========================================================================
void HWDrawList::SortWalls()
void HWDrawList::SortWallsVert(HWDrawInfo* di)
{
auto viewy = di->Viewpoint.Pos.Y;
if (drawitems.Size() > 1)
{
std::sort(drawitems.begin(), drawitems.end(), [=](const HWDrawItem &a, const HWDrawItem &b) -> bool
TArray<HWDrawItem> list1(drawitems.Size(), false);
TArray<HWDrawItem> list2(drawitems.Size(), false);
for (auto& item : drawitems)
{
HWWall * w1 = walls[a.index];
HWWall * w2 = walls[b.index];
HWWall* w1 = walls[item.index];
if (w1->glseg.y1 < viewy) list1.Push(item);
else list2.Push(item);
}
if (w1->texture != w2->texture) return w1->texture < w2->texture;
return (w1->flags & 3) < (w2->flags & 3);
std::sort(list1.begin(), list1.end(), [=](const HWDrawItem& a, const HWDrawItem& b)
{
HWWall* w1 = walls[a.index];
HWWall* w2 = walls[b.index];
if (w1->glseg.y1 != w2->glseg.y1) return w1->glseg.y1 < w2->glseg.y1;
int time1 = w1->sprite ? w1->sprite->time : -1;
int time2 = w2->sprite ? w2->sprite->time : -1;
return time1 < time2;
});
});
std::sort(list2.begin(), list2.end(), [=](const HWDrawItem& a, const HWDrawItem& b)
{
HWWall* w1 = walls[a.index];
HWWall* w2 = walls[b.index];
if (w1->glseg.y1 != w2->glseg.y1) return w1->glseg.y1 > w2->glseg.y1;
int time1 = w1->sprite ? w1->sprite->time : -1;
int time2 = w2->sprite ? w2->sprite->time : -1;
return time1 < time2;
});
drawitems.Clear();
drawitems.Append(list1);
drawitems.Append(list2);
}
}
//==========================================================================
//
//
//
//==========================================================================
void HWDrawList::SortWallsHorz(HWDrawInfo* di)
{
auto viewx = di->Viewpoint.Pos.X;
if (drawitems.Size() > 1)
{
TArray<HWDrawItem> list1(drawitems.Size(), false);
TArray<HWDrawItem> list2(drawitems.Size(), false);
for (auto& item : drawitems)
{
HWWall* w1 = walls[item.index];
if (w1->glseg.x1 < viewx) list1.Push(item);
else list2.Push(item);
}
std::sort(list1.begin(), list1.end(), [=](const HWDrawItem& a, const HWDrawItem& b)
{
HWWall* w1 = walls[a.index];
HWWall* w2 = walls[b.index];
if (w1->glseg.x1 != w2->glseg.x1) return w1->glseg.x1 < w2->glseg.x1;
int time1 = w1->sprite ? w1->sprite->time : -1;
int time2 = w2->sprite ? w2->sprite->time : -1;
return time1 < time2;
});
std::sort(list2.begin(), list2.end(), [=](const HWDrawItem& a, const HWDrawItem& b)
{
HWWall* w1 = walls[a.index];
HWWall* w2 = walls[b.index];
if (w1->glseg.x1 != w2->glseg.x1) return w1->glseg.x1 > w2->glseg.x1;
int time1 = w1->sprite ? w1->sprite->time : -1;
int time2 = w2->sprite ? w2->sprite->time : -1;
return time1 < time2;
});
drawitems.Clear();
drawitems.Append(list1);
drawitems.Append(list2);
}
}
//==========================================================================
//
//
//
//==========================================================================
void HWDrawList::SortFlats(HWDrawInfo* di)
{
auto viewz = di->Viewpoint.Pos.Z;

View File

@ -92,7 +92,8 @@ public:
HWFlat *NewFlat();
HWSprite *NewSprite();
void Reset();
void SortWalls();
void SortWallsHorz(HWDrawInfo* di);
void SortWallsVert(HWDrawInfo* di);
void SortFlats(HWDrawInfo* di);

View File

@ -50,14 +50,11 @@ void HWDrawInfo::AddWall(HWWall *wall)
bool masked = wall->type != RENDERWALL_M2S ? false : (wall->texture && wall->texture->isMasked());
int list;
if (wall->flags & HWWall::HWF_SKYHACK && wall->type == RENDERWALL_M2S)
{
list = GLDL_MASKEDWALLSOFS;
}
else
{
list = masked ? GLDL_MASKEDWALLS : GLDL_PLAINWALLS;
}
if (!masked) list = GLDL_PLAINWALLS;
else if (sprite == nullptr) list = GLDL_MASKEDWALLS;
else if (wall->glseg.x1 == wall->glseg.x2) list = GLDL_MASKEDWALLSV;
else if (wall->glseg.y1 == wall->glseg.y2) list = GLDL_MASKEDWALLSH;
else list = GLDL_MASKEDWALLSS;
auto newwall = drawlists[list].NewWall();
*newwall = *wall;
}

View File

@ -230,7 +230,7 @@ public:
public:
void Process(HWDrawInfo* di, walltype* seg, sectortype* frontsector, sectortype* backsector);
void ProcessWallSprite(HWDrawInfo* di, walltype* seg, sectortype* frontsector, sectortype* backsector);
void ProcessWallSprite(HWDrawInfo* di, spritetype* spr, sectortype* frontsector);
float PointOnSide(float x,float y)
{

View File

@ -149,161 +149,6 @@ void polymost_drawsprite(int32_t snum)
}
break;
case 1: // Wall sprite
{
// Project 3D to 2D
if (globalorientation & 4)
off.x = -off.x;
if (globalorientation & 8)
off.y = -off.y;
vec2f_t const extent = { float(tspr->xrepeat * bsinf(tspr->ang, -16)),
float(tspr->xrepeat * -bcosf(tspr->ang, -16)) };
float f = (float)(tsiz.x >> 1) + (float)off.x;
vec2f_t const vf = { extent.x * f, extent.y * f };
vec2f_t vec0 = { (float)(pos.x - globalposx) - vf.x,
(float)(pos.y - globalposy) - vf.y };
int32_t const s = tspr->owner;
int32_t walldist = 1;
int32_t w = (s == -1) ? -1 : wsprinfo[s].wall;
vec2f_t p0 = { vec0.y * gcosang - vec0.x * gsinang,
vec0.x * gcosang2 + vec0.y * gsinang2 };
vec2f_t const pp = { extent.x * ftsiz.x + vec0.x,
extent.y * ftsiz.x + vec0.y };
vec2f_t p1 = { pp.y * gcosang - pp.x * gsinang,
pp.x * gcosang2 + pp.y * gsinang2 };
if ((p0.y <= SCISDIST) && (p1.y <= SCISDIST))
goto _drawsprite_return;
// Clip to close parallel-screen plane
vec2f_t const op0 = p0;
float t0 = 0.f, t1 = 1.f;
if (p0.y < SCISDIST)
{
t0 = (SCISDIST - p0.y) / (p1.y - p0.y);
p0 = { (p1.x - p0.x) * t0 + p0.x, SCISDIST };
}
if (p1.y < SCISDIST)
{
t1 = (SCISDIST - op0.y) / (p1.y - op0.y);
p1 = { (p1.x - op0.x) * t1 + op0.x, SCISDIST };
}
f = 1.f / p0.y;
const float ryp0 = f * gyxscale;
float sx0 = ghalfx * p0.x * f + ghalfx;
f = 1.f / p1.y;
const float ryp1 = f * gyxscale;
float sx1 = ghalfx * p1.x * f + ghalfx;
pos.z -= ((off.y * tspr->yrepeat) << 2);
if (globalorientation & 128)
{
pos.z += ((tsiz.y * tspr->yrepeat) << 1);
if (tsiz.y & 1)
pos.z += (tspr->yrepeat << 1); // Odd yspans
}
xtex.d = (ryp0 - ryp1) * gxyaspect / (sx0 - sx1);
ytex.d = 0;
otex.d = ryp0 * gxyaspect - xtex.d * sx0;
if (globalorientation & 4)
{
t0 = 1.f - t0;
t1 = 1.f - t1;
}
xtex.u = (t0 * ryp0 - t1 * ryp1) * gxyaspect * ftsiz.x / (sx0 - sx1);
ytex.u = 0;
otex.u = t0 * ryp0 * gxyaspect * ftsiz.x - xtex.u * sx0;
f = ((float) tspr->yrepeat) * ftsiz.y * 4;
float sc0 = ((float) (pos.z - globalposz - f)) * ryp0 + ghoriz;
float sc1 = ((float) (pos.z - globalposz - f)) * ryp1 + ghoriz;
float sf0 = ((float) (pos.z - globalposz)) * ryp0 + ghoriz;
float sf1 = ((float) (pos.z - globalposz)) * ryp1 + ghoriz;
// gvx*sx0 + gvy*sc0 + gvo = 0
// gvx*sx1 + gvy*sc1 + gvo = 0
// gvx*sx0 + gvy*sf0 + gvo = tsizy*(gdx*sx0 + gdo)
f = ftsiz.y * (xtex.d * sx0 + otex.d) / ((sx0 - sx1) * (sc0 - sf0));
if (!(globalorientation & 8))
{
xtex.v = (sc0 - sc1) * f;
ytex.v = (sx1 - sx0) * f;
otex.v = -xtex.v * sx0 - ytex.v * sc0;
}
else
{
xtex.v = (sf1 - sf0) * f;
ytex.v = (sx0 - sx1) * f;
otex.v = -xtex.v * sx0 - ytex.v * sf0;
}
// Clip sprites to ceilings/floors when no parallaxing
if (!(sector[tspr->sectnum].ceilingstat & 1))
{
if (sector[tspr->sectnum].ceilingz > pos.z - (float)((tspr->yrepeat * tsiz.y) << 2))
{
sc0 = (float)(sector[tspr->sectnum].ceilingz - globalposz) * ryp0 + ghoriz;
sc1 = (float)(sector[tspr->sectnum].ceilingz - globalposz) * ryp1 + ghoriz;
}
}
if (!(sector[tspr->sectnum].floorstat & 1))
{
if (sector[tspr->sectnum].floorz < pos.z)
{
sf0 = (float)(sector[tspr->sectnum].floorz - globalposz) * ryp0 + ghoriz;
sf1 = (float)(sector[tspr->sectnum].floorz - globalposz) * ryp1 + ghoriz;
}
}
if (sx0 > sx1)
{
if (globalorientation & 64)
goto _drawsprite_return; // 1-sided sprite
std::swap(sx0, sx1);
std::swap(sc0, sc1);
std::swap(sf0, sf1);
}
vec2f_t const pxy[4] = { { sx0, sc0 }, { sx1, sc1 }, { sx1, sf1 }, { sx0, sf0 } };
vec2_16_t tempsiz = { (int16_t)tsiz.x, (int16_t)tsiz.y };
pow2xsplit = 0;
polymost_drawpoly(pxy, 4, method, tempsiz);
drawpoly_srepeat = 0;
drawpoly_trepeat = 0;
}
break;
case 2: // Floor sprite
else
break;
case 3: // Voxel sprite
break;
}
if (automapping == 1 && (unsigned)spritenum < MAXSPRITES)

View File

@ -1067,3 +1067,110 @@ void HWWall::Process(HWDrawInfo* di, walltype* wal, sectortype* frontsector, sec
globalr = globalg = globalb = 255;
}
void HWWall::ProcessWallSprite(HWDrawInfo* di, spritetype* spr, sectortype* sector)
{
auto tex = tileGetTexture(spr->picnum);
if (!tex || !tex->isValid()) return;
seg = nullptr;
sprite = spr;
vec2_t pos[2];
int sprz = spr->pos.z;
if (spr->cstat & CSTAT_SPRITE_ONE_SIDED)
{
DAngle sprang = buildang(spr->ang).asdeg();
DAngle lookang = bamang(di->Viewpoint.RotAngle).asdeg();
if ((sprang.ToVector() | lookang.ToVector()) >= 0.) return;
}
vertindex = 0;
vertcount = 0;
type = RENDERWALL_M2S;
frontsector = sector;
backsector = sector;
texture = tex;
flags = 0;
dynlightindex = -1;
shade = spr->shade;
palette = spr->pal;
fade = lookups.getFade(sector->floorpal); // fog is per sector.
visibility = sectorVisibility(sector);
bool trans = (sprite->cstat & CSTAT_SPRITE_TRANSLUCENT);
if (trans)
{
RenderStyle = GetRenderStyle(0, !!(sprite->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT));
alpha = GetAlphaFromBlend((sprite->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT) ? DAMETH_TRANS2 : DAMETH_TRANS1, 0);
}
else
{
RenderStyle = LegacyRenderStyles[STYLE_Translucent];
alpha = 1.f;
}
GetWallSpritePosition(spr, spr->pos.vec2, pos, true);
int height, topofs;
if (hw_hightile && TileFiles.tiledata[spr->picnum].h_xsize)
{
height = TileFiles.tiledata[spr->picnum].h_ysize;
topofs = (TileFiles.tiledata[spr->picnum].h_yoffs + spr->yoffset);
}
else
{
height = tex->GetTexelHeight();
topofs = (tex->GetTexelTopOffset() + spr->yoffset);
}
if (spr->cstat & CSTAT_SPRITE_YFLIP)
topofs = -topofs;
sprz -= ((topofs * spr->yrepeat) << 2);
if (spr->cstat & CSTAT_SPRITE_YCENTER)
{
sprz += ((height * spr->yrepeat) << 1);
if (height & 1) sprz += (spr->yrepeat << 1); // Odd yspans (taken from polymost as-is)
}
glseg.fracleft = 0;
glseg.fracright = 1;
glseg.x1 = pos[0].x * (1 / 16.f);
glseg.y1 = pos[0].y * (1 / -16.f);
glseg.x2 = pos[1].x * (1 / 16.f);
glseg.y2 = pos[1].y * (1 / -16.f);
tcs[LOLFT].u = tcs[UPLFT].u = (spr->cstat & CSTAT_SPRITE_XFLIP) ? 1.f : 0.f;
tcs[LORGT].u = tcs[UPRGT].u = (spr->cstat & CSTAT_SPRITE_XFLIP) ? 0.f : 1.f;
tcs[UPLFT].v = tcs[UPRGT].u = (spr->cstat & CSTAT_SPRITE_YFLIP) ? 0.f : 1.f;
tcs[LOLFT].v = tcs[LORGT].u = (spr->cstat & CSTAT_SPRITE_YFLIP) ? 0.f : 1.f;
ztop[0] = ztop[1] = (sprz - height) * (1 / -256.);
zbottom[0] = zbottom[1] = (sprz) * (1 / -256.);
// Clip sprites to ceilings/floors
float origz = ztop[0];
float polyh = (zbottom[0] - origz);
if (!(sector->ceilingstat & CSTAT_SECTOR_SKY))
{
float ceilingz = sector->ceilingz * (1 / 256.f);
if (ceilingz < ztop[0] && ceilingz > zbottom[0])
{
float newv = (ceilingz - origz) / polyh;
tcs[UPLFT].v = tcs[UPRGT].v = newv;
ztop[0] = ztop[1] = ceilingz;
}
}
if (!(sector->floorstat & CSTAT_SECTOR_SKY))
{
float floorz = sector->floorz * (1 / 256.f);
if (floorz < ztop[0] && floorz > zbottom[0])
{
float newv = (floorz - origz) / polyh;
tcs[LOLFT].v = tcs[LORGT].v = newv;
zbottom[0] = zbottom[1] = floorz;
}
}
}