Texel-granular hitscan() for wall-aligned sprites.

The attribute is set per tile from DEF: either
    texhitscanrange <begintile> <endtile>
or
    tilefromtexture <tile> { ... texhitscan ... }
(As a special case, the list may only contain "texhitscan", in which case the
texture is not changed.)

In passing, do some cleanup for "tilefromtexture" DEF parsing: the list tokens
should now be accepted in any order, and errors don't appear in the middle of
the list parsing.

git-svn-id: https://svn.eduke32.com/eduke32@3078 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2012-10-14 20:41:34 +00:00
parent ce948c6ee4
commit d5f7e5becf
3 changed files with 91 additions and 40 deletions

View file

@ -147,6 +147,8 @@ void yax_drawrooms(void (*SpriteAnimFunc)(int32_t,int32_t,int32_t,int32_t),
# define YAX_SKIPWALL(i) (i)=(i)
#endif
#define PICANM_TEXHITSCAN_BIT (1<<28)
#define CLIPMASK0 (((1L)<<16)+1L)
#define CLIPMASK1 (((256L)<<16)+64L)

View file

@ -81,10 +81,11 @@ enum scripttoken_t
T_CACHESIZE,
T_IMPORTTILE,
T_MUSIC,T_ID,T_SOUND,
T_TILEFROMTEXTURE, T_XOFFSET, T_YOFFSET,
T_TILEFROMTEXTURE, T_XOFFSET, T_YOFFSET, T_TEXHITSCAN,
T_INCLUDEDEFAULT,
T_ANIMSOUNDS,
T_NOFLOORPALRANGE,
T_TEXHITSCANRANGE,
T_ECHO,
};
@ -220,6 +221,7 @@ static int32_t defsparser(scriptfile *script)
{ "sound", T_SOUND },
{ "animsounds", T_ANIMSOUNDS }, // dummy
{ "nofloorpalrange", T_NOFLOORPALRANGE }, // dummy
{ "texhitscanrange", T_TEXHITSCANRANGE },
// other stuff
{ "undefmodel", T_UNDEFMODEL },
{ "undefmodelrange", T_UNDEFMODELRANGE },
@ -491,9 +493,9 @@ static int32_t defsparser(scriptfile *script)
case T_TILEFROMTEXTURE:
{
char *texturetokptr = script->ltextptr, *textureend, *fn = NULL;
int32_t tile=-1, token;
int32_t alphacut = 255;
int32_t xoffset = 0, yoffset = 0, goodtogo=0;
int32_t tile=-1;
int32_t alphacut = 255, texhitscan=0;
int32_t xoffset = 0, yoffset = 0;
static const tokenlist tilefromtexturetokens[] =
{
@ -504,13 +506,14 @@ static int32_t defsparser(scriptfile *script)
{ "xoff", T_XOFFSET },
{ "yoffset", T_YOFFSET },
{ "yoff", T_YOFFSET },
{ "texhitscan", T_TEXHITSCAN },
};
if (scriptfile_getsymbol(script,&tile)) break;
if (scriptfile_getbraces(script,&textureend)) break;
while (script->textptr < textureend)
{
token = getatoken(script,tilefromtexturetokens,sizeof(tilefromtexturetokens)/sizeof(tokenlist));
int32_t token = getatoken(script,tilefromtexturetokens,sizeof(tilefromtexturetokens)/sizeof(tokenlist));
switch (token)
{
case T_FILE:
@ -521,24 +524,12 @@ static int32_t defsparser(scriptfile *script)
scriptfile_getsymbol(script,&xoffset); break;
case T_YOFFSET:
scriptfile_getsymbol(script,&yoffset); break;
case T_TEXHITSCAN:
texhitscan = 1;
break;
default:
break;
}
if ((unsigned)tile >= MAXTILES) break; // message is printed later
if (!fn)
{
initprintf("Error: missing 'file name' for tilefromtexture definition near line %s:%d\n",
script->filename, scriptfile_getlinum(script,texturetokptr));
break;
}
alphacut = clamp(alphacut, 0, 255);
if (check_file_exist(fn))
break;
goodtogo = 1;
}
if ((unsigned)tile >= MAXTILES)
@ -548,7 +539,22 @@ static int32_t defsparser(scriptfile *script)
break;
}
if (goodtogo)
if (!fn)
{
// filefromtexture <tile> { texhitscan } sets the bit but doesn't change tile data
if (texhitscan)
picanm[tile] |= PICANM_TEXHITSCAN_BIT;
else
initprintf("Error: missing 'file name' for tilefromtexture definition near line %s:%d\n",
script->filename, scriptfile_getlinum(script,texturetokptr));
break;
}
if (check_file_exist(fn))
break;
alphacut = clamp(alphacut, 0, 255);
{
int32_t xsiz, ysiz, j;
palette_t *picptr = NULL;
@ -567,6 +573,8 @@ static int32_t defsparser(scriptfile *script)
set_picsizanm(tile, xsiz, ysiz, (picanm[tile]&0xff0000ff)+
(xoffset<<8)+(yoffset<<16));
if (texhitscan)
picanm[tile] |= PICANM_TEXHITSCAN_BIT;
tile_from_truecolpic(tile, picptr, alphacut);
@ -1931,6 +1939,21 @@ static int32_t defsparser(scriptfile *script)
}
break;
case T_TEXHITSCANRANGE:
{
int32_t b,e, i;
if (scriptfile_getnumber(script,&b)) break;
if (scriptfile_getnumber(script,&e)) break;
b = max(b, 0);
e = min(e, MAXTILES-1);
for (i=b; i<=e; i++)
picanm[i] |= PICANM_TEXHITSCAN_BIT;
}
break;
case T_SOUND:
case T_MUSIC:
{

View file

@ -7920,8 +7920,10 @@ int32_t changespritestat(int16_t spritenum, int16_t newstatnum)
//
// lintersect (internal)
//
static int32_t lintersect(int32_t x1, int32_t y1, int32_t z1, int32_t x2, int32_t y2, int32_t z2, int32_t x3,
int32_t y3, int32_t x4, int32_t y4, int32_t *intx, int32_t *inty, int32_t *intz)
static int32_t lintersect(int32_t x1, int32_t y1, int32_t z1,
int32_t x2, int32_t y2, int32_t z2,
int32_t x3, int32_t y3, int32_t x4, int32_t y4,
int32_t *intx, int32_t *inty, int32_t *intz)
{
//p1 to p2 is a line segment
int32_t x21, y21, x34, y34, x31, y31, bot, topt, topu, t;
@ -7959,8 +7961,11 @@ int32_t lineintersect(int32_t x1, int32_t y1, int32_t z1, int32_t x2, int32_t y2
//
// rintersect (internal)
//
static int32_t rintersect(int32_t x1, int32_t y1, int32_t z1, int32_t vx_, int32_t vy_, int32_t vz, int32_t x3,
int32_t y3, int32_t x4, int32_t y4, int32_t *intx, int32_t *inty, int32_t *intz)
// returns: -1 if didn't intersect, coefficient (x3--x4 fraction)<<16 else
static int32_t rintersect(int32_t x1, int32_t y1, int32_t z1,
int32_t vx_, int32_t vy_, int32_t vz,
int32_t x3, int32_t y3, int32_t x4, int32_t y4,
int32_t *intx, int32_t *inty, int32_t *intz)
{
//p1 towards p2 is a ray
int64_t x34, y34, x31, y31, bot, topt, topu, t;
@ -7971,16 +7976,16 @@ static int32_t rintersect(int32_t x1, int32_t y1, int32_t z1, int32_t vx_, int32
bot = vx*y34 - vy*x34;
if (bot >= 0)
{
if (bot == 0) return(0);
if (bot == 0) return -1;
x31 = x3-x1; y31 = y3-y1;
topt = x31*y34 - y31*x34; if (topt < 0) return(0);
topu = vx*y31 - vy*x31; if ((topu < 0) || (topu >= bot)) return(0);
topt = x31*y34 - y31*x34; if (topt < 0) return -1;
topu = vx*y31 - vy*x31; if ((topu < 0) || (topu >= bot)) return -1;
}
else
{
x31 = x3-x1; y31 = y3-y1;
topt = x31*y34 - y31*x34; if (topt > 0) return(0);
topu = vx*y31 - vy*x31; if ((topu > 0) || (topu <= bot)) return(0);
topt = x31*y34 - y31*x34; if (topt > 0) return -1;
topu = vx*y31 - vy*x31; if ((topu > 0) || (topu <= bot)) return -1;
}
t = (topt<<16)/bot;
@ -7988,13 +7993,16 @@ static int32_t rintersect(int32_t x1, int32_t y1, int32_t z1, int32_t vx_, int32
*inty = y1 + ((vy*t)>>16);
*intz = z1 + ((vz*t)>>16);
return(1);
t = divscale16(topu, bot);
Bassert((unsigned)t < 65536);
return t;
}
int32_t rayintersect(int32_t x1, int32_t y1, int32_t z1, int32_t vx, int32_t vy, int32_t vz, int32_t x3,
int32_t y3, int32_t x4, int32_t y4, int32_t *intx, int32_t *inty, int32_t *intz)
{
return rintersect(x1, y1, z1, vx, vy, vz, x3, y3, x4, y4, intx, inty, intz);
return (rintersect(x1, y1, z1, vx, vy, vz, x3, y3, x4, y4, intx, inty, intz) != -1);
}
//
@ -11290,7 +11298,7 @@ restart_grand:
x1 = wal->x; y1 = wal->y; x2 = wal2->x; y2 = wal2->y;
if ((int64_t)(x1-sv->x)*(y2-sv->y) < (int64_t)(x2-sv->x)*(y1-sv->y)) continue;
if (rintersect(sv->x,sv->y,sv->z, vx,vy,vz, x1,y1, x2,y2, &intx,&inty,&intz) == 0) continue;
if (rintersect(sv->x,sv->y,sv->z, vx,vy,vz, x1,y1, x2,y2, &intx,&inty,&intz) == -1) continue;
if (klabs(intx-sv->x)+klabs(inty-sv->y) >= klabs((hit->pos.x)-sv->x)+klabs((hit->pos.y)-sv->y))
continue;
@ -11349,7 +11357,8 @@ restart_grand:
#ifdef USE_OPENGL
if (!hitallsprites)
#endif
if ((cstat&dasprclipmask) == 0) continue;
if ((cstat&dasprclipmask) == 0)
continue;
#ifdef HAVE_CLIPSHAPE_FEATURE
// try and see whether this sprite's picnum has sector-like clipping data
@ -11393,6 +11402,9 @@ restart_grand:
break;
case 16:
{
int32_t ucoefup16;
//These lines get the 2 points of the rotated sprite
//Given: (x1, y1) starts out as the center point
tilenum = spr->picnum;
@ -11407,19 +11419,33 @@ restart_grand:
if ((cstat&64) != 0) //back side of 1-way sprite
if ((int64_t)(x1-sv->x)*(y2-sv->y) < (int64_t)(x2-sv->x)*(y1-sv->y)) continue;
if (rintersect(sv->x,sv->y,sv->z,vx,vy,vz,x1,y1,x2,y2,&intx,&inty,&intz) == 0) continue;
ucoefup16 = rintersect(sv->x,sv->y,sv->z,vx,vy,vz,x1,y1,x2,y2,&intx,&inty,&intz);
if (ucoefup16 == -1) continue;
if (klabs(intx-sv->x)+klabs(inty-sv->y) > klabs((hit->pos.x)-sv->x)+klabs((hit->pos.y)-sv->y)) continue;
k = ((tilesizy[spr->picnum]*spr->yrepeat)<<2);
k = ((tilesizy[tilenum]*spr->yrepeat)<<2);
if (cstat&128) daz = spr->z+(k>>1); else daz = spr->z;
if (picanm[spr->picnum]&0x00ff0000) daz -= ((int32_t)((int8_t)((picanm[spr->picnum]>>16)&255))*spr->yrepeat<<2);
if ((intz < daz) && (intz > daz-k))
if (picanm[tilenum]&0x00ff0000) daz -= ((int32_t)((int8_t)((picanm[tilenum]>>16)&255))*spr->yrepeat<<2);
if (intz > daz-k && intz < daz)
{
if (picanm[tilenum]&PICANM_TEXHITSCAN_BIT)
{
// daz-intz > 0 && daz-intz < k
int32_t xtex = mulscale16(ucoefup16, tilesizx[tilenum]);
int32_t vcoefup16 = 65536-divscale16(daz-intz, k);
int32_t ytex = mulscale16(vcoefup16, tilesizy[tilenum]);
const char *texel = (char *)(waloff[tilenum] + tilesizy[tilenum]*xtex + ytex);
if (*texel == 255)
continue;
}
hit->sect = dasector; hit->wall = -1; hit->sprite = z;
hit->pos.x = intx; hit->pos.y = inty; hit->pos.z = intz;
}
break;
}
case 32:
if (vz == 0) continue;
@ -12113,7 +12139,7 @@ int32_t clipmove(vec3_t *pos, int16_t *sectnum,
{
int32_t basez;
if (rintersect(pos->x,pos->y,0, gx,gy,0, x1,y1, x2,y2, &dax,&day,&daz) == 0)
if (rintersect(pos->x,pos->y,0, gx,gy,0, x1,y1, x2,y2, &dax,&day,&daz) == -1)
dax = pos->x, day = pos->y;
daz = getflorzofslope(dasect, dax,day);
daz2 = getflorzofslope(wal->nextsector, dax,day);
@ -12141,7 +12167,7 @@ int32_t clipmove(vec3_t *pos, int16_t *sectnum,
if ((wal->nextsector < 0) || (wal->cstat&dawalclipmask)) clipyou = 1;
else if (editstatus == 0)
{
if (rintersect(pos->x,pos->y,0,gx,gy,0,x1,y1,x2,y2,&dax,&day,&daz) == 0)
if (rintersect(pos->x,pos->y,0,gx,gy,0,x1,y1,x2,y2,&dax,&day,&daz) == -1)
dax = pos->x, day = pos->y;
daz = getflorzofslope(dasect, dax,day);
daz2 = getflorzofslope(wal->nextsector, dax,day);