2018-12-28 14:05:05 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// 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;
|
|
|
|
|
2018-12-28 14:30:23 +00:00
|
|
|
assert(sidetemp.Size() > 0);
|
2018-12-28 14:05:05 +00:00
|
|
|
|
|
|
|
vnum.Clear();
|
2019-01-05 23:41:46 +00:00
|
|
|
vnum.Push(uint32_t(Index(side->V1())));
|
2018-12-28 14:05:05 +00:00
|
|
|
vnumat = 0;
|
|
|
|
|
|
|
|
while (vnum.Size() != vnumat)
|
|
|
|
{
|
|
|
|
uint32_t sidenum = sidetemp[vnum[vnumat++]].b.first;
|
|
|
|
while (sidenum != NO_SIDE)
|
|
|
|
{
|
|
|
|
po->Sidedefs.Push(&Level->sides[sidenum]);
|
2019-01-05 23:41:46 +00:00
|
|
|
AddPolyVert(vnum, uint32_t(Index(Level->sides[sidenum].V2())));
|
2018-12-28 14:05:05 +00:00
|
|
|
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])
|
|
|
|
{
|
2019-01-05 23:41:46 +00:00
|
|
|
Printf(TEXTCOLOR_RED "SpawnPolyobj: Explicit line missing order number in poly %d, linedef %d.\n", tag, Index(Level->sides[i].linedef));
|
2018-12-28 14:05:05 +00:00
|
|
|
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)
|
|
|
|
{
|
2018-12-29 07:49:53 +00:00
|
|
|
if (mthing.EdNum == 0 || mthing.EdNum == -1 || mthing.info == nullptr) continue;
|
2018-12-28 14:05:05 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|