- flat sprite rendering!

This commit is contained in:
Christoph Oelckers 2021-03-26 20:28:44 +01:00
parent fd0e9824b6
commit 1dfb2672a8
14 changed files with 574 additions and 72 deletions

View file

@ -1076,6 +1076,7 @@ set (PCH_SOURCES
core/rendering/scene/hw_clipper.cpp
core/rendering/scene/hw_walls.cpp
core/rendering/scene/hw_flats.cpp
core/rendering/scene/hw_sprites.cpp
core/rendering/scene/hw_drawlistadd.cpp
core/rendering/scene/hw_drawlist.cpp
core/rendering/scene/hw_drawinfo.cpp

View file

@ -3329,6 +3329,7 @@ EXTERN_CVAR(Int, gl_fogmode)
int32_t renderDrawRoomsQ16(int32_t daposx, int32_t daposy, int32_t daposz,
fixed_t daang, fixed_t dahoriz, int16_t dacursectnum)
{
spritesortcnt = 0;
checkRotatedWalls();
if (gl_fogmode == 1) gl_fogmode = 2; // only radial fog works with Build's screwed up coordinate system.

View file

@ -618,7 +618,7 @@ void renderDrawMapView(int cposx, int cposy, int czoom, int cang)
{
auto spr = &sprite[sn];
vec2_t pp[4];
GetFlatSpritePosition(spr, spr->pos.vec2, pp);
GetFlatSpritePosition(spr, spr->pos.vec2, pp, true);
for (unsigned j = 0; j < 4; j++)
{

View file

@ -231,11 +231,21 @@ void GetWallSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out)
//
//==========================================================================
void GetFlatSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out)
void GetFlatSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out, bool render)
{
auto tex = tileGetTexture(spr->picnum);
int width = tex->GetTexelWidth() * spr->xrepeat;
int height = tex->GetTexelHeight() * spr->yrepeat;
int width, height;
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;
}
else
{
width = tex->GetTexelWidth() * spr->xrepeat;
height = tex->GetTexelHeight() * spr->yrepeat;
}
int leftofs = (tex->GetTexelLeftOffset() + spr->xoffset) * spr->xrepeat;
int topofs = (tex->GetTexelTopOffset() + spr->yoffset) * spr->yrepeat;

View file

@ -11,7 +11,7 @@ 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 GetFlatSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out);
void GetFlatSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out, bool render = false);
void checkRotatedWalls();
// y is negated so that the orientation is the same as in GZDoom, in order to use its utilities.

View file

