Border textures WIP

This commit is contained in:
Lactozilla 2024-01-22 18:52:12 -03:00
parent 36e64cb683
commit 77f9d476de
5 changed files with 700 additions and 123 deletions

View file

@ -103,48 +103,51 @@ typedef struct
// LineDef attributes. // LineDef attributes.
// //
// Solid, is an obstacle. enum
#define ML_IMPASSIBLE 1 {
// Solid, is an obstacle.
ML_IMPASSIBLE = 1<<0,
// Blocks monsters only. // Blocks monsters only.
#define ML_BLOCKMONSTERS 2 ML_BLOCKMONSTERS = 1<<1,
// Backside will not be present at all if not two sided. // Backside will not be present at all if not two sided.
#define ML_TWOSIDED 4 ML_TWOSIDED = 1<<2,
// If a texture is pegged, the texture will have // If a texture is pegged, the texture will have
// the end exposed to air held constant at the // the end exposed to air held constant at the
// top or bottom of the texture (stairs or pulled // top or bottom of the texture (stairs or pulled
// down things) and will move with a height change // down things) and will move with a height change
// of one of the neighbor sectors. // of one of the neighbor sectors.
// Unpegged textures allways have the first row of // Unpegged textures allways have the first row of
// the texture at the top pixel of the line for both // the texture at the top pixel of the line for both
// top and bottom textures (use next to windows). // top and bottom textures (use next to windows).
// upper texture unpegged // upper texture unpegged
#define ML_DONTPEGTOP 8 ML_DONTPEGTOP = 1<<3,
// lower texture unpegged // lower texture unpegged
#define ML_DONTPEGBOTTOM 16 ML_DONTPEGBOTTOM = 1<<4,
#define ML_SKEWTD 32 ML_SKEWTD = 1<<5,
// Don't let Knuckles climb on this line // Don't let Knuckles climb on this line
#define ML_NOCLIMB 64 ML_NOCLIMB = 1<<6,
#define ML_NOSKEW 128 ML_NOSKEW = 1<<7,
#define ML_MIDPEG 256 ML_MIDPEG = 1<<8,
#define ML_MIDSOLID 512 ML_MIDSOLID = 1<<9,
#define ML_WRAPMIDTEX 1024 ML_WRAPMIDTEX = 1<<10,
#define ML_NETONLY 2048 // Apply effect only in netgames ML_NETONLY = 1<<11, // Apply effect only in netgames
#define ML_NONET 4096 // Apply effect only in single player games ML_NONET = 1<<12, // Apply effect only in single player games
#define ML_EFFECT6 8192 ML_EFFECT6 = 1<<13,
// Bounce off walls! // Bounce off walls!
#define ML_BOUNCY 16384 ML_BOUNCY = 1<<14,
#define ML_TFERLINE 32768 ML_TFERLINE = 1<<15
};
// Sector definition, from editing. // Sector definition, from editing.
typedef struct typedef struct

View file

