From 509a4a5c235f3a25f9169613d4201a271acf1cf9 Mon Sep 17 00:00:00 2001 From: Lactozilla Date: Fri, 3 May 2024 15:29:30 -0300 Subject: [PATCH] Add clipmidtex property for lines and sides --- doc/specs/udmf_srb2.txt | 8 +++- src/deh_tables.c | 1 + src/doomdata.h | 67 +++++++++++++++------------- src/hardware/hw_main.c | 2 +- src/lua_maplib.c | 11 +++++ src/p_saveg.c | 10 ++++- src/p_setup.c | 13 +++++- src/r_defs.h | 13 +++++- src/r_segs.c | 98 +++++++++++++++++++++++++++++++---------- 9 files changed, 161 insertions(+), 62 deletions(-) diff --git a/doc/specs/udmf_srb2.txt b/doc/specs/udmf_srb2.txt index b25ed1af3..c99ef4ced 100644 --- a/doc/specs/udmf_srb2.txt +++ b/doc/specs/udmf_srb2.txt @@ -1,5 +1,5 @@ =============================================================================== -Universal Doom Map Format Sonic Robo Blast 2 extensions v1.0 19.02.2024 +Universal Doom Map Format Sonic Robo Blast 2 extensions v1.1 03.05.2024 Copyright (c) 2024 Sonic Team Junior uses Universal Doom Map Format Specification v1.1 as a template, @@ -80,6 +80,7 @@ Sonic Robo Blast 2 defines the following standardized fields: noskew = ; // Middle texture is not skewed. midpeg = ; // Middle texture is pegged. midsolid = ; // Middle texture is solid. + clipmidtex = ; // Line's mid textures are clipped to floor and ceiling. wrapmidtex = ; // Line's mid textures are wrapped. nonet = ; // Special only takes effect in singleplayer games. netonly = ; // Special only takes effect in multiplayer games. @@ -143,6 +144,8 @@ Sonic Robo Blast 2 defines the following standardized fields: offsetx_bottom = ; // X offset for lower texture. Default = 0.0. offsety_bottom = ; // Y offset for lower texture. Default = 0.0. + clipmidtex = ; // Side's mid textures are clipped to floor and ceiling. + comment = ; // A comment. Implementors should attach no special // semantic meaning to this field. } @@ -305,6 +308,9 @@ Sonic Robo Blast 2 defines the following standardized fields: Changelog ======================================= +1.1: 03.05.2024 +Added clipmidtex property to lines and sides. + 1.0: 19.02.2024 Initial version. diff --git a/src/deh_tables.c b/src/deh_tables.c index c7c7c6040..0109c9879 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4540,6 +4540,7 @@ const char *const ML_LIST[] = { "EFFECT6", "BOUNCY", "TFERLINE", + "CLIPMIDTEX", NULL }; diff --git a/src/doomdata.h b/src/doomdata.h index 276e03297..45b9ec1b3 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -103,48 +103,53 @@ typedef struct // LineDef attributes. // -// Solid, is an obstacle. -#define ML_IMPASSIBLE 1 +enum +{ + // Solid, is an obstacle. + ML_IMPASSIBLE = 1<<0, -// Blocks monsters only. -#define ML_BLOCKMONSTERS 2 + // Blocks monsters only. + ML_BLOCKMONSTERS = 1<<1, -// Backside will not be present at all if not two sided. -#define ML_TWOSIDED 4 + // Backside will not be present at all if not two sided. + ML_TWOSIDED = 1<<2, -// If a texture is pegged, the texture will have -// the end exposed to air held constant at the -// top or bottom of the texture (stairs or pulled -// down things) and will move with a height change -// of one of the neighbor sectors. -// Unpegged textures allways have the first row of -// the texture at the top pixel of the line for both -// top and bottom textures (use next to windows). + // If a texture is pegged, the texture will have + // the end exposed to air held constant at the + // top or bottom of the texture (stairs or pulled + // down things) and will move with a height change + // of one of the neighbor sectors. + // Unpegged textures allways have the first row of + // the texture at the top pixel of the line for both + // top and bottom textures (use next to windows). -// upper texture unpegged -#define ML_DONTPEGTOP 8 + // upper texture unpegged + ML_DONTPEGTOP = 1<<3, -// lower texture unpegged -#define ML_DONTPEGBOTTOM 16 + // lower texture unpegged + ML_DONTPEGBOTTOM = 1<<4, -#define ML_SKEWTD 32 + ML_SKEWTD = 1<<5, -// Don't let Knuckles climb on this line -#define ML_NOCLIMB 64 + // Don't let Knuckles climb on this line + ML_NOCLIMB = 1<<6, -#define ML_NOSKEW 128 -#define ML_MIDPEG 256 -#define ML_MIDSOLID 512 -#define ML_WRAPMIDTEX 1024 + ML_NOSKEW = 1<<7, + ML_MIDPEG = 1<<8, + ML_MIDSOLID = 1<<9, + ML_WRAPMIDTEX = 1<<10, -#define ML_NETONLY 2048 // Apply effect only in netgames -#define ML_NONET 4096 // Apply effect only in single player games -#define ML_EFFECT6 8192 + ML_NETONLY = 1<<11, // Apply effect only in netgames + ML_NONET = 1<<12, // Apply effect only in single player games + ML_EFFECT6 = 1<<13, -// Bounce off walls! -#define ML_BOUNCY 16384 + // Bounce off walls! + ML_BOUNCY = 1<<14, -#define ML_TFERLINE 32768 + ML_TFERLINE = 1<<15, + + ML_CLIPMIDTEX = 1<<16 +}; // Sector definition, from editing. typedef struct diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index f533082f7..5a08d8347 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -1023,7 +1023,7 @@ static void HWR_RenderMidtexture(INT32 gl_midtexture, float cliplow, float cliph } // The cut-off values of a linedef can always be constant, since every line has an absoulute front and or back sector - if (gl_curline->polyseg) + if (gl_curline->polyseg && ((gl_linedef->flags & ML_CLIPMIDTEX) || (gl_sidedef->flags & SIDEFLAG_CLIP_MIDTEX)) == 0) { lowcut = polybottom; highcut = polytop; diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 6b489f22b..aa29e1b75 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -213,6 +213,7 @@ enum side_e { side_sector, side_special, side_repeatcnt, + side_clipmidtex, side_text }; @@ -241,6 +242,7 @@ static const char *const side_opt[] = { "sector", "special", "repeatcnt", + "clipmidtex", "text", NULL}; @@ -1311,6 +1313,9 @@ static int side_get(lua_State *L) case side_repeatcnt: lua_pushinteger(L, side->repeatcnt); return 1; + case side_clipmidtex: + lua_pushinteger(L, side->flags & SIDEFLAG_CLIP_MIDTEX); + return 1; // TODO: 2.3: Delete case side_text: { @@ -1413,6 +1418,12 @@ static int side_set(lua_State *L) case side_repeatcnt: side->repeatcnt = luaL_checkinteger(L, 3); break; + case side_clipmidtex: + if (luaL_checkboolean(L, 3)) + side->flags |= SIDEFLAG_CLIP_MIDTEX; + else + side->flags &= ~SIDEFLAG_CLIP_MIDTEX; + break; } return 0; } diff --git a/src/p_saveg.c b/src/p_saveg.c index 5e4d6d076..d3fd05c73 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -1393,6 +1393,8 @@ static UINT32 GetSideDiff(const side_t *si, const side_t *spawnsi) diff |= LD_SDBOTSCALEY; if (si->repeatcnt != spawnsi->repeatcnt) diff |= LD_SDREPEATCNT; + if (si->flags != spawnsi->flags) + diff |= LD_SDFLAGS; return diff; } @@ -1436,6 +1438,8 @@ static void ArchiveSide(const side_t *si, UINT32 diff) WRITEFIXED(save_p, si->scaley_bottom); if (diff & LD_SDREPEATCNT) WRITEINT16(save_p, si->repeatcnt); + if (diff & LD_SDFLAGS) + WRITEUINT16(save_p, si->flags); } static void ArchiveLines(void) @@ -1493,7 +1497,7 @@ static void ArchiveLines(void) if (diff & LD_DIFF2) WRITEUINT8(save_p, diff2); if (diff & LD_FLAG) - WRITEINT16(save_p, li->flags); + WRITEUINT32(save_p, li->flags); if (diff & LD_SPECIAL) WRITEINT16(save_p, li->special); if (diff & LD_CLLCOUNT) @@ -1576,6 +1580,8 @@ static void UnArchiveSide(side_t *si) si->scaley_bottom = READFIXED(save_p); if (diff & LD_SDREPEATCNT) si->repeatcnt = READINT16(save_p); + if (diff & LD_SDFLAGS) + si->flags = READUINT16(save_p); } static void UnArchiveLines(void) @@ -1601,7 +1607,7 @@ static void UnArchiveLines(void) li = &lines[i]; if (diff & LD_FLAG) - li->flags = READINT16(save_p); + li->flags = READUINT32(save_p); if (diff & LD_SPECIAL) li->special = READINT16(save_p); if (diff & LD_CLLCOUNT) diff --git a/src/p_setup.c b/src/p_setup.c index 41487d702..4ec77f364 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1363,6 +1363,8 @@ static void P_LoadSidedefs(UINT8 *data) sd->scalex_top = sd->scalex_mid = sd->scalex_bottom = FRACUNIT; sd->scaley_top = sd->scaley_mid = sd->scaley_bottom = FRACUNIT; + sd->flags = 0; + P_SetSidedefSector(i, (UINT16)SHORT(msd->sector)); // Special info stored in texture fields! @@ -1943,6 +1945,8 @@ static void ParseTextmapSidedefParameter(UINT32 i, const char *param, const char P_SetSidedefSector(i, atol(val)); else if (fastcmp(param, "repeatcnt")) sides[i].repeatcnt = atol(val); + else if (fastcmp(param, "clipmidtex") && fastcmp("true", val)) + sides[i].flags |= SIDEFLAG_CLIP_MIDTEX; } static void ParseTextmapLinedefParameter(UINT32 i, const char *param, const char *val) @@ -2025,10 +2029,10 @@ static void ParseTextmapLinedefParameter(UINT32 i, const char *param, const char lines[i].flags |= ML_MIDPEG; else if (fastcmp(param, "midsolid") && fastcmp("true", val)) lines[i].flags |= ML_MIDSOLID; + else if (fastcmp(param, "clipmidtex") && fastcmp("true", val)) + lines[i].flags |= ML_CLIPMIDTEX; else if (fastcmp(param, "wrapmidtex") && fastcmp("true", val)) 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)) lines[i].flags |= ML_NONET; else if (fastcmp(param, "netonly") && fastcmp("true", val)) @@ -2615,6 +2619,8 @@ static void P_WriteTextmap(void) fprintf(f, "midpeg = true;\n"); if (wlines[i].flags & ML_MIDSOLID) fprintf(f, "midsolid = true;\n"); + if (wlines[i].flags & ML_CLIPMIDTEX) + fprintf(f, "clipmidtex = true;\n"); if (wlines[i].flags & ML_WRAPMIDTEX) fprintf(f, "wrapmidtex = true;\n"); if (wlines[i].flags & ML_NONET) @@ -2670,6 +2676,8 @@ static void P_WriteTextmap(void) fprintf(f, "texturemiddle = \"%.*s\";\n", 8, textures[wsides[i].midtexture]->name); if (wsides[i].repeatcnt != 0) fprintf(f, "repeatcnt = %d;\n", wsides[i].repeatcnt); + if (wsides[i].flags & SIDEFLAG_CLIP_MIDTEX) + fprintf(f, "clipmidtex = true;\n"); fprintf(f, "}\n"); fprintf(f, "\n"); } @@ -3072,6 +3080,7 @@ static void P_LoadTextmap(void) sd->bottomtexture = R_TextureNumForName("-"); sd->sector = NULL; sd->repeatcnt = 0; + sd->flags = 0; TextmapParse(sidesPos[i], i, ParseTextmapSidedefParameter); diff --git a/src/r_defs.h b/src/r_defs.h index da4dd2d70..38f67e8e9 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -584,7 +584,7 @@ typedef struct line_s angle_t angle; // Precalculated angle between dx and dy // Animation related. - INT16 flags; + UINT32 flags; INT16 special; taglist_t tags; INT32 args[NUMLINEARGS]; @@ -614,6 +614,12 @@ typedef struct line_s UINT32 secportal; // transferred sector portal } line_t; +// Don't make available to Lua or I will find where you live +typedef enum +{ + SIDEFLAG_CLIP_MIDTEX = 1 << 0, // Like the line counterpart, but only for this side. +} sideflags_t; + typedef struct { // add this to the calculated texture column @@ -622,13 +628,16 @@ typedef struct // add this to the calculated texture top fixed_t rowoffset; - // per-texture offsets for UDMF + // per-texture offsets fixed_t offsetx_top, offsetx_mid, offsetx_bottom; fixed_t offsety_top, offsety_mid, offsety_bottom; fixed_t scalex_top, scalex_mid, scalex_bottom; fixed_t scaley_top, scaley_mid, scaley_bottom; + // Rendering-related flags + UINT16 flags; + // Texture indices. // We do not maintain names here. INT32 toptexture, bottomtexture, midtexture; diff --git a/src/r_segs.c b/src/r_segs.c index e07ced86a..14a445329 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -114,6 +114,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) fixed_t wall_scaley; fixed_t scalestep; fixed_t scale1; + fixed_t texture_top, texture_bottom, texture_height; + boolean clipmidtex; // Calculate light table. // Use different light tables @@ -276,6 +278,9 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) else back = backsector; + clipmidtex = (ldef->flags & ML_CLIPMIDTEX) || (sidedef->flags & SIDEFLAG_CLIP_MIDTEX); + texture_height = FixedDiv(textureheight[texnum], wall_scaley); + if (sidedef->repeatcnt) repeats = 1 + sidedef->repeatcnt; else if (ldef->flags & ML_WRAPMIDTEX) @@ -292,8 +297,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) else low = back->floorheight; - repeats = (high - low)/textureheight[texnum]; - if ((high-low)%textureheight[texnum]) + repeats = (high - low)/texture_height; + if ((high-low)%texture_height) repeats++; // tile an extra time to fill the gap -- Monster Iestyn } else @@ -301,6 +306,33 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) for (times = 0; times < repeats; times++) { + fixed_t left_top = 0, left_bottom = 0; + fixed_t right_top = 0, right_bottom = 0; + fixed_t top_step = 0, bottom_step = 0; + + // Get left and right ends of wall for clipping it + if (clipmidtex) + { + // For this to work correctly with polyobjects, it needs to use its own back sector, rather than the seg's front sector + sector_t *sec_front = curline->polyseg ? + curline->polyseg->lines[0]->backsector : + frontsector; + + // calculate both left ends + left_top = P_GetSectorCeilingZAt(sec_front, ds->leftpos.x, ds->leftpos.y) - viewz; + left_bottom = P_GetSectorFloorZAt(sec_front, ds->leftpos.x, ds->leftpos.y) - viewz; + + // calculate right ends now + right_top = P_GetSectorCeilingZAt(sec_front, ds->rightpos.x, ds->rightpos.y) - viewz; + right_bottom = P_GetSectorFloorZAt(sec_front, ds->rightpos.x, ds->rightpos.y) - viewz; + + top_step = (right_top - left_top) / range; + bottom_step = (right_bottom - left_bottom) / range; + + left_top += top_step * (x1 - ds->x1); + left_bottom += bottom_step * (x1 - ds->x1); + } + if (times > 0) { rw_scalestep = scalestep; @@ -321,7 +353,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) { dc_texturemid = ds->maskedtextureheight[dc_x]; - if (curline->linedef->flags & ML_MIDPEG) + if (ldef->flags & ML_MIDPEG) dc_texturemid += (textureheight[texnum])*times + textureheight[texnum]; else dc_texturemid -= (textureheight[texnum])*times; @@ -341,29 +373,53 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) } } spryscale += rw_scalestep; + if (clipmidtex) + { + left_top += top_step; + left_bottom += bottom_step; + } continue; } - // calculate lighting + texture_top = dc_texturemid; + texture_bottom = texture_top - texture_height; + + // If the texture is meant to be clipped + if (clipmidtex) + { + texture_top = min(FixedMul(left_top, wall_scaley), texture_top); + texture_bottom = max(FixedMul(left_bottom, wall_scaley), texture_bottom); + + left_top += top_step; + left_bottom += bottom_step; + } + + // NB: sprtopscreen needs to start where dc_texturemid does, so that R_DrawMaskedColumn works correctly. + // windowtop however is set so that the column gets clipped properly. + sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); + realbot = centeryfrac - FixedMul(texture_bottom, spryscale); + + // set wall bounds if necessary + if (dc_numlights || clipmidtex) + { + windowtop = centeryfrac - FixedMul(texture_top, spryscale); + windowbottom = realbot; + } + + dc_iscale = FixedMul(ds->invscale[dc_x], wall_scaley); + + col = R_GetColumn(texnum, maskedtexturecol[dc_x] >> FRACBITS); + + // draw light list if there is one if (dc_numlights) { - lighttable_t **xwalllights; - - 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 = R_GetColumn(texnum, maskedtexturecol[dc_x] >> FRACBITS); - for (i = 0; i < dc_numlights; i++) { + lighttable_t **xwalllights; + rlight = &dc_lightlist[i]; - if ((rlight->flags & FOF_NOSHADE)) + if (rlight->flags & FOF_NOSHADE) continue; if (rlight->lightnum < 0) @@ -373,7 +429,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) else xwalllights = scalelight[rlight->lightnum]; - pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; + pindex = FixedMul(FixedMul(spryscale, wall_scaley), LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; if (pindex >= MAXLIGHTSCALE) pindex = MAXLIGHTSCALE - 1; @@ -418,7 +474,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) } // calculate lighting - pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; + pindex = FixedMul(FixedMul(spryscale, wall_scaley), LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; if (pindex >= MAXLIGHTSCALE) pindex = MAXLIGHTSCALE - 1; @@ -428,11 +484,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) 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 = R_GetColumn(texnum, maskedtexturecol[dc_x] >> FRACBITS); colfunc_2s(col, lengthcol); spryscale += rw_scalestep;