@ -283,6 +283,84 @@ HWDecal* HWDrawInfo::AddDecal(bool onmirror)
#endif
}
void HWDrawInfo::DispatchSprites()
{
for (int i = 0; i < spritesortcnt; i++)
{
auto tspr = &tsprite[i];
int tilenum = tspr->picnum;
int spritenum = tspr->owner;
if (spritenum < 0 || (unsigned)tilenum >= MAXTILES)
continue;
setgotpic(tilenum);
if ((tspr->cstat & CSTAT_SPRITE_ALIGNMENT) != CSTAT_SPRITE_ALIGNMENT_SLAB)
tileUpdatePicnum(&tilenum, spritenum + 32768, 0);
while (!(spriteext[spritenum].flags & SPREXT_NOTMD))
{
int pt = Ptile2tile(tspr->picnum, tspr->pal);
if (hw_models && tile2model[pt].modelid >= 0 && tile2model[pt].framenum >= 0)
{
//HWSprite hwsprite;
//if (hwsprite.ProcessModel(pt, tspr)) return;
break;
}
if (r_voxels)
{
if ((tspr->cstat & CSTAT_SPRITE_ALIGNMENT) != CSTAT_SPRITE_ALIGNMENT_SLAB && tiletovox[tspr->picnum] >= 0 && voxmodels[tiletovox[tspr->picnum]])
{
//HWSprite hwsprite;
//if (hwsprite.ProcessVoxel(voxmodels[tiletovox[tspr->picnum]], tspr)) return;
break;
}
else if ((tspr->cstat & CSTAT_SPRITE_ALIGNMENT) == CSTAT_SPRITE_ALIGNMENT_SLAB && tspr->picnum < MAXVOXELS && voxmodels[tspr->picnum])
{
//HWSprite hwsprite;
//hwsprite.ProcessVoxel(voxmodels[tspr->picnum], tspr);
return;
}
}
break;
}
if (spriteext[spritenum].flags & SPREXT_AWAY1)
{
tspr->pos.x += bcos(tspr->ang, -13);
tspr->pos.y += bsin(tspr->ang, -13);
}
else if (spriteext[spritenum].flags & SPREXT_AWAY2)
{
tspr->pos.x -= bcos(tspr->ang, -13);
tspr->pos.y -= bsin(tspr->ang, -13);
}
switch (tspr->cstat & CSTAT_SPRITE_ALIGNMENT)
{
case CSTAT_SPRITE_ALIGNMENT_FACING:
// face sprite
break;
case CSTAT_SPRITE_ALIGNMENT_WALL:
// wall sprite
break;
case CSTAT_SPRITE_ALIGNMENT_FLOOR:
{
HWFlat flat;
flat.ProcessFlatSprite(this, tspr, &sector[tspr->sectnum]);
break;
}
default:
break;
}
}
}
//-----------------------------------------------------------------------------
//
// CreateScene
@ -318,6 +396,7 @@ void HWDrawInfo::CreateScene()
SetupSprite.Clock();
gi->processSprites(view.x, view.y, vp.Pos.Z * -256, bamang(vp.RotAngle), vp.TicFrac * 65536);
DispatchSprites();
SetupSprite.Unclock();
screen->mLights->Unmap();
@ -345,14 +424,6 @@ void HWDrawInfo::RenderScene(FRenderState &state)
state.EnableFog(true);
state.SetRenderStyle(STYLE_Source);
if (gl_sort_textures)
{
drawlists[GLDL_PLAINWALLS].SortWalls();
drawlists[GLDL_PLAINFLATS].SortFlats();
drawlists[GLDL_MASKEDWALLS].SortWalls();
drawlists[GLDL_MASKEDFLATS].SortFlats();
drawlists[GLDL_MASKEDWALLSOFS].SortWalls();
}
// Part 1: solid geometry. This is set up so that there are no transparent parts
state.SetDepthFunc(DF_Less);
@ -362,21 +433,35 @@ void HWDrawInfo::RenderScene(FRenderState &state)
state.EnableTexture(gl_texture);
state.EnableBrightmap(true);
drawlists[GLDL_PLAINWALLS].DrawWalls(this, state, false);
drawlists[GLDL_PLAINFLATS].DrawFlats(this, state, false);
// Part 2: masked geometry. This is set up so that only pixels with alpha>gl_mask_threshold will show
state.AlphaFunc(Alpha_GEqual, gl_mask_threshold);
drawlists[GLDL_MASKEDWALLS].DrawWalls(this, state, false);
drawlists[GLDL_MASKEDFLATS].DrawFlats(this, state, false);
// Part 3: masked geometry with polygon offset. This list is empty most of the time so only waste time on it when in use.
if (drawlists[GLDL_MASKEDWALLSOFS].Size() > 0)
{
state.SetDepthBias(-1, -128);
drawlists[GLDL_MASKEDWALLSOFS].DrawWalls(this, state, false);
state.ClearDepthBias();
}
// This list is masked, non-translucent walls.
drawlists[GLDL_MASKEDWALLS].DrawWalls(this, state, false);
// 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);
// 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);
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);
drawlists[GLDL_MASKEDWALLSH].DrawWalls(this, state, false);
drawlists[GLDL_MASKEDFLATS].DrawFlats(this, state, false);
state.SetColorMask(true);
state.ClearDepthBias();
drawlists[GLDL_MODELS].Draw(this, state, false);

View file

@ -72,6 +72,9 @@ enum DrawListType
GLDL_PLAINWALLS,
GLDL_PLAINFLATS,
GLDL_MASKEDWALLS,
GLDL_MASKEDWALLSS, // arbitrary wall sprites.
GLDL_MASKEDWALLSV, // vertical wall sprites
GLDL_MASKEDWALLSH, // horizontal wall sprites. These two lists merely exist for easier sorting.
GLDL_MASKEDFLATS,
GLDL_MASKEDWALLSOFS,
GLDL_MODELS,
@ -154,6 +157,7 @@ public:
void DrawScene(int drawmode);
void CreateScene();
void DispatchSprites();
void RenderScene(FRenderState &state);
void RenderTranslucent(FRenderState &state);
void RenderPortal(HWPortal *p, FRenderState &state, bool usestencil);

View file

@ -330,7 +330,7 @@ void HWDrawList::SortSpriteIntoPlane(SortNode * head, SortNode * sort)
auto hiz = ss->z1 > ss->z2 ? ss->z1 : ss->z2;
auto loz = ss->z1 < ss->z2 ? ss->z1 : ss->z2;
if ((hiz > fh->z && loz < fh->z) || ss->modelframe)
if ((hiz > fh->z && loz < fh->z))// || ss->modelframe)
{
// We have to split this sprite
HWSprite *s = NewSprite();
@ -723,16 +723,44 @@ void HWDrawList::SortWalls()
}
}
void HWDrawList::SortFlats()
void HWDrawList::SortFlats(HWDrawInfo* di)
{
auto viewz = di->Viewpoint.Pos.Z;
if (drawitems.Size() > 1)
{
std::sort(drawitems.begin(), drawitems.end(), [=](const HWDrawItem &a, const HWDrawItem &b)
TArray<HWDrawItem> list1(drawitems.Size(), false);
TArray<HWDrawItem> list2(drawitems.Size(), false);
for (auto& item : drawitems)
{
HWFlat * w1 = flats[a.index];
HWFlat* w1 = flats[item.index];
if (w1->z < viewz) list1.Push(item);
else list2.Push(item);
}
std::sort(list1.begin(), list1.end(), [=](const HWDrawItem &a, const HWDrawItem &b)
{
HWFlat* w1 = flats[a.index];
HWFlat* w2 = flats[b.index];
return w1->texture < w2->texture;
if (w1->z != w2->z) return w1->z < w2->z;
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)
{
HWFlat* w1 = flats[a.index];
HWFlat* w2 = flats[b.index];
if (w1->z != w2->z) return w2->z < w1->z;
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);
}
}

View file

@ -31,6 +31,7 @@ struct HWDrawItem
HWDrawItemType rendertype;
int index;
HWDrawItem() = default; // we need this for dynamic arrays.
HWDrawItem(HWDrawItemType _rendertype,int _index) : rendertype(_rendertype),index(_index) {}
};
@ -92,7 +93,7 @@ public:
HWSprite *NewSprite();
void Reset();
void SortWalls();
void SortFlats();
void SortFlats(HWDrawInfo* di);
void MakeSortList();

View file

@ -106,33 +106,17 @@ void HWDrawInfo::AddMirrorSurface(HWWall *w)
void HWDrawInfo::AddFlat(HWFlat *flat)
{
int list = GLDL_PLAINFLATS;
int list;;
#if 0
if (flat->renderstyle != STYLE_Translucent || flat->alpha < 1.f - FLT_EPSILON)
if (flat->RenderStyle != LegacyRenderStyles[STYLE_Translucent] || flat->alpha < 1.f - FLT_EPSILON) // flat->texture->GetTranslucency() - fixme
{
// translucent portals go into the translucent border list.
list = GLDL_TRANSLUCENTBORDER;
list = flat->sprite? GLDL_TRANSLUCENT : GLDL_TRANSLUCENTBORDER;
}
else if (flat->texture->GetTranslucency())
else
{
/*
if (flat->stack)
{
list = GLDL_TRANSLUCENTBORDER;
}
else
*/
{
list = GLDL_PLAINFLATS;
}
list = flat->sprite ? GLDL_MASKEDFLATS : GLDL_PLAINFLATS;
}
else //if (flat->hacktype != SSRF_FLOODHACK) // The flood hack may later need different treatment but with the current setup can go into the existing render list.
{
bool masked = flat->texture->isMasked() && flat->stack;
list = masked ? GLDL_MASKEDFLATS : GLDL_PLAINFLATS;
}
#endif
auto newflat = drawlists[list].NewFlat();
*newflat = *flat;
}

View file

@ -153,7 +153,7 @@ public:
texcoord tcs[4];
float alpha;
ERenderStyle RenderStyle;
FRenderStyle RenderStyle;
float ViewDistance;
float visibility;
@ -181,8 +181,9 @@ public:
unsigned int vertcount;
public:
walltype * seg;
sectortype *frontsector, *backsector;
walltype* seg;
spritetype* sprite;
sectortype* frontsector, * backsector;
//private:
void PutWall(HWDrawInfo *di, bool translucent);
@ -229,6 +230,7 @@ public:
public:
void Process(HWDrawInfo* di, walltype* seg, sectortype* frontsector, sectortype* backsector);
void ProcessWallSprite(HWDrawInfo* di, walltype* seg, sectortype* frontsector, sectortype* backsector);
float PointOnSide(float x,float y)
{
@ -249,15 +251,16 @@ class HWFlat
{
public:
sectortype * sec;
spritetype* sprite; // for flat sprites.
FGameTexture *texture;
float z; // the z position of the flat (only valid for non-sloped planes)
FColormap Colormap; // light and fog
ERenderStyle renderstyle;
PalEntry fade;
int shade, palette, visibility;
float alpha;
FRenderStyle RenderStyle;
int iboindex;
//int vboheight;
@ -272,6 +275,7 @@ public:
void PutFlat(HWDrawInfo* di, int whichplane);
void ProcessSector(HWDrawInfo *di, sectortype * frontsector, int which = 7 /*SSRF_RENDERALL*/); // cannot use constant due to circular dependencies.
void ProcessFlatSprite(HWDrawInfo* di, spritetype* sprite, sectortype* sector);
void DrawSubsectors(HWDrawInfo *di, FRenderState &state);
void DrawFlat(HWDrawInfo* di, FRenderState& state, bool translucent);
@ -293,7 +297,7 @@ public:
bool fullbright;
bool polyoffset;
FColormap Colormap;
FSpriteModelFrame * modelframe;
int modeltype;
FRenderStyle RenderStyle;
int OverrideShader;

View file

@ -97,20 +97,44 @@ void HWFlat::SetupLights(HWDrawInfo *di, FLightNode * node, FDynLightData &light
void HWFlat::MakeVertices()
{
auto mesh = sectorGeometry.get(sec - sector, plane);
if (!mesh) return;
auto ret = screen->mVertexData->AllocVertices(mesh->vertices.Size());
auto vp = ret.first;
for (unsigned i = 0; i < mesh->vertices.Size(); i++)
if (vertcount > 0) return;
if (sprite == nullptr)
{
auto& pt = mesh->vertices[i];
auto& uv = mesh->texcoords[i];
vp->SetVertex(pt.X, pt.Z, pt.Y);
vp->SetTexCoord(uv.X, uv.Y);
vp++;
auto mesh = sectorGeometry.get(sec - sector, plane);
if (!mesh) return;
auto ret = screen->mVertexData->AllocVertices(mesh->vertices.Size());
auto vp = ret.first;
for (unsigned i = 0; i < mesh->vertices.Size(); i++)
{
auto& pt = mesh->vertices[i];
auto& uv = mesh->texcoords[i];
vp->SetVertex(pt.X, pt.Z, pt.Y);
vp->SetTexCoord(uv.X, uv.Y);
vp++;
}
vertindex = ret.second;
vertcount = mesh->vertices.Size();
}
else
{
vec2_t pos[4];
GetFlatSpritePosition(sprite, sprite->pos.vec2, pos, true);
auto ret = screen->mVertexData->AllocVertices(6);
auto vp = ret.first;
float x = !(sprite->cstat & CSTAT_SECTOR_XFLIP) ? 0.f : 1.f;
float y = !(sprite->cstat & CSTAT_SECTOR_YFLIP) ? 0.f : 1.f;
for (unsigned i = 0; i < 6; i++)
{
const static unsigned indices[] = { 0, 1, 2, 0, 2, 3 };
int j = indices[i];
vp->SetVertex(pos[j].x * (1 / 16.f), z, pos[j].y * (1 / -16.f));
vp->SetTexCoord(j == 1 || j == 2 ? 1.f - x : x, j == 2 || j == 3 ? 1.f - x : x);
vp++;
}
vertindex = ret.second;
vertcount = 6;
}
vertindex = ret.second;
vertcount = mesh->vertices.Size();
}
//==========================================================================
@ -132,8 +156,16 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent)
}
#endif
auto mesh = sectorGeometry.get(sec - sector, plane);
state.SetNormal(mesh->normal);
if (!sprite)
{
auto mesh = sectorGeometry.get(sec - sector, plane);
state.SetNormal(mesh->normal);
}
else
{
if (z < di->Viewpoint.Pos.Z) state.SetNormal({ 0,1,0 });
else state.SetNormal({ 0, -1, 0 });
}
// Fog must be done before the texture so that the texture selector can override it.
bool foggy = (GlobalMapFog || (fade & 0xffffff));
@ -160,7 +192,7 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent)
if (translucent)
{
state.SetRenderStyle(renderstyle);
state.SetRenderStyle(RenderStyle);
if (!texture->GetTranslucency()) state.AlphaFunc(Alpha_GEqual, gl_mask_threshold);
else state.AlphaFunc(Alpha_GEqual, 0.f);
}
@ -186,6 +218,7 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent)
void HWFlat::PutFlat(HWDrawInfo *di, int whichplane)
{
vertcount = 0;
plane = whichplane;
if (!screen->BuffersArePersistent()) // should be made static buffer content later (when the logic is working)
{
@ -228,6 +261,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sectortype * frontsector, int which)
fade = lookups.getFade(frontsector->floorpal); // fog is per sector.
visibility = sectorVisibility(frontsector);
sec = frontsector;
sprite = nullptr;
//
//
@ -262,7 +296,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sectortype * frontsector, int which)
if (texture && texture->isValid())
{
//iboindex = frontsector->iboindex[sector_t::floor];
renderstyle = STYLE_Translucent;
RenderStyle = STYLE_Translucent;
PutFlat(di, 0);
}
}
@ -303,10 +337,45 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sectortype * frontsector, int which)
if (texture && texture->isValid())
{
//iboindex = frontsector->iboindex[sector_t::floor];
renderstyle = STYLE_Translucent;
RenderStyle = STYLE_Translucent;
PutFlat(di, 1);
}
}
}
}
void HWFlat::ProcessFlatSprite(HWDrawInfo* di, spritetype* sprite, sectortype* sector)
{
int tilenum = sprite->picnum;
texture = tileGetTexture(tilenum);
z = sprite->z * (1 / -256.f);
if (z == di->Viewpoint.Pos.Z) return; // looking right at the edge.
visibility = sectorVisibility(&sector[sprite->sectnum]);// *(4.f / 5.f); // The factor comes directly from Polymost. No idea why this uses a different visibility setting. Bad projection math?
// Weird Build logic that really makes no sense.
if ((sprite->cstat & CSTAT_SPRITE_ONE_SIDED) != 0 && (di->Viewpoint.Pos.Z < z) == ((sprite->cstat & CSTAT_SPRITE_YFLIP) == 0))
return;
if (texture && texture->isValid())
{
this->sprite = sprite;
sec = sector;
shade = sprite->shade;
palette = sprite->pal;
fade = lookups.getFade(sector[sprite->sectnum].floorpal); // fog is per 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;
}
PutFlat(di, 0);
}
}

