- split polyobject init into its own file and cleaned things up a bit.

This commit is contained in:
Christoph Oelckers 2018-12-28 15:05:05 +01:00
parent 9de2f5c1e7
commit 11e9cdae33
7 changed files with 429 additions and 402 deletions

View File

@ -1079,6 +1079,7 @@ set (PCH_SOURCES
maploader/slopes.cpp maploader/slopes.cpp
maploader/glnodes.cpp maploader/glnodes.cpp
maploader/udmf.cpp maploader/udmf.cpp
maploader/polyobjects.cpp
menu/joystickmenu.cpp menu/joystickmenu.cpp
menu/loadsavemenu.cpp menu/loadsavemenu.cpp
menu/menu.cpp menu/menu.cpp

View File

@ -83,6 +83,7 @@ struct FLevelData
TMap<int, FHealthGroup> healthGroups; TMap<int, FHealthGroup> healthGroups;
FBlockmap blockmap; FBlockmap blockmap;
TArray<polyblock_t *> PolyBlockMap;
// These are copies of the loaded map data that get used by the savegame code to skip unaltered fields // These are copies of the loaded map data that get used by the savegame code to skip unaltered fields
// Without such a mechanism the savegame format would become too slow and large because more than 80-90% are normally still unaltered. // Without such a mechanism the savegame format would become too slow and large because more than 80-90% are normally still unaltered.

View File

@ -0,0 +1,415 @@
//-----------------------------------------------------------------------------
//
// Copyright 1994-1996 Raven Software
// Copyright 1999-2016 Randy Heit
// Copyright 2002-2018 Christoph Oelckers
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//-----------------------------------------------------------------------------
//
// HEADER FILES ------------------------------------------------------------
#include "doomdef.h"
#include "p_local.h"
#include "m_bbox.h"
#include "a_sharedglobal.h"
#include "p_3dmidtex.h"
#include "p_lnspec.h"
#include "po_man.h"
#include "p_setup.h"
#include "p_blockmap.h"
#include "p_maputl.h"
#include "r_utility.h"
#include "g_levellocals.h"
#include "actorinlines.h"
#include "v_text.h"
#include "maploader/maploader.h"
//==========================================================================
//
// InitBlockMap
//
//==========================================================================
void MapLoader::InitPolyBlockMap ()
{
int bmapwidth = Level->blockmap.bmapwidth;
int bmapheight = Level->blockmap.bmapheight;
Level->PolyBlockMap.Resize(bmapwidth*bmapheight);
memset (Level->PolyBlockMap.Data(), 0, bmapwidth*bmapheight*sizeof(polyblock_t *));
for(auto &poly : Level->Polyobjects)
{
poly.LinkPolyobj();
}
}
//==========================================================================
//
// InitSideLists [RH]
//
// Group sides by vertex and collect side that are known to belong to a
// polyobject so that they can be initialized fast.
//==========================================================================
void MapLoader::InitSideLists ()
{
auto &sides = Level->sides;
for (unsigned i = 0; i < sides.Size(); ++i)
{
if (sides[i].linedef != NULL &&
(sides[i].linedef->special == Polyobj_StartLine ||
sides[i].linedef->special == Polyobj_ExplicitLine))
{
KnownPolySides.Push (i);
}
}
}
//==========================================================================
//
// AddPolyVert
//
// Helper function for IterFindPolySides()
//
//==========================================================================
static void AddPolyVert(TArray<uint32_t> &vnum, uint32_t vert)
{
for (unsigned int i = vnum.Size() - 1; i-- != 0; )
{
if (vnum[i] == vert)
{ // Already in the set. No need to add it.
return;
}
}
vnum.Push(vert);
}
//==========================================================================
//
// IterFindPolySides
//
// Beginning with the first vertex of the starting side, for each vertex
// in vnum, add all the sides that use it as a first vertex to the polyobj,
// and add all their second vertices to vnum. This continues until there
// are no new vertices in vnum.
//
//==========================================================================
void MapLoader::IterFindPolySides (FPolyObj *po, side_t *side)
{
static TArray<uint32_t> vnum;
unsigned int vnumat;
assert(sidetemp != NULL);
vnum.Clear();
vnum.Push(uint32_t(side->V1()->Index()));
vnumat = 0;
while (vnum.Size() != vnumat)
{
uint32_t sidenum = sidetemp[vnum[vnumat++]].b.first;
while (sidenum != NO_SIDE)
{
po->Sidedefs.Push(&Level->sides[sidenum]);
AddPolyVert(vnum, uint32_t(Level->sides[sidenum].V2()->Index()));
sidenum = sidetemp[sidenum].b.next;
}
}
}
//==========================================================================
//
// SpawnPolyobj
//
//==========================================================================
static int posicmp(const void *a, const void *b)
{
return (*(const side_t **)a)->linedef->args[1] - (*(const side_t **)b)->linedef->args[1];
}
void MapLoader::SpawnPolyobj (int index, int tag, int type)
{
unsigned int ii;
int i;
FPolyObj *po = &Level->Polyobjects[index];
for (ii = 0; ii < KnownPolySides.Size(); ++ii)
{
i = KnownPolySides[ii];
if (i < 0)
{
continue;
}
po->bBlocked = false;
po->bHasPortals = 0;
side_t *sd = &Level->sides[i];
if (sd->linedef->special == Polyobj_StartLine &&
sd->linedef->args[0] == tag)
{
if (po->Sidedefs.Size() > 0)
{
Printf (TEXTCOLOR_RED "SpawnPolyobj: Polyobj %d already spawned.\n", tag);
return;
}
else
{
sd->linedef->special = 0;
sd->linedef->args[0] = 0;
IterFindPolySides(&Level->Polyobjects[index], sd);
po->MirrorNum = sd->linedef->args[1];
po->crush = (type != SMT_PolySpawn) ? 3 : 0;
po->bHurtOnTouch = (type == SMT_PolySpawnHurt);
po->tag = tag;
po->seqType = sd->linedef->args[2];
if (po->seqType < 0 || po->seqType > 63)
{
po->seqType = 0;
}
}
break;
}
}
if (po->Sidedefs.Size() == 0)
{
// didn't find a polyobj through PO_LINE_START
TArray<side_t *> polySideList;
unsigned int psIndexOld;
psIndexOld = po->Sidedefs.Size();
for (ii = 0; ii < KnownPolySides.Size(); ++ii)
{
i = KnownPolySides[ii];
if (i >= 0 &&
Level->sides[i].linedef->special == Polyobj_ExplicitLine &&
Level->sides[i].linedef->args[0] == tag)
{
if (!Level->sides[i].linedef->args[1])
{
Printf(TEXTCOLOR_RED "SpawnPolyobj: Explicit line missing order number in poly %d, linedef %d.\n", tag, Level->sides[i].linedef->Index());
return;
}
else
{
po->Sidedefs.Push(&Level->sides[i]);
}
}
}
qsort(&po->Sidedefs[0], po->Sidedefs.Size(), sizeof(po->Sidedefs[0]), posicmp);
if (po->Sidedefs.Size() > 0)
{
po->crush = (type != SMT_PolySpawn) ? 3 : 0;
po->bHurtOnTouch = (type == SMT_PolySpawnHurt);
po->tag = tag;
po->seqType = po->Sidedefs[0]->linedef->args[3];
po->MirrorNum = po->Sidedefs[0]->linedef->args[2];
}
else
{
Printf(TEXTCOLOR_RED "SpawnPolyobj: Poly %d does not exist\n", tag);
return;
}
}
validcount++;
for(unsigned int i=0; i<po->Sidedefs.Size(); i++)
{
line_t *l = po->Sidedefs[i]->linedef;
if (l->validcount != validcount)
{
FLinePortal *port = l->getPortal();
if (port && (port->mDefFlags & PORTF_PASSABLE))
{
int type = port->mType == PORTT_LINKED ? 2 : 1;
if (po->bHasPortals < type) po->bHasPortals = (uint8_t)type;
}
l->validcount = validcount;
po->Linedefs.Push(l);
vertex_t *v = l->v1;
int j;
for(j = po->Vertices.Size() - 1; j >= 0; j--)
{
if (po->Vertices[j] == v) break;
}
if (j < 0) po->Vertices.Push(v);
v = l->v2;
for(j = po->Vertices.Size() - 1; j >= 0; j--)
{
if (po->Vertices[j] == v) break;
}
if (j < 0) po->Vertices.Push(v);
}
}
po->Sidedefs.ShrinkToFit();
po->Linedefs.ShrinkToFit();
po->Vertices.ShrinkToFit();
}
//==========================================================================
//
// TranslateToStartSpot
//
//==========================================================================
void MapLoader::TranslateToStartSpot (int tag, const DVector2 &origin)
{
FPolyObj *po;
DVector2 delta;
po = PO_GetPolyobj(tag);
if (po == nullptr)
{ // didn't match the tag with a polyobj tag
Printf(TEXTCOLOR_RED "TranslateToStartSpot: Unable to match polyobj tag: %d\n", tag);
return;
}
if (po->Sidedefs.Size() == 0)
{
Printf(TEXTCOLOR_RED "TranslateToStartSpot: Anchor point located without a StartSpot point: %d\n", tag);
return;
}
po->OriginalPts.Resize(po->Sidedefs.Size());
po->PrevPts.Resize(po->Sidedefs.Size());
delta = origin - po->StartSpot.pos;
for (unsigned i = 0; i < po->Sidedefs.Size(); i++)
{
po->Sidedefs[i]->Flags |= WALLF_POLYOBJ;
}
for (unsigned i = 0; i < po->Linedefs.Size(); i++)
{
po->Linedefs[i]->bbox[BOXTOP] -= delta.Y;
po->Linedefs[i]->bbox[BOXBOTTOM] -= delta.Y;
po->Linedefs[i]->bbox[BOXLEFT] -= delta.X;
po->Linedefs[i]->bbox[BOXRIGHT] -= delta.X;
}
for (unsigned i = 0; i < po->Vertices.Size(); i++)
{
po->Vertices[i]->set(po->Vertices[i]->fX() - delta.X, po->Vertices[i]->fY() - delta.Y);
po->OriginalPts[i].pos = po->Vertices[i]->fPos() - po->StartSpot.pos;
}
po->CalcCenter();
// For compatibility purposes
po->CenterSubsector = R_PointInSubsector(po->CenterSpot.pos);
}
//==========================================================================
//
// PO_Init
//
//==========================================================================
void MapLoader::PO_Init (void)
{
int NumPolyobjs = 0;
TArray<FMapThing *> polythings;
for (auto &mthing : MapThingsConverted)
{
if (mthing.EdNum == 0 || mthing.EdNum == -1) continue;
FDoomEdEntry *mentry = mthing.info;
switch (mentry->Special)
{
case SMT_PolyAnchor:
case SMT_PolySpawn:
case SMT_PolySpawnCrush:
case SMT_PolySpawnHurt:
polythings.Push(&mthing);
if (mentry->Special != SMT_PolyAnchor)
NumPolyobjs++;
}
}
int polyIndex;
// [RH] Make this faster
InitSideLists ();
Level->Polyobjects.Resize(NumPolyobjs);
polyIndex = 0; // index polyobj number
// Find the startSpot points, and spawn each polyobj
for (int i=polythings.Size()-1; i >= 0; i--)
{
// 9301 (3001) = no crush, 9302 (3002) = crushing, 9303 = hurting touch
int type = polythings[i]->info->Special;
if (type >= SMT_PolySpawn && type <= SMT_PolySpawnHurt)
{
// Polyobj StartSpot Pt.
Level->Polyobjects[polyIndex].StartSpot.pos = polythings[i]->pos;
SpawnPolyobj(polyIndex, polythings[i]->angle, type);
polyIndex++;
}
}
for (int i = polythings.Size() - 1; i >= 0; i--)
{
int type = polythings[i]->info->Special;
if (type == SMT_PolyAnchor)
{
// Polyobj Anchor Pt.
TranslateToStartSpot (polythings[i]->angle, polythings[i]->pos);
}
}
// check for a startspot without an anchor point
for (auto &poly : Level->Polyobjects)
{
if (poly.OriginalPts.Size() == 0)
{
Printf (TEXTCOLOR_RED "PO_Init: StartSpot located without an Anchor point: %d\n", poly.tag);
}
}
InitPolyBlockMap();
// [RH] Don't need the side lists anymore
KnownPolySides.Reset();
// mark all subsectors which have a seg belonging to a polyobj
// These ones should not be rendered on the textured automap.
for (auto &ss : Level->subsectors)
{
for(uint32_t j=0;j<ss.numlines; j++)
{
if (ss.firstline[j].sidedef != NULL &&
ss.firstline[j].sidedef->Flags & WALLF_POLYOBJ)
{
ss.flags |= SSECF_POLYORG;
break;
}
}
}
// clear all polyobj specials so that they do not obstruct using other lines.
for (auto &line : Level->lines)
{
if (line.special == Polyobj_ExplicitLine || line.special == Polyobj_StartLine)
{
line.special = 0;
}
}
}

View File

@ -581,7 +581,6 @@ void AActor::SetOrigin(double x, double y, double z, bool moving)
// FBlockLinesIterator // FBlockLinesIterator
// //
//=========================================================================== //===========================================================================
extern polyblock_t **PolyBlockMap;
FBlockLinesIterator::FBlockLinesIterator(int _minx, int _miny, int _maxx, int _maxy, bool keepvalidcount) FBlockLinesIterator::FBlockLinesIterator(int _minx, int _miny, int _maxx, int _maxy, bool keepvalidcount)
{ {
@ -621,7 +620,7 @@ void FBlockLinesIterator::StartBlock(int x, int y)
if (level.blockmap.isValidBlock(x, y)) if (level.blockmap.isValidBlock(x, y))
{ {
int offset = y*level.blockmap.bmapwidth + x; int offset = y*level.blockmap.bmapwidth + x;
polyLink = PolyBlockMap? PolyBlockMap[offset] : NULL; polyLink = level.PolyBlockMap.Size() > offset? level.PolyBlockMap[offset] : nullptr;
polyIndex = 0; polyIndex = 0;
list = level.blockmap.GetLines(x, y); list = level.blockmap.GetLines(x, y);

View File

@ -80,8 +80,6 @@ extern unsigned int R_OldBlend;
static void P_Shutdown (); static void P_Shutdown ();
extern polyblock_t **PolyBlockMap;
//=========================================================================== //===========================================================================
// //
// P_PrecacheLevel // P_PrecacheLevel
@ -279,21 +277,17 @@ void P_FreeLevelData ()
level.blockmap.Clear(); level.blockmap.Clear();
level.Polyobjects.Clear(); level.Polyobjects.Clear();
if (PolyBlockMap != nullptr) for(auto &pb : level.PolyBlockMap)
{ {
for (int i = level.blockmap.bmapwidth*level.blockmap.bmapheight-1; i >= 0; --i) polyblock_t *link = pb;
while (link != nullptr)
{ {
polyblock_t *link = PolyBlockMap[i]; polyblock_t *next = link->next;
while (link != nullptr) delete link;
{ link = next;
polyblock_t *next = link->next;
delete link;
link = next;
}
} }
delete[] PolyBlockMap;
PolyBlockMap = nullptr;
} }
level.PolyBlockMap.Reset();
level.deathmatchstarts.Clear(); level.deathmatchstarts.Clear();
level.AllPlayerStarts.Clear(); level.AllPlayerStarts.Clear();

View File

@ -476,7 +476,6 @@ int SightCheck::P_SightBlockLinesIterator (int x, int y)
polyblock_t *polyLink; polyblock_t *polyLink;
unsigned int i; unsigned int i;
extern polyblock_t **PolyBlockMap;
offset = y*level.blockmap.bmapwidth+x; offset = y*level.blockmap.bmapwidth+x;
@ -484,7 +483,7 @@ int SightCheck::P_SightBlockLinesIterator (int x, int y)
// (We still try to delay activating this for as long as possible.) // (We still try to delay activating this for as long as possible.)
portalfound = portalfound || level.PortalBlockmap(x, y).containsLinkedPortals; portalfound = portalfound || level.PortalBlockmap(x, y).containsLinkedPortals;
polyLink = PolyBlockMap[offset]; polyLink = level.PolyBlockMap[offset];
portalfound |= (polyLink && level.PortalBlockmap.hasLinkedPolyPortals); portalfound |= (polyLink && level.PortalBlockmap.hasLinkedPolyPortals);
while (polyLink) while (polyLink)
{ {

View File

@ -2,7 +2,7 @@
// //
// Copyright 1994-1996 Raven Software // Copyright 1994-1996 Raven Software
// Copyright 1999-2016 Randy Heit // Copyright 1999-2016 Randy Heit
// Copyright 2002-2016 Christoph Oelckers // Copyright 2002-2018 Christoph Oelckers
// //
// This program is free software: you can redistribute it and/or modify // This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU General Public License as published by
@ -40,12 +40,6 @@
#include "actorinlines.h" #include "actorinlines.h"
#include "v_text.h" #include "v_text.h"
#include "maploader/maploader.h"
// MACROS ------------------------------------------------------------------
#define PO_MAXPOLYSEGS 64
// TYPES ------------------------------------------------------------------- // TYPES -------------------------------------------------------------------
class DRotatePoly : public DPolyAction class DRotatePoly : public DPolyAction
@ -138,8 +132,6 @@ static void ReleaseAllPolyNodes();
// PUBLIC DATA DEFINITIONS ------------------------------------------------- // PUBLIC DATA DEFINITIONS -------------------------------------------------
polyblock_t **PolyBlockMap;
// PRIVATE DATA DEFINITIONS ------------------------------------------------ // PRIVATE DATA DEFINITIONS ------------------------------------------------
static FPolyNode *FreePolyNodes; static FPolyNode *FreePolyNodes;
@ -1065,7 +1057,7 @@ void FPolyObj::UnLinkPolyobj ()
{ {
if(i >= 0 && i < level.blockmap.bmapwidth && j >= 0 && j < level.blockmap.bmapheight) if(i >= 0 && i < level.blockmap.bmapwidth && j >= 0 && j < level.blockmap.bmapheight)
{ {
link = PolyBlockMap[index+i]; link = level.PolyBlockMap[index+i];
while(link != NULL && link->polyobj != this) while(link != NULL && link->polyobj != this)
{ {
link = link->next; link = link->next;
@ -1249,7 +1241,7 @@ void FPolyObj::LinkPolyobj ()
{ {
if(i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight*bmapwidth) if(i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight*bmapwidth)
{ {
link = &PolyBlockMap[j+i]; link = &level.PolyBlockMap[j+i];
if(!(*link)) if(!(*link))
{ // Create a new link at the current block cell { // Create a new link at the current block cell
*link = new polyblock_t; *link = new polyblock_t;
@ -1384,380 +1376,6 @@ void FPolyObj::ClosestPoint(const DVector2 &fpos, DVector2 &out, side_t **side)
} }
} }
//==========================================================================
//
// InitBlockMap
//
//==========================================================================
void MapLoader::InitPolyBlockMap ()
{
int bmapwidth = Level->blockmap.bmapwidth;
int bmapheight = Level->blockmap.bmapheight;
PolyBlockMap = new polyblock_t *[bmapwidth*bmapheight];
memset (PolyBlockMap, 0, bmapwidth*bmapheight*sizeof(polyblock_t *));
for(auto &poly : Level->Polyobjects)
{
poly.LinkPolyobj();
}
}
//==========================================================================
//
// InitSideLists [RH]
//
// Group sides by vertex and collect side that are known to belong to a
// polyobject so that they can be initialized fast.
//==========================================================================
void MapLoader::InitSideLists ()
{
auto &sides = Level->sides;
for (unsigned i = 0; i < sides.Size(); ++i)
{
if (sides[i].linedef != NULL &&
(sides[i].linedef->special == Polyobj_StartLine ||
sides[i].linedef->special == Polyobj_ExplicitLine))
{
KnownPolySides.Push (i);
}
}
}
//==========================================================================
//
// AddPolyVert
//
// Helper function for IterFindPolySides()
//
//==========================================================================
static void AddPolyVert(TArray<uint32_t> &vnum, uint32_t vert)
{
for (unsigned int i = vnum.Size() - 1; i-- != 0; )
{
if (vnum[i] == vert)
{ // Already in the set. No need to add it.
return;
}
}
vnum.Push(vert);
}
//==========================================================================
//
// IterFindPolySides
//
// Beginning with the first vertex of the starting side, for each vertex
// in vnum, add all the sides that use it as a first vertex to the polyobj,
// and add all their second vertices to vnum. This continues until there
// are no new vertices in vnum.
//
//==========================================================================
void MapLoader::IterFindPolySides (FPolyObj *po, side_t *side)
{
static TArray<uint32_t> vnum;
unsigned int vnumat;
assert(sidetemp != NULL);
vnum.Clear();
vnum.Push(uint32_t(side->V1()->Index()));
vnumat = 0;
while (vnum.Size() != vnumat)
{
uint32_t sidenum = sidetemp[vnum[vnumat++]].b.first;
while (sidenum != NO_SIDE)
{
po->Sidedefs.Push(&Level->sides[sidenum]);
AddPolyVert(vnum, uint32_t(Level->sides[sidenum].V2()->Index()));
sidenum = sidetemp[sidenum].b.next;
}
}
}
//==========================================================================
//
// SpawnPolyobj
//
//==========================================================================
static int posicmp(const void *a, const void *b)
{
return (*(const side_t **)a)->linedef->args[1] - (*(const side_t **)b)->linedef->args[1];
}
void MapLoader::SpawnPolyobj (int index, int tag, int type)
{
unsigned int ii;
int i;
FPolyObj *po = &Level->Polyobjects[index];
for (ii = 0; ii < KnownPolySides.Size(); ++ii)
{
i = KnownPolySides[ii];
if (i < 0)
{
continue;
}
po->bBlocked = false;
po->bHasPortals = 0;
side_t *sd = &Level->sides[i];
if (sd->linedef->special == Polyobj_StartLine &&
sd->linedef->args[0] == tag)
{
if (po->Sidedefs.Size() > 0)
{
Printf (TEXTCOLOR_RED "SpawnPolyobj: Polyobj %d already spawned.\n", tag);
return;
}
else
{
sd->linedef->special = 0;
sd->linedef->args[0] = 0;
IterFindPolySides(&Level->Polyobjects[index], sd);
po->MirrorNum = sd->linedef->args[1];
po->crush = (type != SMT_PolySpawn) ? 3 : 0;
po->bHurtOnTouch = (type == SMT_PolySpawnHurt);
po->tag = tag;
po->seqType = sd->linedef->args[2];
if (po->seqType < 0 || po->seqType > 63)
{
po->seqType = 0;
}
}
break;
}
}
if (po->Sidedefs.Size() == 0)
{
// didn't find a polyobj through PO_LINE_START
TArray<side_t *> polySideList;
unsigned int psIndexOld;
psIndexOld = po->Sidedefs.Size();
for (ii = 0; ii < KnownPolySides.Size(); ++ii)
{
i = KnownPolySides[ii];
if (i >= 0 &&
Level->sides[i].linedef->special == Polyobj_ExplicitLine &&
Level->sides[i].linedef->args[0] == tag)
{
if (!Level->sides[i].linedef->args[1])
{
Printf(TEXTCOLOR_RED "SpawnPolyobj: Explicit line missing order number in poly %d, linedef %d.\n", tag, Level->sides[i].linedef->Index());
return;
}
else
{
po->Sidedefs.Push(&Level->sides[i]);
}
}
}
qsort(&po->Sidedefs[0], po->Sidedefs.Size(), sizeof(po->Sidedefs[0]), posicmp);
if (po->Sidedefs.Size() > 0)
{
po->crush = (type != SMT_PolySpawn) ? 3 : 0;
po->bHurtOnTouch = (type == SMT_PolySpawnHurt);
po->tag = tag;
po->seqType = po->Sidedefs[0]->linedef->args[3];
po->MirrorNum = po->Sidedefs[0]->linedef->args[2];
}
else
{
Printf(TEXTCOLOR_RED "SpawnPolyobj: Poly %d does not exist\n", tag);
return;
}
}
validcount++;
for(unsigned int i=0; i<po->Sidedefs.Size(); i++)
{
line_t *l = po->Sidedefs[i]->linedef;
if (l->validcount != validcount)
{
FLinePortal *port = l->getPortal();
if (port && (port->mDefFlags & PORTF_PASSABLE))
{
int type = port->mType == PORTT_LINKED ? 2 : 1;
if (po->bHasPortals < type) po->bHasPortals = (uint8_t)type;
}
l->validcount = validcount;
po->Linedefs.Push(l);
vertex_t *v = l->v1;
int j;
for(j = po->Vertices.Size() - 1; j >= 0; j--)
{
if (po->Vertices[j] == v) break;
}
if (j < 0) po->Vertices.Push(v);
v = l->v2;
for(j = po->Vertices.Size() - 1; j >= 0; j--)
{
if (po->Vertices[j] == v) break;
}
if (j < 0) po->Vertices.Push(v);
}
}
po->Sidedefs.ShrinkToFit();
po->Linedefs.ShrinkToFit();
po->Vertices.ShrinkToFit();
}
//==========================================================================
//
// TranslateToStartSpot
//
//==========================================================================
void MapLoader::TranslateToStartSpot (int tag, const DVector2 &origin)
{
FPolyObj *po;
DVector2 delta;
po = PO_GetPolyobj(tag);
if (po == nullptr)
{ // didn't match the tag with a polyobj tag
Printf(TEXTCOLOR_RED "TranslateToStartSpot: Unable to match polyobj tag: %d\n", tag);
return;
}
if (po->Sidedefs.Size() == 0)
{
Printf(TEXTCOLOR_RED "TranslateToStartSpot: Anchor point located without a StartSpot point: %d\n", tag);
return;
}
po->OriginalPts.Resize(po->Sidedefs.Size());
po->PrevPts.Resize(po->Sidedefs.Size());
delta = origin - po->StartSpot.pos;
for (unsigned i = 0; i < po->Sidedefs.Size(); i++)
{
po->Sidedefs[i]->Flags |= WALLF_POLYOBJ;
}
for (unsigned i = 0; i < po->Linedefs.Size(); i++)
{
po->Linedefs[i]->bbox[BOXTOP] -= delta.Y;
po->Linedefs[i]->bbox[BOXBOTTOM] -= delta.Y;
po->Linedefs[i]->bbox[BOXLEFT] -= delta.X;
po->Linedefs[i]->bbox[BOXRIGHT] -= delta.X;
}
for (unsigned i = 0; i < po->Vertices.Size(); i++)
{
po->Vertices[i]->set(po->Vertices[i]->fX() - delta.X, po->Vertices[i]->fY() - delta.Y);
po->OriginalPts[i].pos = po->Vertices[i]->fPos() - po->StartSpot.pos;
}
po->CalcCenter();
// For compatibility purposes
po->CenterSubsector = R_PointInSubsector(po->CenterSpot.pos);
}
//==========================================================================
//
// PO_Init
//
//==========================================================================
void MapLoader::PO_Init (void)
{
int NumPolyobjs = 0;
TArray<FMapThing *> polythings;
for (auto &mthing : MapThingsConverted)
{
if (mthing.EdNum == 0 || mthing.EdNum == -1) continue;
FDoomEdEntry *mentry = mthing.info;
switch (mentry->Special)
{
case SMT_PolyAnchor:
case SMT_PolySpawn:
case SMT_PolySpawnCrush:
case SMT_PolySpawnHurt:
polythings.Push(&mthing);
if (mentry->Special != SMT_PolyAnchor)
NumPolyobjs++;
}
}
int polyIndex;
// [RH] Make this faster
InitSideLists ();
Level->Polyobjects.Resize(NumPolyobjs);
polyIndex = 0; // index polyobj number
// Find the startSpot points, and spawn each polyobj
for (int i=polythings.Size()-1; i >= 0; i--)
{
// 9301 (3001) = no crush, 9302 (3002) = crushing, 9303 = hurting touch
int type = polythings[i]->info->Special;
if (type >= SMT_PolySpawn && type <= SMT_PolySpawnHurt)
{
// Polyobj StartSpot Pt.
Level->Polyobjects[polyIndex].StartSpot.pos = polythings[i]->pos;
SpawnPolyobj(polyIndex, polythings[i]->angle, type);
polyIndex++;
}
}
for (int i = polythings.Size() - 1; i >= 0; i--)
{
int type = polythings[i]->info->Special;
if (type == SMT_PolyAnchor)
{
// Polyobj Anchor Pt.
TranslateToStartSpot (polythings[i]->angle, polythings[i]->pos);
}
}
// check for a startspot without an anchor point
for (auto &poly : Level->Polyobjects)
{
if (poly.OriginalPts.Size() == 0)
{
Printf (TEXTCOLOR_RED "PO_Init: StartSpot located without an Anchor point: %d\n", poly.tag);
}
}
InitPolyBlockMap();
// [RH] Don't need the side lists anymore
KnownPolySides.Reset();
// mark all subsectors which have a seg belonging to a polyobj
// These ones should not be rendered on the textured automap.
for (auto &ss : Level->subsectors)
{
for(uint32_t j=0;j<ss.numlines; j++)
{
if (ss.firstline[j].sidedef != NULL &&
ss.firstline[j].sidedef->Flags & WALLF_POLYOBJ)
{
ss.flags |= SSECF_POLYORG;
break;
}
}
}
// clear all polyobj specials so that they do not obstruct using other lines.
for (auto &line : Level->lines)
{
if (line.special == Polyobj_ExplicitLine || line.special == Polyobj_StartLine)
{
line.special = 0;
}
}
}
//========================================================================== //==========================================================================
// //
// PO_Busy // PO_Busy