- use hardware clip planes to split translucent walls and sprites by 3D floor planes.

This method has the advantage that it also works for models, xy-billboarded sprites and walls that require complex splitting of the polygon. The old method using actual polygon splitting only works for strictly vertical data that could be trivially split in two.
This commit is contained in:
Christoph Oelckers 2015-04-05 19:00:35 +02:00
parent 45526c2769
commit cf7cb4f00f

View file

@ -307,41 +307,23 @@ void GLDrawList::SortWallIntoPlane(SortNode * head,SortNode * sort)
{ {
GLFlat * fh=&flats[drawitems[head->itemindex].index]; GLFlat * fh=&flats[drawitems[head->itemindex].index];
GLWall * ws=&walls[drawitems[sort->itemindex].index]; GLWall * ws=&walls[drawitems[sort->itemindex].index];
GLWall * ws1;
bool ceiling = fh->z > FIXED2FLOAT(viewz); bool ceiling = fh->z > FIXED2FLOAT(viewz);
if ((ws->ztop[0] > fh->z || ws->ztop[1] > fh->z) && (ws->zbottom[0] < fh->z || ws->zbottom[1] < fh->z))
if (ws->ztop[0]>fh->z && ws->zbottom[0]<fh->z)
{ {
// We have to split this wall! // We have to split this wall!
// WARNING: NEVER EVER push a member of an array onto the array itself. // WARNING: NEVER EVER push a member of an array onto the array itself.
// Bad things will happen if the memory must be reallocated! // Bad things will happen if the memory must be reallocated!
GLWall w=*ws; GLWall w = *ws;
AddWall(&w); AddWall(&w);
ws1=&walls[walls.Size()-1]; // Splitting is done in the shader with clip planes.
ws=&walls[drawitems[sort->itemindex].index]; // may have been reallocated!
float newtexv = ws->uplft.v + ((ws->lolft.v - ws->uplft.v) / (ws->zbottom[0] - ws->ztop[0])) * (fh->z - ws->ztop[0]);
// I make the very big assumption here that translucent walls in sloped sectors SortNode * sort2 = SortNodes.GetNew();
// and 3D-floors never coexist in the same level. If that were the case this memset(sort2, 0, sizeof(SortNode));
// code would become extremely more complicated. sort2->itemindex = drawitems.Size() - 1;
if (!ceiling)
{
ws->ztop[1] = ws1->zbottom[1] = ws->ztop[0] = ws1->zbottom[0] = fh->z;
ws->uprgt.v = ws1->lorgt.v = ws->uplft.v = ws1->lolft.v = newtexv;
}
else
{
ws1->ztop[1] = ws->zbottom[1] = ws1->ztop[0] = ws->zbottom[0] = fh->z;
ws1->uplft.v = ws->lolft.v = ws1->uprgt.v = ws->lorgt.v=newtexv;
}
SortNode * sort2=SortNodes.GetNew();
memset(sort2,0,sizeof(SortNode));
sort2->itemindex=drawitems.Size()-1;
head->AddToLeft(sort); head->AddToLeft(sort);
head->AddToRight(sort2); head->AddToRight(sort2);
@ -366,29 +348,16 @@ void GLDrawList::SortSpriteIntoPlane(SortNode * head,SortNode * sort)
{ {
GLFlat * fh=&flats[drawitems[head->itemindex].index]; GLFlat * fh=&flats[drawitems[head->itemindex].index];
GLSprite * ss=&sprites[drawitems[sort->itemindex].index]; GLSprite * ss=&sprites[drawitems[sort->itemindex].index];
GLSprite * ss1;
bool ceiling = fh->z > FIXED2FLOAT(viewz); bool ceiling = fh->z > FIXED2FLOAT(viewz);
if (ss->z1>fh->z && ss->z2<fh->z) if ((ss->z1>fh->z && ss->z2<fh->z) || ss->modelframe)
{ {
// We have to split this sprite! // We have to split this sprite
GLSprite s=*ss; GLSprite s=*ss;
AddSprite(&s); AddSprite(&s); // add a copy to avoid reallocation issues.
ss1=&sprites[sprites.Size()-1];
ss=&sprites[drawitems[sort->itemindex].index]; // may have been reallocated!
float newtexv=ss->vt + ((ss->vb-ss->vt)/(ss->z2-ss->z1))*(fh->z-ss->z1);
if (!ceiling) // Splitting is done in the shader with clip planes.
{
ss->z1=ss1->z2=fh->z;
ss->vt=ss1->vb=newtexv;
}
else
{
ss1->z1=ss->z2=fh->z;
ss1->vt=ss->vb=newtexv;
}
SortNode * sort2=SortNodes.GetNew(); SortNode * sort2=SortNodes.GetNew();
memset(sort2,0,sizeof(SortNode)); memset(sort2,0,sizeof(SortNode));
@ -729,11 +698,32 @@ void GLDrawList::DoDraw(int pass, int i, bool trans)
//========================================================================== //==========================================================================
void GLDrawList::DoDrawSorted(SortNode * head) void GLDrawList::DoDrawSorted(SortNode * head)
{ {
do float clipsplit[2];
int relation = 0;
float z = 0.f;
gl_RenderState.GetClipSplit(clipsplit);
if (drawitems[head->itemindex].rendertype == GLDIT_FLAT)
{ {
z = flats[drawitems[head->itemindex].index].z;
relation = z > FIXED2FLOAT(viewz)? 1 : -1;
}
// left is further away, i.e. for stuff above viewz its z coordinate higher, for stuff below viewz its z coordinate is lower
if (head->left) if (head->left)
{ {
if (relation == -1)
{
gl_RenderState.SetClipSplit(clipsplit[0], z); // render below: set flat as top clip plane
}
else if (relation == 1)
{
gl_RenderState.SetClipSplit(z, clipsplit[1]); // render above: set flat as bottom clip plane
}
DoDrawSorted(head->left); DoDrawSorted(head->left);
gl_RenderState.SetClipSplit(clipsplit);
} }
DoDraw(GLPASS_TRANSLUCENT, head->itemindex, true); DoDraw(GLPASS_TRANSLUCENT, head->itemindex, true);
if (head->equal) if (head->equal)
@ -745,8 +735,20 @@ void GLDrawList::DoDrawSorted(SortNode * head)
ehead=ehead->equal; ehead=ehead->equal;
} }
} }
// right is closer, i.e. for stuff above viewz its z coordinate is lower, for stuff below viewz its z coordinate is higher
if (head->right)
{
if (relation == 1)
{
gl_RenderState.SetClipSplit(clipsplit[0], z); // render below: set flat as top clip plane
}
else if (relation == -1)
{
gl_RenderState.SetClipSplit(z, clipsplit[1]); // render above: set flat as bottom clip plane
}
DoDrawSorted(head->right);
gl_RenderState.SetClipSplit(clipsplit);
} }
while ((head=head->right));
} }
//========================================================================== //==========================================================================
@ -763,7 +765,11 @@ void GLDrawList::DrawSorted()
MakeSortList(); MakeSortList();
sorted=DoSort(SortNodes[SortNodeStart]); sorted=DoSort(SortNodes[SortNodeStart]);
} }
glEnable(GL_CLIP_DISTANCE2);
glEnable(GL_CLIP_DISTANCE3);
DoDrawSorted(sorted); DoDrawSorted(sorted);
glDisable(GL_CLIP_DISTANCE2);
glDisable(GL_CLIP_DISTANCE3);
} }
//========================================================================== //==========================================================================