View file

@ -0,0 +1,315 @@
#if 0
void polymost_drawsprite(int32_t snum)
{
vec2_t off = { 0, 0 };
if ((globalorientation & 48) != 48) // only non-voxel sprites should do this
{
int const flag = hw_hightile && TileFiles.tiledata[globalpicnum].h_xsize;
off = { (int32_t)tspr->xoffset + (flag ? TileFiles.tiledata[globalpicnum].h_xoffs : tileLeftOffset(globalpicnum)),
(int32_t)tspr->yoffset + (flag ? TileFiles.tiledata[globalpicnum].h_yoffs : tileTopOffset(globalpicnum)) };
}
int32_t method = DAMETH_MASK | DAMETH_CLAMPED;
if (tspr->cstat & 2)
method = DAMETH_CLAMPED | ((tspr->cstat & 512) ? DAMETH_TRANS2 : DAMETH_TRANS1);
SetRenderStyleFromBlend(!!(tspr->cstat & 2), tspr->blend, !!(tspr->cstat & 512));
drawpoly_alpha = spriteext[spritenum].alpha;
drawpoly_blend = tspr->blend;
sec = (usectorptr_t)&sector[tspr->sectnum];
vec3_t pos = tspr->pos;
vec2_t tsiz;
if (hw_hightile && TileFiles.tiledata[globalpicnum].h_xsize)
tsiz = { TileFiles.tiledata[globalpicnum].h_xsize, TileFiles.tiledata[globalpicnum].h_ysize };
else
tsiz = { tileWidth(globalpicnum), tileHeight(globalpicnum) };
if (tsiz.x <= 0 || tsiz.y <= 0)
return;
vec2f_t const ftsiz = { (float) tsiz.x, (float) tsiz.y };
switch ((globalorientation >> 4) & 3)
{
case 0: // Face sprite
{
// Project 3D to 2D
if (globalorientation & 4)
off.x = -off.x;
// NOTE: yoff not negated not for y flipping, unlike wall and floor
// aligned sprites.
int const ang = (getangle(tspr->x - globalposx, tspr->y - globalposy) + 1024) & 2047;
float foffs = TSPR_OFFSET(tspr);
float foffs2 = TSPR_OFFSET(tspr);
if (fabs(foffs2) < fabs(foffs)) foffs = foffs2;
vec2f_t const offs = { float(bcosf(ang, -6) * foffs), float(bsinf(ang, -6) * foffs) };
vec2f_t s0 = { (float)(tspr->x - globalposx) + offs.x,
(float)(tspr->y - globalposy) + offs.y};
vec2f_t p0 = { s0.y * gcosang - s0.x * gsinang, s0.x * gcosang2 + s0.y * gsinang2 };
if (p0.y <= SCISDIST)
goto _drawsprite_return;
float const ryp0 = 1.f / p0.y;
s0 = { ghalfx * p0.x * ryp0 + ghalfx, ((float)(pos.z - globalposz)) * gyxscale * ryp0 + ghoriz };
float const f = ryp0 * fxdimen * (1.0f / 160.f);
vec2f_t ff = { ((float)tspr->xrepeat) * f,
((float)tspr->yrepeat) * f * ((float)yxaspect * (1.0f / 65536.f)) };
if (tsiz.x & 1)
s0.x += ff.x * 0.5f;
if (globalorientation & 128 && tsiz.y & 1)
s0.y += ff.y * 0.5f;
s0.x -= ff.x * (float) off.x;
s0.y -= ff.y * (float) off.y;
ff.x *= ftsiz.x;
ff.y *= ftsiz.y;
vec2f_t pxy[4];
pxy[0].x = pxy[3].x = s0.x - ff.x * 0.5f;
pxy[1].x = pxy[2].x = s0.x + ff.x * 0.5f;
if (!(globalorientation & 128))
{
pxy[0].y = pxy[1].y = s0.y - ff.y;
pxy[2].y = pxy[3].y = s0.y;
}
else
{
pxy[0].y = pxy[1].y = s0.y - ff.y * 0.5f;
pxy[2].y = pxy[3].y = s0.y + ff.y * 0.5f;
}
xtex.d = ytex.d = ytex.u = xtex.v = 0;
otex.d = ryp0 * gviewxrange;
if (!(globalorientation & 4))
{
xtex.u = ftsiz.x * otex.d / (pxy[1].x - pxy[0].x + .002f);
otex.u = -xtex.u * (pxy[0].x - .001f);
}
else
{
xtex.u = ftsiz.x * otex.d / (pxy[0].x - pxy[1].x - .002f);
otex.u = -xtex.u * (pxy[1].x + .001f);
}
if (!(globalorientation & 8))
{
ytex.v = ftsiz.y * otex.d / (pxy[3].y - pxy[0].y + .002f);
otex.v = -ytex.v * (pxy[0].y - .001f);
}
else
{
ytex.v = ftsiz.y * otex.d / (pxy[0].y - pxy[3].y - .002f);
otex.v = -ytex.v * (pxy[3].y + .001f);
}
// Clip sprites to ceilings/floors when no parallaxing and not sloped
if (!(sector[tspr->sectnum].ceilingstat & 3))
{
s0.y = ((float) (sector[tspr->sectnum].ceilingz - globalposz)) * gyxscale * ryp0 + ghoriz;
if (pxy[0].y < s0.y)
pxy[0].y = pxy[1].y = s0.y;
}
if (!(sector[tspr->sectnum].floorstat & 3))
{
s0.y = ((float) (sector[tspr->sectnum].floorz - globalposz)) * gyxscale * ryp0 + ghoriz;
if (pxy[2].y > s0.y)
pxy[2].y = pxy[3].y = s0.y;
}
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 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)
show2dsprite.Set(spritenum);
_drawsprite_return:
;
}
#endif

View file

@ -766,7 +766,7 @@ void HWWall::DoTexture(HWDrawInfo* di, walltype* wal, walltype* refwall, float r
bool trans = type == RENDERWALL_M2S && (wal->cstat & CSTAT_WALL_TRANSLUCENT);
if (trans)
{
SetRenderStyleFromBlend(!!(wal->cstat & CSTAT_WALL_TRANSLUCENT), 0, !!(wal->cstat & CSTAT_WALL_TRANS_FLIP));
RenderStyle = GetRenderStyle(0, !!(wal->cstat & CSTAT_WALL_TRANS_FLIP));
alpha = GetAlphaFromBlend((wal->cstat & CSTAT_WALL_TRANS_FLIP) ? DAMETH_TRANS2 : DAMETH_TRANS1, 0);
}
PutWall(di, trans);