mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-29 23:23:07 +00:00
- moved the msecnode code to its own file.
Note that this originates from Boom so it needs to keep the Doom license.
This commit is contained in:
parent
7af6bb4da0
commit
09419524f7
5 changed files with 442 additions and 411 deletions
|
@ -1106,6 +1106,7 @@ set (PCH_SOURCES
|
||||||
p_pusher.cpp
|
p_pusher.cpp
|
||||||
p_saveg.cpp
|
p_saveg.cpp
|
||||||
p_scroll.cpp
|
p_scroll.cpp
|
||||||
|
p_secnodes.cpp
|
||||||
p_sectors.cpp
|
p_sectors.cpp
|
||||||
p_setup.cpp
|
p_setup.cpp
|
||||||
p_sight.cpp
|
p_sight.cpp
|
||||||
|
|
|
@ -31,6 +31,13 @@ extern double bmaporgx;
|
||||||
extern double bmaporgy; // origin of block map
|
extern double bmaporgy; // origin of block map
|
||||||
extern FBlockNode** blocklinks; // for thing chains
|
extern FBlockNode** blocklinks; // for thing chains
|
||||||
|
|
||||||
|
// mapblocks are used to check movement
|
||||||
|
// against lines and things
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
MAPBLOCKUNITS = 128
|
||||||
|
};
|
||||||
|
|
||||||
inline int GetBlockX(double xpos)
|
inline int GetBlockX(double xpos)
|
||||||
{
|
{
|
||||||
return int((xpos - bmaporgx) / MAPBLOCKUNITS);
|
return int((xpos - bmaporgx) / MAPBLOCKUNITS);
|
||||||
|
|
|
@ -48,10 +48,6 @@ struct FTranslatedLineTarget;
|
||||||
|
|
||||||
#define BONUSADD 6
|
#define BONUSADD 6
|
||||||
|
|
||||||
// mapblocks are used to check movement
|
|
||||||
// against lines and things
|
|
||||||
#define MAPBLOCKUNITS 128
|
|
||||||
|
|
||||||
// Inspired by Maes
|
// Inspired by Maes
|
||||||
extern int bmapnegx;
|
extern int bmapnegx;
|
||||||
extern int bmapnegy;
|
extern int bmapnegy;
|
||||||
|
|
407
src/p_map.cpp
407
src/p_map.cpp
|
@ -6454,413 +6454,6 @@ bool P_ChangeSector(sector_t *sector, int crunch, double amt, int floorOrCeil, b
|
||||||
return cpos.nofit;
|
return cpos.nofit;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
// phares 3/21/98
|
|
||||||
//
|
|
||||||
// Maintain a freelist of msecnode_t's to reduce memory allocs and frees.
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
msecnode_t *headsecnode = NULL;
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// P_GetSecnode
|
|
||||||
//
|
|
||||||
// Retrieve a node from the freelist. The calling routine
|
|
||||||
// should make sure it sets all fields properly.
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
msecnode_t *P_GetSecnode()
|
|
||||||
{
|
|
||||||
msecnode_t *node;
|
|
||||||
|
|
||||||
if (headsecnode)
|
|
||||||
{
|
|
||||||
node = headsecnode;
|
|
||||||
headsecnode = headsecnode->m_snext;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node = (msecnode_t *)M_Malloc(sizeof(*node));
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// P_PutSecnode
|
|
||||||
//
|
|
||||||
// Returns a node to the freelist.
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
void P_PutSecnode(msecnode_t *node)
|
|
||||||
{
|
|
||||||
node->m_snext = headsecnode;
|
|
||||||
headsecnode = node;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
// phares 3/16/98
|
|
||||||
//
|
|
||||||
// P_AddSecnode
|
|
||||||
//
|
|
||||||
// Searches the current list to see if this sector is
|
|
||||||
// already there. If not, it adds a sector node at the head of the list of
|
|
||||||
// sectors this object appears in. This is called when creating a list of
|
|
||||||
// nodes that will get linked in later. Returns a pointer to the new node.
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
msecnode_t *P_AddSecnode(sector_t *s, AActor *thing, msecnode_t *nextnode, msecnode_t *&sec_thinglist)
|
|
||||||
{
|
|
||||||
msecnode_t *node;
|
|
||||||
|
|
||||||
if (s == 0)
|
|
||||||
{
|
|
||||||
I_FatalError("AddSecnode of 0 for %s\n", thing->GetClass()->TypeName.GetChars());
|
|
||||||
}
|
|
||||||
|
|
||||||
node = nextnode;
|
|
||||||
while (node)
|
|
||||||
{
|
|
||||||
if (node->m_sector == s) // Already have a node for this sector?
|
|
||||||
{
|
|
||||||
node->m_thing = thing; // Yes. Setting m_thing says 'keep it'.
|
|
||||||
return nextnode;
|
|
||||||
}
|
|
||||||
node = node->m_tnext;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Couldn't find an existing node for this sector. Add one at the head
|
|
||||||
// of the list.
|
|
||||||
|
|
||||||
node = P_GetSecnode();
|
|
||||||
|
|
||||||
// killough 4/4/98, 4/7/98: mark new nodes unvisited.
|
|
||||||
node->visited = 0;
|
|
||||||
|
|
||||||
node->m_sector = s; // sector
|
|
||||||
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 sector thread starting at s->touching_thinglist
|
|
||||||
|
|
||||||
node->m_sprev = NULL; // prev node on sector thread
|
|
||||||
node->m_snext = sec_thinglist; // next node on sector thread
|
|
||||||
if (sec_thinglist)
|
|
||||||
node->m_snext->m_sprev = node;
|
|
||||||
sec_thinglist = node;
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// P_DelSecnode
|
|
||||||
//
|
|
||||||
// Deletes a sector node from the list of
|
|
||||||
// sectors this object appears in. Returns a pointer to the next node
|
|
||||||
// on the linked list, or NULL.
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
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
|
|
||||||
msecnode_t* sp; // prev node on sector thread
|
|
||||||
msecnode_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_sector->*listhead = sn;
|
|
||||||
if (sn)
|
|
||||||
sn->m_sprev = sp;
|
|
||||||
|
|
||||||
// Return this node to the freelist
|
|
||||||
|
|
||||||
P_PutSecnode(node);
|
|
||||||
return tn;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
} // phares 3/13/98
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// P_DelSeclist
|
|
||||||
//
|
|
||||||
// Delete an entire sector list
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
void P_DelSeclist(msecnode_t *node, msecnode_t *sector_t::*sechead)
|
|
||||||
{
|
|
||||||
while (node)
|
|
||||||
node = P_DelSecnode(node, sechead);
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
// phares 3/14/98
|
|
||||||
//
|
|
||||||
// P_CreateSecNodeList
|
|
||||||
//
|
|
||||||
// Alters/creates the sector_list that shows what sectors the object resides in
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
msecnode_t *P_CreateSecNodeList(AActor *thing, double radius, msecnode_t *sector_list, msecnode_t *sector_t::*seclisthead)
|
|
||||||
{
|
|
||||||
msecnode_t *node;
|
|
||||||
|
|
||||||
// First, clear out the existing m_thing fields. As each node is
|
|
||||||
// added or verified as needed, m_thing will be set properly. When
|
|
||||||
// finished, delete all nodes where m_thing is still NULL. These
|
|
||||||
// represent the sectors the Thing has vacated.
|
|
||||||
|
|
||||||
node = sector_list;
|
|
||||||
while (node)
|
|
||||||
{
|
|
||||||
node->m_thing = NULL;
|
|
||||||
node = node->m_tnext;
|
|
||||||
}
|
|
||||||
|
|
||||||
FBoundingBox box(thing->X(), thing->Y(), radius);
|
|
||||||
FBlockLinesIterator it(box);
|
|
||||||
line_t *ld;
|
|
||||||
|
|
||||||
while ((ld = it.Next()))
|
|
||||||
{
|
|
||||||
if (!box.inRange(ld) || box.BoxOnLineSide(ld) != -1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// This line crosses through the object.
|
|
||||||
|
|
||||||
// Collect the sector(s) from the line and add to the
|
|
||||||
// sector_list you're examining. If the Thing ends up being
|
|
||||||
// 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, ld->frontsector->*seclisthead);
|
|
||||||
|
|
||||||
// Don't assume all lines are 2-sided, since some Things
|
|
||||||
// like MT_TFOG are allowed regardless of whether their radius takes
|
|
||||||
// them beyond an impassable linedef.
|
|
||||||
|
|
||||||
// killough 3/27/98, 4/4/98:
|
|
||||||
// Use sidedefs instead of 2s flag to determine two-sidedness.
|
|
||||||
|
|
||||||
if (ld->backsector)
|
|
||||||
sector_list = P_AddSecnode(ld->backsector, thing, sector_list, ld->backsector->*seclisthead);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the sector of the (x,y) point to sector_list.
|
|
||||||
|
|
||||||
sector_list = P_AddSecnode(thing->Sector, thing, sector_list, thing->Sector->*seclisthead);
|
|
||||||
|
|
||||||
// Now delete any nodes that won't be used. These are the ones where
|
|
||||||
// m_thing is still NULL.
|
|
||||||
|
|
||||||
node = sector_list;
|
|
||||||
while (node)
|
|
||||||
{
|
|
||||||
if (node->m_thing == NULL)
|
|
||||||
{
|
|
||||||
if (node == sector_list)
|
|
||||||
sector_list = node->m_tnext;
|
|
||||||
node = P_DelSecnode(node, seclisthead);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node = node->m_tnext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sector_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// 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->lineportal_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->lineportal_thinglist; // next node on portal thread
|
|
||||||
if (s->lineportal_thinglist)
|
|
||||||
node->m_snext->m_sprev = node;
|
|
||||||
s->lineportal_thinglist = node;
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// Handle the lists used to render actors from other portal areas
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
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 = GetBlockY(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))
|
|
||||||
{
|
|
||||||
touching_lineportallist = P_AddPortalnode(&p, this, touching_lineportallist);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sector_t *sec = Sector;
|
|
||||||
double lasth = -FLT_MAX;
|
|
||||||
ClearRenderSectorList();
|
|
||||||
while (!sec->PortalBlocksMovement(sector_t::ceiling))
|
|
||||||
{
|
|
||||||
double planeh = sec->GetPortalPlaneZ(sector_t::ceiling);
|
|
||||||
if (planeh <= lasth) break; // broken setup.
|
|
||||||
if (Top() + SPRITE_SPACE < planeh) break;
|
|
||||||
lasth = planeh;
|
|
||||||
DVector2 newpos = Pos() + sec->GetPortalDisplacement(sector_t::ceiling);
|
|
||||||
sec = P_PointInSector(newpos);
|
|
||||||
touching_sectorportallist = P_AddSecnode(sec, this, touching_sectorportallist, sec->sectorportal_thinglist);
|
|
||||||
}
|
|
||||||
sec = Sector;
|
|
||||||
lasth = FLT_MAX;
|
|
||||||
while (!sec->PortalBlocksMovement(sector_t::floor))
|
|
||||||
{
|
|
||||||
double planeh = sec->GetPortalPlaneZ(sector_t::floor);
|
|
||||||
if (planeh >= lasth) break; // broken setup.
|
|
||||||
if (Z() - SPRITE_SPACE > planeh) break;
|
|
||||||
lasth = planeh;
|
|
||||||
DVector2 newpos = Pos() + sec->GetPortalDisplacement(sector_t::floor);
|
|
||||||
sec = P_PointInSector(newpos);
|
|
||||||
touching_sectorportallist = P_AddSecnode(sec, this, touching_sectorportallist, sec->sectorportal_thinglist);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AActor::ClearRenderSectorList()
|
|
||||||
{
|
|
||||||
msecnode_t *node = touching_sectorportallist;
|
|
||||||
while (node)
|
|
||||||
node = P_DelSecnode(node, §or_t::sectorportal_thinglist);
|
|
||||||
touching_sectorportallist = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AActor::ClearRenderLineList()
|
|
||||||
{
|
|
||||||
portnode_t *node = touching_lineportallist;
|
|
||||||
while (node)
|
|
||||||
node = P_DelPortalnode(node);
|
|
||||||
touching_lineportallist = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
434
src/p_secnodes.cpp
Normal file
434
src/p_secnodes.cpp
Normal file
|
@ -0,0 +1,434 @@
|
||||||
|
// Emacs style mode select -*- C++ -*-
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// $Id:$
|
||||||
|
//
|
||||||
|
// Copyright (C) 1998-1996 by id Software, Inc.
|
||||||
|
//
|
||||||
|
// This source is available for distribution and/or modification
|
||||||
|
// only under the terms of the DOOM Source Code License as
|
||||||
|
// published by id Software. All rights reserved.
|
||||||
|
//
|
||||||
|
// The source is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
// $Log:$
|
||||||
|
//
|
||||||
|
// DESCRIPTION:
|
||||||
|
// Boom secnodes
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "r_state.h"
|
||||||
|
#include "p_maputl.h"
|
||||||
|
#include "p_blockmap.h"
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// phares 3/21/98
|
||||||
|
//
|
||||||
|
// Maintain a freelist of msecnode_t's to reduce memory allocs and frees.
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
msecnode_t *headsecnode = NULL;
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// P_GetSecnode
|
||||||
|
//
|
||||||
|
// Retrieve a node from the freelist. The calling routine
|
||||||
|
// should make sure it sets all fields properly.
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
msecnode_t *P_GetSecnode()
|
||||||
|
{
|
||||||
|
msecnode_t *node;
|
||||||
|
|
||||||
|
if (headsecnode)
|
||||||
|
{
|
||||||
|
node = headsecnode;
|
||||||
|
headsecnode = headsecnode->m_snext;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node = (msecnode_t *)M_Malloc(sizeof(*node));
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// P_PutSecnode
|
||||||
|
//
|
||||||
|
// Returns a node to the freelist.
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
void P_PutSecnode(msecnode_t *node)
|
||||||
|
{
|
||||||
|
node->m_snext = headsecnode;
|
||||||
|
headsecnode = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// phares 3/16/98
|
||||||
|
//
|
||||||
|
// P_AddSecnode
|
||||||
|
//
|
||||||
|
// Searches the current list to see if this sector is
|
||||||
|
// already there. If not, it adds a sector node at the head of the list of
|
||||||
|
// sectors this object appears in. This is called when creating a list of
|
||||||
|
// nodes that will get linked in later. Returns a pointer to the new node.
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
msecnode_t *P_AddSecnode(sector_t *s, AActor *thing, msecnode_t *nextnode, msecnode_t *&sec_thinglist)
|
||||||
|
{
|
||||||
|
msecnode_t *node;
|
||||||
|
|
||||||
|
if (s == 0)
|
||||||
|
{
|
||||||
|
I_FatalError("AddSecnode of 0 for %s\n", thing->GetClass()->TypeName.GetChars());
|
||||||
|
}
|
||||||
|
|
||||||
|
node = nextnode;
|
||||||
|
while (node)
|
||||||
|
{
|
||||||
|
if (node->m_sector == s) // Already have a node for this sector?
|
||||||
|
{
|
||||||
|
node->m_thing = thing; // Yes. Setting m_thing says 'keep it'.
|
||||||
|
return nextnode;
|
||||||
|
}
|
||||||
|
node = node->m_tnext;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Couldn't find an existing node for this sector. Add one at the head
|
||||||
|
// of the list.
|
||||||
|
|
||||||
|
node = P_GetSecnode();
|
||||||
|
|
||||||
|
// killough 4/4/98, 4/7/98: mark new nodes unvisited.
|
||||||
|
node->visited = 0;
|
||||||
|
|
||||||
|
node->m_sector = s; // sector
|
||||||
|
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 sector thread starting at s->touching_thinglist
|
||||||
|
|
||||||
|
node->m_sprev = NULL; // prev node on sector thread
|
||||||
|
node->m_snext = sec_thinglist; // next node on sector thread
|
||||||
|
if (sec_thinglist)
|
||||||
|
node->m_snext->m_sprev = node;
|
||||||
|
sec_thinglist = node;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// P_DelSecnode
|
||||||
|
//
|
||||||
|
// Deletes a sector node from the list of
|
||||||
|
// sectors this object appears in. Returns a pointer to the next node
|
||||||
|
// on the linked list, or NULL.
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
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
|
||||||
|
msecnode_t* sp; // prev node on sector thread
|
||||||
|
msecnode_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_sector->*listhead = sn;
|
||||||
|
if (sn)
|
||||||
|
sn->m_sprev = sp;
|
||||||
|
|
||||||
|
// Return this node to the freelist
|
||||||
|
|
||||||
|
P_PutSecnode(node);
|
||||||
|
return tn;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
} // phares 3/13/98
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// P_DelSeclist
|
||||||
|
//
|
||||||
|
// Delete an entire sector list
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
void P_DelSeclist(msecnode_t *node, msecnode_t *sector_t::*sechead)
|
||||||
|
{
|
||||||
|
while (node)
|
||||||
|
node = P_DelSecnode(node, sechead);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// phares 3/14/98
|
||||||
|
//
|
||||||
|
// P_CreateSecNodeList
|
||||||
|
//
|
||||||
|
// Alters/creates the sector_list that shows what sectors the object resides in
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
msecnode_t *P_CreateSecNodeList(AActor *thing, double radius, msecnode_t *sector_list, msecnode_t *sector_t::*seclisthead)
|
||||||
|
{
|
||||||
|
msecnode_t *node;
|
||||||
|
|
||||||
|
// First, clear out the existing m_thing fields. As each node is
|
||||||
|
// added or verified as needed, m_thing will be set properly. When
|
||||||
|
// finished, delete all nodes where m_thing is still NULL. These
|
||||||
|
// represent the sectors the Thing has vacated.
|
||||||
|
|
||||||
|
node = sector_list;
|
||||||
|
while (node)
|
||||||
|
{
|
||||||
|
node->m_thing = NULL;
|
||||||
|
node = node->m_tnext;
|
||||||
|
}
|
||||||
|
|
||||||
|
FBoundingBox box(thing->X(), thing->Y(), radius);
|
||||||
|
FBlockLinesIterator it(box);
|
||||||
|
line_t *ld;
|
||||||
|
|
||||||
|
while ((ld = it.Next()))
|
||||||
|
{
|
||||||
|
if (!box.inRange(ld) || box.BoxOnLineSide(ld) != -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// This line crosses through the object.
|
||||||
|
|
||||||
|
// Collect the sector(s) from the line and add to the
|
||||||
|
// sector_list you're examining. If the Thing ends up being
|
||||||
|
// 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, ld->frontsector->*seclisthead);
|
||||||
|
|
||||||
|
// Don't assume all lines are 2-sided, since some Things
|
||||||
|
// like MT_TFOG are allowed regardless of whether their radius takes
|
||||||
|
// them beyond an impassable linedef.
|
||||||
|
|
||||||
|
// killough 3/27/98, 4/4/98:
|
||||||
|
// Use sidedefs instead of 2s flag to determine two-sidedness.
|
||||||
|
|
||||||
|
if (ld->backsector)
|
||||||
|
sector_list = P_AddSecnode(ld->backsector, thing, sector_list, ld->backsector->*seclisthead);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the sector of the (x,y) point to sector_list.
|
||||||
|
|
||||||
|
sector_list = P_AddSecnode(thing->Sector, thing, sector_list, thing->Sector->*seclisthead);
|
||||||
|
|
||||||
|
// Now delete any nodes that won't be used. These are the ones where
|
||||||
|
// m_thing is still NULL.
|
||||||
|
|
||||||
|
node = sector_list;
|
||||||
|
while (node)
|
||||||
|
{
|
||||||
|
if (node->m_thing == NULL)
|
||||||
|
{
|
||||||
|
if (node == sector_list)
|
||||||
|
sector_list = node->m_tnext;
|
||||||
|
node = P_DelSecnode(node, seclisthead);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node = node->m_tnext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sector_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// 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->lineportal_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->lineportal_thinglist; // next node on portal thread
|
||||||
|
if (s->lineportal_thinglist)
|
||||||
|
node->m_snext->m_sprev = node;
|
||||||
|
s->lineportal_thinglist = node;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Handle the lists used to render actors from other portal areas
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
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 = GetBlockY(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))
|
||||||
|
{
|
||||||
|
touching_lineportallist = P_AddPortalnode(&p, this, touching_lineportallist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sector_t *sec = Sector;
|
||||||
|
double lasth = -FLT_MAX;
|
||||||
|
ClearRenderSectorList();
|
||||||
|
while (!sec->PortalBlocksMovement(sector_t::ceiling))
|
||||||
|
{
|
||||||
|
double planeh = sec->GetPortalPlaneZ(sector_t::ceiling);
|
||||||
|
if (planeh <= lasth) break; // broken setup.
|
||||||
|
if (Top() + SPRITE_SPACE < planeh) break;
|
||||||
|
lasth = planeh;
|
||||||
|
DVector2 newpos = Pos() + sec->GetPortalDisplacement(sector_t::ceiling);
|
||||||
|
sec = P_PointInSector(newpos);
|
||||||
|
touching_sectorportallist = P_AddSecnode(sec, this, touching_sectorportallist, sec->sectorportal_thinglist);
|
||||||
|
}
|
||||||
|
sec = Sector;
|
||||||
|
lasth = FLT_MAX;
|
||||||
|
while (!sec->PortalBlocksMovement(sector_t::floor))
|
||||||
|
{
|
||||||
|
double planeh = sec->GetPortalPlaneZ(sector_t::floor);
|
||||||
|
if (planeh >= lasth) break; // broken setup.
|
||||||
|
if (Z() - SPRITE_SPACE > planeh) break;
|
||||||
|
lasth = planeh;
|
||||||
|
DVector2 newpos = Pos() + sec->GetPortalDisplacement(sector_t::floor);
|
||||||
|
sec = P_PointInSector(newpos);
|
||||||
|
touching_sectorportallist = P_AddSecnode(sec, this, touching_sectorportallist, sec->sectorportal_thinglist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AActor::ClearRenderSectorList()
|
||||||
|
{
|
||||||
|
msecnode_t *node = touching_sectorportallist;
|
||||||
|
while (node)
|
||||||
|
node = P_DelSecnode(node, §or_t::sectorportal_thinglist);
|
||||||
|
touching_sectorportallist = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AActor::ClearRenderLineList()
|
||||||
|
{
|
||||||
|
portnode_t *node = touching_lineportallist;
|
||||||
|
while (node)
|
||||||
|
node = P_DelPortalnode(node);
|
||||||
|
touching_lineportallist = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue