- do some better sorting of slope sprites.

Splitting by translucent floor plane is essential, splitting by wall not that much - sorting by center point should be sufficient here.
This commit is contained in:
Christoph Oelckers 2022-01-03 12:31:54 +01:00
parent 9f83fd3575
commit e2e3b4482d
6 changed files with 155 additions and 21 deletions

View file

@ -110,6 +110,7 @@ struct HWDrawInfo
TArray<HWPortal *> Portals;
tspritetype tsprite[MAXSPRITESONSCREEN];
int spritesortcnt;
TArray<FFlatVertex> SlopeSpriteVertices; // we need to cache these in system memory in case of translucency splits.
// This is needed by the BSP traverser.
bool multithread;

View file

@ -32,6 +32,8 @@
#include "hw_renderstate.h"
#include "hw_drawinfo.h"
#define MIN_EQ (0.0005f)
FMemArena RenderDataAllocator(1024*1024); // Use large blocks to reduce allocation time.
void ResetRenderDataAllocator()
@ -385,7 +387,51 @@ void HWDrawList::SortSpriteIntoPlane(SortNode * head, SortNode * sort)
//
//
//==========================================================================
#define MIN_EQ (0.0005f)
void HWDrawList::SortSlopeIntoPlane(HWDrawInfo* di, SortNode* head, SortNode* sort)
{
HWFlat* fh = flats[drawitems[head->itemindex].index];
HWFlat* ss = flats[drawitems[sort->itemindex].index];
bool ceiling = fh->z > SortZ;
auto svp = &di->SlopeSpriteVertices[ss->slopeindex];
float hiz = -FLT_MAX;
float loz = FLT_MAX;
for (int i = 0; i < ss->slopecount; i++)
{
if (svp[i].z < loz) loz = svp[i].z;
if (svp[i].z > hiz) hiz = svp[i].z;
}
if ((hiz > fh->z && loz < fh->z))
{
// We have to split this sprite
auto s = NewFlat(true);
*s = *ss;
SortNode* sort2 = SortNodes.GetNew();
memset(sort2, 0, sizeof(SortNode));
sort2->itemindex = drawitems.Size() - 1;
head->AddToLeft(sort);
head->AddToRight(sort2);
}
else if ((loz < fh->z && !ceiling) || (hiz > fh->z && ceiling)) // completely on the left side
{
head->AddToLeft(sort);
}
else
{
head->AddToRight(sort);
}
}
//==========================================================================
//
//
//
//==========================================================================
// Lines start-end and fdiv must intersect.
inline double CalcIntersectionVertex(HWWall *w1, HWWall * w2)
@ -579,6 +625,55 @@ void HWDrawList::SortSpriteIntoWall(HWDrawInfo *di, SortNode * head,SortNode * s
}
}
static TArray<float> onside; // static to avoid reallocation.
void HWDrawList::SortSlopeIntoWall(HWDrawInfo* di, SortNode* head, SortNode* sort)
{
HWWall* wh = walls[drawitems[head->itemindex].index];
HWFlat* ss = flats[drawitems[sort->itemindex].index];
auto svp = &di->SlopeSpriteVertices[ss->slopeindex];
onside.Resize(ss->slopecount);
float hiz = -FLT_MAX;
float loz = FLT_MAX;
for (int i = 0; i < ss->slopecount; i++)
{
onside[i] = wh->PointOnSide(svp[i].x, svp[i].y);
if (onside[i] < loz) loz = onside[i];
if (onside[i] > hiz) hiz = onside[i];
}
if (fabs(loz) < MIN_EQ && fabs(hiz) < MIN_EQ)
{
head->AddToEqual(sort);
}
else if (loz < MIN_EQ && hiz < MIN_EQ)
{
head->AddToLeft(sort);
}
else if (hiz > -MIN_EQ && loz > -MIN_EQ)
{
head->AddToRight(sort);
}
else
{
const bool drawWithXYBillboard = false;//
// [Nash] has +ROLLSPRITE
const bool rotated = false;//
// Proper splitting should not be necessary here and can be added once a map shows up that needs it.
if (fabs(hiz) > fabs(loz))
{
head->AddToRight(sort);
}
else
{
head->AddToLeft(sort);
}
}
}
//==========================================================================
//
@ -588,8 +683,8 @@ void HWDrawList::SortSpriteIntoWall(HWDrawInfo *di, SortNode * head,SortNode * s
inline int HWDrawList::CompareSprites(SortNode * a,SortNode * b)
{
HWSprite * s1= sprites[drawitems[a->itemindex].index];
HWSprite * s2= sprites[drawitems[b->itemindex].index];
HWFlatOrSprite* s1 = drawitems[a->itemindex].rendertype == DrawType_SPRITE ? (HWFlatOrSprite*)sprites[drawitems[a->itemindex].index] : flats[drawitems[a->itemindex].index];
HWFlatOrSprite* s2 = drawitems[b->itemindex].rendertype == DrawType_SPRITE ? (HWFlatOrSprite*)sprites[drawitems[b->itemindex].index] : flats[drawitems[b->itemindex].index];
if (s1->depth < s2->depth) return 1;
if (s1->depth > s2->depth) return -1;
@ -659,6 +754,10 @@ SortNode * HWDrawList::DoSort(HWDrawInfo *di, SortNode * head)
case DrawType_SPRITE:
SortSpriteIntoPlane(head,node);
break;
case DrawType_SLOPE:
SortSlopeIntoPlane(di, head, node);
break;
}
node=next;
}
@ -685,6 +784,10 @@ SortNode * HWDrawList::DoSort(HWDrawInfo *di, SortNode * head)
SortSpriteIntoWall(di, head, node);
break;
case DrawType_SLOPE:
SortSlopeIntoWall(di, head, node);
break;
case DrawType_FLAT: break;
}
node=next;
@ -873,10 +976,10 @@ HWWall *HWDrawList::NewWall()
//
//
//==========================================================================
HWFlat *HWDrawList::NewFlat()
HWFlat *HWDrawList::NewFlat(bool slopespr)
{
auto flat = (HWFlat*)RenderDataAllocator.Alloc(sizeof(HWFlat));
drawitems.Push(HWDrawItem(DrawType_FLAT,flats.Push(flat)));
drawitems.Push(HWDrawItem(slopespr? DrawType_SLOPE : DrawType_FLAT,flats.Push(flat)));
return flat;
}
@ -901,6 +1004,7 @@ void HWDrawList::DoDraw(HWDrawInfo *di, FRenderState &state, bool translucent, i
{
switch(drawitems[i].rendertype)
{
case DrawType_SLOPE:
case DrawType_FLAT:
{
HWFlat * f= flats[drawitems[i].index];

View file

@ -24,6 +24,7 @@ enum HWDrawItemType
DrawType_WALL,
DrawType_FLAT,
DrawType_SPRITE,
DrawType_SLOPE,
};
struct HWDrawItem
@ -89,7 +90,7 @@ public:
}
HWWall *NewWall();
HWFlat *NewFlat();
HWFlat *NewFlat(bool slopespr = false);
HWSprite *NewSprite();
void Reset();
void SortWallsHorz(HWDrawInfo* di);
@ -103,8 +104,10 @@ public:
void SortPlaneIntoPlane(SortNode * head,SortNode * sort);
void SortWallIntoPlane(HWDrawInfo* di, SortNode * head,SortNode * sort);
void SortSpriteIntoPlane(SortNode * head,SortNode * sort);
void SortSlopeIntoPlane(HWDrawInfo* di, SortNode* head, SortNode* sort);
void SortWallIntoWall(HWDrawInfo *di, SortNode * head,SortNode * sort);
void SortSpriteIntoWall(HWDrawInfo *di, SortNode * head,SortNode * sort);
void SortSlopeIntoWall(HWDrawInfo* di, SortNode* head, SortNode* sort);
int CompareSprites(SortNode * a,SortNode * b);
SortNode * SortSpriteList(SortNode * head);
SortNode * DoSort(HWDrawInfo *di, SortNode * head);

View file

@ -94,17 +94,19 @@ void HWDrawInfo::AddMirrorSurface(HWWall *w)
void HWDrawInfo::AddFlat(HWFlat *flat)
{
int list;;
bool slopespr = false;
if (flat->RenderStyle != LegacyRenderStyles[STYLE_Translucent] || flat->alpha < 1.f - FLT_EPSILON || checkTranslucentReplacement(flat->texture->GetID(), flat->palette))
{
// translucent portals go into the translucent border list.
list = flat->Sprite? GLDL_TRANSLUCENT : GLDL_TRANSLUCENTBORDER;
slopespr = (flat->Sprite && flat->Sprite->clipdist & TSPR_SLOPESPRITE);
}
else
{
list = flat->Sprite ? GLDL_MASKEDFLATS : GLDL_PLAINFLATS;
}
auto newflat = drawlists[list].NewFlat();
auto newflat = drawlists[list].NewFlat(slopespr);
*newflat = *flat;
}

View file

@ -248,20 +248,32 @@ public:
};
//==========================================================================
//
// Common fields needed by the sprite sorter.
//
//==========================================================================
class HWFlatOrSprite
{
public:
float depth;
tspritetype* Sprite; // for flat sprites.
};
//==========================================================================
//
// One flat plane in the draw list
//
//==========================================================================
class HWFlat
class HWFlat : public HWFlatOrSprite
{
public:
int section;
sectortype * sec;
tspritetype* Sprite; // for flat sprites.
FGameTexture *texture;
sectortype* sec;
FGameTexture* texture;
int section;
float z; // the z position of the flat (only valid for non-sloped planes)
PalEntry fade;
@ -271,10 +283,12 @@ public:
FRenderStyle RenderStyle;
int iboindex;
bool stack;
uint8_t plane;
short slopecount;
FVector2 geoofs;
//int vboheight;
int plane;
int slopeindex;
int vertindex, vertcount; // this should later use a static vertex buffer, but that'd hinder the development phase, so for now vertex data gets created on the fly.
void MakeVertices(HWDrawInfo* di);
@ -298,11 +312,10 @@ public:
//==========================================================================
class HWSprite
class HWSprite : public HWFlatOrSprite
{
public:
tspritetype* Sprite;
PalEntry fade;
int shade, palette;
float visibility;
@ -312,7 +325,6 @@ public:
voxmodel_t* voxel;
int index;
float depth;
int vertexindex;
float x,y,z; // needed for sorting!

View file

@ -165,15 +165,27 @@ void HWFlat::MakeVertices(HWDrawInfo* di)
if (minofs < 0 && maxofs <= -ONPLANE_THRESHOLD && minofs >= ONPLANE_THRESHOLD) z -= minofs;
}
}
unsigned svi = di->SlopeSpriteVertices.Reserve(4);
auto svp = &di->SlopeSpriteVertices[svi];
auto& vpt = di->Viewpoint;
depth = (float)((Sprite->pos.X * (1/16.f) - vpt.Pos.X) * vpt.TanCos + (Sprite->pos.Y * (1 / -16.f) - vpt.Pos.Y) * vpt.TanSin);
for (unsigned j = 0; j < 4; j++)
{
svp->SetVertex(pos[j].X * (1 / 16.f), z + ofsz[j] * (1 / -256.f), pos[j].Y * (1 / -16.f));
if (!canvas) svp->SetTexCoord(j == 1 || j == 2 ? 1.f - x : x, j == 2 || j == 3 ? 1.f - y : y);
else svp->SetTexCoord(j == 1 || j == 2 ? 1.f - x : x, j == 2 || j == 3 ? y : 1.f - y);
svp++;
}
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 + ofsz[j] * (1 / -256.f), pos[j].Y * (1 / -16.f));
if (!canvas) vp->SetTexCoord(j == 1 || j == 2 ? 1.f - x : x, j == 2 || j == 3 ? 1.f - y : y);
else vp->SetTexCoord(j == 1 || j == 2 ? 1.f - x : x, j == 2 || j == 3 ? y : 1.f - y);
vp++;
*vp++ = di->SlopeSpriteVertices[svi + indices[i]];
}
slopeindex = svi;
slopecount = 4;
vertindex = ret.second;
vertcount = 6;
}