- added a new sector list to AActor that collects all portal-linked sectors the actor's center is in. (Inspired by Eternity's solution to the same problem.)

This is for rendering the sprite properly in all areas the actor touches. The original thinglist is not sufficient for this and Boom's touching thinglist has other purposes and collects too much data.
This new list will only get filled in when the actor is actually crossing a portal plane, for the normal sector thinglist will still be used.
This piggybacks on the msecnode_t code which has been extended to be able to handle more than one list by passing the sector's membert pointers as parameters.
This commit is contained in:
Christoph Oelckers 2016-04-17 23:48:04 +02:00
parent f66202aef1
commit 54d78df267
8 changed files with 96 additions and 21 deletions

View File

@ -959,11 +959,14 @@ public:
// Triggers SECSPAC_Exit/SECSPAC_Enter and related events if oldsec != current sector
void CheckSectorTransition(sector_t *oldsec);
void UpdateRenderSectorList();
void ClearRenderSectorList();
// info for drawing
// NOTE: The first member variable *must* be snext.
AActor *snext, **sprev; // links in sector (if needed)
DVector3 __Pos; // double underscores so that it won't get used by accident. Access to this should be exclusively through the designated access functions.
DVector3 OldRenderPos;
DRotator Angles;
DVector3 Vel;
@ -1094,6 +1097,8 @@ public:
// a linked list of sectors where this object appears
struct msecnode_t *touching_sectorlist; // phares 3/14/98
struct msecnode_t *render_sectorlist; // same for cross-portal rendering
TObjPtr<AInventory> Inventory; // [RH] This actor's inventory
DWORD InventoryID; // A unique ID to keep track of inventory items

View File

@ -350,7 +350,8 @@ void P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance,
void P_DelSector_List();
void P_DelSeclist(msecnode_t *); // phares 3/16/98
msecnode_t* P_DelSecnode(msecnode_t *);
msecnode_t *P_AddSecnode(sector_t *s, AActor *thing, msecnode_t *nextnode, msecnode_t *&sec_thinglist);
msecnode_t* P_DelSecnode(msecnode_t *, msecnode_t *sector_t::*head);
void P_CreateSecNodeList(AActor*); // phares 3/14/98
double P_GetMoveFactor(const AActor *mo, double *frictionp); // phares 3/6/98
double P_GetFriction(const AActor *mo, double *frictionfactor);

View File

