mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-27 04:00:42 +00:00
1a8f11e01d
# Conflicts: # source/build/src/sdlayer.cpp # source/common/menu/menu.cpp # source/sw/src/config.cpp # source/sw/src/game.cpp
2636 lines
90 KiB
C++
2636 lines
90 KiB
C++
// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
|
|
// Ken Silverman's official web site: "http://www.advsys.net/ken"
|
|
// See the included license file "BUILDLIC.TXT" for license info.
|
|
//
|
|
// This file has been modified from Ken Silverman's original release
|
|
// by Jonathon Fowler (jf@jonof.id.au)
|
|
// by the EDuke32 team (development@voidpoint.com)
|
|
|
|
#include "a.h"
|
|
#include "build.h"
|
|
#include "baselayer.h"
|
|
#include "clip.h"
|
|
#include "engine_priv.h"
|
|
|
|
static int16_t clipnum;
|
|
static linetype clipit[MAXCLIPNUM];
|
|
static int32_t clipsectnum, origclipsectnum, clipspritenum;
|
|
int16_t clipsectorlist[MAXCLIPSECTORS];
|
|
static int16_t origclipsectorlist[MAXCLIPSECTORS];
|
|
static uint8_t clipsectormap[(MAXSECTORS+7)>>3];
|
|
static uint8_t origclipsectormap[(MAXSECTORS+7)>>3];
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
static int16_t clipspritelist[MAXCLIPNUM]; // sector-like sprite clipping
|
|
#endif
|
|
static int16_t clipobjectval[MAXCLIPNUM];
|
|
static uint8_t clipignore[(MAXCLIPNUM+7)>>3];
|
|
|
|
////// sector-like clipping for sprites //////
|
|
void engineSetClipMap(mapinfo_t *bak, mapinfo_t *newmap)
|
|
{
|
|
if (bak)
|
|
{
|
|
bak->numsectors = numsectors;
|
|
bak->numwalls = numwalls;
|
|
bak->sector = (usectortype *) sector;
|
|
bak->wall = (uwalltype *) wall;
|
|
}
|
|
|
|
if (newmap)
|
|
{
|
|
numsectors = newmap->numsectors;
|
|
numwalls = newmap->numwalls;
|
|
sector = const_cast<sectortype *>((sectortype const *)newmap->sector);
|
|
wall = const_cast<walltype *>((walltype const *)newmap->wall);
|
|
}
|
|
}
|
|
|
|
static mapinfo_t origmapinfo, clipmapinfo;
|
|
int32_t quickloadboard=0;
|
|
|
|
static clipinfo_t clipinfo[CM_MAX];
|
|
static int32_t numclipmaps;
|
|
|
|
static int32_t numclipsects; // number in sectq[]
|
|
static int16_t *sectoidx;
|
|
static int16_t *sectq; // [numsectors]
|
|
static int16_t pictoidx[MAXTILES]; // maps tile num to clipinfo[] index
|
|
static int16_t *tempictoidx;
|
|
|
|
static usectortype *loadsector;
|
|
static uwalltype *loadwall, *loadwallinv;
|
|
static uspritetype *loadsprite;
|
|
|
|
vec2_t hitscangoal = { (1<<29)-1, (1<<29)-1 };
|
|
int32_t hitallsprites = 0;
|
|
|
|
void engineInitClipMaps()
|
|
{
|
|
numclipmaps = 0;
|
|
numclipsects = 0;
|
|
|
|
DO_FREE_AND_NULL(sectq);
|
|
DO_FREE_AND_NULL(sectoidx);
|
|
DO_FREE_AND_NULL(tempictoidx);
|
|
DO_FREE_AND_NULL(loadsector);
|
|
DO_FREE_AND_NULL(loadwall);
|
|
DO_FREE_AND_NULL(loadwallinv);
|
|
DO_FREE_AND_NULL(loadsprite);
|
|
|
|
// two's complement trick, -1 = 0xff
|
|
Bmemset(&pictoidx, -1, sizeof(pictoidx));
|
|
Bmemset(&clipmapinfo, 0, sizeof(mapinfo_t));
|
|
|
|
numsectors = 0;
|
|
numwalls = 0;
|
|
}
|
|
|
|
// loads the clip maps.
|
|
// this should be called before any real map is loaded.
|
|
int32_t engineLoadClipMaps(void)
|
|
{
|
|
int32_t i, k, w;
|
|
|
|
int32_t lwcp = 0;
|
|
size_t fi;
|
|
size_t const g_clipMapFilesNum = g_clipMapFiles.Size();
|
|
|
|
int32_t *fisec = NULL;
|
|
int32_t *fispr = NULL;
|
|
|
|
int32_t ournumsectors=0, ournumwalls=0, ournumsprites=0;
|
|
|
|
engineInitClipMaps();
|
|
|
|
loadsector = (usectortype *) Xmalloc(MAXSECTORS * sizeof(sectortype));
|
|
loadwall = (uwalltype *) Xmalloc(MAXWALLS * sizeof(walltype));
|
|
loadsprite = (uspritetype *) Xmalloc(MAXSPRITES * sizeof(spritetype));
|
|
|
|
if (g_clipMapFilesNum)
|
|
{
|
|
fisec = (int32_t *) Xcalloc(g_clipMapFilesNum, sizeof(int32_t));
|
|
fispr = (int32_t *) Xcalloc(g_clipMapFilesNum, sizeof(int32_t));
|
|
}
|
|
|
|
quickloadboard = 1;
|
|
for (fi = 0; fi < g_clipMapFilesNum; ++fi)
|
|
{
|
|
int16_t ang, cs;
|
|
vec3_t tmppos;
|
|
|
|
fisec[fi] = ournumsectors;
|
|
fispr[fi] = ournumsprites;
|
|
|
|
i = engineLoadBoard(g_clipMapFiles[fi], 8, &tmppos, &ang, &cs);
|
|
if (i<0)
|
|
continue;
|
|
// Numsprites will now be set!
|
|
|
|
initprintf("Loading clip map: %s\n", g_clipMapFiles[fi].GetChars());
|
|
|
|
if (ournumsectors+numsectors>MAXSECTORS ||
|
|
ournumwalls+numwalls>MAXWALLS ||
|
|
ournumsprites+Numsprites>MAXSPRITES)
|
|
{
|
|
initprintf("clip map: warning: exceeded limits when loading %s, aborting.\n", g_clipMapFiles[fi].GetChars());
|
|
break;
|
|
}
|
|
|
|
Bmemcpy(loadsector+ournumsectors, sector, numsectors*sizeof(sectortype));
|
|
Bmemcpy(loadwall+ournumwalls, wall, numwalls*sizeof(walltype));
|
|
Bmemcpy(loadsprite+ournumsprites, sprite, Numsprites*sizeof(spritetype));
|
|
for (i=ournumsectors; i<ournumsectors+numsectors; i++)
|
|
loadsector[i].wallptr += ournumwalls;
|
|
for (i=ournumwalls; i<ournumwalls+numwalls; i++)
|
|
{
|
|
if (loadwall[i].point2>=0)
|
|
loadwall[i].point2 += ournumwalls;
|
|
if (loadwall[i].nextwall>=0)
|
|
{
|
|
loadwall[i].nextwall += ournumwalls;
|
|
loadwall[i].nextsector += ournumsectors;
|
|
}
|
|
}
|
|
for (i=ournumsprites; i<ournumsprites+Numsprites; i++)
|
|
if (loadsprite[i].sectnum>=0)
|
|
loadsprite[i].sectnum += ournumsectors;
|
|
ournumsectors += numsectors;
|
|
ournumwalls += numwalls;
|
|
ournumsprites += Numsprites;
|
|
|
|
++lwcp;
|
|
}
|
|
quickloadboard = 0;
|
|
|
|
if (ournumsectors==0 || ournumwalls==0 || ournumsprites==0) // nothing loaded
|
|
{
|
|
engineInitClipMaps();
|
|
|
|
Xfree(fisec);
|
|
Xfree(fispr);
|
|
|
|
return -1;
|
|
}
|
|
|
|
// shrink
|
|
loadsector = (usectortype *) Xrealloc(loadsector, ournumsectors*sizeof(sectortype));
|
|
loadwall = (uwalltype *) Xrealloc(loadwall, ournumwalls*sizeof(walltype));
|
|
|
|
Bmemcpy(sector, loadsector, ournumsectors*sizeof(sectortype));
|
|
Bmemcpy(wall, loadwall, ournumwalls*sizeof(walltype));
|
|
Bmemcpy(sprite, loadsprite, ournumsprites*sizeof(spritetype));
|
|
numsectors = ournumsectors;
|
|
numwalls = ournumwalls;
|
|
|
|
// vvvv don't use headsprite[sect,stat]! vvvv
|
|
|
|
sectoidx = (int16_t *) Xmalloc(numsectors*sizeof(sectoidx[0]));
|
|
|
|
for (i=0; i<numsectors; i++)
|
|
sectoidx[i] = CM_NONE;
|
|
|
|
// determine outer sectors
|
|
for (i=0; i<numsectors; i++)
|
|
{
|
|
for (w=sector[i].wallptr; w<sector[i].wallptr+sector[i].wallnum; w++)
|
|
if (wall[w].nextsector<0)
|
|
{
|
|
sectoidx[i] = CM_OUTER;
|
|
break;
|
|
}
|
|
}
|
|
// break connections between outer sectors
|
|
for (i=0; i<numsectors; i++)
|
|
{
|
|
if (sectoidx[i] == CM_OUTER)
|
|
for (w=sector[i].wallptr; w<sector[i].wallptr+sector[i].wallnum; w++)
|
|
{
|
|
k = wall[w].nextwall;
|
|
if (k>=0 && sectoidx[wall[w].nextsector]==CM_OUTER)
|
|
{
|
|
wall[k].nextwall = wall[k].nextsector = -1;
|
|
wall[w].nextwall = wall[w].nextsector = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
int16_t ns, outersect;
|
|
int32_t pn, scnt, x, y, z, maxdist;
|
|
|
|
sectq = (int16_t *) Xmalloc(numsectors*sizeof(sectq[0]));
|
|
tempictoidx = (int16_t *) Xmalloc(MAXTILES*sizeof(tempictoidx[0]));
|
|
|
|
for (i=0; i<MAXTILES; i++)
|
|
tempictoidx[i]=-1;
|
|
|
|
// collect sprite picnums
|
|
for (i=0; i<MAXSPRITES && sprite[i].statnum<MAXSTATUS; i++)
|
|
{
|
|
pn = sprite[i].picnum;
|
|
k = sprite[i].sectnum;
|
|
// -v- note the <= ignore sprites in outer sectors
|
|
if (pn<=0 || pn>=MAXTILES || k<0 || k>=numsectors || (sectoidx[k]&CM_OUTER))
|
|
continue;
|
|
|
|
if (numclipmaps >= CM_MAX)
|
|
{
|
|
initprintf("warning: reached max clip map number %d, not processing any more\n", CM_MAX);
|
|
break;
|
|
}
|
|
|
|
// chain
|
|
if (pictoidx[pn]>=0)
|
|
{
|
|
if (sectoidx[k]&CM_SOME)
|
|
{
|
|
for (fi = 0; fi < g_clipMapFilesNum; ++fi)
|
|
if (k>=fisec[fi])
|
|
break;
|
|
initprintf("clip map \"%s\": error: tried to chain picnum %d (sprite %d) in sector %d which"
|
|
" already belongs to picnum %d.\n", g_clipMapFiles[fi].GetChars(), pn, i-fispr[fi], k-fisec[fi],
|
|
clipinfo[sectoidx[k]].picnum);
|
|
engineInitClipMaps();
|
|
|
|
Xfree(fisec);
|
|
Xfree(fispr);
|
|
|
|
return 2;
|
|
}
|
|
|
|
// new one is front
|
|
clipinfo[numclipmaps].next = pictoidx[pn];
|
|
pictoidx[pn] = numclipmaps;
|
|
}
|
|
else
|
|
{
|
|
clipinfo[numclipmaps].next = -1;
|
|
pictoidx[pn] = numclipmaps;
|
|
}
|
|
|
|
if (!CM_NOROT(i))
|
|
{
|
|
if (sprite[i].ang!=1536 && sprite[i].ang!=512)
|
|
{
|
|
for (fi = 0; fi < g_clipMapFilesNum; ++fi)
|
|
if (i>=fispr[fi])
|
|
break;
|
|
initprintf("clip map \"%s\": warning: sprite %d pointing neither northward nor southward. %s will be wrong.\n",
|
|
g_clipMapFiles[fi].GetChars(), i-fispr[fi], (sprite[i].cstat&48)==32 ? "Scaling and flipping" : "X-flipping");
|
|
}
|
|
}
|
|
|
|
clipinfo[numclipmaps].picnum = pn;
|
|
|
|
// collect sectors
|
|
scnt = numclipsects;
|
|
sectq[numclipsects++] = k;
|
|
sectoidx[k] = numclipmaps;
|
|
|
|
clipinfo[numclipmaps].qbeg = scnt;
|
|
|
|
outersect = -1;
|
|
|
|
do
|
|
{
|
|
k = sectq[scnt];
|
|
|
|
for (w=sector[k].wallptr; w<sector[k].wallptr+sector[k].wallnum; w++)
|
|
{
|
|
ns = wall[w].nextsector;
|
|
if (ns>=0)
|
|
{
|
|
if (sectoidx[ns]==CM_NONE)
|
|
{
|
|
sectoidx[ns] = numclipmaps;
|
|
sectq[numclipsects++] = ns;
|
|
}
|
|
else if (sectoidx[ns]&CM_OUTER)
|
|
{
|
|
if (outersect>=0 && ns!=outersect)
|
|
{
|
|
for (fi = 0; fi < g_clipMapFilesNum; ++fi)
|
|
if (ns>=fisec[fi])
|
|
break;
|
|
initprintf("clip map \"%s\": error: encountered more than one outer sector (%d and %d)"
|
|
" for sprite %d.\n", g_clipMapFiles[fi].GetChars(), outersect-fisec[fi], ns-fisec[fi], i-fispr[fi]);
|
|
engineInitClipMaps();
|
|
|
|
Xfree(fisec);
|
|
Xfree(fispr);
|
|
|
|
return 3;
|
|
}
|
|
|
|
outersect = ns;
|
|
sectoidx[outersect] |= numclipmaps;
|
|
}
|
|
else if (sectoidx[ns]!=numclipmaps)
|
|
{
|
|
for (fi = 0; fi < g_clipMapFilesNum; ++fi)
|
|
if (ns>=fisec[fi])
|
|
break;
|
|
initprintf("clip map \"%s\": error: encountered sector %d belonging to index %d"
|
|
" while collecting sectors for sprite %d (index %d).\n",
|
|
g_clipMapFiles[fi].GetChars(), ns-fisec[fi], sectoidx[ns], i-fispr[fi], numclipmaps);
|
|
engineInitClipMaps();
|
|
|
|
Xfree(fisec);
|
|
Xfree(fispr);
|
|
|
|
return 4;
|
|
}
|
|
}
|
|
}
|
|
} while (++scnt < numclipsects);
|
|
|
|
if (outersect==-1)
|
|
{
|
|
initprintf("clip map: INTERNAL ERROR: outersect==-1!\n");
|
|
engineInitClipMaps();
|
|
|
|
Xfree(fisec);
|
|
Xfree(fispr);
|
|
|
|
return 5;
|
|
}
|
|
|
|
sectq[numclipsects++] = outersect; // last is outer
|
|
clipinfo[numclipmaps].qend = numclipsects-1;
|
|
|
|
// normalize
|
|
maxdist = 0;
|
|
|
|
for (scnt=clipinfo[numclipmaps].qbeg; scnt<=clipinfo[numclipmaps].qend; scnt++)
|
|
{
|
|
k = sectq[scnt];
|
|
|
|
x = sprite[i].x;
|
|
y = sprite[i].y;
|
|
z = sprite[i].z;
|
|
|
|
sector[k].floorz -= z;
|
|
sector[k].ceilingz -= z;
|
|
|
|
if (scnt==clipinfo[numclipmaps].qbeg)
|
|
{
|
|
// backup sprite tags since we'll discard sprites later
|
|
sector[k].CM_XREPEAT = sprite[i].xrepeat;
|
|
sector[k].CM_YREPEAT = sprite[i].yrepeat;
|
|
sector[k].CM_XOFFSET = sprite[i].xoffset;
|
|
sector[k].CM_YOFFSET = sprite[i].yoffset;
|
|
sector[k].CM_CSTAT = sprite[i].cstat;
|
|
sector[k].CM_ANG = sprite[i].ang;
|
|
}
|
|
|
|
// backup floor and ceiling z
|
|
CM_FLOORZ(k) = sector[k].floorz;
|
|
CM_CEILINGZ(k) = sector[k].ceilingz;
|
|
|
|
for (w=sector[k].wallptr; w<sector[k].wallptr+sector[k].wallnum; w++)
|
|
{
|
|
wall[w].x -= x;
|
|
wall[w].y -= y;
|
|
|
|
if (scnt!=clipinfo[numclipmaps].qend)
|
|
{
|
|
if (CM_NOROT(i))
|
|
{
|
|
if (klabs(wall[w].x) > maxdist)
|
|
maxdist = klabs(wall[w].x);
|
|
if (klabs(wall[w].y) > maxdist)
|
|
maxdist = klabs(wall[w].y);
|
|
}
|
|
else
|
|
{
|
|
int32_t tmp = ksqrt(uhypsq(wall[w].x, wall[w].y));
|
|
if (tmp > maxdist)
|
|
maxdist = tmp;
|
|
}
|
|
}
|
|
|
|
// aliasing
|
|
if (wall[w].lotag>0 || wall[w].hitag>0)
|
|
{
|
|
int32_t ii;
|
|
|
|
if (wall[w].lotag>0 && wall[w].hitag>0)
|
|
{
|
|
if (wall[w].lotag > wall[w].hitag)
|
|
swapshort(&wall[w].lotag, &wall[w].hitag);
|
|
|
|
for (ii=wall[w].lotag; ii<wall[w].hitag; ii++)
|
|
tempictoidx[ii] = numclipmaps;
|
|
}
|
|
else if (wall[w].lotag>0)
|
|
{
|
|
if (wall[w].lotag<MAXTILES)
|
|
tempictoidx[wall[w].lotag] = numclipmaps;
|
|
}
|
|
else
|
|
{
|
|
if (wall[w].hitag<MAXTILES)
|
|
tempictoidx[wall[w].hitag] = numclipmaps;
|
|
}
|
|
}
|
|
|
|
CM_WALL_X(w) = wall[w].x;
|
|
CM_WALL_Y(w) = wall[w].y;
|
|
}
|
|
}
|
|
|
|
clipinfo[numclipmaps].maxdist = maxdist;
|
|
numclipmaps++;
|
|
}
|
|
}
|
|
|
|
// yes, too much copying, but better than ugly code
|
|
Bmemcpy(loadsector, sector, ournumsectors*sizeof(sectortype));
|
|
Bmemcpy(loadwall, wall, ournumwalls*sizeof(walltype));
|
|
|
|
// loadwallinv will contain all walls with inverted orientation for x/y-flip handling
|
|
loadwallinv = (uwalltype *) Xmalloc(ournumwalls*sizeof(walltype));
|
|
|
|
{
|
|
int32_t j, loopstart, loopend, numloopwalls;
|
|
|
|
// invert walls!
|
|
loopstart = 0;
|
|
for (j=0; j<ournumwalls; j++)
|
|
{
|
|
wall[j].nextsector = wall[j].nextwall = -1;
|
|
|
|
if (wall[j].point2 < j)
|
|
{
|
|
loopend = j+1;
|
|
numloopwalls = loopend-loopstart;
|
|
|
|
if (numloopwalls<3)
|
|
{
|
|
loopstart = loopend;
|
|
continue;
|
|
}
|
|
|
|
for (k=0; k<numloopwalls; k++)
|
|
{
|
|
wall[loopstart+k].x = loadwall[loopstart + (numloopwalls+1-k)%numloopwalls].x;
|
|
wall[loopstart+k].y = loadwall[loopstart + (numloopwalls+1-k)%numloopwalls].y;
|
|
|
|
CM_WALL_X(loopstart+k) = wall[loopstart+k].x;
|
|
CM_WALL_Y(loopstart+k) = wall[loopstart+k].y;
|
|
}
|
|
|
|
loopstart = loopend;
|
|
}
|
|
}
|
|
|
|
// reconstruct wall connections
|
|
for (i=0; i<ournumsectors; i++)
|
|
{
|
|
for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
|
|
checksectorpointer(j, i);
|
|
}
|
|
}
|
|
Bmemcpy(loadwallinv, wall, ournumwalls*sizeof(walltype));
|
|
|
|
clipmapinfo.numsectors = numsectors;
|
|
clipmapinfo.sector = loadsector;
|
|
clipmapinfo.numwalls = numwalls;
|
|
clipmapinfo.wall = loadwall;
|
|
|
|
for (i=0; i<MAXTILES; i++)
|
|
{
|
|
if (pictoidx[i]==-1 && tempictoidx[i]>=0)
|
|
pictoidx[i]=tempictoidx[i];
|
|
}
|
|
|
|
DO_FREE_AND_NULL(loadsprite);
|
|
DO_FREE_AND_NULL(tempictoidx);
|
|
|
|
// don't let other code be distracted by the temporary map we constructed
|
|
numsectors = 0;
|
|
numwalls = 0;
|
|
initspritelists();
|
|
|
|
if (lwcp > 0)
|
|
initprintf("Loaded clip map%s.\n", lwcp==1 ? "" : "s");
|
|
|
|
Xfree(fisec);
|
|
Xfree(fispr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int clipshape_idx_for_sprite(uspriteptr_t const curspr, int curidx)
|
|
{
|
|
// per-sprite init
|
|
curidx = (curidx < 0) ? pictoidx[curspr->picnum] : clipinfo[curidx].next;
|
|
|
|
while (curidx >= 0 && (curspr->cstat & 32) != (sector[sectq[clipinfo[curidx].qbeg]].CM_CSTAT & 32))
|
|
curidx = clipinfo[curidx].next;
|
|
|
|
return curidx;
|
|
}
|
|
|
|
////////// CLIPMOVE //////////
|
|
|
|
int32_t clipmoveboxtracenum = 3;
|
|
|
|
//
|
|
// clipinsidebox
|
|
//
|
|
int clipinsidebox(vec2_t *vect, int wallnum, int walldist)
|
|
{
|
|
int const r = walldist << 1;
|
|
|
|
auto const wal1 = (uwallptr_t)&wall[wallnum];
|
|
auto const wal2 = (uwallptr_t)&wall[wal1->point2];
|
|
|
|
vec2_t const v1 = { wal1->x + walldist - vect->x, wal1->y + walldist - vect->y };
|
|
vec2_t v2 = { wal2->x + walldist - vect->x, wal2->y + walldist - vect->y };
|
|
|
|
if (((v1.x < 0) && (v2.x < 0)) || ((v1.y < 0) && (v2.y < 0)) || ((v1.x >= r) && (v2.x >= r)) || ((v1.y >= r) && (v2.y >= r)))
|
|
return 0;
|
|
|
|
v2.x -= v1.x; v2.y -= v1.y;
|
|
|
|
if (v2.x * (walldist - v1.y) >= v2.y * (walldist - v1.x)) // Front
|
|
{
|
|
v2.x *= ((v2.x > 0) ? (0 - v1.y) : (r - v1.y));
|
|
v2.y *= ((v2.y > 0) ? (r - v1.x) : (0 - v1.x));
|
|
return v2.x < v2.y;
|
|
}
|
|
|
|
v2.x *= ((v2.x > 0) ? (r - v1.y) : (0 - v1.y));
|
|
v2.y *= ((v2.y > 0) ? (0 - v1.x) : (r - v1.x));
|
|
return (v2.x >= v2.y) << 1;
|
|
}
|
|
|
|
|
|
//
|
|
// clipinsideboxline
|
|
//
|
|
int clipinsideboxline(int x, int y, int x1, int y1, int x2, int y2, int walldist)
|
|
{
|
|
int const r = walldist << 1;
|
|
|
|
x1 += walldist - x;
|
|
x2 += walldist - x;
|
|
|
|
if (((x1 < 0) && (x2 < 0)) || ((x1 >= r) && (x2 >= r)))
|
|
return 0;
|
|
|
|
y1 += walldist - y;
|
|
y2 += walldist - y;
|
|
|
|
if (((y1 < 0) && (y2 < 0)) || ((y1 >= r) && (y2 >= r)))
|
|
return 0;
|
|
|
|
x2 -= x1;
|
|
y2 -= y1;
|
|
|
|
if (x2 * (walldist - y1) >= y2 * (walldist - x1)) // Front
|
|
{
|
|
x2 *= ((x2 > 0) ? (0 - y1) : (r - y1));
|
|
y2 *= ((y2 > 0) ? (r - x1) : (0 - x1));
|
|
return x2 < y2;
|
|
}
|
|
|
|
x2 *= ((x2 > 0) ? (r - y1) : (0 - y1));
|
|
y2 *= ((y2 > 0) ? (0 - x1) : (r - x1));
|
|
return (x2 >= y2) << 1;
|
|
}
|
|
|
|
static int32_t clipmove_warned;
|
|
|
|
static inline void addclipsect(int const sectnum)
|
|
{
|
|
if (clipsectnum < MAXCLIPSECTORS)
|
|
{
|
|
bitmap_set(clipsectormap, sectnum);
|
|
clipsectorlist[clipsectnum++] = sectnum;
|
|
}
|
|
else
|
|
clipmove_warned |= 1;
|
|
}
|
|
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
int32_t clipsprite_try(uspriteptr_t const spr, int32_t xmin, int32_t ymin, int32_t xmax, int32_t ymax)
|
|
{
|
|
// try and see whether this sprite's picnum has sector-like clipping data
|
|
int32_t i = pictoidx[spr->picnum];
|
|
// handle sector-like floor sprites separately
|
|
while (i>=0 && (spr->cstat&32) != (clipmapinfo.sector[sectq[clipinfo[i].qbeg]].CM_CSTAT&32))
|
|
i = clipinfo[i].next;
|
|
|
|
if (i>=0)
|
|
{
|
|
int32_t maxcorrection = clipinfo[i].maxdist;
|
|
const int32_t k = sectq[clipinfo[i].qbeg];
|
|
|
|
if ((spr->cstat&CSTAT_SPRITE_ALIGNMENT)!=CSTAT_SPRITE_ALIGNMENT_FLOOR)
|
|
{
|
|
int32_t const tempint1 = clipmapinfo.sector[k].CM_XREPEAT;
|
|
maxcorrection = divideu32_noinline(maxcorrection * (int32_t) spr->xrepeat, tempint1);
|
|
}
|
|
else
|
|
{
|
|
int32_t const tempint1 = clipmapinfo.sector[k].CM_XREPEAT;
|
|
int32_t const tempint2 = clipmapinfo.sector[k].CM_YREPEAT;
|
|
maxcorrection = max(divideu32_noinline(maxcorrection * (int32_t) spr->xrepeat, tempint1),
|
|
divideu32_noinline(maxcorrection * (int32_t) spr->yrepeat, tempint2));
|
|
}
|
|
|
|
maxcorrection -= MAXCLIPDIST;
|
|
|
|
if ((spr->x < xmin - maxcorrection) || (spr->y < ymin - maxcorrection) ||
|
|
(spr->x > xmax + maxcorrection) || (spr->y > ymax + maxcorrection))
|
|
return 1;
|
|
|
|
if (clipspritenum < MAXCLIPNUM)
|
|
clipspritelist[clipspritenum++] = spr-(uspritetype *)sprite;
|
|
//initprintf("%d: clip sprite[%d]\n",clipspritenum,j);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// return: -1 if curspr has x-flip xor y-flip (in the horizontal map plane!), 1 else
|
|
int32_t clipsprite_initindex(int32_t curidx, uspriteptr_t const curspr, int32_t *clipsectcnt, const vec3_t *vect)
|
|
{
|
|
int32_t k, daz = curspr->z;
|
|
int32_t scalex, scaley, scalez, flipx, flipy;
|
|
int32_t flipmul=1;
|
|
|
|
const int32_t j = sectq[clipinfo[curidx].qbeg];
|
|
const int32_t tempint1 = sector[j].CM_XREPEAT;
|
|
const int32_t tempint2 = sector[j].CM_YREPEAT;
|
|
|
|
const int32_t rotang = (curspr->ang - sector[j].CM_ANG)&2047;
|
|
const int32_t dorot = !CM_NOROTS(j);
|
|
|
|
if ((curspr->cstat&CSTAT_SPRITE_ALIGNMENT)!=CSTAT_SPRITE_ALIGNMENT_FLOOR) // face/wall sprite
|
|
{
|
|
scalex = scaley = divscale22(curspr->xrepeat, tempint1);
|
|
scalez = divscale22(curspr->yrepeat, tempint2);
|
|
|
|
flipx = 1-((curspr->cstat&4)>>1);
|
|
flipy = 1;
|
|
}
|
|
else
|
|
{
|
|
scalex = divscale22(curspr->xrepeat, tempint1);
|
|
scaley = divscale22(curspr->yrepeat, tempint2);
|
|
scalez = scalex;
|
|
|
|
flipx = 1-((curspr->cstat&4)>>1);
|
|
flipy = 1-((curspr->cstat&8)>>2);
|
|
}
|
|
|
|
if (dorot)
|
|
{
|
|
flipmul = flipx*flipy;
|
|
if (flipmul==-1)
|
|
wall = (walltype *) loadwallinv;
|
|
}
|
|
|
|
if ((curspr->cstat&128) != (sector[j].CM_CSTAT&128))
|
|
daz += (((curspr->cstat&128)>>6)-1)*((tilesiz[curspr->picnum].y*curspr->yrepeat)<<1);
|
|
|
|
*clipsectcnt = clipsectnum = 0;
|
|
// init sectors for this index
|
|
for (k=clipinfo[curidx].qbeg; k<=clipinfo[curidx].qend; k++)
|
|
{
|
|
int32_t const j = sectq[k];
|
|
auto const sec = §or[j];
|
|
|
|
int32_t const startwall = sec->wallptr, endwall = startwall+sec->wallnum;
|
|
|
|
sec->floorz = daz + mulscale22(scalez, CM_FLOORZ(j));
|
|
sec->ceilingz = daz + mulscale22(scalez, CM_CEILINGZ(j));
|
|
//initprintf("sec %d: f=%d, c=%d\n", j, sec->floorz, sec->ceilingz);
|
|
|
|
for (int w=startwall; w<endwall; w++)
|
|
{
|
|
auto wal = (uwalltype *)(wall + w);
|
|
wal->x = mulscale22(scalex, CM_WALL_X(w));
|
|
wal->y = mulscale22(scaley, CM_WALL_Y(w));
|
|
|
|
if (dorot)
|
|
{
|
|
wal->x *= flipx;
|
|
wal->y *= flipy;
|
|
rotatepoint(zerovec, wal->pos, rotang, &wal->pos);
|
|
}
|
|
|
|
wal->x += curspr->x;
|
|
wal->y += curspr->y;
|
|
}
|
|
|
|
if (inside(vect->x, vect->y, j)==1)
|
|
addclipsect(j);
|
|
}
|
|
|
|
// add outer sector if not inside inner ones
|
|
if (clipsectnum==0)
|
|
addclipsect(sectq[k-1]);
|
|
|
|
return flipmul;
|
|
}
|
|
|
|
#endif
|
|
|
|
static void addclipline(int32_t dax1, int32_t day1, int32_t dax2, int32_t day2, int16_t daoval, int nofix)
|
|
{
|
|
if (clipnum >= MAXCLIPNUM)
|
|
{
|
|
clipmove_warned |= 2;
|
|
return;
|
|
}
|
|
|
|
clipit[clipnum].x1 = dax1; clipit[clipnum].y1 = day1;
|
|
clipit[clipnum].x2 = dax2; clipit[clipnum].y2 = day2;
|
|
clipobjectval[clipnum] = daoval;
|
|
|
|
uint32_t const mask = pow2char[clipnum&7];
|
|
uint8_t &value = clipignore[clipnum>>3];
|
|
value = (value & ~mask) | (-nofix & mask);
|
|
|
|
clipnum++;
|
|
}
|
|
|
|
static FORCE_INLINE void clipmove_tweak_pos(const vec3_t *pos, int32_t gx, int32_t gy, int32_t x1, int32_t y1, int32_t x2,
|
|
int32_t y2, int32_t *daxptr, int32_t *dayptr)
|
|
{
|
|
int32_t daz;
|
|
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829 ||
|
|
rintersect(pos->x, pos->y, 0, gx, gy, 0, x1, y1, x2, y2, daxptr, dayptr, &daz) == -1)
|
|
{
|
|
*daxptr = pos->x;
|
|
*dayptr = pos->y;
|
|
}
|
|
}
|
|
|
|
int32_t getceilzofslope_old(int32_t sectnum, int32_t dax, int32_t day)
|
|
{
|
|
int32_t dx, dy, i, j;
|
|
|
|
if (!(sector[sectnum].ceilingstat&2)) return sector[sectnum].ceilingz;
|
|
j = sector[sectnum].wallptr;
|
|
dx = wall[wall[j].point2].x-wall[j].x;
|
|
dy = wall[wall[j].point2].y-wall[j].y;
|
|
i = (ksqrtasm_old(dx*dx+dy*dy)); if (i == 0) return(sector[sectnum].ceilingz);
|
|
i = divscale15(sector[sectnum].ceilingheinum,i);
|
|
dx *= i; dy *= i;
|
|
return(sector[sectnum].ceilingz+dmulscale23(dx,day-wall[j].y,-dy,dax-wall[j].x));
|
|
}
|
|
|
|
int32_t getflorzofslope_old(int32_t sectnum, int32_t dax, int32_t day)
|
|
{
|
|
int32_t dx, dy, i, j;
|
|
|
|
if (!(sector[sectnum].floorstat&2)) return sector[sectnum].floorz;
|
|
j = sector[sectnum].wallptr;
|
|
dx = wall[wall[j].point2].x-wall[j].x;
|
|
dy = wall[wall[j].point2].y-wall[j].y;
|
|
i = (ksqrtasm_old(dx*dx+dy*dy)); if (i == 0) return sector[sectnum].floorz;
|
|
i = divscale15(sector[sectnum].floorheinum,i);
|
|
dx *= i; dy *= i;
|
|
return(sector[sectnum].floorz+dmulscale23(dx,day-wall[j].y,-dy,dax-wall[j].x));
|
|
}
|
|
|
|
// Returns: should clip?
|
|
static int cliptestsector(int const dasect, int const nextsect, int32_t const flordist, int32_t const ceildist, vec2_t const pos, int32_t const posz)
|
|
{
|
|
Bassert((unsigned)dasect < (unsigned)numsectors && (unsigned)nextsect < (unsigned)numsectors);
|
|
|
|
auto const sec2 = (usectorptr_t)§or[nextsect];
|
|
|
|
switch (enginecompatibility_mode)
|
|
{
|
|
case ENGINECOMPATIBILITY_NONE:
|
|
break;
|
|
case ENGINECOMPATIBILITY_19950829:
|
|
{
|
|
int32_t daz = getflorzofslope_old(dasect, pos.x, pos.y);
|
|
int32_t daz2 = getflorzofslope_old(nextsect, pos.x, pos.y);
|
|
|
|
if (daz2 < daz && (sec2->floorstat&1) == 0)
|
|
if (posz >= daz2-(flordist-1)) return 1;
|
|
daz = getceilzofslope_old(dasect, pos.x, pos.y);
|
|
daz2 = getceilzofslope_old(nextsect, pos.x, pos.y);
|
|
if (daz2 > daz && (sec2->ceilingstat&1) == 0)
|
|
if (posz <= daz2+(ceildist-1)) return 1;
|
|
|
|
return 0;
|
|
}
|
|
default:
|
|
{
|
|
int32_t daz = getflorzofslope(dasect, pos.x, pos.y);
|
|
int32_t daz2 = getflorzofslope(nextsect, pos.x, pos.y);
|
|
|
|
if (daz2 < daz-(1<<8) && (sec2->floorstat&1) == 0)
|
|
if (posz >= daz2-(flordist-1)) return 1;
|
|
daz = getceilzofslope(dasect, pos.x, pos.y);
|
|
daz2 = getceilzofslope(nextsect, pos.x, pos.y);
|
|
if (daz2 > daz+(1<<8) && (sec2->ceilingstat&1) == 0)
|
|
if (posz <= daz2+(ceildist-1)) return 1;
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int32_t daz2 = sec2->floorz;
|
|
int32_t dacz2 = sec2->ceilingz;
|
|
|
|
if ((sec2->floorstat|sec2->ceilingstat) & 2)
|
|
getcorrectzsofslope(nextsect, pos.x, pos.y, &dacz2, &daz2);
|
|
|
|
if (daz2 <= dacz2)
|
|
return 1;
|
|
|
|
auto const sec = (usectorptr_t)§or[dasect];
|
|
|
|
int32_t daz = sec->floorz;
|
|
int32_t dacz = sec->ceilingz;
|
|
|
|
if ((sec->floorstat|sec->ceilingstat) & 2)
|
|
getcorrectzsofslope(dasect, pos.x, pos.y, &dacz, &daz);
|
|
|
|
int32_t const sec2height = klabs(daz2-dacz2);
|
|
|
|
return ((klabs(daz-dacz) > sec2height && // clip if the current sector is taller and the next is too small
|
|
sec2height < (ceildist+(CLIPCURBHEIGHT<<1))) ||
|
|
|
|
((sec2->floorstat&1) == 0 && // parallaxed floor curbs don't clip
|
|
posz >= daz2-(flordist-1) && // also account for desired z distance tolerance
|
|
daz2 < daz-CLIPCURBHEIGHT) || // curbs less tall than 256 z units don't clip
|
|
|
|
((sec2->ceilingstat&1) == 0 &&
|
|
posz <= dacz2+(ceildist-1) &&
|
|
dacz2 > dacz /*+CLIPCURBHEIGHT*/)); // ceilings check the same conditions ^^^^^
|
|
}
|
|
|
|
int32_t clipmovex(vec3_t *pos, int16_t *sectnum,
|
|
int32_t xvect, int32_t yvect,
|
|
int32_t const walldist, int32_t const ceildist, int32_t const flordist, uint32_t const cliptype,
|
|
uint8_t const noslidep)
|
|
{
|
|
const int32_t oboxtracenum = clipmoveboxtracenum;
|
|
|
|
if (noslidep)
|
|
clipmoveboxtracenum = 1;
|
|
int32_t ret = clipmove(pos, sectnum, xvect, yvect,
|
|
walldist, ceildist, flordist, cliptype);
|
|
clipmoveboxtracenum = oboxtracenum;
|
|
|
|
return ret;
|
|
}
|
|
|
|
//
|
|
// raytrace (internal)
|
|
//
|
|
static inline int32_t cliptrace(vec2_t const pos, vec2_t * const goal)
|
|
{
|
|
int32_t hitwall = -1;
|
|
|
|
for (native_t z=clipnum-1; z>=0; z--)
|
|
{
|
|
vec2_t const p1 = { clipit[z].x1, clipit[z].y1 };
|
|
vec2_t const p2 = { clipit[z].x2, clipit[z].y2 };
|
|
vec2_t const area = { p2.x-p1.x, p2.y-p1.y };
|
|
|
|
int32_t topu = area.x*(pos.y-p1.y) - (pos.x-p1.x)*area.y;
|
|
|
|
if (topu <= 0 || area.x*(goal->y-p1.y) > (goal->x-p1.x)*area.y)
|
|
continue;
|
|
|
|
vec2_t const diff = { goal->x-pos.x, goal->y-pos.y };
|
|
|
|
if (diff.x*(p1.y-pos.y) > (p1.x-pos.x)*diff.y || diff.x*(p2.y-pos.y) <= (p2.x-pos.x)*diff.y)
|
|
continue;
|
|
|
|
int32_t const bot = diff.x*area.y - area.x*diff.y;
|
|
native_t cnt = 256;
|
|
|
|
if (!bot)
|
|
continue;
|
|
|
|
vec2_t n;
|
|
|
|
do
|
|
{
|
|
if (--cnt < 0)
|
|
{
|
|
*goal = pos;
|
|
return z;
|
|
}
|
|
|
|
n = { pos.x+scale(diff.x, topu, bot), pos.y+scale(diff.y, topu, bot) };
|
|
topu--;
|
|
} while (area.x*(n.y-p1.y) <= (n.x-p1.x)*area.y);
|
|
|
|
if (klabs(pos.x-n.x)+klabs(pos.y-n.y) < klabs(pos.x-goal->x)+klabs(pos.y-goal->y))
|
|
{
|
|
*goal = n;
|
|
hitwall = z;
|
|
}
|
|
}
|
|
|
|
return hitwall;
|
|
}
|
|
|
|
//
|
|
// keepaway (internal)
|
|
//
|
|
static inline void keepaway(int32_t *x, int32_t *y, int32_t w)
|
|
{
|
|
const int32_t x1 = clipit[w].x1, dx = clipit[w].x2-x1;
|
|
const int32_t y1 = clipit[w].y1, dy = clipit[w].y2-y1;
|
|
const int32_t ox = ksgn(-dy), oy = ksgn(dx);
|
|
char first = (klabs(dx) <= klabs(dy));
|
|
|
|
do
|
|
{
|
|
if (dx*(*y-y1) > (*x-x1)*dy)
|
|
return;
|
|
|
|
if (first == 0)
|
|
*x += ox;
|
|
else
|
|
*y += oy;
|
|
|
|
first ^= 1;
|
|
}
|
|
while (1);
|
|
}
|
|
|
|
static int get_floorspr_clipyou(vec2_t const v1, vec2_t const v2, vec2_t const v3, vec2_t const v4)
|
|
{
|
|
int clipyou = 0;
|
|
|
|
if ((v1.y^v2.y) < 0)
|
|
{
|
|
if ((v1.x^v2.x) < 0) clipyou ^= (v1.x*v2.y < v2.x*v1.y)^(v1.y<v2.y);
|
|
else if (v1.x >= 0) clipyou ^= 1;
|
|
}
|
|
if ((v2.y^v3.y) < 0)
|
|
{
|
|
if ((v2.x^v3.x) < 0) clipyou ^= (v2.x*v3.y < v3.x*v2.y)^(v2.y<v3.y);
|
|
else if (v2.x >= 0) clipyou ^= 1;
|
|
}
|
|
if ((v3.y^v4.y) < 0)
|
|
{
|
|
if ((v3.x^v4.x) < 0) clipyou ^= (v3.x*v4.y < v4.x*v3.y)^(v3.y<v4.y);
|
|
else if (v3.x >= 0) clipyou ^= 1;
|
|
}
|
|
if ((v4.y^v1.y) < 0)
|
|
{
|
|
if ((v4.x^v1.x) < 0) clipyou ^= (v4.x*v1.y < v1.x*v4.y)^(v4.y<v1.y);
|
|
else if (v4.x >= 0) clipyou ^= 1;
|
|
}
|
|
|
|
return clipyou;
|
|
}
|
|
|
|
static void clipupdatesector(vec2_t const pos, int16_t * const sectnum, int walldist)
|
|
{
|
|
if (enginecompatibility_mode != ENGINECOMPATIBILITY_NONE)
|
|
{
|
|
updatesector(pos.x, pos.y, sectnum);
|
|
return;
|
|
}
|
|
|
|
if (inside_p(pos.x, pos.y, *sectnum))
|
|
return;
|
|
|
|
int16_t nsecs = min<int16_t>(getsectordist(pos, *sectnum), INT16_MAX);
|
|
|
|
if (nsecs > (walldist + 8))
|
|
{
|
|
OSD_Printf("%s():%d shortest distance between origin point (%d, %d) and sector %d is %d. Sector may be corrupt!\n",
|
|
EDUKE32_FUNCTION, __LINE__, pos.x, pos.y, *sectnum, nsecs);
|
|
walldist = 0x7fff;
|
|
}
|
|
|
|
static int16_t sectlist[MAXSECTORS];
|
|
static uint8_t sectbitmap[(MAXSECTORS+7)>>3];
|
|
|
|
bfirst_search_init(sectlist, sectbitmap, &nsecs, MAXSECTORS, *sectnum);
|
|
|
|
for (int sectcnt = 0; sectcnt < nsecs; sectcnt++)
|
|
{
|
|
int const listsectnum = sectlist[sectcnt];
|
|
|
|
if (inside_p(pos.x, pos.y, listsectnum))
|
|
SET_AND_RETURN(*sectnum, listsectnum);
|
|
|
|
auto const sec = §or[listsectnum];
|
|
int const startwall = sec->wallptr;
|
|
int const endwall = sec->wallptr + sec->wallnum;
|
|
auto uwal = (uwallptr_t)&wall[startwall];
|
|
|
|
for (int j = startwall; j < endwall; j++, uwal++)
|
|
if (uwal->nextsector >= 0 && bitmap_test(clipsectormap, uwal->nextsector))
|
|
bfirst_search_try(sectlist, sectbitmap, &nsecs, uwal->nextsector);
|
|
}
|
|
|
|
bfirst_search_init(sectlist, sectbitmap, &nsecs, MAXSECTORS, *sectnum);
|
|
|
|
for (int sectcnt = 0; sectcnt < nsecs; sectcnt++)
|
|
{
|
|
int const listsectnum = sectlist[sectcnt];
|
|
|
|
if (inside_p(pos.x, pos.y, listsectnum))
|
|
{
|
|
// add sector to clipping list so the next call to clipupdatesector()
|
|
// finishes in the loop above this one
|
|
addclipsect(listsectnum);
|
|
SET_AND_RETURN(*sectnum, listsectnum);
|
|
}
|
|
|
|
auto const sec = §or[listsectnum];
|
|
int const startwall = sec->wallptr;
|
|
int const endwall = sec->wallptr + sec->wallnum;
|
|
auto uwal = (uwallptr_t)&wall[startwall];
|
|
|
|
// check floor curbs here?
|
|
|
|
for (int j = startwall; j < endwall; j++, uwal++)
|
|
if (uwal->nextsector >= 0 && getwalldist(pos, j) <= (walldist + 8))
|
|
bfirst_search_try(sectlist, sectbitmap, &nsecs, uwal->nextsector);
|
|
}
|
|
|
|
*sectnum = -1;
|
|
}
|
|
|
|
//
|
|
// clipmove
|
|
//
|
|
int32_t clipmove(vec3_t * const pos, int16_t * const sectnum, int32_t xvect, int32_t yvect,
|
|
int32_t const walldist, int32_t const ceildist, int32_t const flordist, uint32_t const cliptype)
|
|
{
|
|
if ((xvect|yvect) == 0 || *sectnum < 0)
|
|
return 0;
|
|
|
|
uspriteptr_t curspr=NULL; // non-NULL when handling sprite with sector-like clipping
|
|
|
|
int const initialsectnum = *sectnum;
|
|
|
|
int32_t const dawalclipmask = (cliptype & 65535); // CLIPMASK0 = 0x00010001
|
|
int32_t const dasprclipmask = (cliptype >> 16); // CLIPMASK1 = 0x01000040
|
|
|
|
vec2_t const move = { xvect, yvect };
|
|
vec2_t goal = { pos->x + (xvect >> 14), pos->y + (yvect >> 14) };
|
|
vec2_t const cent = { (pos->x + goal.x) >> 1, (pos->y + goal.y) >> 1 };
|
|
|
|
//Extra walldist for sprites on sector lines
|
|
vec2_t const diff = { goal.x - (pos->x), goal.y - (pos->y) };
|
|
int32_t const rad = clip_nsqrtasm(compat_maybe_truncate_to_int32(uhypsq(diff.x, diff.y))) + MAXCLIPDIST + walldist + 8;
|
|
vec2_t const clipMin = { cent.x - rad, cent.y - rad };
|
|
vec2_t const clipMax = { cent.x + rad, cent.y + rad };
|
|
|
|
int clipshapeidx = -1;
|
|
int clipsectcnt = 0;
|
|
int clipspritecnt = 0;
|
|
|
|
clipsectorlist[0] = *sectnum;
|
|
|
|
clipsectnum = 1;
|
|
clipnum = 0;
|
|
clipspritenum = 0;
|
|
|
|
clipmove_warned = 0;
|
|
|
|
Bmemset(clipsectormap, 0, (numsectors+7)>>3);
|
|
bitmap_set(clipsectormap, *sectnum);
|
|
|
|
do
|
|
{
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
if (clipsectcnt>=clipsectnum)
|
|
{
|
|
// one bunch of sectors completed (either the very first
|
|
// one or a sector-like sprite one), prepare the next
|
|
|
|
//initprintf("init sprite %d\n", clipspritecnt);
|
|
if (!curspr)
|
|
{
|
|
// init sector-like sprites for clipping
|
|
origclipsectnum = clipsectnum;
|
|
Bmemcpy(origclipsectorlist, clipsectorlist, clipsectnum*sizeof(clipsectorlist[0]));
|
|
Bmemcpy(origclipsectormap, clipsectormap, (numsectors+7)>>3);
|
|
|
|
// replace sector and wall with clip map
|
|
engineSetClipMap(&origmapinfo, &clipmapinfo);
|
|
}
|
|
|
|
curspr = (uspriteptr_t)&sprite[clipspritelist[clipspritecnt]];
|
|
clipshapeidx = clipshape_idx_for_sprite(curspr, clipshapeidx);
|
|
|
|
if (clipshapeidx < 0)
|
|
{
|
|
clipspritecnt++;
|
|
continue;
|
|
}
|
|
|
|
clipsprite_initindex(clipshapeidx, curspr, &clipsectcnt, pos);
|
|
}
|
|
#endif
|
|
|
|
int const dasect = clipsectorlist[clipsectcnt++];
|
|
//if (curspr)
|
|
// initprintf("sprite %d/%d: sect %d/%d (%d)\n", clipspritecnt,clipspritenum, clipsectcnt,clipsectnum,dasect);
|
|
|
|
////////// Walls //////////
|
|
|
|
auto const sec = (usectorptr_t)§or[dasect];
|
|
int const startwall = sec->wallptr;
|
|
int const endwall = startwall + sec->wallnum;
|
|
auto wal = (uwallptr_t)&wall[startwall];
|
|
|
|
for (native_t j=startwall; j<endwall; j++, wal++)
|
|
{
|
|
auto const wal2 = (uwallptr_t)&wall[wal->point2];
|
|
|
|
if ((wal->x < clipMin.x && wal2->x < clipMin.x) || (wal->x > clipMax.x && wal2->x > clipMax.x) ||
|
|
(wal->y < clipMin.y && wal2->y < clipMin.y) || (wal->y > clipMax.y && wal2->y > clipMax.y))
|
|
continue;
|
|
|
|
vec2_t p1 = wal->pos;
|
|
vec2_t p2 = wal2->pos;
|
|
vec2_t d = { p2.x-p1.x, p2.y-p1.y };
|
|
|
|
if (d.x * (pos->y-p1.y) < (pos->x-p1.x) * d.y)
|
|
continue; //If wall's not facing you
|
|
|
|
vec2_t const r = { (d.y > 0) ? clipMax.x : clipMin.x, (d.x > 0) ? clipMin.y : clipMax.y };
|
|
vec2_t v = { d.x * (r.y - p1.y), d.y * (r.x - p1.x) };
|
|
|
|
if (v.x >= v.y)
|
|
continue;
|
|
|
|
int clipyou = 0;
|
|
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
if (curspr)
|
|
{
|
|
if (wal->nextsector>=0)
|
|
{
|
|
auto const sec2 = (usectorptr_t)§or[wal->nextsector];
|
|
|
|
clipmove_tweak_pos(pos, diff.x, diff.y, p1.x, p1.y, p2.x, p2.y, &v.x, &v.y);
|
|
|
|
#define CLIPMV_SPR_F_DAZ2 getcorrectflorzofslope(wal->nextsector, v.x, v.y)
|
|
#define CLIPMV_SPR_F_BASEZ getcorrectflorzofslope(sectq[clipinfo[clipshapeidx].qend], v.x, v.y)
|
|
|
|
if ((sec2->floorstat&1) == 0)
|
|
{
|
|
if (CLIPMV_SPR_F_DAZ2-(flordist-1) <= pos->z && pos->z <= CLIPMV_SPR_F_BASEZ+(flordist-1))
|
|
clipyou = 1;
|
|
}
|
|
|
|
if (clipyou == 0)
|
|
{
|
|
#define CLIPMV_SPR_C_DAZ2 getcorrectceilzofslope(wal->nextsector, v.x, v.y)
|
|
#define CLIPMV_SPR_C_BASEZ getcorrectceilzofslope(sectq[clipinfo[clipshapeidx].qend], v.x, v.y)
|
|
|
|
if ((sec2->ceilingstat & 1) == 0)
|
|
{
|
|
if (CLIPMV_SPR_C_BASEZ-(ceildist-1) <= pos->z && pos->z <= CLIPMV_SPR_C_DAZ2+(ceildist-1))
|
|
clipyou = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
if (wal->nextsector < 0 || (wal->cstat&dawalclipmask))
|
|
{
|
|
clipyou = 1;
|
|
#ifdef YAX_ENABLE
|
|
int const cb = yax_getbunch(dasect, YAX_CEILING);
|
|
|
|
if (cb >= 0 && (sec->ceilingstat & yax_waltosecmask(dawalclipmask)) == 0)
|
|
{
|
|
int const ynw = yax_getnextwall(j, YAX_CEILING);
|
|
|
|
if (ynw >= 0 && wall[ynw].nextsector >= 0 && (wall[ynw].cstat & dawalclipmask) == 0)
|
|
{
|
|
clipmove_tweak_pos(pos, diff.x, diff.y, p1.x, p1.y, p2.x, p2.y, &v.x, &v.y);
|
|
clipyou = cliptestsector(dasect, wall[ynw].nextsector, flordist, ceildist, v, pos->z);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
else if (editstatus == 0)
|
|
{
|
|
clipmove_tweak_pos(pos, diff.x, diff.y, p1.x, p1.y, p2.x, p2.y, &v.x, &v.y);
|
|
clipyou = cliptestsector(dasect, wal->nextsector, flordist, ceildist, v, pos->z);
|
|
}
|
|
|
|
// We're not interested in any sector reached by portal traversal that we're "inside" of.
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE && !curspr && dasect != initialsectnum
|
|
&& inside(pos->x, pos->y, dasect) == 1)
|
|
{
|
|
int k;
|
|
for (k=startwall; k<endwall; k++)
|
|
if (wall[k].nextsector == initialsectnum)
|
|
break;
|
|
if (k == endwall)
|
|
break;
|
|
}
|
|
|
|
if (clipyou)
|
|
{
|
|
int16_t const objtype = curspr ? (int16_t)(curspr - (uspritetype *)sprite) + 49152 : (int16_t)j + 32768;
|
|
|
|
//Add 2 boxes at endpoints
|
|
int32_t bsz = walldist; if (diff.x < 0) bsz = -bsz;
|
|
addclipline(p1.x-bsz, p1.y-bsz, p1.x-bsz, p1.y+bsz, objtype, false);
|
|
addclipline(p2.x-bsz, p2.y-bsz, p2.x-bsz, p2.y+bsz, objtype, false);
|
|
bsz = walldist; if (diff.y < 0) bsz = -bsz;
|
|
addclipline(p1.x+bsz, p1.y-bsz, p1.x-bsz, p1.y-bsz, objtype, false);
|
|
addclipline(p2.x+bsz, p2.y-bsz, p2.x-bsz, p2.y-bsz, objtype, false);
|
|
|
|
v.x = walldist; if (d.y > 0) v.x = -v.x;
|
|
v.y = walldist; if (d.x < 0) v.y = -v.y;
|
|
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE && d.x * (pos->y-p1.y-v.y) < (pos->x-p1.x-v.x) * d.y)
|
|
v.x >>= 1, v.y >>= 1;
|
|
|
|
addclipline(p1.x+v.x, p1.y+v.y, p2.x+v.x, p2.y+v.y, objtype, false);
|
|
}
|
|
else if (wal->nextsector>=0)
|
|
{
|
|
if (bitmap_test(clipsectormap, wal->nextsector) == 0)
|
|
addclipsect(wal->nextsector);
|
|
}
|
|
}
|
|
|
|
if (clipmove_warned & 1)
|
|
OSD_Printf("clipsectnum >= MAXCLIPSECTORS!\n");
|
|
|
|
if (clipmove_warned & 2)
|
|
OSD_Printf("clipnum >= MAXCLIPNUM!\n");
|
|
|
|
////////// Sprites //////////
|
|
|
|
if (dasprclipmask==0)
|
|
continue;
|
|
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
if (curspr)
|
|
continue; // next sector of this index
|
|
#endif
|
|
for (native_t j=headspritesect[dasect]; j>=0; j=nextspritesect[j])
|
|
{
|
|
auto const spr = (uspriteptr_t)&sprite[j];
|
|
const int32_t cstat = spr->cstat;
|
|
|
|
if ((cstat&dasprclipmask) == 0)
|
|
continue;
|
|
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
if (clipsprite_try(spr, clipMin.x, clipMin.y, clipMax.x, clipMax.y))
|
|
continue;
|
|
#endif
|
|
vec2_t p1 = *(vec2_t const *)spr;
|
|
|
|
switch (cstat & (CSTAT_SPRITE_ALIGNMENT_WALL | CSTAT_SPRITE_ALIGNMENT_FLOOR))
|
|
{
|
|
case CSTAT_SPRITE_ALIGNMENT_FACING:
|
|
if (p1.x >= clipMin.x && p1.x <= clipMax.x && p1.y >= clipMin.y && p1.y <= clipMax.y)
|
|
{
|
|
int32_t height, daz = spr->z+spriteheightofs(j, &height, 1);
|
|
|
|
if (pos->z > daz-height-flordist && pos->z < daz+ceildist)
|
|
{
|
|
int32_t bsz = (spr->clipdist << 2)+walldist;
|
|
if (diff.x < 0) bsz = -bsz;
|
|
addclipline(p1.x-bsz, p1.y-bsz, p1.x-bsz, p1.y+bsz, (int16_t)j+49152, false);
|
|
bsz = (spr->clipdist << 2)+walldist;
|
|
if (diff.y < 0) bsz = -bsz;
|
|
addclipline(p1.x+bsz, p1.y-bsz, p1.x-bsz, p1.y-bsz, (int16_t)j+49152, false);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CSTAT_SPRITE_ALIGNMENT_WALL:
|
|
{
|
|
int32_t height, daz = spr->z+spriteheightofs(j, &height, 1);
|
|
|
|
if (pos->z > daz-height-flordist && pos->z < daz+ceildist)
|
|
{
|
|
vec2_t p2;
|
|
|
|
get_wallspr_points(spr, &p1.x, &p2.x, &p1.y, &p2.y);
|
|
|
|
if (clipinsideboxline(cent.x, cent.y, p1.x, p1.y, p2.x, p2.y, rad) != 0)
|
|
{
|
|
vec2_t v = { mulscale14(sintable[(spr->ang+256+512) & 2047], walldist),
|
|
mulscale14(sintable[(spr->ang+256) & 2047], walldist) };
|
|
|
|
if ((p1.x-pos->x) * (p2.y-pos->y) >= (p2.x-pos->x) * (p1.y-pos->y)) // Front
|
|
addclipline(p1.x+v.x, p1.y+v.y, p2.x+v.y, p2.y-v.x, (int16_t)j+49152, false);
|
|
else
|
|
{
|
|
if ((cstat & 64) != 0)
|
|
continue;
|
|
addclipline(p2.x-v.x, p2.y-v.y, p1.x-v.y, p1.y+v.x, (int16_t)j+49152, false);
|
|
}
|
|
|
|
//Side blocker
|
|
if ((p2.x-p1.x) * (pos->x-p1.x)+(p2.y-p1.y) * (pos->y-p1.y) < 0)
|
|
addclipline(p1.x-v.y, p1.y+v.x, p1.x+v.x, p1.y+v.y, (int16_t)j+49152, true);
|
|
else if ((p1.x-p2.x) * (pos->x-p2.x)+(p1.y-p2.y) * (pos->y-p2.y) < 0)
|
|
addclipline(p2.x+v.y, p2.y-v.x, p2.x-v.x, p2.y-v.y, (int16_t)j+49152, true);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case CSTAT_SPRITE_ALIGNMENT_FLOOR:
|
|
{
|
|
if (pos->z > spr->z-flordist && pos->z < spr->z+ceildist)
|
|
{
|
|
if ((cstat&64) != 0)
|
|
if ((pos->z > spr->z) == ((cstat&8)==0))
|
|
continue;
|
|
|
|
rxi[0] = p1.x;
|
|
ryi[0] = p1.y;
|
|
|
|
get_floorspr_points((uspriteptr_t) spr, 0, 0, &rxi[0], &rxi[1], &rxi[2], &rxi[3],
|
|
&ryi[0], &ryi[1], &ryi[2], &ryi[3]);
|
|
|
|
vec2_t v = { mulscale14(sintable[(spr->ang-256+512)&2047], walldist),
|
|
mulscale14(sintable[(spr->ang-256)&2047], walldist) };
|
|
|
|
if ((rxi[0]-pos->x) * (ryi[1]-pos->y) < (rxi[1]-pos->x) * (ryi[0]-pos->y))
|
|
{
|
|
if (clipinsideboxline(cent.x, cent.y, rxi[1], ryi[1], rxi[0], ryi[0], rad) != 0)
|
|
addclipline(rxi[1]-v.y, ryi[1]+v.x, rxi[0]+v.x, ryi[0]+v.y, (int16_t)j+49152, false);
|
|
}
|
|
else if ((rxi[2]-pos->x) * (ryi[3]-pos->y) < (rxi[3]-pos->x) * (ryi[2]-pos->y))
|
|
{
|
|
if (clipinsideboxline(cent.x, cent.y, rxi[3], ryi[3], rxi[2], ryi[2], rad) != 0)
|
|
addclipline(rxi[3]+v.y, ryi[3]-v.x, rxi[2]-v.x, ryi[2]-v.y, (int16_t)j+49152, false);
|
|
}
|
|
|
|
if ((rxi[1]-pos->x) * (ryi[2]-pos->y) < (rxi[2]-pos->x) * (ryi[1]-pos->y))
|
|
{
|
|
if (clipinsideboxline(cent.x, cent.y, rxi[2], ryi[2], rxi[1], ryi[1], rad) != 0)
|
|
addclipline(rxi[2]-v.x, ryi[2]-v.y, rxi[1]-v.y, ryi[1]+v.x, (int16_t)j+49152, false);
|
|
}
|
|
else if ((rxi[3]-pos->x) * (ryi[0]-pos->y) < (rxi[0]-pos->x) * (ryi[3]-pos->y))
|
|
{
|
|
if (clipinsideboxline(cent.x, cent.y, rxi[0], ryi[0], rxi[3], ryi[3], rad) != 0)
|
|
addclipline(rxi[0]+v.x, ryi[0]+v.y, rxi[3]+v.y, ryi[3]-v.x, (int16_t)j+49152, false);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} while (clipsectcnt < clipsectnum || clipspritecnt < clipspritenum);
|
|
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
if (curspr)
|
|
{
|
|
// restore original map
|
|
engineSetClipMap(NULL, &origmapinfo);
|
|
|
|
clipsectnum = origclipsectnum;
|
|
Bmemcpy(clipsectorlist, origclipsectorlist, clipsectnum*sizeof(clipsectorlist[0]));
|
|
Bmemcpy(clipsectormap, origclipsectormap, (numsectors+7)>>3);
|
|
}
|
|
#endif
|
|
|
|
int32_t hitwalls[4], hitwall;
|
|
int32_t clipReturn = 0;
|
|
|
|
native_t cnt = clipmoveboxtracenum;
|
|
|
|
do
|
|
{
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
|
|
for (native_t i=clipnum-1;i>=0;--i)
|
|
{
|
|
if (!bitmap_test(clipignore, i) && clipinsideboxline(pos->x, pos->y, clipit[i].x1, clipit[i].y1, clipit[i].x2, clipit[i].y2, walldist))
|
|
{
|
|
vec2_t const vec = pos->vec2;
|
|
keepaway(&pos->x, &pos->y, i);
|
|
if (inside(pos->x,pos->y, *sectnum) != 1)
|
|
pos->vec2 = vec;
|
|
break;
|
|
}
|
|
}
|
|
|
|
vec2_t vec = goal;
|
|
|
|
if ((hitwall = cliptrace(pos->vec2, &vec)) >= 0)
|
|
{
|
|
vec2_t const clipr = { clipit[hitwall].x2 - clipit[hitwall].x1, clipit[hitwall].y2 - clipit[hitwall].y1 };
|
|
int64_t const templl = compat_maybe_truncate_to_int32((int64_t)clipr.x * clipr.x + (int64_t)clipr.y * clipr.y);
|
|
|
|
if (templl > 0)
|
|
{
|
|
int64_t const templl2 = compat_maybe_truncate_to_int32((int64_t)(goal.x-vec.x)*clipr.x + (int64_t)(goal.y-vec.y)*clipr.y);
|
|
int32_t const i = (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829 || (llabs(templl2)>>11) < templl) ?
|
|
divscale64(templl2, templl, 20) : 0;
|
|
|
|
goal = { mulscale20(clipr.x, i)+vec.x, mulscale20(clipr.y, i)+vec.y };
|
|
}
|
|
|
|
int32_t tempint;
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829)
|
|
tempint = clipr.x*(move.x>>6)+clipr.y*(move.y>>6);
|
|
else
|
|
tempint = dmulscale6(clipr.x, move.x, clipr.y, move.y);
|
|
|
|
for (native_t i=cnt+1, j; i<=clipmoveboxtracenum; ++i)
|
|
{
|
|
j = hitwalls[i];
|
|
|
|
int32_t tempint2;
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829)
|
|
tempint2 = (clipit[j].x2-clipit[j].x1)*(move.x>>6)+(clipit[j].y2-clipit[j].y1)*(move.y>>6);
|
|
else
|
|
tempint2 = dmulscale6(clipit[j].x2-clipit[j].x1, move.x, clipit[j].y2-clipit[j].y1, move.y);
|
|
|
|
if ((tempint ^ tempint2) < 0)
|
|
{
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19961112)
|
|
updatesector(pos->x, pos->y, sectnum);
|
|
return clipReturn;
|
|
}
|
|
}
|
|
|
|
keepaway(&goal.x, &goal.y, hitwall);
|
|
xvect = (goal.x-vec.x)<<14;
|
|
yvect = (goal.y-vec.y)<<14;
|
|
|
|
if (cnt == clipmoveboxtracenum)
|
|
clipReturn = (uint16_t) clipobjectval[hitwall];
|
|
hitwalls[cnt] = hitwall;
|
|
}
|
|
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
|
|
clipupdatesector(vec, sectnum, rad);
|
|
|
|
pos->x = vec.x;
|
|
pos->y = vec.y;
|
|
cnt--;
|
|
} while ((xvect|yvect) != 0 && hitwall >= 0 && cnt > 0);
|
|
|
|
if (enginecompatibility_mode != ENGINECOMPATIBILITY_NONE)
|
|
{
|
|
for (native_t j=0; j<clipsectnum; j++)
|
|
if (inside(pos->x, pos->y, clipsectorlist[j]) == 1)
|
|
{
|
|
*sectnum = clipsectorlist[j];
|
|
return clipReturn;
|
|
}
|
|
|
|
int32_t tempint2, tempint1 = INT32_MAX;
|
|
*sectnum = -1;
|
|
for (native_t j=numsectors-1; j>=0; j--)
|
|
if (inside(pos->x, pos->y, j) == 1)
|
|
{
|
|
if (enginecompatibility_mode != ENGINECOMPATIBILITY_19950829 && (sector[j].ceilingstat&2))
|
|
tempint2 = getceilzofslope(j, pos->x, pos->y) - pos->z;
|
|
else
|
|
tempint2 = sector[j].ceilingz - pos->z;
|
|
|
|
if (tempint2 > 0)
|
|
{
|
|
if (tempint2 < tempint1)
|
|
{
|
|
*sectnum = j; tempint1 = tempint2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (enginecompatibility_mode != ENGINECOMPATIBILITY_19950829 && (sector[j].floorstat&2))
|
|
tempint2 = pos->z - getflorzofslope(j, pos->x, pos->y);
|
|
else
|
|
tempint2 = pos->z - sector[j].floorz;
|
|
|
|
if (tempint2 <= 0)
|
|
{
|
|
*sectnum = j;
|
|
return clipReturn;
|
|
}
|
|
if (tempint2 < tempint1)
|
|
{
|
|
*sectnum = j; tempint1 = tempint2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return clipReturn;
|
|
}
|
|
|
|
|
|
//
|
|
// pushmove
|
|
//
|
|
int pushmove(vec3_t *const vect, int16_t *const sectnum,
|
|
int32_t const walldist, int32_t const ceildist, int32_t const flordist, uint32_t const cliptype, bool clear /*= true*/)
|
|
{
|
|
int bad;
|
|
|
|
const int32_t dawalclipmask = (cliptype&65535);
|
|
// const int32_t dasprclipmask = (cliptype>>16);
|
|
|
|
if (*sectnum < 0)
|
|
return -1;
|
|
|
|
int32_t k = 32;
|
|
|
|
int dir = 1;
|
|
do
|
|
{
|
|
int32_t clipsectcnt = 0;
|
|
|
|
bad = 0;
|
|
|
|
if (clear)
|
|
{
|
|
clipsectorlist[0] = *sectnum;
|
|
clipsectnum = 1;
|
|
|
|
Bmemset(clipsectormap, 0, (numsectors + 7) >> 3);
|
|
bitmap_set(clipsectormap, *sectnum);
|
|
}
|
|
|
|
do
|
|
{
|
|
uwallptr_t wal;
|
|
int32_t startwall, endwall;
|
|
#if 0
|
|
// Push FACE sprites
|
|
for (i=headspritesect[clipsectorlist[clipsectcnt]]; i>=0; i=nextspritesect[i])
|
|
{
|
|
spr = &sprite[i];
|
|
if (((spr->cstat&48) != 0) && ((spr->cstat&48) != 48)) continue;
|
|
if ((spr->cstat&dasprclipmask) == 0) continue;
|
|
|
|
dax = (vect->x)-spr->x; day = (vect->y)-spr->y;
|
|
t = (spr->clipdist<<2)+walldist;
|
|
if ((klabs(dax) < t) && (klabs(day) < t))
|
|
{
|
|
daz = spr->z + spriteheightofs(i, &t, 1);
|
|
if (((vect->z) < daz+ceildist) && ((vect->z) > daz-t-flordist))
|
|
{
|
|
t = (spr->clipdist<<2)+walldist;
|
|
|
|
j = getangle(dax, day);
|
|
dx = (sintable[(j+512)&2047]>>11);
|
|
dy = (sintable[(j)&2047]>>11);
|
|
bad2 = 16;
|
|
do
|
|
{
|
|
vect->x = (vect->x) + dx; vect->y = (vect->y) + dy;
|
|
bad2--; if (bad2 == 0) break;
|
|
} while ((klabs((vect->x)-spr->x) < t) && (klabs((vect->y)-spr->y) < t));
|
|
bad = -1;
|
|
k--; if (k <= 0) return bad;
|
|
updatesector(vect->x, vect->y, sectnum);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
auto sec = (usectorptr_t)§or[clipsectorlist[clipsectcnt]];
|
|
if (dir > 0)
|
|
startwall = sec->wallptr, endwall = startwall + sec->wallnum;
|
|
else
|
|
endwall = sec->wallptr, startwall = endwall + sec->wallnum;
|
|
|
|
int i;
|
|
|
|
for (i=startwall, wal=(uwallptr_t)&wall[startwall]; i!=endwall; i+=dir, wal+=dir)
|
|
if (clipinsidebox(&vect->vec2, i, walldist-4) == 1)
|
|
{
|
|
int j = 0;
|
|
if (wal->nextsector < 0 || wal->cstat&dawalclipmask) j = 1;
|
|
else
|
|
{
|
|
int32_t daz2;
|
|
vec2_t closest;
|
|
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829)
|
|
closest = vect->vec2;
|
|
else
|
|
{
|
|
//Find closest point on wall (dax, day) to (vect->x, vect->y)
|
|
int32_t dax = wall[wal->point2].x-wal->x;
|
|
int32_t day = wall[wal->point2].y-wal->y;
|
|
int32_t daz = dax*((vect->x)-wal->x) + day*((vect->y)-wal->y);
|
|
int32_t t;
|
|
if (daz <= 0)
|
|
t = 0;
|
|
else
|
|
{
|
|
daz2 = dax*dax+day*day;
|
|
if (daz >= daz2) t = (1<<30); else t = divscale30(daz, daz2);
|
|
}
|
|
dax = wal->x + mulscale30(dax, t);
|
|
day = wal->y + mulscale30(day, t);
|
|
|
|
closest = { dax, day };
|
|
}
|
|
|
|
j = cliptestsector(clipsectorlist[clipsectcnt], wal->nextsector, flordist, ceildist, closest, vect->z);
|
|
}
|
|
|
|
if (j != 0)
|
|
{
|
|
j = getangle(wall[wal->point2].x-wal->x, wall[wal->point2].y-wal->y);
|
|
int32_t dx = (sintable[(j+1024)&2047]>>11);
|
|
int32_t dy = (sintable[(j+512)&2047]>>11);
|
|
int bad2 = 16;
|
|
do
|
|
{
|
|
vect->x = (vect->x) + dx; vect->y = (vect->y) + dy;
|
|
bad2--; if (bad2 == 0) break;
|
|
} while (clipinsidebox(&vect->vec2, i, walldist-4) != 0);
|
|
bad = -1;
|
|
k--; if (k <= 0) return bad;
|
|
clipupdatesector(vect->vec2, sectnum, walldist);
|
|
if (*sectnum < 0) return -1;
|
|
}
|
|
else if (bitmap_test(clipsectormap, wal->nextsector) == 0)
|
|
addclipsect(wal->nextsector);
|
|
}
|
|
|
|
clipsectcnt++;
|
|
} while (clipsectcnt < clipsectnum);
|
|
dir = -dir;
|
|
} while (bad != 0);
|
|
|
|
return bad;
|
|
}
|
|
|
|
//
|
|
// getzrange
|
|
//
|
|
void getzrange(const vec3_t *pos, int16_t sectnum,
|
|
int32_t *ceilz, int32_t *ceilhit, int32_t *florz, int32_t *florhit,
|
|
int32_t walldist, uint32_t cliptype)
|
|
{
|
|
if (sectnum < 0)
|
|
{
|
|
*ceilz = INT32_MIN; *ceilhit = -1;
|
|
*florz = INT32_MAX; *florhit = -1;
|
|
return;
|
|
}
|
|
|
|
int32_t clipsectcnt = 0;
|
|
|
|
#ifdef YAX_ENABLE
|
|
// YAX round, -1:center, 0:ceiling, 1:floor
|
|
int32_t mcf=-1;
|
|
#endif
|
|
|
|
uspriteptr_t curspr=NULL; // non-NULL when handling sprite with sector-like clipping
|
|
int32_t curidx=-1, clipspritecnt = 0;
|
|
|
|
//Extra walldist for sprites on sector lines
|
|
const int32_t extradist = walldist+MAXCLIPDIST+1;
|
|
const int32_t xmin = pos->x-extradist, ymin = pos->y-extradist;
|
|
const int32_t xmax = pos->x+extradist, ymax = pos->y+extradist;
|
|
|
|
const int32_t dawalclipmask = (cliptype&65535);
|
|
const int32_t dasprclipmask = (cliptype>>16);
|
|
|
|
vec2_t closest = { pos->x, pos->y };
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
|
|
getsectordist(closest, sectnum, &closest);
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829)
|
|
{
|
|
*ceilz = getceilzofslope_old(sectnum,closest.x,closest.y);
|
|
*florz = getflorzofslope_old(sectnum,closest.x,closest.y);
|
|
}
|
|
else
|
|
getzsofslope(sectnum,closest.x,closest.y,ceilz,florz);
|
|
*ceilhit = sectnum+16384; *florhit = sectnum+16384;
|
|
|
|
#ifdef YAX_ENABLE
|
|
origclipsectorlist[0] = sectnum;
|
|
origclipsectnum = 1;
|
|
#endif
|
|
clipsectorlist[0] = sectnum;
|
|
clipsectnum = 1;
|
|
clipspritenum = 0;
|
|
Bmemset(clipsectormap, 0, (numsectors+7)>>3);
|
|
bitmap_set(clipsectormap, sectnum);
|
|
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
if (0)
|
|
{
|
|
beginagain:
|
|
// replace sector and wall with clip map
|
|
engineSetClipMap(&origmapinfo, &clipmapinfo);
|
|
clipsectcnt = clipsectnum; // should be a nop, "safety"...
|
|
}
|
|
#endif
|
|
|
|
#ifdef YAX_ENABLE
|
|
restart_grand:
|
|
#endif
|
|
do //Collect sectors inside your square first
|
|
{
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
if (clipsectcnt>=clipsectnum)
|
|
{
|
|
// one set of clip-sprite sectors completed, prepare the next
|
|
|
|
curspr = (uspriteptr_t)&sprite[clipspritelist[clipspritecnt]];
|
|
curidx = clipshape_idx_for_sprite(curspr, curidx);
|
|
|
|
if (curidx < 0)
|
|
{
|
|
// didn't find matching clipping sectors for sprite
|
|
clipspritecnt++;
|
|
continue;
|
|
}
|
|
|
|
clipsprite_initindex(curidx, curspr, &clipsectcnt, pos);
|
|
|
|
for (bssize_t i=0; i<clipsectnum; i++)
|
|
{
|
|
int const k = clipsectorlist[i];
|
|
|
|
if (k==sectq[clipinfo[curidx].qend])
|
|
continue;
|
|
|
|
int32_t daz, daz2;
|
|
closest = { pos->x, pos->y };
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
|
|
getsectordist(closest, k, &closest);
|
|
getzsofslope(k,closest.x,closest.y,&daz,&daz2);
|
|
|
|
int32_t fz, cz;
|
|
closest = { pos->x, pos->y };
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
|
|
getsectordist(closest, sectq[clipinfo[curidx].qend], &closest);
|
|
getzsofslope(sectq[clipinfo[curidx].qend],closest.x,closest.y,&cz,&fz);
|
|
|
|
const int hitwhat = (curspr-(uspritetype *)sprite)+49152;
|
|
|
|
if ((sector[k].ceilingstat&1)==0)
|
|
{
|
|
if (pos->z < cz && cz < *florz) { *florz = cz; *florhit = hitwhat; }
|
|
if (pos->z > daz && daz > *ceilz) { *ceilz = daz; *ceilhit = hitwhat; }
|
|
}
|
|
if ((sector[k].floorstat&1)==0)
|
|
{
|
|
if (pos->z < daz2 && daz2 < *florz) { *florz = daz2; *florhit = hitwhat; }
|
|
if (pos->z > fz && fz > *ceilz) { *ceilz = fz; *ceilhit = hitwhat; }
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
////////// Walls //////////
|
|
|
|
auto const startsec = (usectorptr_t)§or[clipsectorlist[clipsectcnt]];
|
|
const int startwall = startsec->wallptr;
|
|
const int endwall = startwall + startsec->wallnum;
|
|
|
|
for (bssize_t j=startwall; j<endwall; j++)
|
|
{
|
|
const int k = wall[j].nextsector;
|
|
|
|
if (k >= 0)
|
|
{
|
|
vec2_t const v1 = wall[j].pos;
|
|
vec2_t const v2 = wall[wall[j].point2].pos;
|
|
|
|
if ((v1.x < xmin && (v2.x < xmin)) || (v1.x > xmax && v2.x > xmax) ||
|
|
(v1.y < ymin && (v2.y < ymin)) || (v1.y > ymax && v2.y > ymax))
|
|
continue;
|
|
|
|
vec2_t const d = { v2.x-v1.x, v2.y-v1.y };
|
|
if (d.x*(pos->y-v1.y) < (pos->x-v1.x)*d.y) continue; //back
|
|
|
|
vec2_t da = { (d.x > 0) ? d.x*(ymin-v1.y) : d.x*(ymax-v1.y),
|
|
(d.y > 0) ? d.y*(xmax-v1.x) : d.y*(xmin-v1.x) };
|
|
|
|
if (da.x >= da.y)
|
|
continue;
|
|
|
|
if (wall[j].cstat&dawalclipmask) continue; // XXX?
|
|
auto const sec = (usectorptr_t)§or[k];
|
|
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
if (curspr)
|
|
{
|
|
if (k==sectq[clipinfo[curidx].qend])
|
|
continue;
|
|
if ((sec->ceilingstat&1) && (sec->floorstat&1))
|
|
continue;
|
|
}
|
|
else
|
|
#endif
|
|
if (editstatus == 0)
|
|
{
|
|
if (((sec->ceilingstat&1) == 0) && (pos->z <= sec->ceilingz+(3<<8))) continue;
|
|
if (((sec->floorstat&1) == 0) && (pos->z >= sec->floorz-(3<<8))) continue;
|
|
}
|
|
|
|
if (bitmap_test(clipsectormap, k) == 0)
|
|
addclipsect(k);
|
|
|
|
if (((v1.x < xmin + MAXCLIPDIST) && (v2.x < xmin + MAXCLIPDIST)) ||
|
|
((v1.x > xmax - MAXCLIPDIST) && (v2.x > xmax - MAXCLIPDIST)) ||
|
|
((v1.y < ymin + MAXCLIPDIST) && (v2.y < ymin + MAXCLIPDIST)) ||
|
|
((v1.y > ymax - MAXCLIPDIST) && (v2.y > ymax - MAXCLIPDIST)))
|
|
continue;
|
|
|
|
if (d.x > 0) da.x += d.x*MAXCLIPDIST; else da.x -= d.x*MAXCLIPDIST;
|
|
if (d.y > 0) da.y -= d.y*MAXCLIPDIST; else da.y += d.y*MAXCLIPDIST;
|
|
if (da.x >= da.y)
|
|
continue;
|
|
#ifdef YAX_ENABLE
|
|
if (mcf==-1 && curspr==NULL)
|
|
origclipsectorlist[origclipsectnum++] = k;
|
|
#endif
|
|
//It actually got here, through all the continue's!!!
|
|
int32_t daz, daz2;
|
|
closest = { pos->x, pos->y };
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
|
|
getsectordist(closest, k, &closest);
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829)
|
|
{
|
|
daz = getceilzofslope_old(k, closest.x,closest.y);
|
|
daz2 = getflorzofslope_old(k, closest.x,closest.y);
|
|
}
|
|
else
|
|
getzsofslope(k, closest.x,closest.y, &daz,&daz2);
|
|
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
if (curspr)
|
|
{
|
|
int32_t fz,cz, hitwhat=(curspr-(uspritetype *)sprite)+49152;
|
|
|
|
closest = { pos->x, pos->y };
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
|
|
getsectordist(closest, sectq[clipinfo[curidx].qend], &closest);
|
|
getzsofslope(sectq[clipinfo[curidx].qend],closest.x,closest.y,&cz,&fz);
|
|
|
|
if ((sec->ceilingstat&1)==0)
|
|
{
|
|
if (pos->z < cz && cz < *florz) { *florz = cz; *florhit = hitwhat; }
|
|
if (pos->z > daz && daz > *ceilz) { *ceilz = daz; *ceilhit = hitwhat; }
|
|
}
|
|
if ((sec->floorstat&1)==0)
|
|
{
|
|
if (pos->z < daz2 && daz2 < *florz) { *florz = daz2; *florhit = hitwhat; }
|
|
if (pos->z > fz && fz > *ceilz) { *ceilz = fz; *ceilhit = hitwhat; }
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
#ifdef YAX_ENABLE
|
|
int16_t cb, fb;
|
|
yax_getbunches(k, &cb, &fb);
|
|
#endif
|
|
if (daz > *ceilz)
|
|
#ifdef YAX_ENABLE
|
|
if (mcf!=YAX_FLOOR && cb < 0)
|
|
#endif
|
|
*ceilz = daz, *ceilhit = k+16384;
|
|
|
|
if (daz2 < *florz)
|
|
#ifdef YAX_ENABLE
|
|
if (mcf!=YAX_CEILING && fb < 0)
|
|
#endif
|
|
*florz = daz2, *florhit = k+16384;
|
|
}
|
|
}
|
|
}
|
|
clipsectcnt++;
|
|
}
|
|
while (clipsectcnt < clipsectnum || clipspritecnt < clipspritenum);
|
|
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
if (curspr)
|
|
{
|
|
engineSetClipMap(NULL, &origmapinfo); // restore original map
|
|
clipsectnum = clipspritenum = 0; // skip the next for loop and check afterwards
|
|
}
|
|
#endif
|
|
|
|
////////// Sprites //////////
|
|
|
|
if (dasprclipmask)
|
|
for (bssize_t i=0; i<clipsectnum; i++)
|
|
{
|
|
for (bssize_t j=headspritesect[clipsectorlist[i]]; j>=0; j=nextspritesect[j])
|
|
{
|
|
const int32_t cstat = sprite[j].cstat;
|
|
int32_t daz, daz2;
|
|
|
|
if (cstat&dasprclipmask)
|
|
{
|
|
int32_t clipyou = 0;
|
|
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
if (clipsprite_try((uspriteptr_t)&sprite[j], xmin,ymin, xmax,ymax))
|
|
continue;
|
|
#endif
|
|
vec2_t v1 = sprite[j].pos.vec2;
|
|
|
|
switch (cstat & CSTAT_SPRITE_ALIGNMENT_MASK)
|
|
{
|
|
case CSTAT_SPRITE_ALIGNMENT_FACING:
|
|
{
|
|
int32_t k = walldist+(sprite[j].clipdist<<2)+1;
|
|
if ((klabs(v1.x-pos->x) <= k) && (klabs(v1.y-pos->y) <= k))
|
|
{
|
|
daz = sprite[j].z + spriteheightofs(j, &k, 1);
|
|
daz2 = daz - k;
|
|
clipyou = 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case CSTAT_SPRITE_ALIGNMENT_WALL:
|
|
{
|
|
vec2_t v2;
|
|
get_wallspr_points((uspriteptr_t)&sprite[j], &v1.x, &v2.x, &v1.y, &v2.y);
|
|
|
|
if (clipinsideboxline(pos->x,pos->y,v1.x,v1.y,v2.x,v2.y,walldist+1) != 0)
|
|
{
|
|
int32_t k;
|
|
daz = sprite[j].z + spriteheightofs(j, &k, 1);
|
|
daz2 = daz-k;
|
|
clipyou = 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case CSTAT_SPRITE_ALIGNMENT_FLOOR:
|
|
{
|
|
daz = sprite[j].z; daz2 = daz;
|
|
|
|
if ((cstat&64) != 0 && (pos->z > daz) == ((cstat&8)==0))
|
|
continue;
|
|
|
|
vec2_t v2, v3, v4;
|
|
get_floorspr_points((uspriteptr_t) &sprite[j], pos->x, pos->y, &v1.x, &v2.x, &v3.x, &v4.x,
|
|
&v1.y, &v2.y, &v3.y, &v4.y);
|
|
|
|
vec2_t const da = { mulscale14(sintable[(sprite[j].ang - 256 + 512) & 2047], walldist + 4),
|
|
mulscale14(sintable[(sprite[j].ang - 256) & 2047], walldist + 4) };
|
|
|
|
v1.x += da.x; v2.x -= da.y; v3.x -= da.x; v4.x += da.y;
|
|
v1.y += da.y; v2.y += da.x; v3.y -= da.y; v4.y -= da.x;
|
|
|
|
clipyou = get_floorspr_clipyou(v1, v2, v3, v4);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (clipyou != 0)
|
|
{
|
|
if ((pos->z > daz) && (daz > *ceilz
|
|
#ifdef YAX_ENABLE
|
|
|| (daz == *ceilz && yax_getbunch(clipsectorlist[i], YAX_CEILING)>=0)
|
|
#endif
|
|
))
|
|
{
|
|
*ceilz = daz;
|
|
*ceilhit = j+49152;
|
|
}
|
|
|
|
if ((pos->z < daz2) && (daz2 < *florz
|
|
#ifdef YAX_ENABLE
|
|
// can have a floor-sprite lying directly on the floor!
|
|
|| (daz2 == *florz && yax_getbunch(clipsectorlist[i], YAX_FLOOR)>=0)
|
|
#endif
|
|
))
|
|
{
|
|
*florz = daz2;
|
|
*florhit = j+49152;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
if (clipspritenum>0)
|
|
goto beginagain;
|
|
#endif
|
|
|
|
#ifdef YAX_ENABLE
|
|
if (numyaxbunches > 0)
|
|
{
|
|
int const dasecclipmask = yax_waltosecmask(dawalclipmask);
|
|
int16_t cb, fb;
|
|
|
|
yax_getbunches(sectnum, &cb, &fb);
|
|
|
|
mcf++;
|
|
clipsectcnt = 0; clipsectnum = 0;
|
|
|
|
int didchange = 0;
|
|
if (cb>=0 && mcf==0 && *ceilhit==sectnum+16384)
|
|
{
|
|
int i;
|
|
for (i=0; i<origclipsectnum; i++)
|
|
{
|
|
int const j = origclipsectorlist[i];
|
|
if (yax_getbunch(j, YAX_CEILING) >= 0)
|
|
if (sector[j].ceilingstat&dasecclipmask)
|
|
break;
|
|
}
|
|
|
|
if (i==origclipsectnum)
|
|
for (i=0; i<origclipsectnum; i++)
|
|
{
|
|
cb = yax_getbunch(origclipsectorlist[i], YAX_CEILING);
|
|
if (cb < 0)
|
|
continue;
|
|
|
|
for (bssize_t SECTORS_OF_BUNCH(cb,YAX_FLOOR, j))
|
|
if (inside(pos->x,pos->y, j)==1)
|
|
{
|
|
addclipsect(j);
|
|
|
|
closest = { pos->x, pos->y };
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
|
|
getsectordist(closest, j, &closest);
|
|
int const daz = getceilzofslope(j, closest.x, closest.y);
|
|
|
|
if (!didchange || daz > *ceilz)
|
|
didchange=1, *ceilhit = j+16384, *ceilz = daz;
|
|
}
|
|
}
|
|
|
|
if (clipsectnum==0)
|
|
mcf++;
|
|
}
|
|
else if (mcf==0)
|
|
mcf++;
|
|
|
|
didchange = 0;
|
|
if (fb>=0 && mcf==1 && *florhit==sectnum+16384)
|
|
{
|
|
int i=0;
|
|
for (; i<origclipsectnum; i++)
|
|
{
|
|
int const j = origclipsectorlist[i];
|
|
if (yax_getbunch(j, YAX_FLOOR) >= 0)
|
|
if (sector[j].floorstat&dasecclipmask)
|
|
break;
|
|
}
|
|
|
|
// (almost) same as above, but with floors...
|
|
if (i==origclipsectnum)
|
|
for (i=0; i<origclipsectnum; i++)
|
|
{
|
|
fb = yax_getbunch(origclipsectorlist[i], YAX_FLOOR);
|
|
if (fb < 0)
|
|
continue;
|
|
|
|
for (bssize_t SECTORS_OF_BUNCH(fb, YAX_CEILING, j))
|
|
if (inside(pos->x,pos->y, j)==1)
|
|
{
|
|
addclipsect(j);
|
|
|
|
closest = { pos->x, pos->y };
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
|
|
getsectordist(closest, j, &closest);
|
|
int const daz = getflorzofslope(j, closest.x,closest.y);
|
|
|
|
if (!didchange || daz < *florz)
|
|
didchange=1, *florhit = j+16384, *florz = daz;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (clipsectnum > 0)
|
|
{
|
|
// sector-like sprite re-init:
|
|
curidx = -1;
|
|
curspr = NULL;
|
|
clipspritecnt = 0; clipspritenum = 0;
|
|
|
|
goto restart_grand;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
// intp: point of currently best (closest) intersection
|
|
int32_t try_facespr_intersect(uspriteptr_t const spr, vec3_t const in,
|
|
int32_t vx, int32_t vy, int32_t vz,
|
|
vec3_t * const intp, int32_t strictly_smaller_than_p)
|
|
{
|
|
vec3_t const sprpos = spr->pos;
|
|
|
|
int32_t const topt = vx * (sprpos.x - in.x) + vy * (sprpos.y - in.y);
|
|
|
|
if (topt <= 0) return 0;
|
|
|
|
int32_t const bot = vx * vx + vy * vy;
|
|
|
|
if (!bot) return 0;
|
|
|
|
vec3_t newpos = { 0, 0, in.z + scale(vz, topt, bot) };
|
|
int32_t siz;
|
|
int32_t const z1 = sprpos.z + spriteheightofsptr(spr, &siz, 1);
|
|
|
|
if (newpos.z < z1 - siz || newpos.z > z1)
|
|
return 0;
|
|
|
|
int32_t const topu = vx * (sprpos.y - in.y) - vy * (sprpos.x - in.x);
|
|
vec2_t const off = { scale(vx, topu, bot), scale(vy, topu, bot) };
|
|
int32_t const dist = off.x * off.x + off.y * off.y;
|
|
|
|
siz = tilesiz[spr->picnum].x * spr->xrepeat;
|
|
|
|
if (dist > mulscale7(siz, siz)) return 0;
|
|
|
|
newpos.vec2 = { in.x + scale(vx, topt, bot), in.y + scale(vy, topt, bot) };
|
|
|
|
if (klabs(newpos.x - in.x) + klabs(newpos.y - in.y) + strictly_smaller_than_p >
|
|
klabs(intp->x - in.x) + klabs(intp->y - in.y))
|
|
return 0;
|
|
|
|
*intp = newpos;
|
|
return 1;
|
|
}
|
|
|
|
static inline void hit_set(hitdata_t *hit, int32_t sectnum, int32_t wallnum, int32_t spritenum,
|
|
int32_t x, int32_t y, int32_t z)
|
|
{
|
|
hit->sect = sectnum;
|
|
hit->wall = wallnum;
|
|
hit->sprite = spritenum;
|
|
hit->pos.x = x;
|
|
hit->pos.y = y;
|
|
hit->pos.z = z;
|
|
}
|
|
|
|
static int32_t hitscan_hitsectcf=-1;
|
|
|
|
// stat, heinum, z: either ceiling- or floor-
|
|
// how: -1: behave like ceiling, 1: behave like floor
|
|
static int32_t hitscan_trysector(const vec3_t *sv, usectorptr_t sec, hitdata_t *hit,
|
|
int32_t vx, int32_t vy, int32_t vz,
|
|
uint16_t stat, int16_t heinum, int32_t z, int32_t how, const intptr_t *tmp)
|
|
{
|
|
int32_t x1 = INT32_MAX, y1, z1;
|
|
int32_t i;
|
|
|
|
if (stat&2)
|
|
{
|
|
auto const wal = (uwallptr_t)&wall[sec->wallptr];
|
|
auto const wal2 = (uwallptr_t)&wall[wal->point2];
|
|
int32_t j, dax=wal2->x-wal->x, day=wal2->y-wal->y;
|
|
|
|
i = nsqrtasm(compat_maybe_truncate_to_int32(uhypsq(dax,day))); if (i == 0) return 1; //continue;
|
|
i = divscale15(heinum,i);
|
|
dax *= i; day *= i;
|
|
|
|
j = (vz<<8)-dmulscale15(dax,vy,-day,vx);
|
|
if (j != 0)
|
|
{
|
|
i = ((z - sv->z)<<8)+dmulscale15(dax,sv->y-wal->y,-day,sv->x-wal->x);
|
|
if (((i^j) >= 0) && ((klabs(i)>>1) < klabs(j)))
|
|
{
|
|
i = divscale30(i,j);
|
|
x1 = sv->x + mulscale30(vx,i);
|
|
y1 = sv->y + mulscale30(vy,i);
|
|
z1 = sv->z + mulscale30(vz,i);
|
|
}
|
|
}
|
|
}
|
|
else if ((how*vz > 0) && (how*sv->z <= how*z))
|
|
{
|
|
z1 = z; i = z1-sv->z;
|
|
if ((klabs(i)>>1) < vz*how)
|
|
{
|
|
i = divscale30(i,vz);
|
|
x1 = sv->x + mulscale30(vx,i);
|
|
y1 = sv->y + mulscale30(vy,i);
|
|
}
|
|
}
|
|
|
|
if ((x1 != INT32_MAX) && (klabs(x1-sv->x)+klabs(y1-sv->y) < klabs((hit->pos.x)-sv->x)+klabs((hit->pos.y)-sv->y)))
|
|
{
|
|
if (tmp==NULL)
|
|
{
|
|
if (inside(x1,y1,sec-(usectortype *)sector) == 1)
|
|
{
|
|
hit_set(hit, sec-(usectortype *)sector, -1, -1, x1, y1, z1);
|
|
hitscan_hitsectcf = (how+1)>>1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const int32_t curidx=(int32_t)tmp[0];
|
|
auto const curspr=(uspritetype *)tmp[1];
|
|
const int32_t thislastsec = tmp[2];
|
|
|
|
if (!thislastsec)
|
|
{
|
|
if (inside(x1,y1,sec-(usectortype *)sector) == 1)
|
|
hit_set(hit, curspr->sectnum, -1, curspr-(uspritetype *)sprite, x1, y1, z1);
|
|
}
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
else
|
|
{
|
|
for (i=clipinfo[curidx].qbeg; i<clipinfo[curidx].qend; i++)
|
|
{
|
|
if (inside(x1,y1,sectq[i]) == 1)
|
|
{
|
|
hit_set(hit, curspr->sectnum, -1, curspr-(uspritetype *)sprite, x1, y1, z1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// hitscan
|
|
//
|
|
int32_t hitscan(const vec3_t *sv, int16_t sectnum, int32_t vx, int32_t vy, int32_t vz,
|
|
hitdata_t *hit, uint32_t cliptype)
|
|
{
|
|
int32_t x1, y1=0, z1=0, x2, y2, intx, inty, intz;
|
|
int32_t i, k, daz;
|
|
int16_t tempshortcnt, tempshortnum;
|
|
|
|
uspriteptr_t curspr = NULL;
|
|
int32_t clipspritecnt, curidx=-1;
|
|
// tmp: { (int32_t)curidx, (spritetype *)curspr, (!=0 if outer sector) }
|
|
intptr_t tmp[3], *tmpptr=NULL;
|
|
#ifdef YAX_ENABLE
|
|
vec3_t newsv;
|
|
int32_t oldhitsect = -1, oldhitsect2 = -2;
|
|
#endif
|
|
const int32_t dawalclipmask = (cliptype&65535);
|
|
const int32_t dasprclipmask = (cliptype>>16);
|
|
|
|
hit->sect = -1; hit->wall = -1; hit->sprite = -1;
|
|
if (sectnum < 0)
|
|
return -1;
|
|
|
|
#ifdef YAX_ENABLE
|
|
restart_grand:
|
|
#endif
|
|
hit->pos.vec2 = hitscangoal;
|
|
|
|
clipsectorlist[0] = sectnum;
|
|
tempshortcnt = 0;
|
|
tempshortnum = 1;
|
|
clipspritecnt = clipspritenum = 0;
|
|
|
|
do
|
|
{
|
|
int32_t dasector, z, startwall, endwall;
|
|
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
if (tempshortcnt >= tempshortnum)
|
|
{
|
|
// one bunch of sectors completed, prepare the next
|
|
if (!curspr)
|
|
engineSetClipMap(&origmapinfo, &clipmapinfo); // replace sector and wall with clip map
|
|
|
|
curspr = (uspriteptr_t)&sprite[clipspritelist[clipspritecnt]];
|
|
curidx = clipshape_idx_for_sprite(curspr, curidx);
|
|
|
|
if (curidx < 0)
|
|
{
|
|
clipspritecnt++;
|
|
continue;
|
|
}
|
|
|
|
tmp[0] = (intptr_t)curidx;
|
|
tmp[1] = (intptr_t)curspr;
|
|
tmpptr = tmp;
|
|
|
|
clipsprite_initindex(curidx, curspr, &i, sv); // &i is dummy
|
|
tempshortnum = (int16_t)clipsectnum;
|
|
tempshortcnt = 0;
|
|
}
|
|
#endif
|
|
dasector = clipsectorlist[tempshortcnt];
|
|
auto const sec = (usectorptr_t)§or[dasector];
|
|
|
|
i = 1;
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
if (curspr)
|
|
{
|
|
if (dasector == sectq[clipinfo[curidx].qend])
|
|
{
|
|
i = -1;
|
|
tmp[2] = 1;
|
|
}
|
|
else tmp[2] = 0;
|
|
}
|
|
#endif
|
|
if (enginecompatibility_mode != ENGINECOMPATIBILITY_19950829)
|
|
{
|
|
if (hitscan_trysector(sv, sec, hit, vx,vy,vz, sec->ceilingstat, sec->ceilingheinum, sec->ceilingz, -i, tmpptr))
|
|
continue;
|
|
if (hitscan_trysector(sv, sec, hit, vx,vy,vz, sec->floorstat, sec->floorheinum, sec->floorz, i, tmpptr))
|
|
continue;
|
|
}
|
|
|
|
////////// Walls //////////
|
|
|
|
startwall = sec->wallptr; endwall = startwall + sec->wallnum;
|
|
for (z=startwall; z<endwall; z++)
|
|
{
|
|
auto const wal = (uwallptr_t)&wall[z];
|
|
auto const wal2 = (uwallptr_t)&wall[wal->point2];
|
|
|
|
int const nextsector = wal->nextsector;
|
|
|
|
if (curspr && nextsector<0) continue;
|
|
|
|
x1 = wal->x; y1 = wal->y; x2 = wal2->x; y2 = wal2->y;
|
|
|
|
if (compat_maybe_truncate_to_int32((coord_t)(x1-sv->x)*(y2-sv->y))
|
|
< compat_maybe_truncate_to_int32((coord_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) == -1) continue;
|
|
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829)
|
|
{
|
|
if (vz != 0)
|
|
if ((intz <= sec->ceilingz) || (intz >= sec->floorz))
|
|
if (klabs(intx-sv->x)+klabs(inty-sv->y) < klabs(hit->pos.x-sv->x)+klabs(hit->pos.y-sv->y))
|
|
{
|
|
//x1,y1,z1 are temp variables
|
|
if (vz > 0) z1 = sec->floorz; else z1 = sec->ceilingz;
|
|
x1 = sv->x + scale(z1-sv->z,vx,vz);
|
|
y1 = sv->y + scale(z1-sv->z,vy,vz);
|
|
if (inside(x1,y1,dasector) == 1)
|
|
{
|
|
hit_set(hit, dasector, -1, -1, x1, y1, z1);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else if (klabs(intx-sv->x)+klabs(inty-sv->y) >= klabs((hit->pos.x)-sv->x)+klabs((hit->pos.y)-sv->y))
|
|
continue;
|
|
|
|
if (!curspr)
|
|
{
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829)
|
|
{
|
|
if ((nextsector < 0) || (wal->cstat&dawalclipmask))
|
|
{
|
|
if ((klabs(intx-sv->x)+klabs(inty-sv->y) < klabs(hit->pos.x-sv->x)+klabs(hit->pos.y-sv->y)))
|
|
hit_set(hit, dasector, z, -1, intx, inty, intz);
|
|
continue;
|
|
}
|
|
|
|
if (intz <= sector[nextsector].ceilingz || intz >= sector[nextsector].floorz)
|
|
{
|
|
if ((klabs(intx-sv->x)+klabs(inty-sv->y) < klabs(hit->pos.x-sv->x)+klabs(hit->pos.y-sv->y)))
|
|
hit_set(hit, dasector, z, -1, intx, inty, intz);
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((nextsector < 0) || (wal->cstat&dawalclipmask))
|
|
{
|
|
hit_set(hit, dasector, z, -1, intx, inty, intz);
|
|
continue;
|
|
}
|
|
|
|
int32_t daz2;
|
|
getzsofslope(nextsector,intx,inty,&daz,&daz2);
|
|
if (intz <= daz || intz >= daz2)
|
|
{
|
|
hit_set(hit, dasector, z, -1, intx, inty, intz);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
else
|
|
{
|
|
if (wal->cstat&dawalclipmask)
|
|
{
|
|
hit_set(hit, curspr->sectnum, -1, curspr-(uspritetype *)sprite, intx, inty, intz);
|
|
continue;
|
|
}
|
|
|
|
int32_t cz, fz, daz2;
|
|
getzsofslope(nextsector,intx,inty,&daz,&daz2);
|
|
getzsofslope(sectq[clipinfo[curidx].qend],intx,inty,&cz,&fz);
|
|
// ceil cz daz daz2 fz floor
|
|
if ((cz <= intz && intz <= daz) || (daz2 <= intz && intz <= fz))
|
|
{
|
|
hit_set(hit, curspr->sectnum, -1, curspr-(uspritetype *)sprite, intx, inty, intz);
|
|
continue;
|
|
}
|
|
}
|
|
#endif
|
|
int zz;
|
|
for (zz = tempshortnum - 1; zz >= 0; zz--)
|
|
if (clipsectorlist[zz] == nextsector) break;
|
|
if (zz < 0) clipsectorlist[tempshortnum++] = nextsector;
|
|
}
|
|
|
|
////////// Sprites //////////
|
|
|
|
if (dasprclipmask==0)
|
|
continue;
|
|
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
if (curspr)
|
|
continue;
|
|
#endif
|
|
for (z=headspritesect[dasector]; z>=0; z=nextspritesect[z])
|
|
{
|
|
auto const spr = (uspriteptr_t)&sprite[z];
|
|
uint32_t const cstat = spr->cstat;
|
|
#ifdef USE_OPENGL
|
|
if (!hitallsprites)
|
|
#endif
|
|
if ((cstat&dasprclipmask) == 0)
|
|
continue;
|
|
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
// try and see whether this sprite's picnum has sector-like clipping data
|
|
i = pictoidx[spr->picnum];
|
|
// handle sector-like floor sprites separately
|
|
while (i>=0 && (cstat&32) != (clipmapinfo.sector[sectq[clipinfo[i].qbeg]].CM_CSTAT&32))
|
|
i = clipinfo[i].next;
|
|
if (i>=0 && clipspritenum<MAXCLIPNUM)
|
|
{
|
|
clipspritelist[clipspritenum++] = z;
|
|
continue;
|
|
}
|
|
#endif
|
|
x1 = spr->x; y1 = spr->y; z1 = spr->z;
|
|
switch (cstat&CSTAT_SPRITE_ALIGNMENT)
|
|
{
|
|
case 0:
|
|
{
|
|
if (try_facespr_intersect(spr, *sv, vx, vy, vz, &hit->pos, 0))
|
|
{
|
|
hit->sect = dasector;
|
|
hit->wall = -1;
|
|
hit->sprite = z;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case CSTAT_SPRITE_ALIGNMENT_WALL:
|
|
{
|
|
int32_t ucoefup16;
|
|
int32_t tilenum = spr->picnum;
|
|
|
|
get_wallspr_points(spr, &x1, &x2, &y1, &y2);
|
|
|
|
if ((cstat&64) != 0) //back side of 1-way sprite
|
|
if (compat_maybe_truncate_to_int32((coord_t)(x1-sv->x)*(y2-sv->y))
|
|
< compat_maybe_truncate_to_int32((coord_t)(x2-sv->x)*(y1-sv->y))) 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;
|
|
|
|
daz = spr->z + spriteheightofs(z, &k, 1);
|
|
if (intz > daz-k && intz < daz)
|
|
{
|
|
if (picanm[tilenum].sf&PICANM_TEXHITSCAN_BIT)
|
|
{
|
|
tileUpdatePicnum(&tilenum, 0);
|
|
|
|
if (tileLoad(tilenum))
|
|
{
|
|
// daz-intz > 0 && daz-intz < k
|
|
int32_t xtex = mulscale16(ucoefup16, tilesiz[tilenum].x);
|
|
int32_t vcoefup16 = 65536-divscale16(daz-intz, k);
|
|
int32_t ytex = mulscale16(vcoefup16, tilesiz[tilenum].y);
|
|
|
|
auto texel = (tilePtr(tilenum) + tilesiz[tilenum].y*xtex + ytex);
|
|
if (*texel == 255)
|
|
continue;
|
|
}
|
|
}
|
|
|
|
hit_set(hit, dasector, -1, z, intx, inty, intz);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case CSTAT_SPRITE_ALIGNMENT_FLOOR:
|
|
{
|
|
int32_t x3, y3, x4, y4, zz;
|
|
intz = z1;
|
|
|
|
if (vz == 0 || ((intz-sv->z)^vz) < 0) continue;
|
|
|
|
if ((cstat&64) != 0)
|
|
if ((sv->z > intz) == ((cstat&8)==0)) continue;
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
|
|
{
|
|
// Abyss crash prevention code ((intz-sv->z)*zx overflowing a 8-bit word)
|
|
// PK: the reason for the crash is not the overflowing (even if it IS a problem;
|
|
// signed overflow is undefined behavior in C), but rather the idiv trap when
|
|
// the resulting quotient doesn't fit into a *signed* 32-bit integer.
|
|
zz = (uint32_t)(intz-sv->z) * vx;
|
|
intx = sv->x+scale(zz,1,vz);
|
|
zz = (uint32_t)(intz-sv->z) * vy;
|
|
inty = sv->y+scale(zz,1,vz);
|
|
}
|
|
else
|
|
{
|
|
intx = sv->x+scale(intz-sv->z,vx,vz);
|
|
inty = sv->y+scale(intz-sv->z,vy,vz);
|
|
}
|
|
|
|
if (klabs(intx-sv->x)+klabs(inty-sv->y) > klabs((hit->pos.x)-sv->x)+klabs((hit->pos.y)-sv->y))
|
|
continue;
|
|
|
|
get_floorspr_points((uspriteptr_t)spr, intx, inty, &x1, &x2, &x3, &x4,
|
|
&y1, &y2, &y3, &y4);
|
|
|
|
if (get_floorspr_clipyou({x1, y1}, {x2, y2}, {x3, y3}, {x4, y4}))
|
|
hit_set(hit, dasector, -1, z, intx, inty, intz);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while (++tempshortcnt < tempshortnum || clipspritecnt < clipspritenum);
|
|
|
|
#ifdef HAVE_CLIPSHAPE_FEATURE
|
|
if (curspr)
|
|
engineSetClipMap(NULL, &origmapinfo);
|
|
#endif
|
|
|
|
#ifdef YAX_ENABLE
|
|
if (numyaxbunches == 0 || editstatus)
|
|
return 0;
|
|
|
|
if (hit->sprite==-1 && hit->wall==-1 && hit->sect!=oldhitsect
|
|
&& hit->sect != oldhitsect2) // 'ping-pong' infloop protection
|
|
{
|
|
if (hit->sect == -1 && oldhitsect >= 0)
|
|
{
|
|
// this is bad: we didn't hit anything after going through a ceiling/floor
|
|
Bmemcpy(&hit->pos, &newsv, sizeof(vec3_t));
|
|
hit->sect = oldhitsect;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 1st, 2nd, ... ceil/floor hit
|
|
// hit->sect is >=0 because if oldhitsect's init and check above
|
|
if (SECTORFLD(hit->sect,stat, hitscan_hitsectcf)&yax_waltosecmask(dawalclipmask))
|
|
return 0;
|
|
|
|
i = yax_getneighborsect(hit->pos.x, hit->pos.y, hit->sect, hitscan_hitsectcf);
|
|
if (i >= 0)
|
|
{
|
|
Bmemcpy(&newsv, &hit->pos, sizeof(vec3_t));
|
|
sectnum = i;
|
|
sv = &newsv;
|
|
|
|
oldhitsect2 = oldhitsect;
|
|
oldhitsect = hit->sect;
|
|
hit->sect = -1;
|
|
|
|
// sector-like sprite re-init:
|
|
curspr = 0;
|
|
curidx = -1;
|
|
tmpptr = NULL;
|
|
|
|
goto restart_grand;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|