- link actors to touching line portals, for use by the renderer.

This commit is contained in:
Christoph Oelckers 2016-04-21 22:59:07 +02:00
parent afa3009f93
commit 382a6e8b9f
5 changed files with 134 additions and 3 deletions

View file

@ -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<AInventory> Inventory; // [RH] This actor's inventory

View file

@ -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<msecnode_t *>(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<portnode_t*>(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;
}
//==========================================================================
//

View file

@ -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);

View file

@ -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;
};

View file

@ -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;