mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-11-11 07:11:39 +00:00
Classic renderer: high-precision sprite drawing, preventing stray lines on top.
Face- and wall-aligned sprites are drawn using the wall routines in BUILD. However, the per-x-screen-coordinate distance (swall[]) is calculated in a way that potentially incurs great precision loss (for example 5 bits for xdimen=1280, yxaspect=65536). This leads to the starting (top) vertical texture coordinate possibly wrapping to large values, leaving an unsightly "stray line" on top of the sprite from certain viewing angles/horiz values. The approach to fix it has two parts: first, the distance is calculated using float values, preventing the precision loss. Because this doesn't fully prevent the unwanted lines, the texture coords are clamped to the mininum and maximum (0 and UINT32_MAX respectively) when calculating them for sprites. Note that stray lines may still appear at the *bottom* of sprites under certain circumstances, for example when viewing at a y-flipped sprite from above. These should be less noticable in real-world usage though. The feature is guarded by a macro HIGH_PRECISION_SPRITE in case using floating point or 64-bit integers is undesirable/impossible on some platforms. git-svn-id: https://svn.eduke32.com/eduke32@3483 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
parent
32b3c074d2
commit
40874820f3
1 changed files with 93 additions and 29 deletions
|
@ -47,6 +47,7 @@
|
||||||
//#define CLASSIC_NONPOW2_YSIZE_WALLS
|
//#define CLASSIC_NONPOW2_YSIZE_WALLS
|
||||||
#define CLASSIC_NONPOW2_YSIZE_SPRITES
|
#define CLASSIC_NONPOW2_YSIZE_SPRITES
|
||||||
|
|
||||||
|
#define HIGH_PRECISION_SPRITE
|
||||||
#define MULTI_COLUMN_VLINE
|
#define MULTI_COLUMN_VLINE
|
||||||
//#define DEBUG_TILESIZY_512
|
//#define DEBUG_TILESIZY_512
|
||||||
|
|
||||||
|
@ -2223,6 +2224,9 @@ static int16_t uplc[MAXXDIM], dplc[MAXXDIM];
|
||||||
static int16_t uwall[MAXXDIM], dwall[MAXXDIM];
|
static int16_t uwall[MAXXDIM], dwall[MAXXDIM];
|
||||||
static int32_t swplc[MAXXDIM], lplc[MAXXDIM];
|
static int32_t swplc[MAXXDIM], lplc[MAXXDIM];
|
||||||
static int32_t swall[MAXXDIM], lwall[MAXXDIM+4];
|
static int32_t swall[MAXXDIM], lwall[MAXXDIM+4];
|
||||||
|
#ifdef HIGH_PRECISION_SPRITE
|
||||||
|
static float swallf[MAXXDIM];
|
||||||
|
#endif
|
||||||
int32_t xdimen = -1, xdimenrecip, halfxdimen, xdimenscale, xdimscale;
|
int32_t xdimen = -1, xdimenrecip, halfxdimen, xdimenscale, xdimscale;
|
||||||
int32_t ydimen;
|
int32_t ydimen;
|
||||||
static int32_t wx1, wy1, wx2, wy2;
|
static int32_t wx1, wy1, wx2, wy2;
|
||||||
|
@ -2252,7 +2256,12 @@ static int32_t globalxpanning, globalypanning;
|
||||||
int32_t globalshade, globalorientation;
|
int32_t globalshade, globalorientation;
|
||||||
int16_t globalpicnum;
|
int16_t globalpicnum;
|
||||||
static int16_t globalshiftval;
|
static int16_t globalshiftval;
|
||||||
static int32_t globalzd, globalyscale;
|
#ifdef HIGH_PRECISION_SPRITE
|
||||||
|
static int64_t globalzd;
|
||||||
|
#else
|
||||||
|
static int32_t globalzd;
|
||||||
|
#endif
|
||||||
|
static int32_t globalyscale;
|
||||||
static int32_t globalxspan, globalyspan, globalispow2=1; // true if texture has power-of-two x and y size
|
static int32_t globalxspan, globalyspan, globalispow2=1; // true if texture has power-of-two x and y size
|
||||||
static intptr_t globalbufplc;
|
static intptr_t globalbufplc;
|
||||||
|
|
||||||
|
@ -2679,12 +2688,38 @@ static WSHELPER_DECL void calc_bufplc(intptr_t *bufplc, int32_t lw, int32_t tsiz
|
||||||
*bufplc = waloff[globalpicnum] + i;
|
*bufplc = waloff[globalpicnum] + i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WSHELPER_DECL void calc_vplcinc(uint32_t *vplc, int32_t *vinc, int64_t sw, int32_t y1v)
|
static WSHELPER_DECL void calc_vplcinc_wall(uint32_t *vplc, int32_t *vinc, int64_t sw, int32_t y1v)
|
||||||
{
|
{
|
||||||
*vinc = sw*globalyscale;
|
*vinc = sw*globalyscale;
|
||||||
*vplc = globalzd + (uint32_t)(*vinc)*(y1v-globalhoriz+1);
|
*vplc = globalzd + (uint32_t)(*vinc)*(y1v-globalhoriz+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HIGH_PRECISION_SPRITE
|
||||||
|
static WSHELPER_DECL void calc_vplcinc_sprite(uint32_t *vplc, int32_t *vinc, int32_t x, int32_t y1v)
|
||||||
|
{
|
||||||
|
int64_t tmpvinc = swallf[x];
|
||||||
|
int64_t tmpvplc = globalzd + tmpvinc*(y1v-globalhoriz+1);
|
||||||
|
|
||||||
|
*vinc = tmpvinc;
|
||||||
|
// Clamp the vertical texture coordinate!
|
||||||
|
*vplc = min(max(0, tmpvplc), UINT32_MAX);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int32_t drawing_sprite = 0;
|
||||||
|
|
||||||
|
static WSHELPER_DECL void calc_vplcinc(uint32_t *vplc, int32_t *vinc, const int32_t *swal, int32_t x, int32_t y1v)
|
||||||
|
{
|
||||||
|
#if !defined HIGH_PRECISION_SPRITE
|
||||||
|
(void)drawing_sprite;
|
||||||
|
#else
|
||||||
|
if (drawing_sprite)
|
||||||
|
calc_vplcinc_sprite(vplc, vinc, x, y1v);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
calc_vplcinc_wall(vplc, vinc, swal[x], y1v);
|
||||||
|
}
|
||||||
|
|
||||||
#undef NONPOW2_YSIZE_ASM
|
#undef NONPOW2_YSIZE_ASM
|
||||||
#if !defined ENGINE_USING_A_C
|
#if !defined ENGINE_USING_A_C
|
||||||
# if defined CLASSIC_NONPOW2_YSIZE_WALLS || defined CLASSIC_NONPOW2_YSIZE_SPRITES
|
# if defined CLASSIC_NONPOW2_YSIZE_WALLS || defined CLASSIC_NONPOW2_YSIZE_SPRITES
|
||||||
|
@ -2748,7 +2783,7 @@ static void maskwallscan(int32_t x1, int32_t x2)
|
||||||
palookupoffse[0] = fpalookup + getpalookupsh(mulscale16(swall[x],globvis));
|
palookupoffse[0] = fpalookup + getpalookupsh(mulscale16(swall[x],globvis));
|
||||||
|
|
||||||
calc_bufplc(&bufplce[0], lwall[x], tsizx, tsizy);
|
calc_bufplc(&bufplce[0], lwall[x], tsizx, tsizy);
|
||||||
calc_vplcinc(&vplce[0], &vince[0], swall[x], y1ve[0]);
|
calc_vplcinc(&vplce[0], &vince[0], swall, x, y1ve[0]);
|
||||||
|
|
||||||
mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0],p+ylookup[y1ve[0]]);
|
mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0],p+ylookup[y1ve[0]]);
|
||||||
}
|
}
|
||||||
|
@ -2764,7 +2799,7 @@ static void maskwallscan(int32_t x1, int32_t x2)
|
||||||
if (y2ve[z] < y1ve[z]) { bad += pow2char[z]; continue; }
|
if (y2ve[z] < y1ve[z]) { bad += pow2char[z]; continue; }
|
||||||
|
|
||||||
calc_bufplc(&bufplce[z], lwall[dax], tsizx, tsizy);
|
calc_bufplc(&bufplce[z], lwall[dax], tsizx, tsizy);
|
||||||
calc_vplcinc(&vplce[z], &vince[z], swall[dax], y1ve[z]);
|
calc_vplcinc(&vplce[z], &vince[z], swall, dax, y1ve[z]);
|
||||||
}
|
}
|
||||||
if (bad == 15) continue;
|
if (bad == 15) continue;
|
||||||
|
|
||||||
|
@ -2821,7 +2856,7 @@ do_mvlineasm1:
|
||||||
palookupoffse[0] = fpalookup + getpalookupsh(mulscale16(swall[x],globvis));
|
palookupoffse[0] = fpalookup + getpalookupsh(mulscale16(swall[x],globvis));
|
||||||
|
|
||||||
calc_bufplc(&bufplce[0], lwall[x], tsizx, tsizy);
|
calc_bufplc(&bufplce[0], lwall[x], tsizx, tsizy);
|
||||||
calc_vplcinc(&vplce[0], &vince[0], swall[x], y1ve[0]);
|
calc_vplcinc(&vplce[0], &vince[0], swall, x, y1ve[0]);
|
||||||
|
|
||||||
#ifdef NONPOW2_YSIZE_ASM
|
#ifdef NONPOW2_YSIZE_ASM
|
||||||
if (globalshiftval==0)
|
if (globalshiftval==0)
|
||||||
|
@ -3740,7 +3775,7 @@ static void wallscan(int32_t x1, int32_t x2,
|
||||||
palookupoffse[0] = fpalookup + getpalookupsh(mulscale16(swal[x],globvis));
|
palookupoffse[0] = fpalookup + getpalookupsh(mulscale16(swal[x],globvis));
|
||||||
|
|
||||||
calc_bufplc(&bufplce[0], lwal[x], tsizx, tsizy);
|
calc_bufplc(&bufplce[0], lwal[x], tsizx, tsizy);
|
||||||
calc_vplcinc(&vplce[0], &vince[0], swal[x], y1ve[0]);
|
calc_vplcinc(&vplce[0], &vince[0], swal, x, y1ve[0]);
|
||||||
|
|
||||||
vlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0],x+frameoffset+ylookup[y1ve[0]]);
|
vlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0],x+frameoffset+ylookup[y1ve[0]]);
|
||||||
}
|
}
|
||||||
|
@ -3754,7 +3789,7 @@ static void wallscan(int32_t x1, int32_t x2,
|
||||||
if (y2ve[z] < y1ve[z]) { bad += pow2char[z]; continue; }
|
if (y2ve[z] < y1ve[z]) { bad += pow2char[z]; continue; }
|
||||||
|
|
||||||
calc_bufplc(&bufplce[z], lwal[x+z], tsizx, tsizy);
|
calc_bufplc(&bufplce[z], lwal[x+z], tsizx, tsizy);
|
||||||
calc_vplcinc(&vplce[z], &vince[z], swal[x+z], y1ve[z]);
|
calc_vplcinc(&vplce[z], &vince[z], swal, x+z, y1ve[z]);
|
||||||
}
|
}
|
||||||
if (bad == 15) continue;
|
if (bad == 15) continue;
|
||||||
|
|
||||||
|
@ -3811,7 +3846,7 @@ do_vlineasm1:
|
||||||
palookupoffse[0] = fpalookup + getpalookupsh(mulscale16(swal[x],globvis));
|
palookupoffse[0] = fpalookup + getpalookupsh(mulscale16(swal[x],globvis));
|
||||||
|
|
||||||
calc_bufplc(&bufplce[0], lwal[x], tsizx, tsizy);
|
calc_bufplc(&bufplce[0], lwal[x], tsizx, tsizy);
|
||||||
calc_vplcinc(&vplce[0], &vince[0], swal[x], y1ve[0]);
|
calc_vplcinc(&vplce[0], &vince[0], swal, x, y1ve[0]);
|
||||||
|
|
||||||
#ifdef NONPOW2_YSIZE_ASM
|
#ifdef NONPOW2_YSIZE_ASM
|
||||||
if (globalshiftval==0)
|
if (globalshiftval==0)
|
||||||
|
@ -3845,7 +3880,7 @@ static void transmaskvline(int32_t x)
|
||||||
palookupoffs = FP_OFF(palookup[globalpal]) + getpalookupsh(mulscale16(swall[x],globvis));
|
palookupoffs = FP_OFF(palookup[globalpal]) + getpalookupsh(mulscale16(swall[x],globvis));
|
||||||
|
|
||||||
calc_bufplc(&bufplc, lwall[x], -tilesizx[globalpicnum], -tilesizy[globalpicnum]);
|
calc_bufplc(&bufplc, lwall[x], -tilesizx[globalpicnum], -tilesizy[globalpicnum]);
|
||||||
calc_vplcinc(&vplc, &vinc, swall[x], y1v);
|
calc_vplcinc(&vplc, &vinc, swall, x, y1v);
|
||||||
|
|
||||||
p = ylookup[y1v]+x+frameoffset;
|
p = ylookup[y1v]+x+frameoffset;
|
||||||
|
|
||||||
|
@ -3888,8 +3923,8 @@ static void transmaskvline2(int32_t x)
|
||||||
|
|
||||||
calc_bufplc(&bufplce[0], lwall[x], -tilesizx[globalpicnum], -tilesizy[globalpicnum]);
|
calc_bufplc(&bufplce[0], lwall[x], -tilesizx[globalpicnum], -tilesizy[globalpicnum]);
|
||||||
calc_bufplc(&bufplce[1], lwall[x2], -tilesizx[globalpicnum], -tilesizy[globalpicnum]);
|
calc_bufplc(&bufplce[1], lwall[x2], -tilesizx[globalpicnum], -tilesizy[globalpicnum]);
|
||||||
calc_vplcinc(&vplce[0], &vince[0], swall[x], y1ve[0]);
|
calc_vplcinc(&vplce[0], &vince[0], swall, x, y1ve[0]);
|
||||||
calc_vplcinc(&vplce[1], &vince[1], swall[x2], y1ve[1]);
|
calc_vplcinc(&vplce[1], &vince[1], swall, x2, y1ve[1]);
|
||||||
|
|
||||||
y1 = max(y1ve[0],y1ve[1]);
|
y1 = max(y1ve[0],y1ve[1]);
|
||||||
y2 = min(y2ve[0],y2ve[1]);
|
y2 = min(y2ve[0],y2ve[1]);
|
||||||
|
@ -4070,18 +4105,14 @@ static inline void ceilspritehline(int32_t x2, int32_t y)
|
||||||
if ((globalorientation&2) == 0)
|
if ((globalorientation&2) == 0)
|
||||||
mhline(globalbufplc,bx,(x2-x1)<<16,0L,by,ylookup[y]+x1+frameoffset);
|
mhline(globalbufplc,bx,(x2-x1)<<16,0L,by,ylookup[y]+x1+frameoffset);
|
||||||
else
|
else
|
||||||
{
|
|
||||||
thline(globalbufplc,bx,(x2-x1)<<16,0L,by,ylookup[y]+x1+frameoffset);
|
thline(globalbufplc,bx,(x2-x1)<<16,0L,by,ylookup[y]+x1+frameoffset);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((globalorientation&2) == 0)
|
if ((globalorientation&2) == 0)
|
||||||
nonpow2_mhline(globalbufplc,bx,(x2-x1)<<16,0L,by,(char *)(ylookup[y]+x1+frameoffset));
|
nonpow2_mhline(globalbufplc,bx,(x2-x1)<<16,0L,by,(char *)(ylookup[y]+x1+frameoffset));
|
||||||
else
|
else
|
||||||
{
|
|
||||||
nonpow2_thline(globalbufplc,bx,(x2-x1)<<16,0L,by,(char *)(ylookup[y]+x1+frameoffset));
|
nonpow2_thline(globalbufplc,bx,(x2-x1)<<16,0L,by,(char *)(ylookup[y]+x1+frameoffset));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5681,16 +5712,32 @@ draw_as_face_sprite:
|
||||||
qinterpolatedown16((intptr_t)&lwall[lx],rx-lx+1,linum,linuminc);
|
qinterpolatedown16((intptr_t)&lwall[lx],rx-lx+1,linum,linuminc);
|
||||||
clearbuf(&swall[lx],rx-lx+1,mulscale19(yp,xdimscale));
|
clearbuf(&swall[lx],rx-lx+1,mulscale19(yp,xdimscale));
|
||||||
|
|
||||||
|
{
|
||||||
|
#ifdef HIGH_PRECISION_SPRITE
|
||||||
|
union { float f; int32_t i; } sw = {
|
||||||
|
// initialize the float of the union
|
||||||
|
((cstat&8) ? -1 : 1)
|
||||||
|
* (float)yp * xdimscale
|
||||||
|
* (1<<(22-19)) / (yspan*tspr->yrepeat)
|
||||||
|
};
|
||||||
|
|
||||||
|
clearbuf(&swallf[lx], rx-lx+1, sw.i);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
drawing_sprite = 1;
|
||||||
|
|
||||||
if ((cstat&2) == 0)
|
if ((cstat&2) == 0)
|
||||||
maskwallscan(lx,rx);
|
maskwallscan(lx,rx);
|
||||||
else
|
else
|
||||||
transmaskwallscan(lx,rx);
|
transmaskwallscan(lx,rx);
|
||||||
|
|
||||||
|
drawing_sprite = 0;
|
||||||
}
|
}
|
||||||
else if ((cstat&48) == 16)
|
else if ((cstat&48) == 16)
|
||||||
{
|
{
|
||||||
int32_t swapped, top, bot, topinc, botinc;
|
int32_t swapped, top, bot, topinc, botinc;
|
||||||
int32_t xv, yv, hplc, hinc;
|
int32_t xv, yv, sx1, sx2, sy1, sy2;
|
||||||
int32_t sx1, sx2, sy1, sy2;
|
|
||||||
|
|
||||||
if ((cstat&4) > 0) xoff = -xoff;
|
if ((cstat&4) > 0) xoff = -xoff;
|
||||||
if ((cstat&8) > 0) yoff = -yoff;
|
if ((cstat&8) > 0) yoff = -yoff;
|
||||||
|
@ -5796,10 +5843,6 @@ draw_as_face_sprite:
|
||||||
rx1[MAXWALLSB-1] = xp1; ry1[MAXWALLSB-1] = yp1;
|
rx1[MAXWALLSB-1] = xp1; ry1[MAXWALLSB-1] = yp1;
|
||||||
rx2[MAXWALLSB-1] = xp2; ry2[MAXWALLSB-1] = yp2;
|
rx2[MAXWALLSB-1] = xp2; ry2[MAXWALLSB-1] = yp2;
|
||||||
|
|
||||||
hplc = divscale19(xdimenscale,sy1);
|
|
||||||
hinc = divscale19(xdimenscale,sy2);
|
|
||||||
hinc = (hinc-hplc)/(sx2-sx1+1);
|
|
||||||
|
|
||||||
setup_globals_sprite1(tspr, sec, yspan, yoff, tilenum, cstat, &z1, &z2);
|
setup_globals_sprite1(tspr, sec, yspan, yoff, tilenum, cstat, &z1, &z2);
|
||||||
|
|
||||||
if (((sec->ceilingstat&1) == 0) && (z1 < sec->ceilingz))
|
if (((sec->ceilingstat&1) == 0) && (z1 < sec->ceilingz))
|
||||||
|
@ -5813,8 +5856,29 @@ draw_as_face_sprite:
|
||||||
yb2[MAXWALLSB-1] = sy2;
|
yb2[MAXWALLSB-1] = sy2;
|
||||||
owallmost(uwall, MAXWALLSB-1, z1-globalposz);
|
owallmost(uwall, MAXWALLSB-1, z1-globalposz);
|
||||||
owallmost(dwall, MAXWALLSB-1, z2-globalposz);
|
owallmost(dwall, MAXWALLSB-1, z2-globalposz);
|
||||||
for (i=sx1; i<=sx2; i++)
|
|
||||||
{ swall[i] = (krecipasm(hplc)<<2); hplc += hinc; }
|
{
|
||||||
|
int32_t hplc = divscale19(xdimenscale,sy1);
|
||||||
|
const int32_t hplc2 = divscale19(xdimenscale,sy2);
|
||||||
|
int32_t hinc = sx2-sx1 ? (hplc2-hplc)/(sx2-sx1) : 0;
|
||||||
|
|
||||||
|
#ifdef HIGH_PRECISION_SPRITE
|
||||||
|
const float cc = ((1<<19)*(float)xdimen*yxaspect)/320.f;
|
||||||
|
float hplcf = cc/sy1;
|
||||||
|
const float hincf = sx2-sx1 ? (cc/sy2 - hplcf)/(sx2-sx1) : 0;
|
||||||
|
const float loopcc = ((cstat&8) ? -1 : 1)*((float)(1<<30)*(1<<24))
|
||||||
|
/ (yspan*tspr->yrepeat);
|
||||||
|
#endif
|
||||||
|
for (i=sx1; i<=sx2; i++)
|
||||||
|
{
|
||||||
|
swall[i] = (krecipasm(hplc)<<2);
|
||||||
|
hplc += hinc;
|
||||||
|
#ifdef HIGH_PRECISION_SPRITE
|
||||||
|
swallf[i] = loopcc/hplcf;
|
||||||
|
hplcf += hincf;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (i=smostwallcnt-1; i>=0; i--)
|
for (i=smostwallcnt-1; i>=0; i--)
|
||||||
{
|
{
|
||||||
|
@ -5923,14 +5987,14 @@ draw_as_face_sprite:
|
||||||
searchstat = 3; searchit = 1;
|
searchstat = 3; searchit = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drawing_sprite = 1;
|
||||||
|
|
||||||
if ((cstat&2) == 0)
|
if ((cstat&2) == 0)
|
||||||
{
|
|
||||||
maskwallscan(sx1,sx2);
|
maskwallscan(sx1,sx2);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
transmaskwallscan(sx1,sx2);
|
transmaskwallscan(sx1,sx2);
|
||||||
}
|
|
||||||
|
drawing_sprite = 0;
|
||||||
}
|
}
|
||||||
else if ((cstat&48) == 32)
|
else if ((cstat&48) == 32)
|
||||||
{
|
{
|
||||||
|
@ -6271,8 +6335,8 @@ draw_as_face_sprite:
|
||||||
lx = 0; rx = xdim-1;
|
lx = 0; rx = xdim-1;
|
||||||
for (x=lx; x<=rx; x++)
|
for (x=lx; x<=rx; x++)
|
||||||
{
|
{
|
||||||
lwall[x] = (int32_t)startumost[x+windowx1]-windowy1;
|
lwall[x] = startumost[x+windowx1]-windowy1;
|
||||||
swall[x] = (int32_t)startdmost[x+windowx1]-windowy1;
|
swall[x] = startdmost[x+windowx1]-windowy1;
|
||||||
}
|
}
|
||||||
for (i=smostwallcnt-1; i>=0; i--)
|
for (i=smostwallcnt-1; i>=0; i--)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue