added wall texture skewing.

This uses the same UDMF properties as Eternity recently introduced for the same feature.
This commit is contained in:
Professor Hastig 2023-10-20 08:06:04 +02:00
parent 9cd57faec1
commit f92f6b8de4
7 changed files with 151 additions and 26 deletions

View file

@ -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<DInterpolation*> interpolation;
int flags;
int16_t flags;
int8_t skew;
FTextureID texture;
TextureManipulation TextureFx;
PalEntry SpecialColors[2];

View file

@ -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);

View file

@ -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<typename T>
bool Flag(T &value, int mask, FName key)

View file

@ -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)

View file

@ -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)

View file

@ -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);

View file

@ -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 (texturetop<topleft && texturetop<topright) topleft=topright=texturetop;
if (texturebottom>bottomleft && 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);
}
}