Commit f9952017 authored by Richard Gobeille's avatar Richard Gobeille
Browse files

engine: improvements to the updatesector family of functions

Implements the concept outlined in MR 114 and adds some additional checks to prevent more calls to getsectordist() than necessary
parent 785390e9
......@@ -1683,7 +1683,27 @@ static FORCE_INLINE void renderEnableFog(void)
#endif
}
static FORCE_INLINE CONSTEXPR int inside_p(int32_t const x, int32_t const y, int const sectnum) { return (sectnum >= 0 && inside(x, y, sectnum) == 1); }
/* Different "is inside" predicates.
* NOTE: The redundant bound checks are expected to be optimized away in the
* inlined code. */
static FORCE_INLINE CONSTEXPR int inside_p(int32_t const x, int32_t const y, int const sectnum)
{
return ((unsigned)sectnum < MAXSECTORS && inside(x, y, sectnum) == 1);
}
static FORCE_INLINE CONSTEXPR int inside_exclude_p(int32_t const x, int32_t const y, int const sectnum, const uint8_t *excludesectbitmap)
{
return ((unsigned)sectnum < MAXSECTORS && !bitmap_test(excludesectbitmap, sectnum) && inside_p(x, y, sectnum));
}
/* NOTE: no bound check for inside_z_p */
static FORCE_INLINE int inside_z_p(int32_t const x, int32_t const y, int32_t const z, int const sectnum)
{
int32_t cz, fz;
getzsofslope(sectnum, x, y, &cz, &fz);
return (z >= cz && z <= fz && inside_p(x, y, sectnum));
}
#define SET_AND_RETURN(Lval, Rval) \
do \
......
......@@ -12317,23 +12317,6 @@ int32_t lastwall(int16_t point)
////////// UPDATESECTOR* FAMILY OF FUNCTIONS //////////
/* Different "is inside" predicates.
* NOTE: The redundant bound checks are expected to be optimized away in the
* inlined code. */
static FORCE_INLINE CONSTEXPR int inside_exclude_p(int32_t const x, int32_t const y, int const sectnum, const uint8_t *excludesectbitmap)
{
return (sectnum>=0 && !bitmap_test(excludesectbitmap, sectnum) && inside_p(x, y, sectnum));
}
/* NOTE: no bound check */
static inline int inside_z_p(int32_t const x, int32_t const y, int32_t const z, int const sectnum)
{
int32_t cz, fz;
getzsofslope(sectnum, x, y, &cz, &fz);
return (z >= cz && z <= fz && inside_p(x, y, sectnum));
}
int32_t getwalldist(vec2_t const in, int const wallnum)
{
vec2_t closest;
......@@ -12401,36 +12384,27 @@ int findwallbetweensectors(int sect1, int sect2)
//
// updatesector[z]
//
void updatesector(int32_t const x, int32_t const y, int16_t * const sectnum)
int16_t updatesectorneighborlist[MAXSECTORS];
uint8_t updatesectorneighbormap[(MAXSECTORS+7)>>3];
void updatesector_compat(int32_t const x, int32_t const y, int16_t* const sectnum)
{
MICROPROFILE_SCOPEI("Engine", EDUKE32_FUNCTION, MP_AUTO);
if (inside_p(x, y, *sectnum))
return;
if (enginecompatibilitymode == ENGINE_EDUKE32)
{
int16_t sect = *sectnum;
updatesectorneighbor(x, y, &sect, INITIALUPDATESECTORDIST, MAXUPDATESECTORDIST);
if (sect != -1)
SET_AND_RETURN(*sectnum, sect);
}
else
if ((unsigned) *sectnum < (unsigned) numsectors)
{
if (inside_p(x, y, *sectnum))
return;
const uwalltype* wal = (uwalltype*) &wall[sector[*sectnum].wallptr];
int wallsleft = sector[*sectnum].wallnum;
if ((unsigned)*sectnum < (unsigned)numsectors)
do
{
const uwalltype *wal = (uwalltype *)&wall[sector[*sectnum].wallptr];
int wallsleft = sector[*sectnum].wallnum;
do
{
int const next = wal->nextsector;
if (inside_p(x, y, next))
int const next = wal->nextsector;
if (inside_p(x, y, next))
SET_AND_RETURN(*sectnum, next);
wal++;
}
while (--wallsleft);
}
while (--wallsleft);
}
// we need to support passing in a sectnum of -1, unfortunately
......@@ -12442,6 +12416,49 @@ void updatesector(int32_t const x, int32_t const y, int16_t * const sectnum)
*sectnum = -1;
}
void updatesector_tryremaining(int32_t const x, int32_t const y, int16_t *const sectnum)
{
// we need to support passing in a sectnum of -1, unfortunately
int16_t const sect = *sectnum == -1 ? numsectors >> 1 : *sectnum;
int trycnt = max<int>(numsectors - sect, sect);
// re-use the bitmap generated by updatesectorneighbor[z]
// since these sectors were already checked there, there's
// no need to check them again.
if (inside_exclude_p(x, y, sect, updatesectorneighbormap))
SET_AND_RETURN(*sectnum, sect);
int16_t highsect = sect, lowsect = sect;
do
{
if (++highsect < numsectors && inside_exclude_p(x, y, highsect, updatesectorneighbormap))
SET_AND_RETURN(*sectnum, highsect);
if (--lowsect >= 0 && inside_exclude_p(x, y, lowsect, updatesectorneighbormap))
SET_AND_RETURN(*sectnum, lowsect);
} while (trycnt--);
*sectnum = -1;
}
void updatesector(int32_t const x, int32_t const y, int16_t* const sectnum)
{
MICROPROFILE_SCOPEI("Engine", EDUKE32_FUNCTION, MP_AUTO);
if (enginecompatibilitymode != ENGINE_EDUKE32)
{
updatesector_compat(x, y, sectnum);
return;
}
int16_t sect = *sectnum;
updatesectorneighbor(x, y, &sect, INITIALUPDATESECTORDIST, MAXUPDATESECTORDIST);
if (sect != -1)
SET_AND_RETURN(*sectnum, sect);
updatesector_tryremaining(x, y, sectnum);
}
void updatesectorexclude(int32_t const x, int32_t const y, int16_t * const sectnum, const uint8_t * const excludesectbitmap)
{
if (inside_exclude_p(x, y, *sectnum, excludesectbitmap))
......@@ -12469,87 +12486,71 @@ void updatesectorexclude(int32_t const x, int32_t const y, int16_t * const sectn
*sectnum = -1;
}
// new: if *sectnum >= MAXSECTORS, *sectnum-=MAXSECTORS is considered instead
// as starting sector and the 'initial' z check is skipped
// (not initial anymore because it follows the sector updating due to TROR)
void updatesectorz(int32_t const x, int32_t const y, int32_t const z, int16_t * const sectnum)
void updatesectorz_compat(int32_t const x, int32_t const y, int32_t const z, int16_t * const sectnum)
{
MICROPROFILE_SCOPEI("Engine", EDUKE32_FUNCTION, MP_AUTO);
if (enginecompatibilitymode == ENGINE_EDUKE32)
{
int16_t sect = *sectnum;
updatesectorneighborz(x, y, z, &sect, INITIALUPDATESECTORDIST, MAXUPDATESECTORDIST);
if (sect != -1)
SET_AND_RETURN(*sectnum, sect);
}
else
if ((uint32_t) (*sectnum) < 2*MAXSECTORS)
{
if ((uint32_t)(*sectnum) < 2*MAXSECTORS)
{
int32_t nofirstzcheck = 0;
int32_t nofirstzcheck = 0;
if (*sectnum >= MAXSECTORS)
{
*sectnum -= MAXSECTORS;
nofirstzcheck = 1;
}
if (*sectnum >= MAXSECTORS)
{
*sectnum -= MAXSECTORS;
nofirstzcheck = 1;
}
#ifdef YAX_ENABLE
int mcf = -1;
restart:
int mcf = -1;
restart:
#endif
// this block used to be outside the "if" and caused crashes in Polymost Mapster32
int32_t cz, fz;
getzsofslope(*sectnum, x, y, &cz, &fz);
// this block used to be outside the "if" and caused crashes in Polymost Mapster32
int32_t cz, fz;
getzsofslope(*sectnum, x, y, &cz, &fz);
#ifdef YAX_ENABLE
if ((mcf == -1 || mcf == YAX_CEILING) && z < cz)
if ((mcf == -1 || mcf == YAX_CEILING) && z < cz)
{
int const next = yax_getneighborsect(x, y, *sectnum, YAX_CEILING);
if (next >= 0)
{
int const next = yax_getneighborsect(x, y, *sectnum, YAX_CEILING);
if (next >= 0)
{
if (z >= getceilzofslope(next, x, y))
SET_AND_RETURN(*sectnum, next);
if (z >= getceilzofslope(next, x, y))
SET_AND_RETURN(*sectnum, next);
*sectnum = next;
mcf = YAX_CEILING;
goto restart;
}
*sectnum = next;
mcf = YAX_CEILING;
goto restart;
}
}
if ((mcf == -1 || mcf == YAX_FLOOR) && z > fz)
if ((mcf == -1 || mcf == YAX_FLOOR) && z > fz)
{
int const next = yax_getneighborsect(x, y, *sectnum, YAX_FLOOR);
if (next >= 0)
{
int const next = yax_getneighborsect(x, y, *sectnum, YAX_FLOOR);
if (next >= 0)
{
if (z <= getflorzofslope(next, x, y))
SET_AND_RETURN(*sectnum, next);
if (z <= getflorzofslope(next, x, y))
SET_AND_RETURN(*sectnum, next);
*sectnum = next;
mcf = YAX_FLOOR;
goto restart;
}
*sectnum = next;
mcf = YAX_FLOOR;
goto restart;
}
}
#endif
if (nofirstzcheck || (z >= cz && z <= fz))
if (inside_p(x, y, *sectnum))
return;
if (nofirstzcheck || (z >= cz && z <= fz))
if (inside_p(x, y, *sectnum))
return;
uwalltype const * wal = (uwalltype *)&wall[sector[*sectnum].wallptr];
int wallsleft = sector[*sectnum].wallnum;
do
{
// YAX: TODO: check neighboring sectors here too?
int const next = wal->nextsector;
if (next>=0 && inside_z_p(x,y,z, next))
SET_AND_RETURN(*sectnum, next);
uwalltype const* wal = (uwalltype*) &wall[sector[*sectnum].wallptr];
int wallsleft = sector[*sectnum].wallnum;
do
{
// YAX: TODO: check neighboring sectors here too?
int const next = wal->nextsector;
if (next>=0 && inside_z_p(x, y, z, next))
SET_AND_RETURN(*sectnum, next);
wal++;
}
while (--wallsleft);
wal++;
}
while (--wallsleft);
}
// we need to support passing in a sectnum of -1, unfortunately
......@@ -12560,39 +12561,65 @@ restart:
*sectnum = -1;
}
// new: if *sectnum >= MAXSECTORS, *sectnum-=MAXSECTORS is considered instead
// as starting sector and the 'initial' z check is skipped
// (not initial anymore because it follows the sector updating due to TROR)
void updatesectorz(int32_t const x, int32_t const y, int32_t const z, int16_t * const sectnum)
{
MICROPROFILE_SCOPEI("Engine", EDUKE32_FUNCTION, MP_AUTO);
if (enginecompatibilitymode != ENGINE_EDUKE32)
{
updatesectorz_compat(x, y, z, sectnum);
return;
}
int16_t sect = *sectnum;
updatesectorneighborz(x, y, z, &sect, INITIALUPDATESECTORDIST, MAXUPDATESECTORDIST);
if (sect != -1)
SET_AND_RETURN(*sectnum, sect);
updatesector_tryremaining(x, y, sectnum);
}
void updatesectorneighbor(int32_t const x, int32_t const y, int16_t * const sectnum, int32_t initialMaxDistance /*= INITIALUPDATESECTORDIST*/, int32_t maxDistance /*= MAXUPDATESECTORDIST*/)
{
int const initialsectnum = *sectnum;
if ((unsigned)initialsectnum < (unsigned)numsectors && getsectordist({x, y}, initialsectnum) <= initialMaxDistance)
if ((unsigned)initialsectnum < (unsigned)numsectors)
{
if (inside_p(x, y, initialsectnum))
return;
static int16_t sectlist[MAXSECTORS];
static uint8_t sectbitmap[(MAXSECTORS+7)>>3];
int16_t nsecs;
bfirst_search_init(updatesectorneighborlist, updatesectorneighbormap, &nsecs, MAXSECTORS, initialsectnum);
bfirst_search_init(sectlist, sectbitmap, &nsecs, MAXSECTORS, initialsectnum);
int32_t const initialDistance = getsectordist({x, y}, initialsectnum);
for (int sectcnt=0; sectcnt<nsecs; sectcnt++)
// initialDistance == 0 means the point passed to getsectordist was inside the passed sectnum
if (initialDistance == 0)
return;
else if (initialDistance <= initialMaxDistance)
{
int const listsectnum = sectlist[sectcnt];
for (int sectcnt = 0; sectcnt < nsecs; sectcnt++)
{
int const listsectnum = updatesectorneighborlist[sectcnt];
if (inside_p(x, y, listsectnum))
SET_AND_RETURN(*sectnum, listsectnum);
if (inside_p(x, y, listsectnum))
SET_AND_RETURN(*sectnum, listsectnum);
auto const sec = &sector[listsectnum];
int const startwall = sec->wallptr;
int const endwall = sec->wallptr + sec->wallnum;
auto uwal = (uwallptr_t)&wall[startwall];
auto const sec = &sector[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 && getsectordist({x, y}, uwal->nextsector) <= maxDistance)
bfirst_search_try(sectlist, sectbitmap, &nsecs, uwal->nextsector);
for (int j = startwall; j < endwall; j++, uwal++)
if (uwal->nextsector >= 0 && !bitmap_test(updatesectorneighbormap, uwal->nextsector) && getsectordist({ x, y }, uwal->nextsector) <= maxDistance)
bfirst_search_try(updatesectorneighborlist, updatesectorneighbormap, &nsecs, uwal->nextsector);
}
}
}
Bmemset(updatesectorneighbormap, 0, (MAXSECTORS+7)>>3);
*sectnum = -1;
}
......@@ -12611,67 +12638,68 @@ void updatesectorneighborz(int32_t const x, int32_t const y, int32_t const z, in
restart:
#endif
uint32_t const correctedsectnum = (unsigned)*sectnum;
if (correctedsectnum < (unsigned)numsectors && getsectordist({x, y}, correctedsectnum) <= initialMaxDistance)
{
int32_t cz, fz;
getzsofslope(correctedsectnum, x, y, &cz, &fz);
if (correctedsectnum < (unsigned)numsectors)
{
int16_t nsecs;
bfirst_search_init(updatesectorneighborlist, updatesectorneighbormap, &nsecs, MAXSECTORS, correctedsectnum);
#ifdef YAX_ENABLE
if ((mcf == -1 || mcf == YAX_CEILING) && z < cz)
if (getsectordist({x, y}, correctedsectnum) <= initialMaxDistance)
{
int const next = yax_getneighborsect(x, y, correctedsectnum, YAX_CEILING);
if (next >= 0)
int32_t cz, fz;
getzsofslope(correctedsectnum, x, y, &cz, &fz);
#ifdef YAX_ENABLE
if ((mcf == -1 || mcf == YAX_CEILING) && z < cz)
{
if (z >= getceilzofslope(next, x, y))
SET_AND_RETURN(*sectnum, next);
int const next = yax_getneighborsect(x, y, correctedsectnum, YAX_CEILING);
if (next >= 0)
{
if (z >= getceilzofslope(next, x, y))
SET_AND_RETURN(*sectnum, next);
*sectnum = next;
mcf = YAX_CEILING;
goto restart;
*sectnum = next;
mcf = YAX_CEILING;
goto restart;
}
}
}
if ((mcf == -1 || mcf == YAX_FLOOR) && z > fz)
{
int const next = yax_getneighborsect(x, y, correctedsectnum, YAX_FLOOR);
if (next >= 0)
if ((mcf == -1 || mcf == YAX_FLOOR) && z > fz)
{
if (z <= getflorzofslope(next, x, y))
SET_AND_RETURN(*sectnum, next);
int const next = yax_getneighborsect(x, y, correctedsectnum, YAX_FLOOR);
if (next >= 0)
{
if (z <= getflorzofslope(next, x, y))
SET_AND_RETURN(*sectnum, next);
*sectnum = next;
mcf = YAX_FLOOR;
goto restart;
*sectnum = next;
mcf = YAX_FLOOR;
goto restart;
}
}
}
#endif
if ((nofirstzcheck || (z >= cz && z <= fz)) && inside_p(x, y, *sectnum))
return;
static int16_t sectlist[MAXSECTORS];
static uint8_t sectbitmap[(MAXSECTORS+7)>>3];
int16_t nsecs;
bfirst_search_init(sectlist, sectbitmap, &nsecs, MAXSECTORS, correctedsectnum);
if ((nofirstzcheck || (z >= cz && z <= fz)) && inside_p(x, y, *sectnum))
return;
for (int sectcnt=0; sectcnt<nsecs; sectcnt++)
{
int const listsectnum = sectlist[sectcnt];
for (int sectcnt=0; sectcnt<nsecs; sectcnt++)
{
int const listsectnum = updatesectorneighborlist[sectcnt];
if (inside_z_p(x, y, z, listsectnum))
SET_AND_RETURN(*sectnum, listsectnum);
if (inside_z_p(x, y, z, listsectnum))
SET_AND_RETURN(*sectnum, listsectnum);
auto const sec = &sector[listsectnum];
int const startwall = sec->wallptr;
int const endwall = sec->wallptr + sec->wallnum;
auto uwal = (uwallptr_t)&wall[startwall];
auto const sec = &sector[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 && getsectordist({x, y}, uwal->nextsector) <= maxDistance)
bfirst_search_try(sectlist, sectbitmap, &nsecs, uwal->nextsector);
for (int j=startwall; j<endwall; j++, uwal++)
if (uwal->nextsector >= 0 && !bitmap_test(updatesectorneighbormap, uwal->nextsector) && getsectordist({x, y}, uwal->nextsector) <= maxDistance)
bfirst_search_try(updatesectorneighborlist, updatesectorneighbormap, &nsecs, uwal->nextsector);
}
}
}
Bmemset(updatesectorneighbormap, 0, (MAXSECTORS+7)>>3);
*sectnum = -1;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment