Merge branch 'accurate-papersprites' into 'master'

Accurate papersprite projection

See merge request STJr/SRB2!657
This commit is contained in:
James R 2020-01-10 16:02:23 -05:00
commit dc151fc7a4
2 changed files with 92 additions and 79 deletions

View file

@ -740,9 +740,7 @@ void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight)
static void R_DrawVisSprite(vissprite_t *vis) static void R_DrawVisSprite(vissprite_t *vis)
{ {
column_t *column; column_t *column;
#ifdef RANGECHECK
INT32 texturecolumn; INT32 texturecolumn;
#endif
fixed_t frac; fixed_t frac;
patch_t *patch = vis->patch; patch_t *patch = vis->patch;
fixed_t this_scale = vis->mobj->scale; fixed_t this_scale = vis->mobj->scale;
@ -890,28 +888,51 @@ static void R_DrawVisSprite(vissprite_t *vis)
if (vis->x2 >= vid.width) if (vis->x2 >= vid.width)
vis->x2 = vid.width-1; vis->x2 = vid.width-1;
for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale) // Split drawing loops for paper and non-paper to reduce conditional checks per sprite
if (vis->scalestep)
{ {
#ifdef RANGECHECK // Papersprite drawing loop
texturecolumn = frac>>FRACBITS; for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, spryscale += vis->scalestep)
if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
I_Error("R_DrawSpriteRange: bad texturecolumn at %d from end", vis->x2 - dc_x);
column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn]));
#else
column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS]));
#endif
if (vis->scalestep)
{ {
angle_t angle = ((vis->centerangle + xtoviewangle[dc_x]) >> ANGLETOFINESHIFT) & 0xFFF;
texturecolumn = (vis->paperoffset - FixedMul(FINETANGENT(angle), vis->paperdistance)) / this_scale;
if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
continue;
if (vis->xiscale < 0) // Flipped sprite
texturecolumn = SHORT(patch->width) - 1 - texturecolumn;
sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale)); sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale));
dc_iscale = (0xffffffffu / (unsigned)spryscale); dc_iscale = (0xffffffffu / (unsigned)spryscale);
column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn]));
if (vis->cut & SC_VFLIP)
R_DrawFlippedMaskedColumn(column, patch->height);
else
R_DrawMaskedColumn(column);
}
}
else
{
// Non-paper drawing loop
for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale)
{
#ifdef RANGECHECK
texturecolumn = frac>>FRACBITS;
if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
I_Error("R_DrawSpriteRange: bad texturecolumn at %d from end", vis->x2 - dc_x);
column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn]));
#else
column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS]));
#endif
if (vis->cut & SC_VFLIP)
R_DrawFlippedMaskedColumn(column, patch->height);
else
R_DrawMaskedColumn(column);
} }
if (vis->cut & SC_VFLIP)
R_DrawFlippedMaskedColumn(column, patch->height);
else
R_DrawMaskedColumn(column);
spryscale += vis->scalestep;
} }
colfunc = colfuncs[BASEDRAWFUNC]; colfunc = colfuncs[BASEDRAWFUNC];
@ -1070,8 +1091,6 @@ static void R_SplitSprite(vissprite_t *sprite)
} }
} }
//#define PROPERPAPER // This was reverted less than 7 hours before 2.2's release because of very strange, frequent crashes.
// //
// R_ProjectSprite // R_ProjectSprite
// Generates a vissprite for a thing // Generates a vissprite for a thing
@ -1108,7 +1127,9 @@ static void R_ProjectSprite(mobj_t *thing)
fixed_t iscale; fixed_t iscale;
fixed_t scalestep; fixed_t scalestep;
fixed_t offset, offset2; fixed_t offset, offset2;
boolean papersprite = !!(thing->frame & FF_PAPERSPRITE); boolean papersprite = !!(thing->frame & FF_PAPERSPRITE);
fixed_t paperoffset = 0, paperdistance = 0; angle_t centerangle = 0;
INT32 dispoffset = thing->info->dispoffset; INT32 dispoffset = thing->info->dispoffset;
@ -1127,10 +1148,6 @@ static void R_ProjectSprite(mobj_t *thing)
UINT32 rollangle = AngleFixed(arollangle)>>FRACBITS; UINT32 rollangle = AngleFixed(arollangle)>>FRACBITS;
#endif #endif
#ifndef PROPERPAPER
fixed_t ang_scale = FRACUNIT;
#endif
// transform the origin point // transform the origin point
tr_x = thing->x - viewx; tr_x = thing->x - viewx;
tr_y = thing->y - viewy; tr_y = thing->y - viewy;
@ -1141,7 +1158,7 @@ static void R_ProjectSprite(mobj_t *thing)
tz = gxt-gyt; tz = gxt-gyt;
// thing is behind view plane? // thing is behind view plane?
if (!(papersprite) && (tz < FixedMul(MINZ, this_scale))) // papersprite clipping is handled later if (!papersprite && (tz < FixedMul(MINZ, this_scale))) // papersprite clipping is handled later
return; return;
gxt = -FixedMul(tr_x, viewsin); gxt = -FixedMul(tr_x, viewsin);
@ -1149,7 +1166,7 @@ static void R_ProjectSprite(mobj_t *thing)
tx = -(gyt + gxt); tx = -(gyt + gxt);
// too far off the side? // too far off the side?
if (abs(tx) > tz<<2) if (!papersprite && abs(tx) > tz<<2) // papersprite clipping is handled later
return; return;
// aspect ratio stuff // aspect ratio stuff
@ -1213,13 +1230,7 @@ static void R_ProjectSprite(mobj_t *thing)
#endif #endif
if (sprframe->rotate != SRF_SINGLE || papersprite) if (sprframe->rotate != SRF_SINGLE || papersprite)
{
ang = R_PointToAngle (thing->x, thing->y) - (thing->player ? thing->player->drawangle : thing->angle); ang = R_PointToAngle (thing->x, thing->y) - (thing->player ? thing->player->drawangle : thing->angle);
#ifndef PROPERPAPER
if (papersprite)
ang_scale = abs(FINESINE(ang>>ANGLETOFINESHIFT));
#endif
}
if (sprframe->rotate == SRF_SINGLE) if (sprframe->rotate == SRF_SINGLE)
{ {
@ -1280,31 +1291,11 @@ static void R_ProjectSprite(mobj_t *thing)
else else
offset = -spr_offset; offset = -spr_offset;
offset = FixedMul(offset, this_scale); offset = FixedMul(offset, this_scale);
#ifndef PROPERPAPER
tx += FixedMul(offset, ang_scale);
x1 = (centerxfrac + FixedMul (tx,xscale)) >>FRACBITS;
// off the right side?
if (x1 > viewwidth)
return;
#endif
offset2 = FixedMul(spr_width, this_scale); offset2 = FixedMul(spr_width, this_scale);
#ifndef PROPERPAPER
tx += FixedMul(offset2, ang_scale);
x2 = ((centerxfrac + FixedMul (tx,xscale)) >> FRACBITS) - (papersprite ? 2 : 1);
// off the left side
if (x2 < 0)
return;
#endif
if (papersprite) if (papersprite)
{ {
fixed_t fixed_t xscale2, yscale2, cosmul, sinmul, tx2, tz2;
#ifdef PROPERPAPER
xscale2,
#endif
yscale2, cosmul, sinmul, tz2;
INT32 range; INT32 range;
if (ang >= ANGLE_180) if (ang >= ANGLE_180)
@ -1322,19 +1313,23 @@ static void R_ProjectSprite(mobj_t *thing)
gyt = -FixedMul(tr_y, viewsin); gyt = -FixedMul(tr_y, viewsin);
tz = gxt-gyt; tz = gxt-gyt;
yscale = FixedDiv(projectiony, tz); yscale = FixedDiv(projectiony, tz);
if (yscale < 64) return; // Fix some funky visuals //if (yscale < 64) return; // Fix some funky visuals
#ifdef PROPERPAPER
gxt = -FixedMul(tr_x, viewsin); gxt = -FixedMul(tr_x, viewsin);
gyt = FixedMul(tr_y, viewcos); gyt = FixedMul(tr_y, viewcos);
tx = -(gyt + gxt); tx = -(gyt + gxt);
xscale = FixedDiv(projection, tz); xscale = FixedDiv(projection, tz);
x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS; x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS;
// off the right side? // Get paperoffset (offset) and paperoffset (distance)
if (x1 > viewwidth) paperoffset = -FixedMul(tr_x, cosmul) - FixedMul(tr_y, sinmul);
return; paperdistance = -FixedMul(tr_x, sinmul) + FixedMul(tr_y, cosmul);
#endif if (paperdistance < 0)
{
paperoffset = -paperoffset;
paperdistance = -paperdistance;
}
centerangle = viewangle - thing->angle;
tr_x += FixedMul(offset2, cosmul); tr_x += FixedMul(offset2, cosmul);
tr_y += FixedMul(offset2, sinmul); tr_y += FixedMul(offset2, sinmul);
@ -1342,38 +1337,52 @@ static void R_ProjectSprite(mobj_t *thing)
gyt = -FixedMul(tr_y, viewsin); gyt = -FixedMul(tr_y, viewsin);
tz2 = gxt-gyt; tz2 = gxt-gyt;
yscale2 = FixedDiv(projectiony, tz2); yscale2 = FixedDiv(projectiony, tz2);
if (yscale2 < 64) return; // ditto //if (yscale2 < 64) return; // ditto
#ifdef PROPERPAPER
gxt = -FixedMul(tr_x, viewsin); gxt = -FixedMul(tr_x, viewsin);
gyt = FixedMul(tr_y, viewcos); gyt = FixedMul(tr_y, viewcos);
tx = -(gyt + gxt); tx2 = -(gyt + gxt);
xscale2 = FixedDiv(projection, tz2); xscale2 = FixedDiv(projection, tz2);
x2 = (centerxfrac + FixedMul(tx,xscale2))>>FRACBITS; x2--; x2 = ((centerxfrac + FixedMul(tx2,xscale2))>>FRACBITS);
if (max(tz, tz2) < FixedMul(MINZ, this_scale)) // non-papersprite clipping is handled earlier
return;
// Needs partially clipped
if (tz < FixedMul(MINZ, this_scale))
{
fixed_t div = FixedDiv(tz2-tz, FixedMul(MINZ, this_scale)-tz);
tx += FixedDiv(tx2-tx, div);
tz = FixedMul(MINZ, this_scale);
yscale = FixedDiv(projectiony, tz);
xscale = FixedDiv(projection, tz);
x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS;
}
else if (tz2 < FixedMul(MINZ, this_scale))
{
fixed_t div = FixedDiv(tz-tz2, FixedMul(MINZ, this_scale)-tz2);
tx2 += FixedDiv(tx-tx2, div);
tz2 = FixedMul(MINZ, this_scale);
yscale2 = FixedDiv(projectiony, tz2);
xscale2 = FixedDiv(projection, tz2);
x2 = (centerxfrac + FixedMul(tx2,xscale2))>>FRACBITS;
}
// off the right side?
if (x1 > viewwidth)
return;
// off the left side // off the left side
if (x2 < 0) if (x2 < 0)
return; return;
#endif
if (max(tz, tz2) < FixedMul(MINZ, this_scale)) // non-papersprite clipping is handled earlier
return;
if ((range = x2 - x1) <= 0) if ((range = x2 - x1) <= 0)
return; return;
#ifdef PROPERPAPER
range++; // fencepost problem range++; // fencepost problem
#endif
scalestep = (yscale2 - yscale)/range; scalestep = ((yscale2 - yscale)/range) ?: 1;
xscale = xscale = FixedDiv(range<<FRACBITS, abs(offset2));
#ifdef PROPERPAPER
FixedDiv(range<<FRACBITS, abs(offset2))+1
#else
FixedMul(xscale, ang_scale)
#endif
;
// The following two are alternate sorting methods which might be more applicable in some circumstances. TODO - maybe enable via MF2? // The following two are alternate sorting methods which might be more applicable in some circumstances. TODO - maybe enable via MF2?
// sortscale = max(yscale, yscale2); // sortscale = max(yscale, yscale2);
@ -1383,7 +1392,6 @@ static void R_ProjectSprite(mobj_t *thing)
{ {
scalestep = 0; scalestep = 0;
yscale = sortscale; yscale = sortscale;
#ifdef PROPERPAPER
tx += offset; tx += offset;
x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS; x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS;
@ -1397,7 +1405,6 @@ static void R_ProjectSprite(mobj_t *thing)
// off the left side // off the left side
if (x2 < 0) if (x2 < 0)
return; return;
#endif
} }
if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) // toast 16/09/16 (SYMMETRY) if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) // toast 16/09/16 (SYMMETRY)
@ -1518,6 +1525,9 @@ static void R_ProjectSprite(mobj_t *thing)
vis->pzt = vis->pz + vis->thingheight; vis->pzt = vis->pz + vis->thingheight;
vis->texturemid = vis->gzt - viewz; vis->texturemid = vis->gzt - viewz;
vis->scalestep = scalestep; vis->scalestep = scalestep;
vis->paperoffset = paperoffset;
vis->paperdistance = paperdistance;
vis->centerangle = centerangle;
vis->mobj = thing; // Easy access! Tails 06-07-2002 vis->mobj = thing; // Easy access! Tails 06-07-2002

View file

@ -181,8 +181,11 @@ typedef struct vissprite_s
fixed_t startfrac; // horizontal position of x1 fixed_t startfrac; // horizontal position of x1
fixed_t scale, sortscale; // sortscale only differs from scale for paper sprites and MF2_LINKDRAW fixed_t scale, sortscale; // sortscale only differs from scale for paper sprites and MF2_LINKDRAW
fixed_t scalestep; // only for paper sprites, 0 otherwise fixed_t scalestep; // only for paper sprites, 0 otherwise
fixed_t paperoffset, paperdistance; // for paper sprites, offset/dist relative to the angle
fixed_t xiscale; // negative if flipped fixed_t xiscale; // negative if flipped
angle_t centerangle; // for paper sprites
fixed_t texturemid; fixed_t texturemid;
patch_t *patch; patch_t *patch;