diff --git a/src/actor.h b/src/actor.h index a56d0d6d9..10bbd119a 100644 --- a/src/actor.h +++ b/src/actor.h @@ -965,6 +965,7 @@ public: void CheckSectorTransition(sector_t *oldsec); void UpdateRenderSectorList(); void ClearRenderSectorList(); + void ClearRenderLineList(); // info for drawing // NOTE: The first member variable *must* be snext. @@ -1101,7 +1102,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 + struct msecnode_t *render_sectorlist; // same for cross-sectorportal rendering + struct portnode_t *render_portallist; // and for cross-lineportal TObjPtr Inventory; // [RH] This actor's inventory diff --git a/src/p_map.cpp b/src/p_map.cpp index c89418a32..72746f2fb 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -44,6 +44,7 @@ #include "p_trace.h" #include "p_checkposition.h" #include "r_utility.h" +#include "p_blockmap.h" #include "s_sound.h" #include "decallib.h" @@ -6238,6 +6239,91 @@ void P_CreateSecNodeList(AActor *thing) } +//============================================================================= +// +// P_DelPortalnode +// +// Same for line portal nodes +// +//============================================================================= + +portnode_t *P_DelPortalnode(portnode_t *node) +{ + portnode_t* tp; // prev node on thing thread + portnode_t* tn; // next node on thing thread + portnode_t* sp; // prev node on sector thread + portnode_t* sn; // next node on sector thread + + if (node) + { + // Unlink from the Thing thread. The Thing thread begins at + // sector_list and not from AActor->touching_sectorlist. + + tp = node->m_tprev; + tn = node->m_tnext; + if (tp) + tp->m_tnext = tn; + if (tn) + tn->m_tprev = tp; + + // Unlink from the sector thread. This thread begins at + // sector_t->touching_thinglist. + + sp = node->m_sprev; + sn = node->m_snext; + if (sp) + sp->m_snext = sn; + else + node->m_portal->render_thinglist = sn; + if (sn) + sn->m_sprev = sp; + + // Return this node to the freelist (use the same one as for msecnodes, since both types are the same size.) + P_PutSecnode(reinterpret_cast(node)); + return tn; + } + return NULL; +} + + +//============================================================================= +// +// P_AddPortalnode +// +//============================================================================= + +portnode_t *P_AddPortalnode(FLinePortal *s, AActor *thing, portnode_t *nextnode) +{ + portnode_t *node; + + if (s == 0) + { + I_FatalError("AddSecnode of 0 for %s\n", thing->GetClass()->TypeName.GetChars()); + } + + node = reinterpret_cast(P_GetSecnode()); + + // killough 4/4/98, 4/7/98: mark new nodes unvisited. + node->visited = 0; + + node->m_portal = s; // portal + node->m_thing = thing; // mobj + node->m_tprev = NULL; // prev node on Thing thread + node->m_tnext = nextnode; // next node on Thing thread + if (nextnode) + nextnode->m_tprev = node; // set back link on Thing + + // Add new node at head of portal thread starting at s->touching_thinglist + + node->m_sprev = NULL; // prev node on portal thread + node->m_snext = s->render_thinglist; // next node on portal thread + if (s->render_thinglist) + node->m_snext->m_sprev = node; + s->render_thinglist = node; + return node; +} + + //========================================================================== // // Handle the lists used to render actors from other portal areas @@ -6249,6 +6335,27 @@ void AActor::UpdateRenderSectorList() static const double SPRITE_SPACE = 64.; if (Pos() != OldRenderPos && !(flags & MF_NOSECTOR)) { + // Only check if the map contains line portals + ClearRenderLineList(); + if (PortalBlockmap.containsLines && Pos().XY() != OldRenderPos.XY()) + { + int bx = GetBlockX(X()); + int by = GetBlockX(Y()); + FBoundingBox bb(X(), Y(), MIN(radius*1.5, 128.)); // Don't go further than 128 map units, even for large actors + // Are there any portals near the actor's position? + if (bx >= 0 && by >= 0 && bx < bmapwidth && by < bmapheight && PortalBlockmap(bx, by).neighborContainsLines) + { + // Go through the entire list. In most cases this is faster than setting up a blockmap iterator + for (auto &p : linePortals) + { + if (p.mType == PORTT_VISUAL) continue; + if (bb.inRange(p.mOrigin) && bb.BoxOnLineSide(p.mOrigin)) + { + render_portallist = P_AddPortalnode(&p, this, render_portallist); + } + } + } + } sector_t *sec = Sector; double lasth = -FLT_MAX; ClearRenderSectorList(); @@ -6284,6 +6391,14 @@ void AActor::ClearRenderSectorList() render_sectorlist = NULL; } +void AActor::ClearRenderLineList() +{ + portnode_t *node = render_portallist; + while (node) + node = P_DelPortalnode(node); + render_portallist = NULL; +} + //========================================================================== // diff --git a/src/portal.cpp b/src/portal.cpp index 3dfd9a050..6abd4e8da 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -119,8 +119,8 @@ static void BuildBlockmap() while (*list != -1) { line_t *ld = &lines[*list++]; - - if (ld->isLinePortal()) + FLinePortal *port = ld->getPortal(); + if (port && port->mType != PORTT_VISUAL) { PortalBlockmap.containsLines = true; block.portallines.Push(ld); diff --git a/src/portal.h b/src/portal.h index 9c05f23b7..bba674def 100644 --- a/src/portal.h +++ b/src/portal.h @@ -7,6 +7,7 @@ struct FPortalGroupArray; class ASkyViewpoint; +struct portnode_t; //============================================================================ // // This table holds the offsets for the different parts of a map @@ -189,6 +190,7 @@ struct FLinePortal DAngle mAngleDiff; double mSinRot; double mCosRot; + portnode_t *render_thinglist; void *mRenderData; }; diff --git a/src/r_defs.h b/src/r_defs.h index 9f04dc2aa..ad043a404 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -1387,6 +1387,18 @@ struct msecnode_t bool visited; // killough 4/4/98, 4/7/98: used in search algorithms }; +// use the same memory layout as msecnode_t so both can be used from the same freelist. +struct portnode_t +{ + FLinePortal *m_portal; // a portal containing this object + AActor *m_thing; // this object + struct portnode_t *m_tprev; // prev msecnode_t for this thing + struct portnode_t *m_tnext; // next msecnode_t for this thing + struct portnode_t *m_sprev; // prev msecnode_t for this portal + struct portnode_t *m_snext; // next msecnode_t for this portal + bool visited; +}; + struct FPolyNode; struct FMiniBSP;