@ -1366,6 +1366,15 @@ static void P_LoadSidedefs(UINT8 *data)
sd->scalex_top = sd->scalex_mid = sd->scalex_bottom = FRACUNIT; sd->scalex_top = sd->scalex_mid = sd->scalex_bottom = FRACUNIT;
sd->scaley_top = sd->scaley_mid = sd->scaley_bottom = FRACUNIT; sd->scaley_top = sd->scaley_mid = sd->scaley_bottom = FRACUNIT;
sd->flags = 0;
for (unsigned j = 0; j < NUM_WALL_OVERLAYS; j++)
{
sd->overlays[j].texture = R_TextureNumForName("-");
sd->overlays[j].offsetx = sd->overlays[j].offsety = 0;
sd->overlays[j].scalex = sd->overlays[j].scaley = FRACUNIT;
}
P_SetSidedefSector(i, (UINT16)SHORT(msd->sector)); P_SetSidedefSector(i, (UINT16)SHORT(msd->sector));
// Special info stored in texture fields! // Special info stored in texture fields!
@ -1896,6 +1905,24 @@ static void ParseTextmapSectorParameter(UINT32 i, const char *param, const char
} }
} }
static void ParseTextmapSidedefOverlay(unsigned which, UINT32 i, const char *param, const char *val)
{
if (fastcmp(param, "texture"))
sides[i].overlays[which].texture = R_TextureNumForName(val);
else if (fastcmp(param, "offsetx"))
sides[i].overlays[which].offsetx = FLOAT_TO_FIXED(atof(val));
else if (fastcmp(param, "offsety"))
sides[i].overlays[which].offsety = FLOAT_TO_FIXED(atof(val));
else if (fastcmp(param, "scalex"))
sides[i].overlays[which].scalex = FLOAT_TO_FIXED(atof(val));
else if (fastcmp(param, "scaley"))
sides[i].overlays[which].scaley = FLOAT_TO_FIXED(atof(val));
else if (fastcmp(param, "noskew") && fastcmp("true", val))
sides[i].flags |= GET_SIDEFLAG_EDGENOSKEW(which);
else if (fastcmp(param, "wrap") && fastcmp("true", val))
sides[i].flags |= GET_SIDEFLAG_EDGEWRAP(which);
}
static void ParseTextmapSidedefParameter(UINT32 i, const char *param, const char *val) static void ParseTextmapSidedefParameter(UINT32 i, const char *param, const char *val)
{ {
if (fastcmp(param, "offsetx")) if (fastcmp(param, "offsetx"))
@ -1936,6 +1963,19 @@ static void ParseTextmapSidedefParameter(UINT32 i, const char *param, const char
P_SetSidedefSector(i, atol(val)); P_SetSidedefSector(i, atol(val));
else if (fastcmp(param, "repeatcnt")) else if (fastcmp(param, "repeatcnt"))
sides[i].repeatcnt = atol(val); sides[i].repeatcnt = atol(val);
// Oh God there's a total of 28 fields to read. Uhhh
// Okay, so ParseTextmapSidedefOverlay handles the parsing of all the parameters edges have.
else if (fastncmp(param, "edge_", 5) && strlen(param) > 5)
{
if (fastncmp(param, "edge_top_upper_", 15) && strlen(param) > 15)
ParseTextmapSidedefOverlay(EDGE_TEXTURE_TOP_UPPER, i, param + 15, val);
else if (fastncmp(param, "edge_top_lower_", 15) && strlen(param) > 15)
ParseTextmapSidedefOverlay(EDGE_TEXTURE_TOP_LOWER, i, param + 15, val);
else if (fastncmp(param, "edge_bottom_upper_", 18) && strlen(param) > 18)
ParseTextmapSidedefOverlay(EDGE_TEXTURE_BOTTOM_UPPER, i, param + 18, val);
else if (fastncmp(param, "edge_bottom_lower_", 18) && strlen(param) > 18)
ParseTextmapSidedefOverlay(EDGE_TEXTURE_BOTTOM_LOWER, i, param + 18, val);
}
} }
static void ParseTextmapLinedefParameter(UINT32 i, const char *param, const char *val) static void ParseTextmapLinedefParameter(UINT32 i, const char *param, const char *val)
@ -2020,8 +2060,6 @@ static void ParseTextmapLinedefParameter(UINT32 i, const char *param, const char
lines[i].flags |= ML_MIDSOLID; lines[i].flags |= ML_MIDSOLID;
else if (fastcmp(param, "wrapmidtex") && fastcmp("true", val)) else if (fastcmp(param, "wrapmidtex") && fastcmp("true", val))
lines[i].flags |= ML_WRAPMIDTEX; lines[i].flags |= ML_WRAPMIDTEX;
/*else if (fastcmp(param, "effect6") && fastcmp("true", val))
lines[i].flags |= ML_EFFECT6;*/
else if (fastcmp(param, "nonet") && fastcmp("true", val)) else if (fastcmp(param, "nonet") && fastcmp("true", val))
lines[i].flags |= ML_NONET; lines[i].flags |= ML_NONET;
else if (fastcmp(param, "netonly") && fastcmp("true", val)) else if (fastcmp(param, "netonly") && fastcmp("true", val))
@ -2190,6 +2228,24 @@ typedef struct
mapthing_t *angleanchor; mapthing_t *angleanchor;
} sectorspecialthings_t; } sectorspecialthings_t;
static void WriteTextmapEdgeTexture(const char *prefix, unsigned i, side_t *side, FILE *f)
{
if (side->overlays[i].texture > 0 && side->overlays[i].texture < numtextures)
fprintf(f, "%s""texture = \"%.*s\";\n", prefix, 8, textures[side->overlays[i].texture]->name);
if (side->overlays[i].offsetx != 0)
fprintf(f, "%s""offsetx = %f;\n", prefix, FIXED_TO_FLOAT(side->overlays[i].offsetx));
if (side->overlays[i].offsety != 0)
fprintf(f, "%s""offsety = %f;\n", prefix, FIXED_TO_FLOAT(side->overlays[i].offsety));
if (side->overlays[i].scalex != FRACUNIT)
fprintf(f, "%s""scalex = %f;\n", prefix, FIXED_TO_FLOAT(side->overlays[i].scalex));
if (side->overlays[i].scaley != FRACUNIT)
fprintf(f, "%s""scaley = %f;\n", prefix, FIXED_TO_FLOAT(side->overlays[i].scaley));
if (side->flags & GET_SIDEFLAG_EDGENOSKEW(i))
fprintf(f, "%s""noskew = true;\n", prefix);
if (side->flags & GET_SIDEFLAG_EDGEWRAP(i))
fprintf(f, "%s""wrap = true;\n", prefix);
}
static void P_WriteTextmap(void) static void P_WriteTextmap(void)
{ {
size_t i, j; size_t i, j;
@ -2654,6 +2710,10 @@ static void P_WriteTextmap(void)
fprintf(f, "texturemiddle = \"%.*s\";\n", 8, textures[wsides[i].midtexture]->name); fprintf(f, "texturemiddle = \"%.*s\";\n", 8, textures[wsides[i].midtexture]->name);
if (wsides[i].repeatcnt != 0) if (wsides[i].repeatcnt != 0)
fprintf(f, "repeatcnt = %d;\n", wsides[i].repeatcnt); fprintf(f, "repeatcnt = %d;\n", wsides[i].repeatcnt);
WriteTextmapEdgeTexture("edge_top_upper_", EDGE_TEXTURE_TOP_UPPER, &wsides[i], f);
WriteTextmapEdgeTexture("edge_top_lower_", EDGE_TEXTURE_TOP_LOWER, &wsides[i], f);
WriteTextmapEdgeTexture("edge_bottom_upper_", EDGE_TEXTURE_BOTTOM_UPPER, &wsides[i], f);
WriteTextmapEdgeTexture("edge_bottom_lower_", EDGE_TEXTURE_BOTTOM_LOWER, &wsides[i], f);
fprintf(f, "}\n"); fprintf(f, "}\n");
fprintf(f, "\n"); fprintf(f, "\n");
} }
@ -3041,9 +3101,16 @@ static void P_LoadTextmap(void)
sd->offsety_top = sd->offsety_mid = sd->offsety_bottom = 0; sd->offsety_top = sd->offsety_mid = sd->offsety_bottom = 0;
sd->scalex_top = sd->scalex_mid = sd->scalex_bottom = FRACUNIT; sd->scalex_top = sd->scalex_mid = sd->scalex_bottom = FRACUNIT;
sd->scaley_top = sd->scaley_mid = sd->scaley_bottom = FRACUNIT; sd->scaley_top = sd->scaley_mid = sd->scaley_bottom = FRACUNIT;
sd->flags = 0;
sd->toptexture = R_TextureNumForName("-"); sd->toptexture = R_TextureNumForName("-");
sd->midtexture = R_TextureNumForName("-"); sd->midtexture = R_TextureNumForName("-");
sd->bottomtexture = R_TextureNumForName("-"); sd->bottomtexture = R_TextureNumForName("-");
for (unsigned j = 0; j < NUM_WALL_OVERLAYS; j++)
{
sd->overlays[j].texture = R_TextureNumForName("-");
sd->overlays[j].offsetx = sd->overlays[j].offsety = 0;
sd->overlays[j].scalex = sd->overlays[j].scaley = FRACUNIT;
}
sd->sector = NULL; sd->sector = NULL;
sd->repeatcnt = 0; sd->repeatcnt = 0;

