From da3355a1536d212e58ced550bcfd5a56efd2f8af Mon Sep 17 00:00:00 2001 From: Lactozilla Date: Sat, 4 May 2024 03:39:41 -0300 Subject: [PATCH] Fix #1247 --- src/r_draw.c | 2 +- src/r_draw.h | 5 +- src/r_draw8.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++ src/r_segs.c | 63 +++++++++++++----- src/r_things.c | 12 ++-- 5 files changed, 235 insertions(+), 23 deletions(-) diff --git a/src/r_draw.c b/src/r_draw.c index 86f7e488c..feb4693bb 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -74,7 +74,7 @@ UINT8 *dc_transmap; // one of the translucency tables UINT8 *dc_translation; struct r_lightlist_s *dc_lightlist = NULL; -INT32 dc_numlights = 0, dc_maxlights, dc_texheight; +INT32 dc_numlights = 0, dc_maxlights, dc_texheight, dc_postlength; // ========================================================================= // SPAN DRAWING CODE STUFF diff --git a/src/r_draw.h b/src/r_draw.h index 1a828312a..77588d7de 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -41,8 +41,7 @@ extern UINT8 *dc_translation; extern struct r_lightlist_s *dc_lightlist; extern INT32 dc_numlights, dc_maxlights; -//Fix TUTIFRUTI -extern INT32 dc_texheight; +extern INT32 dc_texheight, dc_postlength; // ----------------------- // SPAN DRAWING CODE STUFF @@ -154,8 +153,10 @@ void R_VideoErase(size_t ofs, INT32 count); // ----------------- void R_DrawColumn_8(void); +void R_DrawColumnClamped_8(void); void R_DrawShadeColumn_8(void); void R_DrawTranslucentColumn_8(void); +void R_DrawTranslucentColumnClamped_8(void); void R_DrawDropShadowColumn_8(void); void R_DrawTranslatedColumn_8(void); void R_DrawTranslatedTranslucentColumn_8(void); diff --git a/src/r_draw8.c b/src/r_draw8.c index 99fb71e28..735127f88 100644 --- a/src/r_draw8.c +++ b/src/r_draw8.c @@ -100,6 +100,98 @@ void R_DrawColumn_8(void) } } +/** \brief The R_DrawColumnClamped_8 function + Same as R_DrawColumn_8, but prevents artifacts from showing up (caused by fixed-point imprecisions) +*/ +void R_DrawColumnClamped_8(void) +{ + INT32 count; + UINT8 *dest; + fixed_t frac; + fixed_t fracstep; + + count = dc_yh - dc_yl; + + if (count < 0) // Zero length, column does not exceed a pixel. + return; + +#ifdef RANGECHECK + if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height) + return; +#endif + + // Framebuffer destination address. + dest = &topleft[dc_yl*vid.width + dc_x]; + + count++; + + // Determine scaling, which is the only mapping to be done. + fracstep = dc_iscale; + frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep); + + // Inner loop that does the actual texture mapping, e.g. a DDA-like scaling. + // This is as fast as it gets. + { + const UINT8 *source = dc_source; + const lighttable_t *colormap = dc_colormap; + INT32 heightmask = dc_texheight-1; + INT32 idx; + if (dc_texheight & heightmask) // not a power of 2 -- killough + { + heightmask++; + heightmask <<= FRACBITS; + + if (frac < 0) + while ((frac += heightmask) < 0); + else + while (frac >= heightmask) + frac -= heightmask; + + do + { + // Re-map color indices from wall texture column + // using a lighting/special effects LUT. + // heightmask is the Tutti-Frutti fix + idx = frac>>FRACBITS; + if (idx >= 0 && idx < dc_postlength) + *dest = colormap[source[idx]]; + dest += vid.width; + + // Avoid overflow. + if (fracstep > 0x7FFFFFFF - frac) + frac += fracstep - heightmask; + else + frac += fracstep; + + while (frac >= heightmask) + frac -= heightmask; + } while (--count); + } + else + { + while ((count -= 2) >= 0) // texture height is a power of 2 + { + idx = (frac>>FRACBITS) & heightmask; + if (idx >= 0 && idx < dc_postlength) + *dest = colormap[source[idx]]; + dest += vid.width; + frac += fracstep; + idx = (frac>>FRACBITS) & heightmask; + if (idx >= 0 && idx < dc_postlength) + *dest = colormap[source[idx]]; + dest += vid.width; + frac += fracstep; + } + if (count & 1) + { + idx = (frac>>FRACBITS) & heightmask; + if (idx >= 0 && idx < dc_postlength) + *dest = colormap[source[idx]]; + } + } + } +} + /** \brief The R_DrawShadeColumn_8 function Experiment to make software go faster. Taken from the Boom source */ @@ -212,6 +304,90 @@ void R_DrawTranslucentColumn_8(void) } } +/** \brief The R_DrawTranslucentColumnClamped_8 function + Same as R_DrawTranslucentColumn_8, but prevents artifacts from showing up (caused by fixed-point imprecisions) +*/ +void R_DrawTranslucentColumnClamped_8(void) +{ + INT32 count; + UINT8 *dest; + fixed_t frac, fracstep; + + count = dc_yh - dc_yl + 1; + + if (count <= 0) // Zero length, column does not exceed a pixel. + return; + +#ifdef RANGECHECK + if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height) + I_Error("R_DrawTranslucentColumnClamped_8: %d to %d at %d", dc_yl, dc_yh, dc_x); +#endif + + dest = &topleft[dc_yl*vid.width + dc_x]; + + // Looks familiar. + fracstep = dc_iscale; + frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep); + + // Inner loop that does the actual texture mapping, e.g. a DDA-like scaling. + // This is as fast as it gets. + { + const UINT8 *source = dc_source; + const UINT8 *transmap = dc_transmap; + const lighttable_t *colormap = dc_colormap; + INT32 heightmask = dc_texheight - 1; + INT32 idx; + if (dc_texheight & heightmask) + { + heightmask++; + heightmask <<= FRACBITS; + + if (frac < 0) + while ((frac += heightmask) < 0) + ; + else + while (frac >= heightmask) + frac -= heightmask; + + do + { + // Re-map color indices from wall texture column + // using a lighting/special effects LUT. + // heightmask is the Tutti-Frutti fix + idx = frac>>FRACBITS; + if (idx >= 0 && idx < dc_postlength) + *dest = *(transmap + (colormap[source[idx]]<<8) + (*dest)); + dest += vid.width; + if ((frac += fracstep) >= heightmask) + frac -= heightmask; + } + while (--count); + } + else + { + while ((count -= 2) >= 0) // texture height is a power of 2 + { + idx = (frac>>FRACBITS)&heightmask; + if (idx >= 0 && idx < dc_postlength) + *dest = *(transmap + (colormap[source[idx]]<<8) + (*dest)); + dest += vid.width; + frac += fracstep; + idx = (frac>>FRACBITS)&heightmask; + if (idx >= 0 && idx < dc_postlength) + *dest = *(transmap + (colormap[source[idx]]<<8) + (*dest)); + dest += vid.width; + frac += fracstep; + } + if (count & 1) + { + idx = (frac>>FRACBITS)&heightmask; + if (idx >= 0 && idx < dc_postlength) + *dest = *(transmap + (colormap[source[idx]]<<8) + (*dest)); + } + } + } +} + // Hack: A cut-down copy of R_DrawTranslucentColumn_8 that does not read texture // data since something about calculating the texture reading address for drop shadows is broken. // dc_texturemid and dc_iscale get wrong values for drop shadows, however those are not strictly diff --git a/src/r_segs.c b/src/r_segs.c index e07ced86a..b7f9cd77b 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -515,6 +515,8 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) fixed_t wall_scalex, wall_scaley; UINT8 vertflip; unsigned lengthcol; + boolean fog = false; + boolean fuzzy = false; void (*colfunc_2s) (column_t *, unsigned); @@ -528,8 +530,6 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector; sidedef = R_GetFFloorSide(curline, pfloor); - colfunc = colfuncs[BASEDRAWFUNC]; - if (pfloor->master->flags & ML_TFERLINE) { line_t *newline = R_GetFFloorLine(curline, pfloor); @@ -547,7 +547,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) if (pfloor->fofflags & FOF_TRANSLUCENT) { - boolean fuzzy = true; + fuzzy = true; // Hacked up support for alpha value in software mode Tails 09-24-2002 // ...unhacked by toaster 04-01-2021, re-hacked a little by sphere 19-11-2021 @@ -560,17 +560,14 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) else if (!(dc_transmap = R_GetTranslucencyTable(trans)) || trans == 0) fuzzy = false; // Opaque } - - if (fuzzy) - colfunc = colfuncs[COLDRAWFUNC_FUZZY]; } else if (pfloor->fofflags & FOF_FOG) + { colfunc = colfuncs[COLDRAWFUNC_FOG]; + fog = true; + } range = max(ds->x2-ds->x1, 1); - //SoM: Moved these up here so they are available for my lightlist calculations - rw_scalestep = ds->scalestep; - spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep; dc_numlights = 0; if (frontsector->numlights) @@ -673,9 +670,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) // Get correct light level! if ((frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG))) lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT); - else if (pfloor->fofflags & FOF_FOG) + else if (fog) lightnum = (pfloor->master->frontsector->lightlevel >> LIGHTSEGSHIFT); - else if (colfunc == colfuncs[COLDRAWFUNC_FUZZY]) + else if (fuzzy) lightnum = LIGHTLEVELS-1; else lightnum = R_FakeFlat(frontsector, &tempsec, &templight, &templight, false) @@ -703,6 +700,14 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) vertflip = !vertflip; } + //SoM: Moved these up here so they are available for my lightlist calculations + // Lactozilla: Moved them back down + // This uses floating point math now, because the fixed-point imprecisions + // become more severe the bigger the texture is scaled. + double dwall_scaley = FixedToDouble(wall_scaley); + double scalestep = FixedToDouble(ds->scalestep) / dwall_scaley; + double yscale = (FixedToDouble(ds->scale1) + (x1 - ds->x1)*scalestep) / dwall_scaley; + thicksidecol = ffloortexturecolumn; wall_offsetx = ds->offsetx + sidedef->offsetx_mid; @@ -824,15 +829,41 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) rlight->botheight += rlight->botheightstep; } } - spryscale += rw_scalestep; + yscale += scalestep; continue; } - dc_iscale = FixedMul(0xffffffffu / (unsigned)spryscale, wall_scaley); - // Get data for the column col = R_GetColumn(texnum, ((thicksidecol[dc_x] + wall_offsetx) >> FRACBITS)); + spryscale = DoubleToFixed(yscale); + + // Eh. I tried fixing the scaling artifacts but it still wasn't perfect. + // So this checks if the column has gaps in it or not, and if it does, uses a version of the column drawers + // that prevents the artifacts from being visible. + // Note that if rendering fog then none of this matters because there's no texture mapping to be done + if (!fog) + { + dc_iscale = 0xffffffffu / (unsigned)spryscale; + + // Column has a single post and it matches the texture height, use regular column drawers + if (col->num_posts == 1 && col->posts[0].topdelta == 0 && col->posts[0].length == (unsigned)dc_texheight) + { + if (fuzzy) + colfunc = colfuncs[COLDRAWFUNC_FUZZY]; + else + colfunc = colfuncs[BASEDRAWFUNC]; + } + else + { + // Otherwise use column drawers with extra checks + if (fuzzy) + colfunc = R_DrawTranslucentColumnClamped_8; + else + colfunc = R_DrawColumnClamped_8; + } + } + // SoM: New code does not rely on R_DrawColumnShadowed_8 which // will (hopefully) put less strain on the stack. if (dc_numlights) @@ -947,7 +978,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) if (windowtop < windowbottom) colfunc_2s (col, lengthcol); - spryscale += rw_scalestep; + yscale += scalestep; continue; } @@ -966,7 +997,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) // draw the texture colfunc_2s (col, lengthcol); - spryscale += rw_scalestep; + yscale += scalestep; } colfunc = colfuncs[BASEDRAWFUNC]; diff --git a/src/r_things.c b/src/r_things.c index c46d81624..fb9757a9a 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -839,8 +839,10 @@ void R_DrawMaskedColumn(column_t *column, unsigned lengthcol) { post_t *post = &column->posts[i]; + dc_postlength = post->length; + INT32 topscreen = sprtopscreen + spryscale*post->topdelta; - INT32 bottomscreen = topscreen + spryscale*post->length; + INT32 bottomscreen = topscreen + spryscale*dc_postlength; dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS; dc_yh = (bottomscreen-1)>>FRACBITS; @@ -909,10 +911,12 @@ void R_DrawFlippedMaskedColumn(column_t *column, unsigned lengthcol) if (!post->length) continue; - topdelta = lengthcol-post->length-post->topdelta; + dc_postlength = post->length; + + topdelta = lengthcol-dc_postlength-post->topdelta; topscreen = sprtopscreen + spryscale*topdelta; - bottomscreen = sprbotscreen == INT32_MAX ? topscreen + spryscale*post->length - : sprbotscreen + spryscale*post->length; + bottomscreen = sprbotscreen == INT32_MAX ? topscreen + spryscale*dc_postlength + : sprbotscreen + spryscale*dc_postlength; dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS; dc_yh = (bottomscreen-1)>>FRACBITS;