@ -5555,6 +5555,7 @@ int P_PushUp(AActor *thing, FChangePosition *cpos)
intersect->SetZ(oldz);
return 2;
}
intersect->UpdateRenderSectorList();
}
thing->CheckPortalTransition(true);
return 0;
@ -5602,6 +5603,7 @@ int P_PushDown(AActor *thing, FChangePosition *cpos)
intersect->SetZ(oldz);
return 2;
}
intersect->UpdateRenderSectorList();
}
}
thing->CheckPortalTransition(true);
@ -5634,6 +5636,7 @@ void PIT_FloorDrop(AActor *thing, FChangePosition *cpos)
{
thing->SetZ(thing->floorz);
P_CheckFakeFloorTriggers(thing, oldz);
thing->UpdateRenderSectorList();
}
}
else if ((thing->Z() != oldfloorz && !(thing->flags & MF_NOLIFTDROP)))
@ -5642,6 +5645,7 @@ void PIT_FloorDrop(AActor *thing, FChangePosition *cpos)
{
thing->AddZ(-oldfloorz + thing->floorz);
P_CheckFakeFloorTriggers(thing, oldz);
thing->UpdateRenderSectorList();
}
}
if (thing->player && thing->player->mo == thing)
@ -5689,10 +5693,12 @@ void PIT_FloorRaise(AActor *thing, FChangePosition *cpos)
{
default:
P_CheckFakeFloorTriggers(thing, oldz);
thing->UpdateRenderSectorList();
break;
case 1:
P_DoCrunch(thing, cpos);
P_CheckFakeFloorTriggers(thing, oldz);
thing->UpdateRenderSectorList();
break;
case 2:
P_DoCrunch(thing, cpos);
@ -5735,6 +5741,7 @@ void PIT_CeilingLower(AActor *thing, FChangePosition *cpos)
{
thing->SetZ(thing->floorz);
}
thing->UpdateRenderSectorList();
switch (P_PushDown(thing, cpos))
{
case 2:
@ -5744,9 +5751,11 @@ void PIT_CeilingLower(AActor *thing, FChangePosition *cpos)
thing->SetZ(thing->floorz);
P_DoCrunch(thing, cpos);
P_CheckFakeFloorTriggers(thing, oldz);
thing->UpdateRenderSectorList();
break;
default:
P_CheckFakeFloorTriggers(thing, oldz);
thing->UpdateRenderSectorList();
break;
}
}
@ -5782,6 +5791,7 @@ void PIT_CeilingRaise(AActor *thing, FChangePosition *cpos)
thing->SetZ(thing->ceilingz - thing->Height);
}
P_CheckFakeFloorTriggers(thing, oldz);
thing->UpdateRenderSectorList();
}
else if ((thing->flags2 & MF2_PASSMOBJ) && !isgood && thing->Top() < thing->ceilingz)
{
@ -5789,6 +5799,7 @@ void PIT_CeilingRaise(AActor *thing, FChangePosition *cpos)
if (!P_TestMobjZ(thing, true, &onmobj) && onmobj->Z() <= thing->Z())
{
thing->SetZ(MIN(thing->ceilingz - thing->Height, onmobj->Top()));
thing->UpdateRenderSectorList();
}
}
if (thing->player && thing->player->mo == thing)
@ -6023,7 +6034,7 @@ void P_PutSecnode(msecnode_t *node)
//
//=============================================================================
msecnode_t *P_AddSecnode(sector_t *s, AActor *thing, msecnode_t *nextnode)
msecnode_t *P_AddSecnode(sector_t *s, AActor *thing, msecnode_t *nextnode, msecnode_t *&sec_thinglist)
{
msecnode_t *node;
@ -6061,10 +6072,10 @@ msecnode_t *P_AddSecnode(sector_t *s, AActor *thing, msecnode_t *nextnode)
// Add new node at head of sector thread starting at s->touching_thinglist
node->m_sprev = NULL; // prev node on sector thread
node->m_snext = s->touching_thinglist; // next node on sector thread
if (s->touching_thinglist)
node->m_snext = sec_thinglist; // next node on sector thread
if (sec_thinglist)
node->m_snext->m_sprev = node;
s->touching_thinglist = node;
sec_thinglist = node;
return node;
}
@ -6078,7 +6089,7 @@ msecnode_t *P_AddSecnode(sector_t *s, AActor *thing, msecnode_t *nextnode)
//
//=============================================================================
msecnode_t *P_DelSecnode(msecnode_t *node)
msecnode_t *P_DelSecnode(msecnode_t *node, msecnode_t *sector_t::*listhead)
{
msecnode_t* tp; // prev node on thing thread
msecnode_t* tn; // next node on thing thread
@ -6105,7 +6116,7 @@ msecnode_t *P_DelSecnode(msecnode_t *node)
if (sp)
sp->m_snext = sn;
else
node->m_sector->touching_thinglist = sn;
node->m_sector->*listhead = sn;
if (sn)
sn->m_sprev = sp;
@ -6145,7 +6156,7 @@ void P_DelSector_List()
void P_DelSeclist(msecnode_t *node)
{
while (node)
node = P_DelSecnode(node);
node = P_DelSecnode(node, &sector_t::touching_thinglist);
}
//=============================================================================
@ -6173,13 +6184,15 @@ void P_CreateSecNodeList(AActor *thing)
node = node->m_tnext;
}
FBoundingBox box(thing->X(), thing->Y(), thing->radius);
FBlockLinesIterator it(box);
line_t *ld;
FPortalGroupArray grouplist;
FMultiBlockLinesIterator mit(grouplist, thing);
FMultiBlockLinesIterator::CheckResult cres;
while ((ld = it.Next()))
while (mit.Next(&cres))
{
if (!box.inRange(ld) || box.BoxOnLineSide(ld) != -1)
line_t *ld = cres.line;
if (!mit.Box().inRange(ld) || mit.Box().BoxOnLineSide(ld) != -1)
continue;
// This line crosses through the object.
@ -6189,7 +6202,7 @@ void P_CreateSecNodeList(AActor *thing)
// allowed to move to this position, then the sector_list
// will be attached to the Thing's AActor at touching_sectorlist.
sector_list = P_AddSecnode(ld->frontsector, thing, sector_list);
sector_list = P_AddSecnode(ld->frontsector, thing, sector_list, ld->frontsector->touching_thinglist);
// Don't assume all lines are 2-sided, since some Things
// like MT_TFOG are allowed regardless of whether their radius takes
@ -6199,12 +6212,12 @@ void P_CreateSecNodeList(AActor *thing)
// Use sidedefs instead of 2s flag to determine two-sidedness.
if (ld->backsector)
sector_list = P_AddSecnode(ld->backsector, thing, sector_list);
sector_list = P_AddSecnode(ld->backsector, thing, sector_list, ld->backsector->touching_thinglist);
}
// Add the sector of the (x,y) point to sector_list.
sector_list = P_AddSecnode(thing->Sector, thing, sector_list);
sector_list = P_AddSecnode(thing->Sector, thing, sector_list, thing->Sector->touching_thinglist);
// Now delete any nodes that won't be used. These are the ones where
// m_thing is still NULL.
@ -6216,7 +6229,7 @@ void P_CreateSecNodeList(AActor *thing)
{
if (node == sector_list)
sector_list = node->m_tnext;
node = P_DelSecnode(node);
node = P_DelSecnode(node, &sector_t::touching_thinglist);
}
else
{
@ -6225,6 +6238,54 @@ void P_CreateSecNodeList(AActor *thing)
}
}
//==========================================================================
//
// Handle the lists used to render actors from other portal areas
//
//==========================================================================
void AActor::UpdateRenderSectorList()
{
static const double SPRITE_SPACE = 64.;
if (Pos() != OldRenderPos)
{
sector_t *sec = Sector;
double lasth = -FLT_MAX;
ClearRenderSectorList();
while (!sec->PortalBlocksMovement(sector_t::ceiling))
{
double planeh = sec->SkyBoxes[sector_t::ceiling]->specialf1;
if (planeh < lasth) break; // broken setup.
if (Top() + SPRITE_SPACE < planeh) break;
lasth = planeh;
DVector2 newpos = Pos() + sec->SkyBoxes[sector_t::ceiling]->Scale;
sec = P_PointInSector(newpos);
render_sectorlist = P_AddSecnode(sec, this, render_sectorlist, sec->render_thinglist);
}
lasth = FLT_MAX;
while (!sec->PortalBlocksMovement(sector_t::floor))
{
double planeh = sec->SkyBoxes[sector_t::floor]->specialf1;
if (planeh > lasth) break; // broken setup.
if (Z() - SPRITE_SPACE > planeh) break;
lasth = planeh;
DVector2 newpos = Pos() + sec->SkyBoxes[sector_t::floor]->Scale;
sec = P_PointInSector(newpos);
render_sectorlist = P_AddSecnode(sec, this, render_sectorlist, sec->render_thinglist);
}
}
}
void AActor::ClearRenderSectorList()
{
msecnode_t *node = render_sectorlist;
while (node)
node = P_DelSecnode(node, &sector_t::render_thinglist);
render_sectorlist = NULL;
}
//==========================================================================
//
//