View file

@ -555,6 +555,21 @@ typedef enum
#define NO_SIDEDEF 0xFFFFFFFF #define NO_SIDEDEF 0xFFFFFFFF
enum
{
EDGE_TEXTURE_TOP_UPPER,
EDGE_TEXTURE_TOP_LOWER,
EDGE_TEXTURE_BOTTOM_UPPER,
EDGE_TEXTURE_BOTTOM_LOWER,
NUM_WALL_OVERLAYS
};
#define IS_TOP_EDGE_TEXTURE(i) ((i) == EDGE_TEXTURE_TOP_UPPER || (i) == EDGE_TEXTURE_TOP_LOWER)
#define IS_BOTTOM_EDGE_TEXTURE(i) (!IS_TOP_EDGE_TEXTURE(i))
#define IS_UPPER_EDGE_TEXTURE(i) ((i) == EDGE_TEXTURE_TOP_UPPER || (i) == EDGE_TEXTURE_BOTTOM_UPPER)
#define IS_LOWER_EDGE_TEXTURE(i) (!IS_UPPER_EDGE_TEXTURE(i))
typedef struct line_s typedef struct line_s
{ {
// Vertices, from v1 to v2. // Vertices, from v1 to v2.
@ -595,6 +610,23 @@ typedef struct line_s
UINT32 secportal; // transferred sector portal UINT32 secportal; // transferred sector portal
} line_t; } line_t;
// Don't make available to Lua or I will find where you live
enum
{
SIDEFLAG_EDGENOSKEW1 = 1<<7,
SIDEFLAG_EDGENOSKEW2 = 1<<8,
SIDEFLAG_EDGENOSKEW3 = 1<<9,
SIDEFLAG_EDGENOSKEW4 = 1<<10,
SIDEFLAG_EDGEWRAP1 = 1<<11,
SIDEFLAG_EDGEWRAP2 = 1<<12,
SIDEFLAG_EDGEWRAP3 = 1<<13,
SIDEFLAG_EDGEWRAP4 = 1<<14
};
#define GET_SIDEFLAG_EDGENOSKEW(which) (SIDEFLAG_EDGENOSKEW1<<(which))
#define GET_SIDEFLAG_EDGEWRAP(which) (SIDEFLAG_EDGEWRAP1<<(which))
typedef struct typedef struct
{ {
// add this to the calculated texture column // add this to the calculated texture column
@ -610,10 +642,19 @@ typedef struct
fixed_t scalex_top, scalex_mid, scalex_bottom; fixed_t scalex_top, scalex_mid, scalex_bottom;
fixed_t scaley_top, scaley_mid, scaley_bottom; fixed_t scaley_top, scaley_mid, scaley_bottom;
UINT16 flags;
// Texture indices. // Texture indices.
// We do not maintain names here. // We do not maintain names here.
INT32 toptexture, bottomtexture, midtexture; INT32 toptexture, bottomtexture, midtexture;
// Upper and lower overlays for top and bottom textures
struct {
INT32 texture;
fixed_t offsetx, offsety;
fixed_t scalex, scaley;
} overlays[NUM_WALL_OVERLAYS];
// Linedef the sidedef belongs to // Linedef the sidedef belongs to
line_t *line; line_t *line;
@ -808,6 +849,7 @@ typedef struct drawseg_s
INT16 *sprtopclip; INT16 *sprtopclip;
INT16 *sprbottomclip; INT16 *sprbottomclip;
fixed_t *maskedtexturecol; fixed_t *maskedtexturecol;
fixed_t *maskedtextureheight; // For handling sloped midtextures
fixed_t *invscale; fixed_t *invscale;
struct visplane_s *ffloorplanes[MAXFFLOORS]; struct visplane_s *ffloorplanes[MAXFFLOORS];
@ -819,8 +861,6 @@ typedef struct drawseg_s
UINT8 portalpass; // if > 0 and <= portalrender, do not affect sprite clipping UINT8 portalpass; // if > 0 and <= portalrender, do not affect sprite clipping
fixed_t maskedtextureheight[MAXVIDWIDTH]; // For handling sloped midtextures
vertex_t leftpos, rightpos; // Used for rendering FOF walls with slopes vertex_t leftpos, rightpos; // Used for rendering FOF walls with slopes
} drawseg_t; } drawseg_t;

View file

@ -38,6 +38,9 @@ static boolean maskedtexture;
static INT32 toptexture, bottomtexture, midtexture; static INT32 toptexture, bottomtexture, midtexture;
static INT32 numthicksides, numbackffloors; static INT32 numthicksides, numbackffloors;
static boolean hasoverlaytexture;
static INT32 overlaytexture[NUM_WALL_OVERLAYS];
angle_t rw_normalangle; angle_t rw_normalangle;
// angle to line origin // angle to line origin
angle_t rw_angle1; angle_t rw_angle1;
@ -61,6 +64,14 @@ static fixed_t rw_toptexturescalex, rw_toptexturescaley;
static fixed_t rw_bottomtexturescalex, rw_bottomtexturescaley; static fixed_t rw_bottomtexturescalex, rw_bottomtexturescaley;
static fixed_t rw_invmidtexturescalex, rw_invtoptexturescalex, rw_invbottomtexturescalex; static fixed_t rw_invmidtexturescalex, rw_invtoptexturescalex, rw_invbottomtexturescalex;
static struct
{
fixed_t mid, slide;
fixed_t back, backslide;
fixed_t scalex, scaley, invscalex;
fixed_t offsetx, offsety;
} rw_overlay[NUM_WALL_OVERLAYS];
// Lactozilla: 3D floor clipping // Lactozilla: 3D floor clipping
static boolean rw_floormarked = false; static boolean rw_floormarked = false;
static boolean rw_ceilingmarked = false; static boolean rw_ceilingmarked = false;
@ -79,6 +90,13 @@ static fixed_t *maskedtextureheight = NULL;
static fixed_t *thicksidecol = NULL; static fixed_t *thicksidecol = NULL;
static fixed_t *invscale = NULL; static fixed_t *invscale = NULL;
static boolean texcoltables;
// TODO: Allocate dynamically
static fixed_t overlaytextureheight[NUM_WALL_OVERLAYS][MAXVIDWIDTH];
static fixed_t overlaytexturecol[NUM_WALL_OVERLAYS][MAXVIDWIDTH];
static INT16 overlayopening[2][MAXVIDWIDTH];
//SoM: 3/23/2000: Use boom opening limit removal //SoM: 3/23/2000: Use boom opening limit removal
static size_t numopenings; static size_t numopenings;
static INT16 *openings, *lastopening; static INT16 *openings, *lastopening;
@ -144,13 +162,93 @@ transnum_t R_GetLinedefTransTable(fixed_t alpha)
return (20*(FRACUNIT - alpha - 1) + FRACUNIT) >> (FRACBITS+1); return (20*(FRACUNIT - alpha - 1) + FRACUNIT) >> (FRACBITS+1);
} }
// Setup lighting based on the presence/lack-of 3D floors.
static void R_PrepareMaskedSegLightlist(drawseg_t *ds, INT32 range)
{
lightlist_t *light;
r_lightlist_t *rlight;
INT32 lightnum;
dc_numlights = 0;
if (frontsector->numlights)
{
dc_numlights = frontsector->numlights;
if (dc_numlights >= dc_maxlights)
{
dc_maxlights = dc_numlights;
dc_lightlist = Z_Realloc(dc_lightlist, sizeof (*dc_lightlist) * dc_maxlights, PU_STATIC, NULL);
}
for (INT32 i = 0; i < dc_numlights; i++)
{
fixed_t leftheight, rightheight;
light = &frontsector->lightlist[i];
rlight = &dc_lightlist[i];
leftheight = P_GetLightZAt(light, ds-> leftpos.x, ds-> leftpos.y);
rightheight = P_GetLightZAt(light, ds->rightpos.x, ds->rightpos.y);
leftheight -= viewz;
rightheight -= viewz;
rlight->height = (centeryfrac) - FixedMul(leftheight , ds->scale1);
rlight->heightstep = (centeryfrac) - FixedMul(rightheight, ds->scale2);
rlight->heightstep = (rlight->heightstep-rlight->height)/(range);
//if (x1 > ds->x1)
//rlight->height -= (x1 - ds->x1)*rlight->heightstep;
rlight->startheight = rlight->height; // keep starting value here to reset for each repeat
rlight->lightlevel = *light->lightlevel;
rlight->extra_colormap = *light->extra_colormap;
rlight->flags = light->flags;
if ((colfunc != colfuncs[COLDRAWFUNC_FUZZY])
|| (rlight->flags & FOF_FOG)
|| (rlight->extra_colormap && (rlight->extra_colormap->flags & CMF_FOG)))
lightnum = (rlight->lightlevel >> LIGHTSEGSHIFT);
else
lightnum = LIGHTLEVELS - 1;
if (rlight->extra_colormap && (rlight->extra_colormap->flags & CMF_FOG))
;
else if (curline->v1->y == curline->v2->y)
lightnum--;
else if (curline->v1->x == curline->v2->x)
lightnum++;
rlight->lightnum = lightnum;
}
}
else
{
if ((colfunc != colfuncs[COLDRAWFUNC_FUZZY])
|| (frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG)))
lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT);
else
lightnum = LIGHTLEVELS - 1;
if (colfunc == colfuncs[COLDRAWFUNC_FOG]
|| (frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG)))
;
else if (curline->v1->y == curline->v2->y)
lightnum--;
else if (curline->v1->x == curline->v2->x)
lightnum++;
if (lightnum < 0)
walllights = scalelight[0];
else if (lightnum >= LIGHTLEVELS)
walllights = scalelight[LIGHTLEVELS - 1];
else
walllights = scalelight[lightnum];
}
}
void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
{ {
size_t pindex; size_t pindex;
column_t *col; column_t *col;
INT32 lightnum, texnum, i; INT32 texnum, i;
fixed_t height, realbot; fixed_t height, realbot;
lightlist_t *light;
r_lightlist_t *rlight; r_lightlist_t *rlight;
void (*colfunc_2s)(column_t *); void (*colfunc_2s)(column_t *);
line_t *ldef; line_t *ldef;
@ -236,77 +334,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
} }
// Setup lighting based on the presence/lack-of 3D floors. // Setup lighting based on the presence/lack-of 3D floors.
dc_numlights = 0; R_PrepareMaskedSegLightlist(ds, range);
if (frontsector->numlights)
{
dc_numlights = frontsector->numlights;
if (dc_numlights >= dc_maxlights)
{
dc_maxlights = dc_numlights;
dc_lightlist = Z_Realloc(dc_lightlist, sizeof (*dc_lightlist) * dc_maxlights, PU_STATIC, NULL);
}
for (i = 0; i < dc_numlights; i++)
{
fixed_t leftheight, rightheight;
light = &frontsector->lightlist[i];
rlight = &dc_lightlist[i];
leftheight = P_GetLightZAt(light, ds-> leftpos.x, ds-> leftpos.y);
rightheight = P_GetLightZAt(light, ds->rightpos.x, ds->rightpos.y);
leftheight -= viewz;
rightheight -= viewz;
rlight->height = (centeryfrac) - FixedMul(leftheight , ds->scale1);
rlight->heightstep = (centeryfrac) - FixedMul(rightheight, ds->scale2);
rlight->heightstep = (rlight->heightstep-rlight->height)/(range);
//if (x1 > ds->x1)
//rlight->height -= (x1 - ds->x1)*rlight->heightstep;
rlight->startheight = rlight->height; // keep starting value here to reset for each repeat
rlight->lightlevel = *light->lightlevel;
rlight->extra_colormap = *light->extra_colormap;
rlight->flags = light->flags;
if ((colfunc != colfuncs[COLDRAWFUNC_FUZZY])
|| (rlight->flags & FOF_FOG)
|| (rlight->extra_colormap && (rlight->extra_colormap->flags & CMF_FOG)))
lightnum = (rlight->lightlevel >> LIGHTSEGSHIFT);
else
lightnum = LIGHTLEVELS - 1;
if (rlight->extra_colormap && (rlight->extra_colormap->flags & CMF_FOG))
;
else if (curline->v1->y == curline->v2->y)
lightnum--;
else if (curline->v1->x == curline->v2->x)
lightnum++;
rlight->lightnum = lightnum;
}
}
else
{
if ((colfunc != colfuncs[COLDRAWFUNC_FUZZY])
|| (frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG)))
lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT);
else
lightnum = LIGHTLEVELS - 1;
if (colfunc == colfuncs[COLDRAWFUNC_FOG]
|| (frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG)))
;
else if (curline->v1->y == curline->v2->y)
lightnum--;
else if (curline->v1->x == curline->v2->x)
lightnum++;
if (lightnum < 0)
walllights = scalelight[0];
else if (lightnum >= LIGHTLEVELS)
walllights = scalelight[LIGHTLEVELS - 1];
else
walllights = scalelight[lightnum];
}
maskedtexturecol = ds->maskedtexturecol; maskedtexturecol = ds->maskedtexturecol;
@ -489,6 +517,268 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
colfunc = colfuncs[BASEDRAWFUNC]; colfunc = colfuncs[BASEDRAWFUNC];
} }
// Renders a texture right on top of the wall texture
static void R_RenderExtraTexture(drawseg_t *ds, unsigned which, INT32 x1, INT32 x2)
{
size_t pindex;
column_t *col;
INT32 i;
fixed_t height, realbot;
r_lightlist_t *rlight;
void (*colfunc_2s)(column_t *);
INT32 times, repeats;
INT64 overflow_test;
INT32 range;
fixed_t wall_scaley;
fixed_t scalestep;
fixed_t scale1;
fixed_t *extraheight = overlaytextureheight[which];
fixed_t *texturecol = overlaytexturecol[which];
INT32 texnum = overlaytexture[which];
UINT8 vertflip = textures[texnum]->flip & 2;
// Calculate light table.
// Use different light tables
// for horizontal / vertical / diagonal. Diagonal?
// OPTIMIZE: get rid of LIGHTSEGSHIFT globally
windowbottom = windowtop = sprbotscreen = INT32_MAX;
wall_scaley = rw_overlay[which].scaley;
if (wall_scaley < 0)
{
wall_scaley = -wall_scaley;
vertflip = !vertflip;
}
scalestep = FixedDiv(ds->scalestep, wall_scaley);
scale1 = FixedDiv(ds->scale1, wall_scaley);
range = max(ds->x2-ds->x1, 1);
rw_scalestep = scalestep;
spryscale = scale1 + (x1 - ds->x1)*rw_scalestep;
// Texture must be cached before setting colfunc_2s,
// otherwise texture[texnum]->holes may be false when it shouldn't be
R_CheckTextureCache(texnum);
// handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info in SRB2
if (textures[texnum]->holes)
{
if (vertflip) // vertically flipped?
{
colfunc_2s = R_DrawFlippedMaskedColumn;
lengthcol = textures[texnum]->height;
}
else
colfunc_2s = R_DrawMaskedColumn; // render the usual 2sided single-patch packed texture
}
else
{
// FIXME: Composite textures don't get flipped vertically
colfunc_2s = R_Render2sidedMultiPatchColumn; // render multipatch with no holes (no post_t info)
lengthcol = textures[texnum]->height;
}
// Setup lighting based on the presence/lack-of 3D floors.
R_PrepareMaskedSegLightlist(ds, range);
mfloorclip = overlayopening[1];
mceilingclip = overlayopening[0];
if (sidedef->flags & GET_SIDEFLAG_EDGEWRAP(which))
{
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(backsector, ds_p->leftpos.x, ds_p->leftpos.y),
P_GetSectorFloorZAt(backsector, 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)
{
rw_scalestep = scalestep;
spryscale = scale1 + (x1 - ds->x1)*rw_scalestep;
// reset all lights to their starting heights
for (i = 0; i < dc_numlights; i++)
{
rlight = &dc_lightlist[i];
rlight->height = rlight->startheight;
}
}
dc_texheight = textureheight[texnum]>>FRACBITS;
// draw the columns
for (dc_x = x1; dc_x <= x2; dc_x++)
{
dc_texturemid = extraheight[dc_x];
if (IS_LOWER_EDGE_TEXTURE(which))
dc_texturemid += (textureheight[texnum])*times + textureheight[texnum];
else
dc_texturemid -= (textureheight[texnum])*times;
// Check for overflows first
overflow_test = (INT64)centeryfrac - (((INT64)dc_texturemid*spryscale)>>FRACBITS);
if (overflow_test < 0) overflow_test = -overflow_test;
if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL)
{
// Eh, no, go away, don't waste our time
if (dc_numlights)
{
for (i = 0; i < dc_numlights; i++)
{
rlight = &dc_lightlist[i];
rlight->height += rlight->heightstep;
}
}
spryscale += rw_scalestep;
continue;
}
// calculate lighting
if (dc_numlights)
{
lighttable_t **xwalllights;
sprbotscreen = INT32_MAX;
sprtopscreen = windowtop = (centeryfrac - FixedMul(dc_texturemid, spryscale));
realbot = FixedMul(textureheight[texnum], spryscale) + sprtopscreen;
dc_iscale = FixedMul(ds->invscale[dc_x], wall_scaley);
windowbottom = realbot;
// draw the texture
col = (column_t *)((UINT8 *)R_GetColumn(texnum, (texturecol[dc_x] >> FRACBITS)) - 3);
for (i = 0; i < dc_numlights; i++)
{
rlight = &dc_lightlist[i];
if ((rlight->flags & FOF_NOSHADE))
continue;
if (rlight->lightnum < 0)
xwalllights = scalelight[0];
else if (rlight->lightnum >= LIGHTLEVELS)
xwalllights = scalelight[LIGHTLEVELS-1];
else
xwalllights = scalelight[rlight->lightnum];
pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT;
if (pindex >= MAXLIGHTSCALE)
pindex = MAXLIGHTSCALE - 1;
if (rlight->extra_colormap)
rlight->rcolormap = rlight->extra_colormap->colormap + (xwalllights[pindex] - colormaps);
else
rlight->rcolormap = xwalllights[pindex];
height = rlight->height;
rlight->height += rlight->heightstep;
if (height <= windowtop)
{
dc_colormap = rlight->rcolormap;
continue;
}
windowbottom = height;
if (windowbottom >= realbot)
{
windowbottom = realbot;
colfunc_2s(col);
for (i++; i < dc_numlights; i++)
{
rlight = &dc_lightlist[i];
rlight->height += rlight->heightstep;
}
continue;
}
colfunc_2s(col);
windowtop = windowbottom + 1;
dc_colormap = rlight->rcolormap;
}
windowbottom = realbot;
if (windowtop < windowbottom)
colfunc_2s(col);
spryscale += rw_scalestep;
continue;
}
// calculate lighting
pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT;
if (pindex >= MAXLIGHTSCALE)
pindex = MAXLIGHTSCALE - 1;
dc_colormap = walllights[pindex];
if (frontsector->extra_colormap)
dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps);
sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
dc_iscale = FixedMul(ds->invscale[dc_x], wall_scaley);
// draw the texture
col = (column_t *)((UINT8 *)R_GetColumn(texnum, (texturecol[dc_x] >> FRACBITS)) - 3);
colfunc_2s(col);
spryscale += rw_scalestep;
}
}
}
// Loop through R_DrawMaskedColumn calls // Loop through R_DrawMaskedColumn calls
static void R_DrawRepeatMaskedColumn(column_t *col) static void R_DrawRepeatMaskedColumn(column_t *col)
{ {
@ -790,8 +1080,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
// Texture must be cached before setting colfunc_2s, // Texture must be cached before setting colfunc_2s,
// otherwise texture[texnum]->holes may be false when it shouldn't be // otherwise texture[texnum]->holes may be false when it shouldn't be
R_CheckTextureCache(texnum); R_CheckTextureCache(texnum);
//faB: handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info anymore in Doom Legacy // handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info in SRB2
if (textures[texnum]->holes) if (textures[texnum]->holes)
{ {
if (textures[texnum]->flip & 2) // vertically flipped? if (textures[texnum]->flip & 2) // vertically flipped?
@ -1077,6 +1368,15 @@ static void R_RenderSegLoop (void)
INT32 bottom; INT32 bottom;
INT32 i; INT32 i;
fixed_t oldoverlaycolumn[NUM_WALL_OVERLAYS];
fixed_t overlaycolumn[NUM_WALL_OVERLAYS];
if (hasoverlaytexture)
{
for (i = 0; i < NUM_WALL_OVERLAYS; i++)
oldoverlaycolumn[i] = -1;
}
for (; rw_x < rw_stopx; rw_x++) for (; rw_x < rw_stopx; rw_x++)
{ {
// mark floor / ceiling areas // mark floor / ceiling areas
@ -1469,6 +1769,47 @@ static void R_RenderSegLoop (void)
oldtexturecolumn = texturecolumn; oldtexturecolumn = texturecolumn;
} }
if (hasoverlaytexture)
{
#define ALIGN_UPPER(which) \
if (overlaytexture[which]) \
overlaytextureheight[which][rw_x] = max(rw_overlay[which].mid, rw_overlay[which].back)
#define ALIGN_LOWER(which) \
if (overlaytexture[which]) \
overlaytextureheight[which][rw_x] = min(rw_overlay[which].mid, rw_overlay[which].back)
ALIGN_UPPER(EDGE_TEXTURE_TOP_UPPER);
ALIGN_LOWER(EDGE_TEXTURE_TOP_LOWER);
ALIGN_UPPER(EDGE_TEXTURE_BOTTOM_UPPER);
ALIGN_LOWER(EDGE_TEXTURE_BOTTOM_LOWER);
#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)
{
rw_overlay[i].mid += FixedMul(rw_overlay[i].slide, oldoverlaycolumn[i]-overlaycolumn[i]);
rw_overlay[i].back += FixedMul(rw_overlay[i].backslide, oldoverlaycolumn[i]-overlaycolumn[i]);
}
oldoverlaycolumn[i] = overlaycolumn[i];
}
}
if (invscale) if (invscale)
invscale[rw_x] = 0xffffffffu / (unsigned)rw_scale; invscale[rw_x] = 0xffffffffu / (unsigned)rw_scale;
@ -1560,7 +1901,7 @@ static void R_AllocClippingTables(size_t range)
static void R_AllocTextureColumnTables(size_t range) static void R_AllocTextureColumnTables(size_t range)
{ {
size_t pos = curtexturecolumntable - texturecolumntable; size_t pos = curtexturecolumntable - texturecolumntable;
size_t need = range * 3; size_t need = range * 4;
if (pos + need < texturecolumntablesize) if (pos + need < texturecolumntablesize)
return; return;
@ -1581,12 +1922,109 @@ static void R_AllocTextureColumnTables(size_t range)
for (drawseg_t *ds = drawsegs; ds < ds_p; ds++) for (drawseg_t *ds = drawsegs; ds < ds_p; ds++)
{ {
// Check if it's in range of the tables // Check if it's in range of the tables
if (ds->maskedtexturecol + ds->x1 >= oldtable && ds->maskedtexturecol + ds->x1 <= oldlast) #define CHECK(which) \
ds->maskedtexturecol = (ds->maskedtexturecol - oldtable) + texturecolumntable; if (which + ds->x1 >= oldtable && which + ds->x1 <= oldlast) \
if (ds->thicksidecol + ds->x1 >= oldtable && ds->thicksidecol + ds->x1 <= oldlast) which = (which - oldtable) + texturecolumntable
ds->thicksidecol = (ds->thicksidecol - oldtable) + texturecolumntable;
if (ds->invscale + ds->x1 >= oldtable && ds->invscale + ds->x1 <= oldlast) CHECK(ds->maskedtexturecol);
ds->invscale = (ds->invscale - oldtable) + texturecolumntable; CHECK(ds->maskedtextureheight);
CHECK(ds->thicksidecol);
CHECK(ds->invscale);
#undef CHECK
}
}
static void R_AddOverlayTextures(fixed_t ceilingfrontslide, fixed_t floorfrontslide, fixed_t ceilingbackslide, fixed_t floorbackslide)
{
INT32 texnums[4] = {
R_GetTextureNum(sidedef->overlays[0].texture),
R_GetTextureNum(sidedef->overlays[1].texture),
R_GetTextureNum(sidedef->overlays[2].texture),
R_GetTextureNum(sidedef->overlays[3].texture)
};
if (!backsector)
{
// If one-sided, render just the upper top and the lower bottom overlays
overlaytexture[0] = texnums[0] ? texnums[0] : texnums[2];
overlaytexture[3] = texnums[1] ? texnums[1] : texnums[3];
}
else
{
overlaytexture[0] = texnums[0];
overlaytexture[1] = texnums[1];
overlaytexture[2] = texnums[2];
overlaytexture[3] = texnums[3];
}
for (unsigned i = 0; i < NUM_WALL_OVERLAYS; i++)
{
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;
rw_overlay[i].scalex = sidedef->overlays[i].scalex;
rw_overlay[i].scaley = sidedef->overlays[i].scaley;
rw_overlay[i].offsetx = sidedef->overlays[i].offsetx;
rw_overlay[i].offsety = sidedef->overlays[i].offsety;
rw_overlay[i].invscalex = FixedDiv(FRACUNIT, rw_overlay[i].scalex);
if (sidedef->flags & GET_SIDEFLAG_EDGENOSKEW(i))
{
if (IS_BOTTOM_EDGE_TEXTURE(i))
{
rw_overlay[i].mid = frontsector->floorheight;
rw_overlay[i].back = backsector ? backsector->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].slide = 0;
rw_overlay[i].backslide = 0;
rw_overlay[i].mid -= viewz;
rw_overlay[i].back -= viewz;
}
else if (IS_BOTTOM_EDGE_TEXTURE(i))
{
rw_overlay[i].mid = worldbottom;
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;
}
else
{
rw_overlay[i].mid = worldtop;
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].mid = FixedMul(rw_overlay[i].mid, abs(rw_overlay[i].scaley));
rw_overlay[i].back = FixedMul(rw_overlay[i].back, abs(rw_overlay[i].scaley));
rw_overlay[i].mid += sidedef->rowoffset + rw_overlay[i].offsety;
rw_overlay[i].back += sidedef->rowoffset + rw_overlay[i].offsety;
}
} }
} }
@ -1768,12 +2206,18 @@ void R_StoreWallRange(INT32 start, INT32 stop)
worldbottomslope -= viewz; worldbottomslope -= viewz;
midtexture = toptexture = bottomtexture = maskedtexture = 0; midtexture = toptexture = bottomtexture = maskedtexture = 0;
hasoverlaytexture = false;
memset(overlaytexture, 0, sizeof(overlaytexture));
ds_p->maskedtexturecol = NULL; ds_p->maskedtexturecol = NULL;
ds_p->maskedtextureheight = NULL;
ds_p->numthicksides = numthicksides = 0; ds_p->numthicksides = numthicksides = 0;
ds_p->thicksidecol = NULL; ds_p->thicksidecol = NULL;
ds_p->invscale = NULL; ds_p->invscale = NULL;
ds_p->tsilheight = 0; ds_p->tsilheight = 0;
texcoltables = false;
numbackffloors = 0; numbackffloors = 0;
for (i = 0; i < MAXFFLOORS; i++) for (i = 0; i < MAXFFLOORS; i++)
@ -2133,6 +2577,8 @@ void R_StoreWallRange(INT32 start, INT32 stop)
// allocate space for masked texture tables // allocate space for masked texture tables
R_AllocTextureColumnTables(rw_stopx - start); R_AllocTextureColumnTables(rw_stopx - start);
texcoltables = true;
if (frontsector && backsector && !Tag_Compare(&frontsector->tags, &backsector->tags) && (backsector->ffloors || frontsector->ffloors)) if (frontsector && backsector && !Tag_Compare(&frontsector->tags, &backsector->tags) && (backsector->ffloors || frontsector->ffloors))
{ {
ffloor_t *rover; ffloor_t *rover;
@ -2331,7 +2777,8 @@ void R_StoreWallRange(INT32 start, INT32 stop)
ds_p->maskedtexturecol = maskedtexturecol = curtexturecolumntable - rw_x; ds_p->maskedtexturecol = maskedtexturecol = curtexturecolumntable - rw_x;
curtexturecolumntable += rw_stopx - rw_x; curtexturecolumntable += rw_stopx - rw_x;
maskedtextureheight = ds_p->maskedtextureheight; // note to red, this == &(ds_p->maskedtextureheight[0]) ds_p->maskedtextureheight = maskedtextureheight = curtexturecolumntable - rw_x;
curtexturecolumntable += rw_stopx - rw_x;
maskedtexture = true; maskedtexture = true;
@ -2355,7 +2802,6 @@ void R_StoreWallRange(INT32 start, INT32 stop)
rw_midtexturemid = rw_midtextureback = max(frontsector->floorheight, backsector->floorheight) - viewz; rw_midtexturemid = rw_midtextureback = max(frontsector->floorheight, backsector->floorheight) - viewz;
else else
rw_midtexturemid = rw_midtextureback = min(frontsector->ceilingheight, backsector->ceilingheight) - viewz; rw_midtexturemid = rw_midtextureback = min(frontsector->ceilingheight, backsector->ceilingheight) - viewz;
} }
else if (linedef->flags & ML_MIDPEG) else if (linedef->flags & ML_MIDPEG)
{ {
@ -2378,14 +2824,16 @@ void R_StoreWallRange(INT32 start, INT32 stop)
rw_midtexturemid += sidedef->rowoffset + sidedef->offsety_mid; rw_midtexturemid += sidedef->rowoffset + sidedef->offsety_mid;
rw_midtextureback += sidedef->rowoffset + sidedef->offsety_mid; rw_midtextureback += sidedef->rowoffset + sidedef->offsety_mid;
maskedtexture = true;
} }
} }
// calculate rw_offset (only needed for textured lines)
segtextured = midtexture || toptexture || bottomtexture || maskedtexture || (numthicksides > 0); segtextured = midtexture || toptexture || bottomtexture || maskedtexture || (numthicksides > 0);
// check if extra textures need to be rendered
if (segtextured)
R_AddOverlayTextures(ceilingfrontslide, floorfrontslide, ceilingbackslide, floorbackslide);
// calculate rw_offset (only needed for textured lines)
if (segtextured) if (segtextured)
{ {
fixed_t sideoffset = sidedef->textureoffset; fixed_t sideoffset = sidedef->textureoffset;
@ -2851,6 +3299,14 @@ void R_StoreWallRange(INT32 start, INT32 stop)
rw_tsilheight = &(ds_p->tsilheight); rw_tsilheight = &(ds_p->tsilheight);
rw_bsilheight = &(ds_p->bsilheight); rw_bsilheight = &(ds_p->bsilheight);
// Overlay rendering needs to use the floor/ceiling clip from before the wall is rendered
// (otherwise it would be clipped and therefore wouldn't be visible)
if (hasoverlaytexture)
{
M_Memcpy(&overlayopening[0][start], ceilingclip + start, 2*(rw_stopx - start));
M_Memcpy(&overlayopening[1][start], floorclip + start, 2*(rw_stopx - start));
}
R_RenderSegLoop(); R_RenderSegLoop();
colfunc = colfuncs[BASEDRAWFUNC]; colfunc = colfuncs[BASEDRAWFUNC];
@ -2889,5 +3345,16 @@ void R_StoreWallRange(INT32 start, INT32 stop)
ds_p->silhouette |= SIL_BOTTOM; ds_p->silhouette |= SIL_BOTTOM;
ds_p->bsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MAX : INT32_MIN; ds_p->bsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MAX : INT32_MIN;
} }
// Render up to four extra textures when everything is done
if (hasoverlaytexture)
{
for (i = 0; i < NUM_WALL_OVERLAYS; i++)
{
if (overlaytexture[i])
R_RenderExtraTexture(ds_p, i, ds_p->x1, ds_p->x2);
}
}
ds_p++; ds_p++;
} }

View file

@ -3642,7 +3642,7 @@ static void R_DrawMaskedList (drawnode_t* head)
R_DoneWithNode(r2); R_DoneWithNode(r2);
r2 = next; r2 = next;
} }
else if (r2->seg && r2->seg->maskedtexturecol != NULL) else if (r2->seg && r2->seg->maskedtexturecol != NULL && r2->seg->maskedtextureheight != NULL)
{ {
next = r2->prev; next = r2->prev;
R_RenderMaskedSegRange(r2->seg, r2->seg->x1, r2->seg->x2); R_RenderMaskedSegRange(r2->seg, r2->seg->x1, r2->seg->x2);