From f92f6b8de4e20a62292565d185e5c0b43e866c0d Mon Sep 17 00:00:00 2001 From: Professor Hastig Date: Fri, 20 Oct 2023 08:06:04 +0200 Subject: [PATCH] added wall texture skewing. This uses the same UDMF properties as Eternity recently introduced for the same feature. --- src/gamedata/r_defs.h | 16 +++- src/maploader/udmf.cpp | 59 ++++++++++++ src/maploader/udmf.h | 1 + src/namedef_custom.h | 4 + src/p_saveg.cpp | 1 + .../hwrenderer/scene/hw_drawstructs.h | 6 +- src/rendering/hwrenderer/scene/hw_walls.cpp | 90 ++++++++++++++----- 7 files changed, 151 insertions(+), 26 deletions(-) diff --git a/src/gamedata/r_defs.h b/src/gamedata/r_defs.h index 4af030b28..0517b0f93 100644 --- a/src/gamedata/r_defs.h +++ b/src/gamedata/r_defs.h @@ -1194,6 +1194,19 @@ struct side_t walltop = 0, wallbottom = 1, }; + enum ESkew + { + skew_none = 0, + skew_front = 1, + skew_back = 2, + // for mid textures there's 4 options + skew_front_floor = 1, + skew_front_ceiling = 2, + skew_back_floor = 3, + skew_back_ceiling = 4 + + }; + struct part { enum EPartFlags @@ -1209,7 +1222,8 @@ struct side_t double xScale; double yScale; TObjPtr interpolation; - int flags; + int16_t flags; + int8_t skew; FTextureID texture; TextureManipulation TextureFx; PalEntry SpecialColors[2]; diff --git a/src/maploader/udmf.cpp b/src/maploader/udmf.cpp index e51a82433..abd1fabbf 100644 --- a/src/maploader/udmf.cpp +++ b/src/maploader/udmf.cpp @@ -104,6 +104,24 @@ static char HexenSectorSpecialOk[256]={ 1,1,1,1,1, }; +static const char* udmfsolidskewtypes[] = +{ + "none", + "front", + "back", + nullptr +}; + +static const char* udmfmaskedskewtypes[] = +{ + "none", + "front_floor", + "front_ceiling", + "back_floor", + "back_ceiling", + nullptr +}; + static inline bool P_IsThingSpecial(int specnum) { return (specnum >= Thing_Projectile && specnum <= Thing_SpawnNoFog) || @@ -282,6 +300,20 @@ const char *UDMFParserBase::CheckString(FName key) return parsedString.GetChars(); } +int UDMFParserBase::MatchString(FName key, const char* const* strings, int defval) +{ + const char* string = CheckString(key); + for (int i = 0; *strings != nullptr; i++, strings++) + { + if (!stricmp(string, *strings)) + { + return i; + } + } + sc.ScriptMessage("Unknown value %s for key '%s'", string, key.GetChars()); + return defval; +} + //=========================================================================== // // Storage of UDMF user properties @@ -1484,6 +1516,22 @@ public: CHECK_N(Zd | Zdt) break; + case NAME_skew_top_type: + CHECK_N(Zd | Zdt) + sd->textures[side_t::top].skew = MatchString(key, udmfsolidskewtypes, 0); + break; + + case NAME_skew_middle_type: + CHECK_N(Zd | Zdt) + sd->textures[side_t::mid].skew = MatchString(key, udmfmaskedskewtypes, 0); + break; + + case NAME_skew_bottom_type: + CHECK_N(Zd | Zdt) + sd->textures[side_t::bottom].skew = MatchString(key, udmfsolidskewtypes, 0); + break; + + default: if (strnicmp("user_", key.GetChars(), 5)) DPrintf(DMSG_WARNING, "Unknown UDMF sidedef key %s\n", key.GetChars()); @@ -2200,6 +2248,17 @@ public: sides[side].sector = &Level->sectors[intptr_t(sides[side].sector)]; lines[line].sidedef[sd] = &sides[side]; + if (sd == 1) + { + // fix flags for backside. The definition is linedef relative, not sidedef relative. + static const uint8_t swaps[] = { 0, side_t::skew_back, side_t::skew_front }; + static const uint8_t swapsm[] = {0, side_t::skew_back_floor, side_t::skew_back_ceiling, side_t::skew_front_floor, side_t::skew_front_ceiling}; + + sides[side].textures[side_t::top].skew = swaps[sides[side].textures[side_t::top].skew]; + sides[side].textures[side_t::bottom].skew = swaps[sides[side].textures[side_t::bottom].skew]; + sides[side].textures[side_t::mid].skew = swapsm[sides[side].textures[side_t::mid].skew]; + } + loader->ProcessSideTextures(!isExtended, &sides[side], sides[side].sector, &ParsedSideTextures[mapside], lines[line].special, lines[line].args[0], &tempalpha[sd], missingTex); diff --git a/src/maploader/udmf.h b/src/maploader/udmf.h index ed18345b5..38d904288 100644 --- a/src/maploader/udmf.h +++ b/src/maploader/udmf.h @@ -21,6 +21,7 @@ protected: DAngle CheckAngle(FName key); bool CheckBool(FName key); const char *CheckString(FName key); + int MatchString(FName key, const char* const* strings, int defval); template bool Flag(T &value, int mask, FName key) diff --git a/src/namedef_custom.h b/src/namedef_custom.h index a5604475d..9d1c2e22b 100644 --- a/src/namedef_custom.h +++ b/src/namedef_custom.h @@ -858,4 +858,8 @@ xx(lm_sampledist_ceiling) xx(lm_suncolor) xx(lm_sampledistance) +xx(skew_bottom_type) +xx(skew_middle_type) +xx(skew_top_type) + xx(Corona) diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 156226b57..9f481be06 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -140,6 +140,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, side_t::part &part, si ("texture", part.texture, def->texture) ("interpolation", part.interpolation) ("flags", part.flags, def->flags) + ("skew", part.skew, def->skew) ("color1", part.SpecialColors[0], def->SpecialColors[0]) ("color2", part.SpecialColors[1], def->SpecialColors[1]) ("addcolor", part.AdditiveColor, def->AdditiveColor) diff --git a/src/rendering/hwrenderer/scene/hw_drawstructs.h b/src/rendering/hwrenderer/scene/hw_drawstructs.h index af65baf09..e758ee887 100644 --- a/src/rendering/hwrenderer/scene/hw_drawstructs.h +++ b/src/rendering/hwrenderer/scene/hw_drawstructs.h @@ -237,19 +237,19 @@ public: bool DoHorizon(HWWallDispatcher* di, seg_t* seg, sector_t* fs, vertex_t* v1, vertex_t* v2); bool SetWallCoordinates(seg_t* seg, FTexCoordInfo* tci, float ceilingrefheight, - float topleft, float topright, float bottomleft, float bottomright, float t_ofs); + float topleft, float topright, float bottomleft, float bottomright, float t_ofs, float skew); void DoTexture(HWWallDispatcher* di, int type, seg_t* seg, int peg, float ceilingrefheight, float floorrefheight, float CeilingHeightstart, float CeilingHeightend, float FloorHeightstart, float FloorHeightend, - float v_offset); + float v_offset, float skew); void DoMidTexture(HWWallDispatcher* di, seg_t* seg, bool drawfogboundary, sector_t* front, sector_t* back, sector_t* realfront, sector_t* realback, float fch1, float fch2, float ffh1, float ffh2, - float bch1, float bch2, float bfh1, float bfh2, float zalign); + float bch1, float bch2, float bfh1, float bfh2, float zalign, float skew); void GetPlanePos(F3DFloor::planeref* planeref, float& left, float& right); diff --git a/src/rendering/hwrenderer/scene/hw_walls.cpp b/src/rendering/hwrenderer/scene/hw_walls.cpp index c92481102..5e0048545 100644 --- a/src/rendering/hwrenderer/scene/hw_walls.cpp +++ b/src/rendering/hwrenderer/scene/hw_walls.cpp @@ -1016,7 +1016,7 @@ static float ZeroLightmapUVs[8] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0. // //========================================================================== bool HWWall::SetWallCoordinates(seg_t * seg, FTexCoordInfo *tci, float texturetop, - float topleft, float topright, float bottomleft, float bottomright, float t_ofs) + float topleft, float topright, float bottomleft, float bottomright, float t_ofs, float skew) { // // @@ -1109,8 +1109,8 @@ bool HWWall::SetWallCoordinates(seg_t * seg, FTexCoordInfo *tci, float textureto if (tci) { - tcs[UPRGT].v = tci->FloatToTexV(-ztop[1] + texturetop); - tcs[LORGT].v = tci->FloatToTexV(-zbottom[1] + texturetop); + tcs[UPRGT].v = tci->FloatToTexV(-ztop[1] + texturetop + skew); + tcs[LORGT].v = tci->FloatToTexV(-zbottom[1] + texturetop + skew); } lightuv[UPRGT].v = srclightuv[UPRGT].v; @@ -1132,7 +1132,7 @@ bool HWWall::SetWallCoordinates(seg_t * seg, FTexCoordInfo *tci, float textureto zbottom[1] = ztop[1] = inter_y; if (tci) { - tcs[LORGT].v = tcs[UPRGT].v = tci->FloatToTexV(-ztop[1] + texturetop); + tcs[LORGT].v = tcs[UPRGT].v = tci->FloatToTexV(-ztop[1] + texturetop + skew); } lightuv[UPRGT].v = srclightuv[UPRGT].v + inter_x * (srclightuv[UPRGT].v - srclightuv[UPLFT].v); @@ -1258,7 +1258,7 @@ void HWWall::DoTexture(HWWallDispatcher *di, int _type,seg_t * seg, int peg, float ceilingrefheight,float floorrefheight, float topleft,float topright, float bottomleft,float bottomright, - float v_offset) + float v_offset, float skew) { if (topleft<=bottomleft && topright<=bottomright) return; @@ -1300,7 +1300,7 @@ void HWWall::DoTexture(HWWallDispatcher *di, int _type,seg_t * seg, int peg, if (peg) floatceilingref += tci.mRenderHeight - flh - v_offset; if (!SetWallCoordinates(seg, &tci, floatceilingref, topleft, topright, bottomleft, bottomright, - seg->sidedef->GetTextureXOffset(texpos))) return; + seg->sidedef->GetTextureXOffset(texpos), skew)) return; if (seg->linedef->special == Line_Mirror && _type == RENDERWALL_M1S && gl_mirrors && !(di->Level->ib_compatflags & BCOMPATF_NOMIRRORS)) { @@ -1332,7 +1332,7 @@ void HWWall::DoMidTexture(HWWallDispatcher *di, seg_t * seg, bool drawfogboundar sector_t * front, sector_t * back, sector_t * realfront, sector_t * realback, float fch1, float fch2, float ffh1, float ffh2, - float bch1, float bch2, float bfh1, float bfh2, float zalign) + float bch1, float bch2, float bfh1, float bfh2, float zalign, float skew) { FTexCoordInfo tci; @@ -1449,10 +1449,10 @@ void HWWall::DoMidTexture(HWWallDispatcher *di, seg_t * seg, bool drawfogboundar // if we don't need a fog sheet let's clip away some unnecessary parts of the polygon // // - if (!drawfogboundary && !wrap) + if (!drawfogboundary && !wrap && skew == 0) { - if (texturetopbottomleft && texturebottom>bottomright) bottomleft=bottomright=texturebottom; + if (texturetop < topleft && texturetop < topright) topleft = topright = texturetop; + if (texturebottom > bottomleft && texturebottom > bottomright) bottomleft = bottomright = texturebottom; } } else @@ -1465,8 +1465,10 @@ void HWWall::DoMidTexture(HWWallDispatcher *di, seg_t * seg, bool drawfogboundar // unwanted side effects. // // - topleft=topright=texturetop; - bottomleft=bottomright=texturebottom; + topleft = texturetop; + topright = texturetop + skew; + bottomleft = texturebottom; + bottomright = texturebottom + skew; } // nothing visible - skip the rest @@ -1529,7 +1531,7 @@ void HWWall::DoMidTexture(HWWallDispatcher *di, seg_t * seg, bool drawfogboundar // mid textures on portal lines need the same offsetting as mid textures on sky lines flags |= HWF_SKYHACK; } - SetWallCoordinates(seg, &tci, texturetop, topleft, topright, bottomleft, bottomright, t_ofs); + SetWallCoordinates(seg, &tci, texturetop, topleft, topright, bottomleft, bottomright, t_ofs, skew); // // @@ -1588,7 +1590,7 @@ void HWWall::DoMidTexture(HWWallDispatcher *di, seg_t * seg, bool drawfogboundar FloatRect *splitrect; int v = texture->GetAreas(&splitrect); if (seg->frontsector == seg->backsector) flags |= HWF_NOSPLIT; // we don't need to do vertex splits if a line has both sides in the same sector - if (v>0 && !drawfogboundary && !(seg->linedef->flags&ML_WRAP_MIDTEX) && !(flags & HWF_NOSLICE)) + if (v>0 && !drawfogboundary && !(seg->linedef->flags&ML_WRAP_MIDTEX) && !(flags & HWF_NOSLICE) && skew == 0) { // split the poly! int i,t=0; @@ -2042,6 +2044,10 @@ inline int CalcRelLight(int lightlevel, int orglightlevel, int rel) } } +CVAR(Int, topskew, 0, 0) +CVAR(Int, midskew, 0, 0) +CVAR(Int, bottomskew, 0, 0) + //========================================================================== // // @@ -2198,9 +2204,14 @@ void HWWall::Process(HWWallDispatcher *di, seg_t *seg, sector_t * frontsector, s texture = TexMan.GetGameTexture(seg->sidedef->GetTexture(side_t::mid), true); if (texture && texture->isValid()) { + int skewflag = seg->sidedef->textures[side_t::mid].skew; + if (skewflag == 0) skewflag = midskew; + float skew = + skewflag == side_t::skew_front_ceiling ? fch2 - fch1 : + skewflag == side_t::skew_front_floor ? ffh2 - ffh1 : 0.; DoTexture(di, RENDERWALL_M1S, seg, (seg->linedef->flags & ML_DONTPEGBOTTOM) > 0, crefz, frefz, // must come from the original! - fch1, fch2, ffh1, ffh2, 0); + fch1, fch2, ffh1, ffh2, 0, skew); } } } @@ -2268,9 +2279,15 @@ void HWWall::Process(HWWallDispatcher *di, seg_t *seg, sector_t * frontsector, s texture = TexMan.GetGameTexture(seg->sidedef->GetTexture(side_t::top), true); if (texture && texture->isValid()) { + int skewflag = seg->sidedef->textures[side_t::top].skew; + if (skewflag == 0) skewflag = topskew; + float skew = + skewflag == side_t::skew_front ? fch2 - fch1 : + skewflag == side_t::skew_back ? bch2 - bch1 : 0.; + DoTexture(di, RENDERWALL_TOP, seg, (seg->linedef->flags & (ML_DONTPEGTOP)) == 0, crefz, realback->GetPlaneTexZ(sector_t::ceiling), - fch1, fch2, bch1a, bch2a, 0); + fch1, fch2, bch1a, bch2a, 0, skew); } else if (!(seg->sidedef->Flags & WALLF_POLYOBJ)) { @@ -2283,7 +2300,7 @@ void HWWall::Process(HWWallDispatcher *di, seg_t *seg, sector_t * frontsector, s { DoTexture(di, RENDERWALL_TOP, seg, (seg->linedef->flags & (ML_DONTPEGTOP)) == 0, crefz, realback->GetPlaneTexZ(sector_t::ceiling), - fch1, fch2, bch1a, bch2a, 0); + fch1, fch2, bch1a, bch2a, 0, 0); } } else @@ -2318,6 +2335,28 @@ void HWWall::Process(HWWallDispatcher *di, seg_t *seg, sector_t * frontsector, s lightlevel = hw_ClampLight(seg->sidedef->GetLightLevel(foggy, orglightlevel, side_t::mid, false, &rel)); rellight = CalcRelLight(lightlevel, orglightlevel, rel); + float skew; + int skewflag = seg->sidedef->textures[side_t::mid].skew; + if (skewflag == 0) skewflag = midskew; + switch (skewflag) + { + default: + skew = 0; + break; + case side_t::skew_front_ceiling: + skew = fch2 - fch1; + break; + case side_t::skew_back_ceiling: + skew = bch2 - bch1; + break; + case side_t::skew_front_floor: + skew = bfh2 - bfh1; + break; + case side_t::skew_back_floor: + skew = ffh2 - ffh1; + break; + } + if (isportal) { lineportal = seg->linedef->getPortal()->mGroup; @@ -2330,7 +2369,7 @@ void HWWall::Process(HWWallDispatcher *di, seg_t *seg, sector_t * frontsector, s if (texture && seg->backsector != nullptr) { DoMidTexture(di, seg, drawfogboundary, frontsector, backsector, realfront, realback, - fch1, fch2, ffh1, ffh2, bch1, bch2, bfh1, bfh2, zalign); + fch1, fch2, ffh1, ffh2, bch1, bch2, bfh1, bfh2, zalign, skew); } } else @@ -2339,7 +2378,7 @@ void HWWall::Process(HWWallDispatcher *di, seg_t *seg, sector_t * frontsector, s if (texture || drawfogboundary) { DoMidTexture(di, seg, drawfogboundary, frontsector, backsector, realfront, realback, - fch1, fch2, ffh1, ffh2, bch1, bch2, bfh1, bfh2, zalign); + fch1, fch2, ffh1, ffh2, bch1, bch2, bfh1, bfh2, zalign, skew); } if (backsector->e->XFloor.ffloors.Size() || frontsector->e->XFloor.ffloors.Size()) @@ -2352,6 +2391,7 @@ void HWWall::Process(HWWallDispatcher *di, seg_t *seg, sector_t * frontsector, s /* bottom texture */ // the back sector's ceiling obstructs part of this wall (specially important for sky sectors) + float bfh1a = bch1, bfh2a = bch2; if (fch1 < bfh1 && fch2 < bfh2 && (seg->linedef->flags & ML_DRAWFULLHEIGHT) == 0) { bfh1 = fch1; @@ -2365,12 +2405,18 @@ void HWWall::Process(HWWallDispatcher *di, seg_t *seg, sector_t * frontsector, s texture = TexMan.GetGameTexture(seg->sidedef->GetTexture(side_t::bottom), true); if (texture && texture->isValid()) { + int skewflag = seg->sidedef->textures[side_t::bottom].skew; + if (skewflag == 0) skewflag = bottomskew; + float skew = + skewflag == side_t::skew_back ? bfh2a - bfh1a : + skewflag == side_t::skew_front ? ffh2 - ffh1 : 0.; + DoTexture(di, RENDERWALL_BOTTOM, seg, (seg->linedef->flags & ML_DONTPEGBOTTOM) > 0, realback->GetPlaneTexZ(sector_t::floor), frefz, bfh1, bfh2, ffh1, ffh2, frontsector->GetTexture(sector_t::ceiling) == skyflatnum && backsector->GetTexture(sector_t::ceiling) == skyflatnum ? frefz - realback->GetPlaneTexZ(sector_t::ceiling) : - frefz - crefz); + frefz - crefz, skew); } else if (!(seg->sidedef->Flags & WALLF_POLYOBJ)) { @@ -2386,7 +2432,7 @@ void HWWall::Process(HWWallDispatcher *di, seg_t *seg, sector_t * frontsector, s { DoTexture(di, RENDERWALL_BOTTOM, seg, (seg->linedef->flags & ML_DONTPEGBOTTOM) > 0, realback->GetPlaneTexZ(sector_t::floor), frefz, - bfh1, bfh2, ffh1, ffh2, frefz - crefz); + bfh1, bfh2, ffh1, ffh2, frefz - crefz, 0); } } else if (backsector->GetTexture(sector_t::floor) != skyflatnum) @@ -2458,7 +2504,7 @@ void HWWall::ProcessLowerMiniseg(HWWallDispatcher *di, seg_t *seg, sector_t * fr FTexCoordInfo tci; type = RENDERWALL_BOTTOM; tci.GetFromTexture(texture, 1, 1, false); - SetWallCoordinates(seg, &tci, bfh, bfh, bfh, ffh, ffh, 0); + SetWallCoordinates(seg, &tci, bfh, bfh, bfh, ffh, ffh, 0, 0); PutWall(di, false); } }