From 54d78df2678633b257ac39e414ced9348f1ca724 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 17 Apr 2016 23:48:04 +0200 Subject: [PATCH] - 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. --- src/actor.h | 5 +++ src/p_local.h | 3 +- src/p_map.cpp | 93 ++++++++++++++++++++++++++++++++++++++++--------- src/p_mobj.cpp | 7 ++++ src/p_setup.cpp | 1 + src/p_udmf.cpp | 1 + src/p_user.cpp | 6 ++-- src/r_defs.h | 1 + 8 files changed, 96 insertions(+), 21 deletions(-) diff --git a/src/actor.h b/src/actor.h index e7fe048ef9..d369e5fa92 100644 --- a/src/actor.h +++ b/src/actor.h @@ -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 Inventory; // [RH] This actor's inventory DWORD InventoryID; // A unique ID to keep track of inventory items diff --git a/src/p_local.h b/src/p_local.h index a5336a9ee1..1a89154956 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -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); diff --git a/src/p_map.cpp b/src/p_map.cpp index 8254ac5bb0..d1cd918160 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -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, §or_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, §or_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, §or_t::render_thinglist); + render_sectorlist = NULL; +} + + //========================================================================== // // diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f018be55b5..18caa2f3c1 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -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 (); diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 148dcbea85..718e54e9b6 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -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 diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 017f73cf15..20852a5858 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -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 diff --git a/src/p_user.cpp b/src/p_user.cpp index 30a849b846..4860440704 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -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, §or_t::touching_thinglist); } else { diff --git a/src/r_defs.h b/src/r_defs.h index 2b7b4a218f..79af0929f2 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -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