Decal work. Not finished yet.

This commit is contained in:
Christoph Oelckers 2018-04-27 11:40:23 +02:00
parent bbea6e7e3c
commit 200848a487
6 changed files with 173 additions and 133 deletions

View file

@ -555,6 +555,7 @@ bool FDrawInfo::PutWallCompat(GLWall *wall, int passflag)
int list = list_indices[masked][foggy]; int list = list_indices[masked][foggy];
auto newwall = dldrawlists[list].NewWall(); auto newwall = dldrawlists[list].NewWall();
*newwall = *wall; *newwall = *wall;
if (!masked) newwall->ProcessDecals(this);
return true; return true;
} }

View file

@ -46,143 +46,141 @@ struct DecalVertex
float u,v; float u,v;
}; };
//========================================================================== struct GLDecal
// {
// unsigned int vertindex;
// FMaterial *gltexture;
//========================================================================== GLWall *wall;
void FDrawInfo::DrawDecal(GLWall *wall, DBaseDecal *decal) DBaseDecal *decal;
DecalVertex dv[4];
float zcenter;
int light;
int rel;
float a;
FColormap colormap;
};
void GLWall::ProcessDecal(HWDrawInfo *di, DBaseDecal *decal)
{ {
auto seg = wall->seg;
line_t * line = seg->linedef; line_t * line = seg->linedef;
side_t * side = seg->sidedef; side_t * side = seg->sidedef;
int i; int i;
float zpos; float zpos;
int light;
int rel;
float a;
bool flipx, flipy; bool flipx, flipy;
DecalVertex dv[4];
FTextureID decalTile; FTextureID decalTile;
GLDecal gldecal;
if (decal->RenderFlags & RF_INVISIBLE) return; if (decal->RenderFlags & RF_INVISIBLE) return;
if (wall->type == RENDERWALL_FFBLOCK && wall->gltexture->isMasked()) return; // No decals on 3D floors with transparent textures. if (type == RENDERWALL_FFBLOCK && gltexture->isMasked()) return; // No decals on 3D floors with transparent textures.
//if (decal->sprite != 0xffff)
{ decalTile = decal->PicNum;
decalTile = decal->PicNum; flipx = !!(decal->RenderFlags & RF_XFLIP);
flipx = !!(decal->RenderFlags & RF_XFLIP); flipy = !!(decal->RenderFlags & RF_YFLIP);
flipy = !!(decal->RenderFlags & RF_YFLIP);
}
/*
else
{
decalTile = SpriteFrames[sprites[decal->sprite].spriteframes + decal->frame].lump[0];
flipx = SpriteFrames[sprites[decal->sprite].spriteframes + decal->frame].flip & 1;
}
*/
FTexture *texture = TexMan[decalTile]; FTexture *texture = TexMan[decalTile];
if (texture == NULL) return; if (texture == NULL) return;
FMaterial *tex;
tex = FMaterial::ValidateTexture(texture, true);
// the sectors are only used for their texture origin coordinates // the sectors are only used for their texture origin coordinates
// so we don't need the fake sectors for deep water etc. // so we don't need the fake sectors for deep water etc.
// As this is a completely split wall fragment no further splits are // As this is a completely split wall fragment no further splits are
// necessary for the decal. // necessary for the decal.
sector_t *frontsector; sector_t *frontsector;
// for 3d-floor segments use the model sector as reference // for 3d-floor segments use the model sector as reference
if ((decal->RenderFlags&RF_CLIPMASK) == RF_CLIPMID) frontsector = decal->Sector; if ((decal->RenderFlags&RF_CLIPMASK) == RF_CLIPMID) frontsector = decal->Sector;
else frontsector = seg->frontsector; else frontsector = seg->frontsector;
switch (decal->RenderFlags & RF_RELMASK) switch (decal->RenderFlags & RF_RELMASK)
{ {
default: default:
// No valid decal can have this type. If one is encountered anyway // No valid decal can have this type. If one is encountered anyway
// it is in some way invalid so skip it. // it is in some way invalid so skip it.
return; return;
//zpos = decal->z; //zpos = decal->z;
//break; //break;
case RF_RELUPPER: case RF_RELUPPER:
if (wall->type != RENDERWALL_TOP) return; if (type != RENDERWALL_TOP) return;
if (line->flags & ML_DONTPEGTOP) if (line->flags & ML_DONTPEGTOP)
{ {
zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling); zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling);
} }
else else
{ {
zpos = decal->Z + seg->backsector->GetPlaneTexZ(sector_t::ceiling); zpos = decal->Z + seg->backsector->GetPlaneTexZ(sector_t::ceiling);
} }
break; break;
case RF_RELLOWER: case RF_RELLOWER:
if (wall->type != RENDERWALL_BOTTOM) return; if (type != RENDERWALL_BOTTOM) return;
if (line->flags & ML_DONTPEGBOTTOM) if (line->flags & ML_DONTPEGBOTTOM)
{ {
zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling); zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling);
} }
else else
{ {
zpos = decal->Z + seg->backsector->GetPlaneTexZ(sector_t::floor); zpos = decal->Z + seg->backsector->GetPlaneTexZ(sector_t::floor);
} }
break; break;
case RF_RELMID: case RF_RELMID:
if (wall->type == RENDERWALL_TOP || wall->type == RENDERWALL_BOTTOM) return; if (type == RENDERWALL_TOP || type == RENDERWALL_BOTTOM) return;
if (line->flags & ML_DONTPEGBOTTOM) if (line->flags & ML_DONTPEGBOTTOM)
{ {
zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::floor); zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::floor);
} }
else else
{ {
zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling); zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling);
} }
} }
memset(&gldecal, 0, sizeof(gldecal));
gldecal.gltexture = FMaterial::ValidateTexture(texture, true);
gldecal.wall = this;
gldecal.decal = decal;
if (decal->RenderFlags & RF_FULLBRIGHT) if (decal->RenderFlags & RF_FULLBRIGHT)
{ {
light = 255; gldecal.light = 255;
rel = 0; gldecal.rel = 0;
} }
else else
{ {
light = wall->lightlevel; gldecal.light = lightlevel;
rel = wall->rellight + getExtraLight(); gldecal.rel = rellight + getExtraLight();
} }
FColormap p = wall->Colormap; gldecal.colormap = Colormap;
if (level.flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING) if (level.flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING)
{ {
p.Decolorize(); gldecal.colormap.Decolorize();
} }
gldecal.a = decal->Alpha;
a = decal->Alpha;
// now clip the decal to the actual polygon // now clip the decal to the actual polygon
FMaterial *tex = gldecal.gltexture;
float decalwidth = tex->TextureWidth() * decal->ScaleX; float decalwidth = tex->TextureWidth() * decal->ScaleX;
float decalheight = tex->TextureHeight() * decal->ScaleY; float decalheight = tex->TextureHeight() * decal->ScaleY;
float decallefto = tex->GetLeftOffset() * decal->ScaleX; float decallefto = tex->GetLeftOffset() * decal->ScaleX;
float decaltopo = tex->GetTopOffset() * decal->ScaleY; float decaltopo = tex->GetTopOffset() * decal->ScaleY;
auto &glseg = wall->glseg;
float leftedge = glseg.fracleft * side->TexelLength; float leftedge = glseg.fracleft * side->TexelLength;
float linelength = glseg.fracright * side->TexelLength - leftedge; float linelength = glseg.fracright * side->TexelLength - leftedge;
// texel index of the decal's left edge // texel index of the decal's left edge
float decalpixpos = (float)side->TexelLength * decal->LeftDistance - (flipx ? decalwidth - decallefto : decallefto) - leftedge; float decalpixpos = (float)side->TexelLength * decal->LeftDistance - (flipx ? decalwidth - decallefto : decallefto) - leftedge;
float left, right; float left, right;
float lefttex, righttex; float lefttex, righttex;
// decal is off the left edge // decal is off the left edge
if (decalpixpos < 0) if (decalpixpos < 0)
{ {
@ -194,7 +192,7 @@ void FDrawInfo::DrawDecal(GLWall *wall, DBaseDecal *decal)
left = decalpixpos; left = decalpixpos;
lefttex = 0; lefttex = 0;
} }
// decal is off the right edge // decal is off the right edge
if (decalpixpos + decalwidth > linelength) if (decalpixpos + decalwidth > linelength)
{ {
@ -207,36 +205,37 @@ void FDrawInfo::DrawDecal(GLWall *wall, DBaseDecal *decal)
righttex = decalwidth; righttex = decalwidth;
} }
if (right <= left) return; // nothing to draw if (right <= left) return; // nothing to draw
// one texture unit on the wall as vector // one texture unit on the wall as vector
float vx = (glseg.x2 - glseg.x1) / linelength; float vx = (glseg.x2 - glseg.x1) / linelength;
float vy = (glseg.y2 - glseg.y1) / linelength; float vy = (glseg.y2 - glseg.y1) / linelength;
DecalVertex *dv = gldecal.dv;
dv[1].x = dv[0].x = glseg.x1 + vx * left; dv[1].x = dv[0].x = glseg.x1 + vx * left;
dv[1].y = dv[0].y = glseg.y1 + vy * left; dv[1].y = dv[0].y = glseg.y1 + vy * left;
dv[3].x = dv[2].x = glseg.x1 + vx * right; dv[3].x = dv[2].x = glseg.x1 + vx * right;
dv[3].y = dv[2].y = glseg.y1 + vy * right; dv[3].y = dv[2].y = glseg.y1 + vy * right;
zpos += (flipy ? decalheight - decaltopo : decaltopo); zpos += (flipy ? decalheight - decaltopo : decaltopo);
dv[1].z = dv[2].z = zpos; dv[1].z = dv[2].z = zpos;
dv[0].z = dv[3].z = dv[1].z - decalheight; dv[0].z = dv[3].z = dv[1].z - decalheight;
dv[1].v = dv[2].v = tex->GetVT(); dv[1].v = dv[2].v = tex->GetVT();
dv[1].u = dv[0].u = tex->GetU(lefttex / decal->ScaleX); dv[1].u = dv[0].u = tex->GetU(lefttex / decal->ScaleX);
dv[3].u = dv[2].u = tex->GetU(righttex / decal->ScaleX); dv[3].u = dv[2].u = tex->GetU(righttex / decal->ScaleX);
dv[0].v = dv[3].v = tex->GetVB(); dv[0].v = dv[3].v = tex->GetVB();
// now clip to the top plane // now clip to the top plane
float vzt = (wall->ztop[1] - wall->ztop[0]) / linelength; float vzt = (ztop[1] - ztop[0]) / linelength;
float topleft = wall->ztop[0] + vzt * left; float topleft = ztop[0] + vzt * left;
float topright = wall->ztop[0] + vzt * right; float topright = ztop[0] + vzt * right;
// completely below the wall // completely below the wall
if (topleft < dv[0].z && topright < dv[3].z) if (topleft < dv[0].z && topright < dv[3].z)
return; return;
if (topleft < dv[1].z || topright < dv[2].z) if (topleft < dv[1].z || topright < dv[2].z)
{ {
// decal has to be clipped at the top // decal has to be clipped at the top
@ -246,16 +245,16 @@ void FDrawInfo::DrawDecal(GLWall *wall, DBaseDecal *decal)
dv[1].z = topleft; dv[1].z = topleft;
dv[2].z = topright; dv[2].z = topright;
} }
// now clip to the bottom plane // now clip to the bottom plane
float vzb = (wall->zbottom[1] - wall->zbottom[0]) / linelength; float vzb = (zbottom[1] - zbottom[0]) / linelength;
float bottomleft = wall->zbottom[0] + vzb * left; float bottomleft = zbottom[0] + vzb * left;
float bottomright = wall->zbottom[0] + vzb * right; float bottomright = zbottom[0] + vzb * right;
// completely above the wall // completely above the wall
if (bottomleft > dv[1].z && bottomright > dv[2].z) if (bottomleft > dv[1].z && bottomright > dv[2].z)
return; return;
if (bottomleft > dv[0].z || bottomright > dv[3].z) if (bottomleft > dv[0].z || bottomright > dv[3].z)
{ {
// decal has to be clipped at the bottom // decal has to be clipped at the bottom
@ -265,8 +264,8 @@ void FDrawInfo::DrawDecal(GLWall *wall, DBaseDecal *decal)
dv[0].z = bottomleft; dv[0].z = bottomleft;
dv[3].z = bottomright; dv[3].z = bottomright;
} }
if (flipx) if (flipx)
{ {
float ur = tex->GetUR(); float ur = tex->GetUR();
@ -278,13 +277,56 @@ void FDrawInfo::DrawDecal(GLWall *wall, DBaseDecal *decal)
for (i = 0; i < 4; i++) dv[i].v = vb - dv[i].v; for (i = 0; i < 4; i++) dv[i].v = vb - dv[i].v;
} }
gldecal.zcenter = zpos - decalheight * 0.5f;
auto verts = gl_drawinfo->AllocVertices(4);
gldecal.vertindex = verts.second;
for (i = 0; i < 4; i++)
{
verts.first[i].Set(dv[i].x, dv[i].z, dv[i].y, dv[i].u, dv[i].v);
}
di->AddDecal(&gldecal);
}
//==========================================================================
//
//
//
//==========================================================================
void GLWall::ProcessDecals(HWDrawInfo *di)
{
if (seg->sidedef != nullptr)
{
DBaseDecal *decal = seg->sidedef->AttachedDecals;
while (decal)
{
ProcessDecal(di, decal);
decal = decal->WallNext;
}
}
}
//==========================================================================
//
//
//
//==========================================================================
void FDrawInfo::DrawDecal(GLWall *__wall, DBaseDecal *__decal)
{
GLDecal *gldecal;
auto wall = gldecal->wall;
auto decal = gldecal->decal;
auto tex = gldecal->gltexture;
auto &seg = wall->seg;
// calculate dynamic light effect. // calculate dynamic light effect.
if (gl_lights && GLRenderer->mLightCount && !mDrawer->FixedColormap && gl_light_sprites) if (gl_lights && GLRenderer->mLightCount && !mDrawer->FixedColormap && gl_light_sprites)
{ {
// Note: This should be replaced with proper shader based lighting. // Note: This should be replaced with proper shader based lighting.
double x, y; double x, y;
decal->GetXY(seg->sidedef, x, y); decal->GetXY(seg->sidedef, x, y);
gl_SetDynSpriteLight(nullptr, x, y, zpos - decalheight * 0.5f, wall->sub); gl_SetDynSpriteLight(nullptr, x, y, gldecal->zcenter, wall->sub);
} }
// alpha color only has an effect when using an alpha texture. // alpha color only has an effect when using an alpha texture.
@ -293,9 +335,6 @@ void FDrawInfo::DrawDecal(GLWall *wall, DBaseDecal *decal)
gl_RenderState.SetObjectColor(decal->AlphaColor | 0xff000000); gl_RenderState.SetObjectColor(decal->AlphaColor | 0xff000000);
} }
gl_SetRenderStyle(decal->RenderStyle, false, false); gl_SetRenderStyle(decal->RenderStyle, false, false);
gl_RenderState.SetMaterial(tex, CLAMP_XY, decal->Translation, 0, !!(decal->RenderStyle.Flags & STYLEF_RedIsAlpha)); gl_RenderState.SetMaterial(tex, CLAMP_XY, decal->Translation, 0, !!(decal->RenderStyle.Flags & STYLEF_RedIsAlpha));
@ -305,7 +344,7 @@ void FDrawInfo::DrawDecal(GLWall *wall, DBaseDecal *decal)
else gl_RenderState.AlphaFunc(GL_GREATER, 0.f); else gl_RenderState.AlphaFunc(GL_GREATER, 0.f);
mDrawer->SetColor(light, rel, p, a); mDrawer->SetColor(gldecal->light, gldecal->rel, gldecal->colormap, gldecal->a);
// for additively drawn decals we must temporarily set the fog color to black. // for additively drawn decals we must temporarily set the fog color to black.
PalEntry fc = gl_RenderState.GetFogColor(); PalEntry fc = gl_RenderState.GetFogColor();
if (decal->RenderStyle.BlendOp == STYLEOP_Add && decal->RenderStyle.DestAlpha == STYLEALPHA_One) if (decal->RenderStyle.BlendOp == STYLEOP_Add && decal->RenderStyle.DestAlpha == STYLEALPHA_One)
@ -313,18 +352,12 @@ void FDrawInfo::DrawDecal(GLWall *wall, DBaseDecal *decal)
gl_RenderState.SetFog(0, -1); gl_RenderState.SetFog(0, -1);
} }
gl_RenderState.SetNormal(glseg.Normal()); gl_RenderState.SetNormal(wall->glseg.Normal());
FQuadDrawer qd;
for (i = 0; i < 4; i++)
{
qd.Set(i, dv[i].x, dv[i].z, dv[i].y, dv[i].u, dv[i].v);
}
if (wall->lightlist == nullptr) if (wall->lightlist == nullptr)
{ {
gl_RenderState.Apply(); gl_RenderState.Apply();
qd.Render(GL_TRIANGLE_FAN); GLRenderer->mVBO->RenderArray(GL_TRIANGLE_FAN, gldecal->vertindex, 4);
} }
else else
{ {
@ -334,6 +367,7 @@ void FDrawInfo::DrawDecal(GLWall *wall, DBaseDecal *decal)
{ {
secplane_t &lowplane = k == lightlist.Size() - 1 ? wall->bottomplane : lightlist[k + 1].plane; secplane_t &lowplane = k == lightlist.Size() - 1 ? wall->bottomplane : lightlist[k + 1].plane;
DecalVertex *dv = gldecal->dv;
float low1 = lowplane.ZatPoint(dv[1].x, dv[1].y); float low1 = lowplane.ZatPoint(dv[1].x, dv[1].y);
float low2 = lowplane.ZatPoint(dv[2].x, dv[2].y); float low2 = lowplane.ZatPoint(dv[2].x, dv[2].y);
@ -343,13 +377,13 @@ void FDrawInfo::DrawDecal(GLWall *wall, DBaseDecal *decal)
FColormap thiscm; FColormap thiscm;
thiscm.FadeColor = wall->Colormap.FadeColor; thiscm.FadeColor = wall->Colormap.FadeColor;
thiscm.CopyFrom3DLight(&lightlist[k]); thiscm.CopyFrom3DLight(&lightlist[k]);
mDrawer->SetColor(thisll, rel, thiscm, a); mDrawer->SetColor(thisll, gldecal->rel, thiscm, gldecal->a);
if (level.flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING) thiscm.Decolorize(); if (level.flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING) thiscm.Decolorize();
mDrawer->SetFog(thisll, rel, &thiscm, wall->RenderStyle == STYLE_Add); mDrawer->SetFog(thisll, gldecal->rel, &thiscm, wall->RenderStyle == STYLE_Add);
gl_RenderState.SetSplitPlanes(lightlist[k].plane, lowplane); gl_RenderState.SetSplitPlanes(lightlist[k].plane, lowplane);
gl_RenderState.Apply(); gl_RenderState.Apply();
qd.Render(GL_TRIANGLE_FAN); GLRenderer->mVBO->RenderArray(GL_TRIANGLE_FAN, gldecal->vertindex, 4);
} }
if (low1 <= dv[0].z && low2 <= dv[3].z) break; if (low1 <= dv[0].z && low2 <= dv[3].z) break;
} }
@ -391,7 +425,6 @@ void FDrawInfo::DoDrawDecals(GLWall *wall)
{ {
gl_RenderState.EnableSplit(false); gl_RenderState.EnableSplit(false);
} }
} }
} }

