Proper overflow checking, applied to FOFs and midtex's too

This fixes the annoying flickering when you pass by water, FOFs, tall grass, etc.
This commit is contained in:
Inuyasha 2016-05-02 05:29:30 -07:00
parent 37575d2219
commit 7c79bbc0b3
4 changed files with 47 additions and 51 deletions

View File

@ -1787,17 +1787,6 @@ UINT8 M_CountBits(UINT32 num, UINT8 size)
return sum;
}
/** Get the most significant bit in a number.
* (integer log2)
*/
UINT8 M_HighestBit(UINT32 num)
{
UINT8 i = 0;
while (num >>= 1) ++i;
return i;
}
const char *GetRevisionString(void)
{
static char rev[9] = {0};

View File

@ -95,7 +95,6 @@ void M_SetupMemcpy(void);
// counting bits, for weapon ammo code, usually
FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size);
FUNCMATH UINT8 M_HighestBit(UINT32 num);
// Flags for AA trees.
#define AATREE_ZUSER 1 // Treat values as z_zone-allocated blocks and set their user fields

View File

@ -288,6 +288,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
line_t *ldef;
sector_t *front, *back;
INT32 times, repeats;
INT64 overflow_test;
#ifdef ESLOPE
INT32 range;
#endif
@ -485,7 +486,6 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
}
#ifndef ESLOPE
if (curline->linedef->flags & ML_DONTPEGBOTTOM)
{
@ -523,6 +523,16 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
// calculate lighting
if (maskedtexturecol[dc_x] != INT16_MAX)
{
// 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
spryscale += rw_scalestep;
continue;
}
if (dc_numlights)
{
lighttable_t **xwalllights;
@ -947,16 +957,38 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
// Set heights according to plane, or slope, whichever
{
fixed_t left_top, right_top, left_bottom, right_bottom;
INT64 overflow_test;
left_top = *pfloor->t_slope ? P_GetZAt(*pfloor->t_slope, ds->leftpos.x, ds->leftpos.y) : *pfloor->topheight;
right_top = *pfloor->t_slope ? P_GetZAt(*pfloor->t_slope, ds->rightpos.x, ds->rightpos.y) : *pfloor->topheight;
left_bottom = *pfloor->b_slope ? P_GetZAt(*pfloor->b_slope, ds->leftpos.x, ds->leftpos.y) : *pfloor->bottomheight;
right_bottom = *pfloor->b_slope ? P_GetZAt(*pfloor->b_slope, ds->rightpos.x, ds->rightpos.y) : *pfloor->bottomheight;
if (*pfloor->t_slope)
{
left_top = P_GetZAt(*pfloor->t_slope, ds->leftpos.x, ds->leftpos.y) - viewz;
right_top = P_GetZAt(*pfloor->t_slope, ds->rightpos.x, ds->rightpos.y) - viewz;
}
else
left_top = right_top = *pfloor->topheight - viewz;
left_top -= viewz;
right_top -= viewz;
left_bottom -= viewz;
right_bottom -= viewz;
if (*pfloor->b_slope)
{
left_bottom = P_GetZAt(*pfloor->b_slope, ds->leftpos.x, ds->leftpos.y) - viewz;
right_bottom = P_GetZAt(*pfloor->b_slope, ds->rightpos.x, ds->rightpos.y) - viewz;
}
else
left_bottom = right_bottom = *pfloor->bottomheight - viewz;
// overflow tests
// if any of these fail, abandon. likely we're too high up to see anything anyway
overflow_test = (INT64)centeryfrac - (((INT64)left_top*ds->scale1)>>FRACBITS);
if (overflow_test < 0) overflow_test = -overflow_test;
if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return;
overflow_test = (INT64)centeryfrac - (((INT64)left_bottom*ds->scale1)>>FRACBITS);
if (overflow_test < 0) overflow_test = -overflow_test;
if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return;
overflow_test = (INT64)centeryfrac - (((INT64)right_top*ds->scale2)>>FRACBITS);
if (overflow_test < 0) overflow_test = -overflow_test;
if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return;
overflow_test = (INT64)centeryfrac - (((INT64)right_bottom*ds->scale2)>>FRACBITS);
if (overflow_test < 0) overflow_test = -overflow_test;
if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return;
top_frac = centeryfrac - FixedMul(left_top, ds->scale1);
bottom_frac = centeryfrac - FixedMul(left_bottom, ds->scale1);
@ -1133,19 +1165,6 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
if (pfloor->flags & FF_FOG && pfloor->master->frontsector->extra_colormap)
dc_colormap = pfloor->master->frontsector->extra_colormap->colormap + (dc_colormap - colormaps);
//Handle over/underflows before they happen. This fixes the textures part of the FOF rendering bug.
//...for the most part, anyway.
if (((signed)dc_texturemid > 0 && (spryscale>>FRACBITS > INT32_MAX / (signed)dc_texturemid))
|| ((signed)dc_texturemid < 0 && (spryscale) && (signed)(dc_texturemid)>>FRACBITS < (INT32_MIN / spryscale)))
{
spryscale += rw_scalestep;
#ifdef ESLOPE
top_frac += top_step;
bottom_frac += bottom_step;
#endif
continue;
}
#ifdef ESLOPE
sprtopscreen = windowtop = top_frac;
sprbotscreen = windowbottom = bottom_frac;

View File

@ -744,10 +744,16 @@ static void R_DrawVisSprite(vissprite_t *vis)
patch_t *patch = W_CacheLumpNum(vis->patch, PU_CACHE);
fixed_t this_scale = vis->mobj->scale;
INT32 x1, x2;
INT64 overflow_test;
if (!patch)
return;
// Check for overflow
overflow_test = (INT64)centeryfrac - (((INT64)vis->texturemid*vis->scale)>>FRACBITS);
if (overflow_test < 0) overflow_test = -overflow_test;
if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // fixed point mult would overflow
colfunc = basecolfunc; // hack: this isn't resetting properly somewhere.
dc_colormap = vis->colormap;
if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash"
@ -1239,15 +1245,6 @@ static void R_ProjectSprite(mobj_t *thing)
return;
}
// quick check for possible overflows
// if either of these triggers then there's a possibility that drawing is unsafe
if (M_HighestBit(abs(gzt - viewz)) + M_HighestBit(abs(yscale)) > 47 // 31 bits + 16 from the division by FRACUNIT
|| M_HighestBit(abs(gz - viewz)) + M_HighestBit(abs(yscale)) > 47)
{
CONS_Debug(DBG_RENDER, "Suspected overflow in ProjectSprite (sprite %s), ignoring\n", sprnames[thing->sprite]);
return;
}
// store information in a vissprite
vis = R_NewVisSprite();
vis->heightsec = heightsec; //SoM: 3/17/2000
@ -1458,14 +1455,6 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
return;
}
// quick check for possible overflows
// if either of these triggers then there's a possibility that drawing is unsafe
if (M_HighestBit(abs(gzt - viewz)) + M_HighestBit(abs(yscale)) > 47) // 31 bits + 16 from the division by FRACUNIT
{
CONS_Debug(DBG_RENDER, "Suspected overflow in ProjectPrecipitationSprite (sprite %s), ignoring\n", sprnames[thing->sprite]);
return;
}
// store information in a vissprite
vis = R_NewVisSprite();
vis->scale = yscale; //<<detailshift;