Support overlay textures on 3D floor sides

This commit is contained in:
Lactozilla 2024-01-26 19:46:41 -03:00
parent 1de411020d
commit 61e48af0dc

View file

@ -72,6 +72,9 @@ static struct
fixed_t offsetx, offsety;
} rw_overlay[NUM_WALL_OVERLAYS];
static fixed_t oldoverlaycolumn[NUM_WALL_OVERLAYS];
static fixed_t overlaycolumn[NUM_WALL_OVERLAYS];
// Lactozilla: 3D floor clipping
static boolean rw_floormarked = false;
static boolean rw_ceilingmarked = false;
@ -104,6 +107,10 @@ static INT16 *openings, *lastopening;
static size_t texturecolumntablesize;
static fixed_t *texturecolumntable, *curtexturecolumntable;
static void R_AddOverlayTextures(sector_t *sec_front, sector_t *sec_back, fixed_t left_top, fixed_t left_bottom, fixed_t left_high, fixed_t left_low, fixed_t ceilingfrontslide, fixed_t floorfrontslide, fixed_t ceilingbackslide, fixed_t floorbackslide);
static void R_StoreOverlayColumn(INT32 x, fixed_t textureoffset);
void R_ClearSegTables(void)
{
lastopening = openings;
@ -198,6 +205,84 @@ transnum_t R_GetLinedefTransTable(fixed_t alpha)
return (20*(FRACUNIT - alpha - 1) + FRACUNIT) >> (FRACBITS+1);
}
static INT32 R_GetOverlayTextureRepeats(drawseg_t *ds, unsigned which, sector_t *sec_front, sector_t *sec_back)
{
INT32 repeats = 1;
if (!(sidedef->overlays[which].flags & SIDEOVERLAYFLAG_WRAP))
return repeats;
fixed_t high, low;
fixed_t texheight = textureheight[overlaytexture[which]];
if (sec_back)
{
if (IS_TOP_EDGE_TEXTURE(which))
{
if (sidedef->overlays[which].flags & SIDEOVERLAYFLAG_NOSKEW)
{
high = sec_front->ceilingheight;
low = sec_back->ceilingheight;
}
else
{
high = max(
P_GetSectorCeilingZAt(sec_front, ds->leftpos.x, ds->leftpos.y),
P_GetSectorCeilingZAt(sec_front, ds->rightpos.x, ds->rightpos.y)
);
low = min(
P_GetSectorCeilingZAt(sec_back, ds->leftpos.x, ds->leftpos.y),
P_GetSectorCeilingZAt(sec_back, ds->rightpos.x, ds->rightpos.y)
);
}
}
else
{
if (sidedef->overlays[which].flags & SIDEOVERLAYFLAG_NOSKEW)
{
high = sec_back->floorheight;
low = sec_back->floorheight;
}
else
{
high = max(
P_GetSectorFloorZAt(sec_front, ds->leftpos.x, ds->leftpos.y),
P_GetSectorFloorZAt(sec_front, ds->rightpos.x, ds->rightpos.y)
);
low = min(
P_GetSectorFloorZAt(sec_back, ds->leftpos.x, ds->leftpos.y),
P_GetSectorFloorZAt(sec_back, ds->rightpos.x, ds->rightpos.y)
);
}
}
}
else
{
if (sidedef->overlays[which].flags & SIDEOVERLAYFLAG_NOSKEW)
{
high = sec_front->ceilingheight;
low = sec_front->floorheight;
}
else
{
high = max(
P_GetSectorCeilingZAt(sec_front, ds->leftpos.x, ds->leftpos.y),
P_GetSectorCeilingZAt(sec_front, ds->rightpos.x, ds->rightpos.y)
);
low = min(
P_GetSectorFloorZAt(sec_front, ds->leftpos.x, ds->leftpos.y),
P_GetSectorFloorZAt(sec_front, ds->rightpos.x, ds->rightpos.y)
);
}
}
repeats = (high - low)/texheight;
if ((high-low)%texheight)
repeats++; // tile an extra time to fill the gap -- Monster Iestyn
return max(repeats, 1);
}
// Setup lighting based on the presence/lack-of 3D floors.
static void R_PrepareMaskedSegLightlist(drawseg_t *ds, INT32 range)
{
@ -572,7 +657,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
}
// Renders a texture right on top of the wall texture
static void R_RenderExtraTexture(drawseg_t *ds, unsigned which, INT32 x1, INT32 x2)
static void R_RenderExtraTexture(unsigned which, INT32 x1, INT32 x2, INT32 repeats, drawseg_t *ds)
{
size_t pindex;
column_t *col;
@ -580,7 +665,7 @@ static void R_RenderExtraTexture(drawseg_t *ds, unsigned which, INT32 x1, INT32
fixed_t height, realbot;
r_lightlist_t *rlight;
void (*colfunc_2s)(column_t *);
INT32 times, repeats;
INT32 times;
INT64 overflow_test;
INT32 range;
@ -647,54 +732,6 @@ static void R_RenderExtraTexture(drawseg_t *ds, unsigned which, INT32 x1, INT32
mfloorclip = overlayopening[1];
mceilingclip = overlayopening[0];
if (sidedef->overlays[which].flags & SIDEOVERLAYFLAG_WRAP)
{
fixed_t high, low;
if (backsector)
{
if (IS_TOP_EDGE_TEXTURE(which))
{
high = max(
P_GetSectorCeilingZAt(frontsector, ds_p->leftpos.x, ds_p->leftpos.y),
P_GetSectorCeilingZAt(frontsector, ds_p->rightpos.x, ds_p->rightpos.y)
);
low = min(
P_GetSectorCeilingZAt(backsector, ds_p->leftpos.x, ds_p->leftpos.y),
P_GetSectorCeilingZAt(backsector, ds_p->rightpos.x, ds_p->rightpos.y)
);
}
else
{
high = max(
P_GetSectorFloorZAt(frontsector, ds_p->leftpos.x, ds_p->leftpos.y),
P_GetSectorFloorZAt(frontsector, ds_p->rightpos.x, ds_p->rightpos.y)
);
low = min(
P_GetSectorFloorZAt(backsector, ds_p->leftpos.x, ds_p->leftpos.y),
P_GetSectorFloorZAt(backsector, ds_p->rightpos.x, ds_p->rightpos.y)
);
}
}
else
{
high = max(
P_GetSectorCeilingZAt(frontsector, ds_p->leftpos.x, ds_p->leftpos.y),
P_GetSectorCeilingZAt(frontsector, ds_p->rightpos.x, ds_p->rightpos.y)
);
low = min(
P_GetSectorFloorZAt(frontsector, ds_p->leftpos.x, ds_p->leftpos.y),
P_GetSectorFloorZAt(frontsector, ds_p->rightpos.x, ds_p->rightpos.y)
);
}
repeats = (high - low)/textureheight[texnum];
if ((high-low)%textureheight[texnum])
repeats++; // tile an extra time to fill the gap -- Monster Iestyn
}
else
repeats = 1;
for (times = 0; times < repeats; times++)
{
if (times > 0)
@ -885,8 +922,6 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
sector_t tempsec;
INT32 templight;
INT32 i, p;
fixed_t bottombounds = viewheight << FRACBITS;
fixed_t topbounds = (con_clipviewtop - 1) << FRACBITS;
fixed_t offsetvalue;
lightlist_t *light;
r_lightlist_t *rlight;
@ -896,7 +931,8 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
// NOTE: INT64 instead of fixed_t because overflow concerns
INT64 top_frac, top_step, bottom_frac, bottom_step;
// skew FOF walls with slopes?
fixed_t ffloortextureslide = 0;
fixed_t ffloortextureslide = 0, topslopeslide = 0, bottomslopeslide = 0;
angle_t lineangle;
INT32 oldx = -1;
fixed_t left_top, left_bottom; // needed here for slope skewing
pslope_t *skewslope = NULL;
@ -913,7 +949,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
// OPTIMIZE: get rid of LIGHTSEGSHIFT globally
curline = ds->curline;
backsector = pfloor->target;
backsector = NULL;
frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector;
sidedef = &sides[pfloor->master->sidenum[0]];
@ -921,7 +957,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
if (pfloor->master->flags & ML_TFERLINE)
{
size_t linenum = curline->linedef-backsector->lines[0];
size_t linenum = curline->linedef-pfloor->target->lines[0];
newline = pfloor->master->frontsector->lines[0] + linenum;
sidedef = &sides[newline->sidenum[0]];
lineflags = newline->flags;
@ -1134,11 +1170,10 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
offsetvalue -= FixedMul(*pfloor->topheight - *pfloor->bottomheight, wall_scaley);
}
lineangle = R_PointToAngle2(curline->v1->x, curline->v1->y, curline->v2->x, curline->v2->y);
if (skewslope)
{
angle_t lineangle = R_PointToAngle2(curline->v1->x, curline->v1->y, curline->v2->x, curline->v2->y);
ffloortextureslide = FixedMul(skewslope->zdelta, FINECOSINE((lineangle-skewslope->xydirection)>>ANGLETOFINESHIFT));
}
dc_texturemid += offsetvalue;
@ -1190,6 +1225,21 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
bottom_frac += bottom_step * (x1 - ds->x1);
}
hasoverlaytexture = false;
if (*pfloor->t_slope)
topslopeslide = FixedMul((*pfloor->t_slope)->zdelta, FINECOSINE((lineangle-(*pfloor->t_slope)->xydirection)>>ANGLETOFINESHIFT));
if (*pfloor->b_slope)
bottomslopeslide = FixedMul((*pfloor->b_slope)->zdelta, FINECOSINE((lineangle-(*pfloor->b_slope)->xydirection)>>ANGLETOFINESHIFT));
R_AddOverlayTextures(pfloor->master->frontsector, NULL, left_top, left_bottom, 0, 0, topslopeslide, bottomslopeslide, 0, 0);
if (hasoverlaytexture)
{
for (i = 0; i < NUM_WALL_OVERLAYS; i++)
oldoverlaycolumn[i] = -1;
}
// draw the columns
for (dc_x = x1; dc_x <= x2; dc_x++)
{
@ -1213,8 +1263,29 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
top_frac += top_step;
bottom_frac += bottom_step;
if (hasoverlaytexture)
{
#define ALIGN_UPPER(which) \
if (overlaytexture[which]) \
overlaytextureheight[which][dc_x] = max(rw_overlay[which].mid, rw_overlay[which].back)
#define ALIGN_LOWER(which) \
if (overlaytexture[which]) \
overlaytextureheight[which][dc_x] = min(rw_overlay[which].mid, rw_overlay[which].back)
ALIGN_UPPER(EDGE_TEXTURE_TOP_UPPER);
ALIGN_LOWER(EDGE_TEXTURE_BOTTOM_LOWER);
#undef ALIGN_UPPER
#undef ALIGN_LOWER
R_StoreOverlayColumn(dc_x, ds->thicksidecol[dc_x]);
overlayopening[0][dc_x] = max((windowtop + FRACUNIT)>>FRACBITS, mceilingclip[dc_x] + 1);
overlayopening[1][dc_x] = min((windowbottom - 1)>>FRACBITS, mfloorclip[dc_x] - 1);
}
// SoM: If column is out of range, why bother with it??
if (windowbottom < topbounds || windowtop > bottombounds)
if (windowbottom < 0 || windowtop > (viewheight << FRACBITS))
{
if (dc_numlights)
{
@ -1372,6 +1443,24 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
}
colfunc = colfuncs[BASEDRAWFUNC];
// Render up to two extra textures when everything is done
if (hasoverlaytexture)
{
INT32 repeats;
if (overlaytexture[EDGE_TEXTURE_TOP_UPPER])
{
repeats = R_GetOverlayTextureRepeats(ds, EDGE_TEXTURE_TOP_UPPER, pfloor->master->frontsector, NULL);
R_RenderExtraTexture(EDGE_TEXTURE_TOP_UPPER, x1, x2, repeats, ds);
}
if (overlaytexture[EDGE_TEXTURE_BOTTOM_LOWER])
{
repeats = R_GetOverlayTextureRepeats(ds, EDGE_TEXTURE_BOTTOM_LOWER, pfloor->master->frontsector, NULL);
R_RenderExtraTexture(EDGE_TEXTURE_BOTTOM_LOWER, x1, x2, repeats, ds);
}
}
#undef CLAMPMAX
#undef CLAMPMIN
}
@ -1447,9 +1536,6 @@ static void R_RenderSegLoop (void)
void (*drawmiddle)(UINT8 *, INT32) = R_DrawRegularWall;
void (*drawbottom)(UINT8 *, INT32) = R_DrawRegularWall;
fixed_t oldoverlaycolumn[NUM_WALL_OVERLAYS];
fixed_t overlaycolumn[NUM_WALL_OVERLAYS];
if (dc_numlights)
colfunc = colfuncs[COLDRAWFUNC_SHADOWED];
@ -1865,31 +1951,7 @@ static void R_RenderSegLoop (void)
#undef ALIGN_UPPER
#undef ALIGN_LOWER
for (i = 0; i < NUM_WALL_OVERLAYS; i++)
{
fixed_t offset;
if (!overlaytexture[i])
continue;
offset = sidedef->textureoffset + rw_overlay[i].offsetx;
if (rw_overlay[i].scalex < 0)
offset = -offset;
overlaycolumn[i] = FixedDiv(textureoffset, rw_overlay[i].invscalex);
overlaytexturecol[i][rw_x] = overlaycolumn[i] + offset;
if (oldoverlaycolumn[i] != -1)
{
INT32 diff = oldoverlaycolumn[i]-overlaycolumn[i];
if (rw_overlay[i].scalex < 0)
diff = -diff;
rw_overlay[i].mid += FixedMul(rw_overlay[i].slide, diff);
rw_overlay[i].back += FixedMul(rw_overlay[i].backslide, diff);
}
oldoverlaycolumn[i] = overlaycolumn[i];
}
R_StoreOverlayColumn(rw_x, textureoffset);
}
if (invscale)
@ -2017,7 +2079,7 @@ static void R_AllocTextureColumnTables(size_t range)
}
}
static void R_AddOverlayTextures(fixed_t ceilingfrontslide, fixed_t floorfrontslide, fixed_t ceilingbackslide, fixed_t floorbackslide)
static void R_AddOverlayTextures(sector_t *sec_front, sector_t *sec_back, fixed_t left_top, fixed_t left_bottom, fixed_t left_high, fixed_t left_low, fixed_t ceilingfrontslide, fixed_t floorfrontslide, fixed_t ceilingbackslide, fixed_t floorbackslide)
{
INT32 texnums[4] = {
R_GetTextureNum(sidedef->overlays[0].texture),
@ -2026,7 +2088,7 @@ static void R_AddOverlayTextures(fixed_t ceilingfrontslide, fixed_t floorfrontsl
R_GetTextureNum(sidedef->overlays[3].texture)
};
if (!backsector)
if (!sec_back)
{
// If one-sided, render just the upper top and the lower bottom overlays
overlaytexture[0] = texnums[0];
@ -2044,21 +2106,7 @@ static void R_AddOverlayTextures(fixed_t ceilingfrontslide, fixed_t floorfrontsl
{
if (overlaytexture[i] > 0 && overlaytexture[i] < numtextures)
{
if (!texcoltables)
{
// allocate space for masked texture tables
R_AllocTextureColumnTables(rw_stopx - rw_x);
texcoltables = true;
}
if (!maskedtexturecol)
{
ds_p->maskedtexturecol = maskedtexturecol = curtexturecolumntable - rw_x;
curtexturecolumntable += rw_stopx - rw_x;
}
maskedtexture = hasoverlaytexture = true;
hasoverlaytexture = true;
rw_overlay[i].scalex = sidedef->overlays[i].scalex;
rw_overlay[i].scaley = sidedef->overlays[i].scaley;
@ -2071,13 +2119,13 @@ static void R_AddOverlayTextures(fixed_t ceilingfrontslide, fixed_t floorfrontsl
{
if (IS_BOTTOM_EDGE_TEXTURE(i))
{
rw_overlay[i].mid = frontsector->floorheight;
rw_overlay[i].back = backsector ? backsector->floorheight : rw_overlay[i].mid;
rw_overlay[i].mid = sec_front->floorheight;
rw_overlay[i].back = sec_back ? sec_back->floorheight : rw_overlay[i].mid;
}
else
{
rw_overlay[i].mid = frontsector->ceilingheight;
rw_overlay[i].back = backsector ? backsector->ceilingheight : rw_overlay[i].mid;
rw_overlay[i].mid = sec_front->ceilingheight;
rw_overlay[i].back = sec_back ? sec_back->ceilingheight : rw_overlay[i].mid;
}
rw_overlay[i].slide = 0;
@ -2088,17 +2136,17 @@ static void R_AddOverlayTextures(fixed_t ceilingfrontslide, fixed_t floorfrontsl
}
else if (IS_BOTTOM_EDGE_TEXTURE(i))
{
rw_overlay[i].mid = worldbottom;
rw_overlay[i].mid = left_bottom;
rw_overlay[i].slide = floorfrontslide;
rw_overlay[i].back = backsector ? worldlow : rw_overlay[i].mid;
rw_overlay[i].backslide = backsector ? floorbackslide : rw_overlay[i].slide;
rw_overlay[i].back = sec_back ? left_low : rw_overlay[i].mid;
rw_overlay[i].backslide = sec_back ? floorbackslide : rw_overlay[i].slide;
}
else
{
rw_overlay[i].mid = worldtop;
rw_overlay[i].mid = left_top;
rw_overlay[i].slide = ceilingfrontslide;
rw_overlay[i].back = backsector ? worldhigh : rw_overlay[i].mid;
rw_overlay[i].backslide = backsector ? ceilingbackslide : rw_overlay[i].slide;
rw_overlay[i].back = sec_back ? left_high : rw_overlay[i].mid;
rw_overlay[i].backslide = sec_back ? ceilingbackslide : rw_overlay[i].slide;
}
rw_overlay[i].mid = FixedMul(rw_overlay[i].mid, abs(rw_overlay[i].scaley));
@ -2110,6 +2158,35 @@ static void R_AddOverlayTextures(fixed_t ceilingfrontslide, fixed_t floorfrontsl
}
}
static void R_StoreOverlayColumn(INT32 x, fixed_t textureoffset)
{
for (unsigned i = 0; i < NUM_WALL_OVERLAYS; i++)
{
fixed_t offset;
if (!overlaytexture[i])
continue;
offset = sidedef->textureoffset + rw_overlay[i].offsetx;
if (rw_overlay[i].scalex < 0)
offset = -offset;
overlaycolumn[i] = FixedDiv(textureoffset, rw_overlay[i].invscalex);
overlaytexturecol[i][x] = overlaycolumn[i] + offset;
if (oldoverlaycolumn[i] != -1)
{
INT32 diff = oldoverlaycolumn[i]-overlaycolumn[i];
if (rw_overlay[i].scalex < 0)
diff = -diff;
rw_overlay[i].mid += FixedMul(rw_overlay[i].slide, diff);
rw_overlay[i].back += FixedMul(rw_overlay[i].backslide, diff);
}
oldoverlaycolumn[i] = overlaycolumn[i];
}
}
//
// R_StoreWallRange
// A wall segment will be drawn
@ -2914,7 +2991,28 @@ void R_StoreWallRange(INT32 start, INT32 stop)
// check if extra textures need to be rendered
if (segtextured)
R_AddOverlayTextures(ceilingfrontslide, floorfrontslide, ceilingbackslide, floorbackslide);
{
R_AddOverlayTextures(frontsector, backsector, worldtop, worldbottom, worldhigh, worldlow, ceilingfrontslide, floorfrontslide, ceilingbackslide, floorbackslide);
if (hasoverlaytexture)
{
if (!texcoltables)
{
// allocate space for masked texture tables
R_AllocTextureColumnTables(rw_stopx - rw_x);
texcoltables = true;
}
if (!maskedtexturecol)
{
ds_p->maskedtexturecol = maskedtexturecol = curtexturecolumntable - rw_x;
curtexturecolumntable += rw_stopx - rw_x;
}
maskedtexture = true;
}
}
// calculate rw_offset (only needed for textured lines)
if (segtextured)
@ -3435,7 +3533,10 @@ void R_StoreWallRange(INT32 start, INT32 stop)
for (i = 0; i < NUM_WALL_OVERLAYS; i++)
{
if (overlaytexture[i])
R_RenderExtraTexture(ds_p, i, ds_p->x1, ds_p->x2);
{
INT32 repeats = R_GetOverlayTextureRepeats(ds_p, i, frontsector, backsector);
R_RenderExtraTexture(i, ds_p->x1, ds_p->x2, repeats, ds_p);
}
}
}