diff --git a/src/gl/compatibility/gl_20.cpp b/src/gl/compatibility/gl_20.cpp index 57405e4ab..1c99b1825 100644 --- a/src/gl/compatibility/gl_20.cpp +++ b/src/gl/compatibility/gl_20.cpp @@ -555,6 +555,7 @@ bool FDrawInfo::PutWallCompat(GLWall *wall, int passflag) int list = list_indices[masked][foggy]; auto newwall = dldrawlists[list].NewWall(); *newwall = *wall; + if (!masked) newwall->ProcessDecals(this); return true; } diff --git a/src/gl/scene/gl_decal.cpp b/src/gl/scene/gl_decal.cpp index 0dd0b91f3..fa6f3dbba 100644 --- a/src/gl/scene/gl_decal.cpp +++ b/src/gl/scene/gl_decal.cpp @@ -46,143 +46,141 @@ struct DecalVertex float u,v; }; -//========================================================================== -// -// -// -//========================================================================== -void FDrawInfo::DrawDecal(GLWall *wall, DBaseDecal *decal) +struct GLDecal +{ + unsigned int vertindex; + FMaterial *gltexture; + GLWall *wall; + 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; side_t * side = seg->sidedef; int i; float zpos; - int light; - int rel; - float a; bool flipx, flipy; - DecalVertex dv[4]; FTextureID decalTile; - - + GLDecal gldecal; + + if (decal->RenderFlags & RF_INVISIBLE) return; - if (wall->type == RENDERWALL_FFBLOCK && wall->gltexture->isMasked()) return; // No decals on 3D floors with transparent textures. - - //if (decal->sprite != 0xffff) - { - decalTile = decal->PicNum; - flipx = !!(decal->RenderFlags & RF_XFLIP); - 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; - } - */ + if (type == RENDERWALL_FFBLOCK && gltexture->isMasked()) return; // No decals on 3D floors with transparent textures. + + + decalTile = decal->PicNum; + flipx = !!(decal->RenderFlags & RF_XFLIP); + flipy = !!(decal->RenderFlags & RF_YFLIP); + FTexture *texture = TexMan[decalTile]; if (texture == NULL) return; - FMaterial *tex; - - - tex = FMaterial::ValidateTexture(texture, true); - - + // the sectors are only used for their texture origin coordinates // so we don't need the fake sectors for deep water etc. // As this is a completely split wall fragment no further splits are // necessary for the decal. sector_t *frontsector; - + // for 3d-floor segments use the model sector as reference if ((decal->RenderFlags&RF_CLIPMASK) == RF_CLIPMID) frontsector = decal->Sector; else frontsector = seg->frontsector; - + switch (decal->RenderFlags & RF_RELMASK) { - default: - // No valid decal can have this type. If one is encountered anyway - // it is in some way invalid so skip it. - return; - //zpos = decal->z; - //break; - - case RF_RELUPPER: - if (wall->type != RENDERWALL_TOP) return; - if (line->flags & ML_DONTPEGTOP) - { - zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling); - } - else - { - zpos = decal->Z + seg->backsector->GetPlaneTexZ(sector_t::ceiling); - } - break; - case RF_RELLOWER: - if (wall->type != RENDERWALL_BOTTOM) return; - if (line->flags & ML_DONTPEGBOTTOM) - { - zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling); - } - else - { - zpos = decal->Z + seg->backsector->GetPlaneTexZ(sector_t::floor); - } - break; - case RF_RELMID: - if (wall->type == RENDERWALL_TOP || wall->type == RENDERWALL_BOTTOM) return; - if (line->flags & ML_DONTPEGBOTTOM) - { - zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::floor); - } - else - { - zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling); - } + default: + // No valid decal can have this type. If one is encountered anyway + // it is in some way invalid so skip it. + return; + //zpos = decal->z; + //break; + + case RF_RELUPPER: + if (type != RENDERWALL_TOP) return; + if (line->flags & ML_DONTPEGTOP) + { + zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling); + } + else + { + zpos = decal->Z + seg->backsector->GetPlaneTexZ(sector_t::ceiling); + } + break; + case RF_RELLOWER: + if (type != RENDERWALL_BOTTOM) return; + if (line->flags & ML_DONTPEGBOTTOM) + { + zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling); + } + else + { + zpos = decal->Z + seg->backsector->GetPlaneTexZ(sector_t::floor); + } + break; + case RF_RELMID: + if (type == RENDERWALL_TOP || type == RENDERWALL_BOTTOM) return; + if (line->flags & ML_DONTPEGBOTTOM) + { + zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::floor); + } + else + { + 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) { - light = 255; - rel = 0; + gldecal.light = 255; + gldecal.rel = 0; } else { - light = wall->lightlevel; - rel = wall->rellight + getExtraLight(); + gldecal.light = lightlevel; + gldecal.rel = rellight + getExtraLight(); } - - FColormap p = wall->Colormap; - + + gldecal.colormap = Colormap; + if (level.flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING) { - p.Decolorize(); + gldecal.colormap.Decolorize(); } - - - - a = decal->Alpha; - + + gldecal.a = decal->Alpha; + // now clip the decal to the actual polygon + FMaterial *tex = gldecal.gltexture; + float decalwidth = tex->TextureWidth() * decal->ScaleX; float decalheight = tex->TextureHeight() * decal->ScaleY; float decallefto = tex->GetLeftOffset() * decal->ScaleX; float decaltopo = tex->GetTopOffset() * decal->ScaleY; - - auto &glseg = wall->glseg; + float leftedge = glseg.fracleft * side->TexelLength; float linelength = glseg.fracright * side->TexelLength - leftedge; - + // texel index of the decal's left edge float decalpixpos = (float)side->TexelLength * decal->LeftDistance - (flipx ? decalwidth - decallefto : decallefto) - leftedge; - + float left, right; float lefttex, righttex; - + // decal is off the left edge if (decalpixpos < 0) { @@ -194,7 +192,7 @@ void FDrawInfo::DrawDecal(GLWall *wall, DBaseDecal *decal) left = decalpixpos; lefttex = 0; } - + // decal is off the right edge if (decalpixpos + decalwidth > linelength) { @@ -207,36 +205,37 @@ void FDrawInfo::DrawDecal(GLWall *wall, DBaseDecal *decal) righttex = decalwidth; } if (right <= left) return; // nothing to draw - + // one texture unit on the wall as vector float vx = (glseg.x2 - glseg.x1) / linelength; float vy = (glseg.y2 - glseg.y1) / linelength; - + + DecalVertex *dv = gldecal.dv; dv[1].x = dv[0].x = glseg.x1 + vx * left; dv[1].y = dv[0].y = glseg.y1 + vy * left; - + dv[3].x = dv[2].x = glseg.x1 + vx * right; dv[3].y = dv[2].y = glseg.y1 + vy * right; - + zpos += (flipy ? decalheight - decaltopo : decaltopo); - + dv[1].z = dv[2].z = zpos; dv[0].z = dv[3].z = dv[1].z - decalheight; dv[1].v = dv[2].v = tex->GetVT(); - + dv[1].u = dv[0].u = tex->GetU(lefttex / decal->ScaleX); dv[3].u = dv[2].u = tex->GetU(righttex / decal->ScaleX); dv[0].v = dv[3].v = tex->GetVB(); - + // now clip to the top plane - float vzt = (wall->ztop[1] - wall->ztop[0]) / linelength; - float topleft = wall->ztop[0] + vzt * left; - float topright = wall->ztop[0] + vzt * right; - + float vzt = (ztop[1] - ztop[0]) / linelength; + float topleft = ztop[0] + vzt * left; + float topright = ztop[0] + vzt * right; + // completely below the wall if (topleft < dv[0].z && topright < dv[3].z) return; - + if (topleft < dv[1].z || topright < dv[2].z) { // decal has to be clipped at the top @@ -246,16 +245,16 @@ void FDrawInfo::DrawDecal(GLWall *wall, DBaseDecal *decal) dv[1].z = topleft; dv[2].z = topright; } - + // now clip to the bottom plane - float vzb = (wall->zbottom[1] - wall->zbottom[0]) / linelength; - float bottomleft = wall->zbottom[0] + vzb * left; - float bottomright = wall->zbottom[0] + vzb * right; - + float vzb = (zbottom[1] - zbottom[0]) / linelength; + float bottomleft = zbottom[0] + vzb * left; + float bottomright = zbottom[0] + vzb * right; + // completely above the wall if (bottomleft > dv[1].z && bottomright > dv[2].z) return; - + if (bottomleft > dv[0].z || bottomright > dv[3].z) { // decal has to be clipped at the bottom @@ -265,8 +264,8 @@ void FDrawInfo::DrawDecal(GLWall *wall, DBaseDecal *decal) dv[0].z = bottomleft; dv[3].z = bottomright; } - - + + if (flipx) { 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; } + 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. if (gl_lights && GLRenderer->mLightCount && !mDrawer->FixedColormap && gl_light_sprites) { // Note: This should be replaced with proper shader based lighting. double 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. @@ -293,9 +335,6 @@ void FDrawInfo::DrawDecal(GLWall *wall, DBaseDecal *decal) gl_RenderState.SetObjectColor(decal->AlphaColor | 0xff000000); } - - - gl_SetRenderStyle(decal->RenderStyle, false, false); 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); - 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. PalEntry fc = gl_RenderState.GetFogColor(); 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.SetNormal(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); - } + gl_RenderState.SetNormal(wall->glseg.Normal()); if (wall->lightlist == nullptr) { gl_RenderState.Apply(); - qd.Render(GL_TRIANGLE_FAN); + GLRenderer->mVBO->RenderArray(GL_TRIANGLE_FAN, gldecal->vertindex, 4); } 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; + DecalVertex *dv = gldecal->dv; float low1 = lowplane.ZatPoint(dv[1].x, dv[1].y); float low2 = lowplane.ZatPoint(dv[2].x, dv[2].y); @@ -343,13 +377,13 @@ void FDrawInfo::DrawDecal(GLWall *wall, DBaseDecal *decal) FColormap thiscm; thiscm.FadeColor = wall->Colormap.FadeColor; 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(); - 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.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; } @@ -391,7 +425,6 @@ void FDrawInfo::DoDrawDecals(GLWall *wall) { gl_RenderState.EnableSplit(false); } - } } diff --git a/src/gl/scene/gl_wall.h b/src/gl/scene/gl_wall.h index 504c6f21c..03cc9dadd 100644 --- a/src/gl/scene/gl_wall.h +++ b/src/gl/scene/gl_wall.h @@ -86,7 +86,7 @@ public: void SetFrom3DFloor(F3DFloor *rover, bool top, bool underside); void ProcessSector(sector_t * frontsector); void Draw(int pass, bool trans); - + GLFlat(const GLFlat &other) { memcpy(this, &other, sizeof(GLFlat)); diff --git a/src/gl/scene/gl_walls_draw.cpp b/src/gl/scene/gl_walls_draw.cpp index de2e9a657..4a68d4ac6 100644 --- a/src/gl/scene/gl_walls_draw.cpp +++ b/src/gl/scene/gl_walls_draw.cpp @@ -461,6 +461,7 @@ void FDrawInfo::AddWall(GLWall *wall) wall->MakeVertices(this, false); auto newwall = drawlists[list].NewWall(); *newwall = *wall; + if (!masked) newwall->ProcessDecals(this); } 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].v = tcs[GLWall::LORGT].v = tcs[GLWall::UPLFT].v = tcs[GLWall::UPRGT].v = v.Z; newwall->MakeVertices(this, false); + newwall->ProcessDecals(this); } //========================================================================== diff --git a/src/hwrenderer/scene/hw_drawinfo.h b/src/hwrenderer/scene/hw_drawinfo.h index 13533cbfc..e2db5f132 100644 --- a/src/hwrenderer/scene/hw_drawinfo.h +++ b/src/hwrenderer/scene/hw_drawinfo.h @@ -6,6 +6,7 @@ struct FSectorPortalGroup; struct FLinePortalSpan; struct FFlatVertex; class GLWall; +struct GLDecal; //========================================================================== // @@ -127,6 +128,7 @@ public: virtual void AddWall(GLWall *w) = 0; virtual void AddPortal(GLWall *w, int portaltype) = 0; virtual void AddMirrorSurface(GLWall *w) = 0; + virtual void AddDecal(GLDecal *d) = 0; virtual void ProcessActorsInPortal(FLinePortalSpan *glport) = 0; virtual std::pair AllocVertices(unsigned int count) = 0; diff --git a/src/hwrenderer/scene/hw_drawstructs.h b/src/hwrenderer/scene/hw_drawstructs.h index 262e5ed05..a508b2a81 100644 --- a/src/hwrenderer/scene/hw_drawstructs.h +++ b/src/hwrenderer/scene/hw_drawstructs.h @@ -236,6 +236,8 @@ public: float fch1, float fch2, float ffh1, float ffh2, 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 SplitLeftEdge (FFlatVertex *&ptr);