Duke3d: optimize A_RadiusDamage()

This results in far fewer calls to getwalldist(), inside(), and cansee(), which should significantly lessen the performance hit from a large number of A_RadiusDamage() calls in areas with many small detail sectors.

# Conflicts:
#	source/duke3d/src/actors.cpp
This commit is contained in:
Richard C. Gobeille 2020-05-30 01:34:23 -07:00 committed by Christoph Oelckers
parent b15cc31a38
commit 91d9883845

View file

@ -272,44 +272,52 @@ void A_RadiusDamage(int const spriteNum, int const blastRadius, int const dmg1,
auto const pSprite = (uspriteptr_t)&sprite[spriteNum]; auto const pSprite = (uspriteptr_t)&sprite[spriteNum];
int16_t sectorList[MAXDAMAGESECTORS]; int16_t numSectors, sectorList[MAXDAMAGESECTORS];
uint8_t sectorMap[(MAXSECTORS+7)>>3]; uint8_t * const sectorMap = (uint8_t *)Balloca((numsectors+7)>>3);
int16_t numSectors; bfirst_search_init(sectorList, sectorMap, &numSectors, numsectors, pSprite->sectnum);
bfirst_search_init(sectorList, sectorMap, &numSectors, MAXSECTORS, pSprite->sectnum);
#ifndef EDUKE32_STANDALONE #ifndef EDUKE32_STANDALONE
// rockets from the Devastator skip propagating damage to other sectors
if (!FURY && (pSprite->picnum == RPG && pSprite->xrepeat < 11)) if (!FURY && (pSprite->picnum == RPG && pSprite->xrepeat < 11))
goto SKIPWALLCHECK; goto wallsfinished;
#endif #endif
uint8_t *wallTouched;
wallTouched = (uint8_t *)Balloca((numwalls+7)>>3);
Bmemset(wallTouched, 0, (numwalls+7)>>3);
uint8_t *wallCanSee;
wallCanSee = (uint8_t *)Balloca((numwalls+7)>>3);
Bmemset(wallCanSee, 0, (numwalls+7)>>3);
for (int sectorCount=0; sectorCount < numSectors; ++sectorCount) for (int sectorCount=0; sectorCount < numSectors; ++sectorCount)
{ {
int const sectorNum = sectorList[sectorCount]; int const sectorNum = sectorList[sectorCount];
auto const &listSector = sector[sectorNum]; auto const &listSector = sector[sectorNum];
vec2_t closest;
if (getsectordist(pSprite->pos.vec2, sectorNum, &closest) >= blastRadius) vec2_t closest = {};
continue; int32_t distance = INT32_MAX;
int const startWall = listSector.wallptr; int const startWall = listSector.wallptr;
int const endWall = listSector.wallnum + startWall; int const endWall = listSector.wallnum + startWall;
int32_t floorZ, ceilZ;
getzsofslope(sectorNum, closest.x, closest.y, &ceilZ, &floorZ);
if (((ceilZ - pSprite->z) >> 8) < blastRadius)
Sect_DamageCeiling_Internal(spriteNum, sectorNum);
if (((pSprite->z - floorZ) >> 8) < blastRadius)
Sect_DamageFloor_Internal(spriteNum, sectorNum);
int w = startWall; int w = startWall;
for (auto pWall = (uwallptr_t)&wall[startWall]; w < endWall; ++w, ++pWall) for (auto pWall = (uwallptr_t)&wall[startWall]; w < endWall; ++w, ++pWall)
{ {
if (getwalldist(pSprite->pos.vec2, w, &closest) >= blastRadius) vec2_t p = pSprite->pos.vec2;
continue; int32_t walldist = blastRadius - 1;
if (bitmap_test(wallTouched, w) == 0)
walldist = getwalldist(p, w, &p);
if (walldist < blastRadius)
{
if (walldist < distance)
{
distance = walldist;
closest = p;
}
int16_t aSector = sectorNum; int16_t aSector = sectorNum;
vec3_t vect = { (((pWall->x + wall[pWall->point2].x) >> 1) + pSprite->x) >> 1, vec3_t vect = { (((pWall->x + wall[pWall->point2].x) >> 1) + pSprite->x) >> 1,
@ -319,12 +327,24 @@ void A_RadiusDamage(int const spriteNum, int const blastRadius, int const dmg1,
if (aSector == -1) if (aSector == -1)
{ {
vect.vec2 = closest; vect.vec2 = p;
aSector = sectorNum; aSector = sectorNum;
} }
if (cansee(vect.x, vect.y, vect.z, aSector, pSprite->x, pSprite->y, pSprite->z, pSprite->sectnum)) bitmap_set(wallTouched, w);
A_DamageWall_Internal(spriteNum, w, { closest.x, closest.y, pSprite->z }, pSprite->picnum);
if (pWall->nextwall != -1)
bitmap_set(wallTouched, pWall->nextwall);
if (bitmap_test(wallCanSee, w) == 1 || cansee(vect.x, vect.y, vect.z, aSector, pSprite->x, pSprite->y, pSprite->z, pSprite->sectnum))
{
bitmap_set(wallCanSee, w);
if (pWall->nextwall != -1)
bitmap_set(wallCanSee, pWall->nextwall);
A_DamageWall_Internal(spriteNum, w, { p.x, p.y, pSprite->z }, pSprite->picnum);
}
int const nextSector = pWall->nextsector; int const nextSector = pWall->nextsector;
@ -334,12 +354,25 @@ void A_RadiusDamage(int const spriteNum, int const blastRadius, int const dmg1,
if (numSectors == MAXDAMAGESECTORS) if (numSectors == MAXDAMAGESECTORS)
{ {
Printf("Sprite %d tried to damage more than %d sectors!\n", spriteNum, MAXDAMAGESECTORS); Printf("Sprite %d tried to damage more than %d sectors!\n", spriteNum, MAXDAMAGESECTORS);
goto SKIPWALLCHECK; goto wallsfinished;
} }
} }
} }
SKIPWALLCHECK: if (distance >= blastRadius)
continue;
int32_t floorZ, ceilZ;
getzsofslope(sectorNum, closest.x, closest.y, &ceilZ, &floorZ);
if (((ceilZ - pSprite->z) >> 8) < blastRadius)
Sect_DamageCeiling_Internal(spriteNum, sectorNum);
if (((pSprite->z - floorZ) >> 8) < blastRadius)
Sect_DamageFloor_Internal(spriteNum, sectorNum);
}
wallsfinished:
int const randomZOffset = -ZOFFSET2 + (krand()&(ZOFFSET5-1)); int const randomZOffset = -ZOFFSET2 + (krand()&(ZOFFSET5-1));
for (int sectorCount=0; sectorCount < numSectors; ++sectorCount) for (int sectorCount=0; sectorCount < numSectors; ++sectorCount)
@ -353,9 +386,10 @@ SKIPWALLCHECK:
if (bitmap_test(g_radiusDmgStatnums, pDamage->statnum)) if (bitmap_test(g_radiusDmgStatnums, pDamage->statnum))
{ {
int const spriteDist = (pDamage->picnum == APLAYER) int spriteDist = dist(pSprite, pDamage);
? FindDistance3D(pSprite->x - pDamage->x, pSprite->y - pDamage->y, pSprite->z - (pDamage->z - PHEIGHT))
: dist(pSprite, pDamage); if (pDamage->picnum == APLAYER)
spriteDist = FindDistance3D(pSprite->x - pDamage->x, pSprite->y - pDamage->y, pSprite->z - (pDamage->z - PHEIGHT));
if (spriteDist < blastRadius) if (spriteDist < blastRadius)
A_RadiusDamageObject_Internal(spriteNum, damageSprite, blastRadius, spriteDist, randomZOffset, dmg1, dmg2, dmg3, dmg4); A_RadiusDamageObject_Internal(spriteNum, damageSprite, blastRadius, spriteDist, randomZOffset, dmg1, dmg2, dmg3, dmg4);