View file

@ -86,7 +86,7 @@ public:
void SetFrom3DFloor(F3DFloor *rover, bool top, bool underside); void SetFrom3DFloor(F3DFloor *rover, bool top, bool underside);
void ProcessSector(sector_t * frontsector); void ProcessSector(sector_t * frontsector);
void Draw(int pass, bool trans); void Draw(int pass, bool trans);
GLFlat(const GLFlat &other) GLFlat(const GLFlat &other)
{ {
memcpy(this, &other, sizeof(GLFlat)); memcpy(this, &other, sizeof(GLFlat));

View file

@ -461,6 +461,7 @@ void FDrawInfo::AddWall(GLWall *wall)
wall->MakeVertices(this, false); wall->MakeVertices(this, false);
auto newwall = drawlists[list].NewWall(); auto newwall = drawlists[list].NewWall();
*newwall = *wall; *newwall = *wall;
if (!masked) newwall->ProcessDecals(this);
} }
wall->dynlightindex = -1; wall->dynlightindex = -1;
} }
@ -482,6 +483,7 @@ void FDrawInfo::AddMirrorSurface(GLWall *w)
tcs[GLWall::LOLFT].u = tcs[GLWall::LORGT].u = tcs[GLWall::UPLFT].u = tcs[GLWall::UPRGT].u = v.X; tcs[GLWall::LOLFT].u = tcs[GLWall::LORGT].u = tcs[GLWall::UPLFT].u = tcs[GLWall::UPRGT].u = v.X;
tcs[GLWall::LOLFT].v = tcs[GLWall::LORGT].v = tcs[GLWall::UPLFT].v = tcs[GLWall::UPRGT].v = v.Z; tcs[GLWall::LOLFT].v = tcs[GLWall::LORGT].v = tcs[GLWall::UPLFT].v = tcs[GLWall::UPRGT].v = v.Z;
newwall->MakeVertices(this, false); newwall->MakeVertices(this, false);
newwall->ProcessDecals(this);
} }
//========================================================================== //==========================================================================