View File

@ -3752,6 +3752,9 @@ void AActor::Tick ()
if (!CheckNoDelay())
return; // freed itself
// cycle through states, calling action functions at transitions
UpdateRenderSectorList();
if (tics != -1)
{
// [RH] Use tics <= 0 instead of == 0 so that spawnstates
@ -4011,6 +4014,7 @@ AActor *AActor::StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t a
}
actor->SetXYZ(pos);
actor->OldRenderPos = { FLT_MAX, FLT_MAX, FLT_MAX };
actor->picnum.SetInvalid();
actor->health = actor->SpawnHealth();
@ -4322,12 +4326,15 @@ void AActor::Deactivate (AActor *activator)
}
}
//
// P_RemoveMobj
//
void AActor::Destroy ()
{
ClearRenderSectorList();
// [RH] Destroy any inventory this actor is carrying
DestroyAllInventory ();

View File

@ -1510,6 +1510,7 @@ void P_LoadSectors (MapData *map, FMissingTextureTracker &missingtex)
tagManager.AddSectorTag(i, LittleShort(ms->tag));
ss->thinglist = NULL;
ss->touching_thinglist = NULL; // phares 3/14/98
ss->render_thinglist = NULL;
ss->seqType = defSeqType;
ss->SeqName = NAME_None;
ss->nextsec = -1; //jff 2/26/98 add fields to support locking out

View File

@ -1291,6 +1291,7 @@ public:
sec->SetAlpha(sector_t::ceiling, 1.);
sec->thinglist = NULL;
sec->touching_thinglist = NULL; // phares 3/14/98
sec->render_thinglist = NULL;
sec->seqType = (level.flags & LEVEL_SNDSEQTOTALCTRL) ? 0 : -1;
sec->nextsec = -1; //jff 2/26/98 add fields to support locking out
sec->prevsec = -1; // stair retriggering until build completes

View File

@ -2860,8 +2860,6 @@ void P_PredictPlayer (player_t *player)
}
}
extern msecnode_t *P_AddSecnode (sector_t *s, AActor *thing, msecnode_t *nextnode);
void P_UnPredictPlayer ()
{
player_t *player = &players[consoleplayer];
@ -2922,7 +2920,7 @@ void P_UnPredictPlayer ()
sector_list = NULL;
for (i = PredictionTouchingSectorsBackup.Size(); i-- > 0;)
{
sector_list = P_AddSecnode(PredictionTouchingSectorsBackup[i], act, sector_list);
sector_list = P_AddSecnode(PredictionTouchingSectorsBackup[i], act, sector_list, PredictionTouchingSectorsBackup[i]->touching_thinglist);
}
act->touching_sectorlist = sector_list; // Attach to thing
sector_list = NULL; // clear for next time
@ -2934,7 +2932,7 @@ void P_UnPredictPlayer ()
{
if (node == sector_list)
sector_list = node->m_tnext;
node = P_DelSecnode(node);
node = P_DelSecnode(node, &sector_t::touching_thinglist);
}
else
{

View File

@ -1057,6 +1057,7 @@ public:
// list of mobjs that are at least partially in the sector
// thinglist is a subset of touching_thinglist
struct msecnode_t *touching_thinglist; // phares 3/14/98
struct msecnode_t *render_thinglist; // for cross-portal rendering.
double gravity; // [RH] Sector gravity (1.0 is normal)
FNameNoInit damagetype; // [RH] Means-of-death for applied damage