View file

@ -6,6 +6,7 @@ struct FSectorPortalGroup;
struct FLinePortalSpan; struct FLinePortalSpan;
struct FFlatVertex; struct FFlatVertex;
class GLWall; class GLWall;
struct GLDecal;
//========================================================================== //==========================================================================
// //
@ -127,6 +128,7 @@ public:
virtual void AddWall(GLWall *w) = 0; virtual void AddWall(GLWall *w) = 0;
virtual void AddPortal(GLWall *w, int portaltype) = 0; virtual void AddPortal(GLWall *w, int portaltype) = 0;
virtual void AddMirrorSurface(GLWall *w) = 0; virtual void AddMirrorSurface(GLWall *w) = 0;
virtual void AddDecal(GLDecal *d) = 0;
virtual void ProcessActorsInPortal(FLinePortalSpan *glport) = 0; virtual void ProcessActorsInPortal(FLinePortalSpan *glport) = 0;
virtual std::pair<FFlatVertex *, unsigned int> AllocVertices(unsigned int count) = 0; virtual std::pair<FFlatVertex *, unsigned int> AllocVertices(unsigned int count) = 0;

View file

@ -236,6 +236,8 @@ public:
float fch1, float fch2, float ffh1, float ffh2, float fch1, float fch2, float ffh1, float ffh2,
float bch1, float bch2, float bfh1, float bfh2); float bch1, float bch2, float bfh1, float bfh2);
void ProcessDecal(HWDrawInfo *di, DBaseDecal *decal);
void ProcessDecals(HWDrawInfo *di);
void CreateVertices(FFlatVertex *&ptr, bool nosplit); void CreateVertices(FFlatVertex *&ptr, bool nosplit);
void SplitLeftEdge (FFlatVertex *&ptr); void SplitLeftEdge (FFlatVertex *&ptr);