- added a TStaticArray class that allows safe access to resizable static data (like the sectors, linedefs, etc.) for the VM.

- used this to replace the line list in Sector because that gets already used and implemented proper bounds checks for this type of array.
This commit is contained in:
Christoph Oelckers 2017-01-02 21:40:52 +01:00
parent b31b6589e7
commit 1a16f664e4
24 changed files with 456 additions and 233 deletions

View file

@ -560,6 +560,7 @@ void PType::StaticInit()
RUNTIME_CLASS(PClassPointer)->TypeTableType = RUNTIME_CLASS(PClassPointer); RUNTIME_CLASS(PClassPointer)->TypeTableType = RUNTIME_CLASS(PClassPointer);
RUNTIME_CLASS(PEnum)->TypeTableType = RUNTIME_CLASS(PEnum); RUNTIME_CLASS(PEnum)->TypeTableType = RUNTIME_CLASS(PEnum);
RUNTIME_CLASS(PArray)->TypeTableType = RUNTIME_CLASS(PArray); RUNTIME_CLASS(PArray)->TypeTableType = RUNTIME_CLASS(PArray);
RUNTIME_CLASS(PResizableArray)->TypeTableType = RUNTIME_CLASS(PResizableArray);
RUNTIME_CLASS(PDynArray)->TypeTableType = RUNTIME_CLASS(PDynArray); RUNTIME_CLASS(PDynArray)->TypeTableType = RUNTIME_CLASS(PDynArray);
RUNTIME_CLASS(PMap)->TypeTableType = RUNTIME_CLASS(PMap); RUNTIME_CLASS(PMap)->TypeTableType = RUNTIME_CLASS(PMap);
RUNTIME_CLASS(PStruct)->TypeTableType = RUNTIME_CLASS(PStruct); RUNTIME_CLASS(PStruct)->TypeTableType = RUNTIME_CLASS(PStruct);
@ -2050,6 +2051,80 @@ PArray *NewArray(PType *type, unsigned int count)
return (PArray *)atype; return (PArray *)atype;
} }
/* PArray *****************************************************************/
IMPLEMENT_CLASS(PResizableArray, false, false)
//==========================================================================
//
// PArray - Default Constructor
//
//==========================================================================
PResizableArray::PResizableArray()
{
mDescriptiveName = "ResizableArray";
}
//==========================================================================
//
// PArray - Parameterized Constructor
//
//==========================================================================
PResizableArray::PResizableArray(PType *etype)
: PArray(etype, 0)
{
mDescriptiveName.Format("ResizableArray<%s>", etype->DescriptiveName());
}
//==========================================================================
//
// PArray :: IsMatch
//
//==========================================================================
bool PResizableArray::IsMatch(intptr_t id1, intptr_t id2) const
{
const PType *elemtype = (const PType *)id1;
unsigned int count = (unsigned int)(intptr_t)id2;
return elemtype == ElementType && count == 0;
}
//==========================================================================
//
// PArray :: GetTypeIDs
//
//==========================================================================
void PResizableArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const
{
id1 = (intptr_t)ElementType;
id2 = 0;
}
//==========================================================================
//
// NewResizableArray
//
// Returns a PArray for the given type and size, making sure not to create
// duplicates.
//
//==========================================================================
PResizableArray *NewResizableArray(PType *type)
{
size_t bucket;
PType *atype = TypeTable.FindType(RUNTIME_CLASS(PResizableArray), (intptr_t)type, 0, &bucket);
if (atype == NULL)
{
atype = new PResizableArray(type);
TypeTable.AddType(atype, RUNTIME_CLASS(PResizableArray), (intptr_t)type, 0, bucket);
}
return (PResizableArray *)atype;
}
/* PDynArray **************************************************************/ /* PDynArray **************************************************************/
IMPLEMENT_CLASS(PDynArray, false, true) IMPLEMENT_CLASS(PDynArray, false, true)

View file

@ -660,6 +660,20 @@ protected:
PArray(); PArray();
}; };
class PResizableArray : public PArray
{
DECLARE_CLASS(PResizableArray, PArray);
HAS_OBJECT_POINTERS;
public:
PResizableArray(PType *etype);
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
protected:
PResizableArray();
};
class PDynArray : public PCompoundType class PDynArray : public PCompoundType
{ {
DECLARE_CLASS(PDynArray, PCompoundType); DECLARE_CLASS(PDynArray, PCompoundType);
@ -919,6 +933,7 @@ extern FTypeTable TypeTable;
// Returns a type from the TypeTable. Will create one if it isn't present. // Returns a type from the TypeTable. Will create one if it isn't present.
PMap *NewMap(PType *keytype, PType *valuetype); PMap *NewMap(PType *keytype, PType *valuetype);
PArray *NewArray(PType *type, unsigned int count); PArray *NewArray(PType *type, unsigned int count);
PResizableArray *NewResizableArray(PType *type);
PDynArray *NewDynArray(PType *type); PDynArray *NewDynArray(PType *type);
PPointer *NewPointer(PType *type, bool isconst = false); PPointer *NewPointer(PType *type, bool isconst = false);
PClassPointer *NewClassPointer(PClass *restrict); PClassPointer *NewClassPointer(PClass *restrict);

View file

@ -305,7 +305,6 @@ static void PrepareTransparentDoors(sector_t * sector)
int notextures=0; int notextures=0;
int nobtextures=0; int nobtextures=0;
int selfref=0; int selfref=0;
int i;
sector_t * nextsec=NULL; sector_t * nextsec=NULL;
#ifdef _DEBUG #ifdef _DEBUG
@ -323,15 +322,15 @@ static void PrepareTransparentDoors(sector_t * sector)
if (sector->transdoor) if (sector->transdoor)
{ {
for (i=0; i<sector->linecount; i++) for (auto ln : sector->Lines)
{ {
if (sector->lines[i]->frontsector==sector->lines[i]->backsector) if (ln->frontsector == ln->backsector)
{ {
selfref++; selfref++;
continue; continue;
} }
sector_t * sec=getNextSector(sector->lines[i], sector); sector_t * sec=getNextSector(ln, sector);
if (sec==NULL) if (sec==NULL)
{ {
solidwall=true; solidwall=true;
@ -341,15 +340,15 @@ static void PrepareTransparentDoors(sector_t * sector)
{ {
nextsec=sec; nextsec=sec;
int side = sector->lines[i]->sidedef[0]->sector == sec; int side = ln->sidedef[0]->sector == sec;
if (sector->GetPlaneTexZ(sector_t::floor)!=sec->GetPlaneTexZ(sector_t::floor)+1. || sec->floorplane.isSlope()) if (sector->GetPlaneTexZ(sector_t::floor)!=sec->GetPlaneTexZ(sector_t::floor)+1. || sec->floorplane.isSlope())
{ {
sector->transdoor=false; sector->transdoor=false;
return; return;
} }
if (!sector->lines[i]->sidedef[1-side]->GetTexture(side_t::top).isValid()) notextures++; if (!ln->sidedef[1-side]->GetTexture(side_t::top).isValid()) notextures++;
if (!sector->lines[i]->sidedef[1-side]->GetTexture(side_t::bottom).isValid()) nobtextures++; if (!ln->sidedef[1-side]->GetTexture(side_t::bottom).isValid()) nobtextures++;
} }
} }
if (sector->GetTexture(sector_t::ceiling)==skyflatnum) if (sector->GetTexture(sector_t::ceiling)==skyflatnum)
@ -358,19 +357,19 @@ static void PrepareTransparentDoors(sector_t * sector)
return; return;
} }
if (selfref+nobtextures!=sector->linecount) if (selfref+nobtextures!=sector->Lines.Size())
{ {
sector->transdoor=false; sector->transdoor=false;
} }
if (selfref+notextures!=sector->linecount) if (selfref+notextures!=sector->Lines.Size())
{ {
// This is a crude attempt to fix an incorrect transparent door effect I found in some // This is a crude attempt to fix an incorrect transparent door effect I found in some
// WolfenDoom maps but considering the amount of code required to handle it I left it in. // WolfenDoom maps but considering the amount of code required to handle it I left it in.
// Do this only if the sector only contains one-sided walls or ones with no lower texture. // Do this only if the sector only contains one-sided walls or ones with no lower texture.
if (solidwall) if (solidwall)
{ {
if (solidwall+nobtextures+selfref==sector->linecount && nextsec) if (solidwall+nobtextures+selfref==sector->Lines.Size() && nextsec)
{ {
sector->heightsec=nextsec; sector->heightsec=nextsec;
sector->heightsec->MoreFlags=0; sector->heightsec->MoreFlags=0;
@ -604,9 +603,8 @@ void gl_PreprocessLevel()
PrepareTransparentDoors(&sectors[i]); PrepareTransparentDoors(&sectors[i]);
// This ignores vertices only used for seg splitting because those aren't needed here // This ignores vertices only used for seg splitting because those aren't needed here
for(int j = 0; j < sectors[i].linecount; j++) for(auto l : sectors[i].Lines)
{ {
line_t *l = sectors[i].lines[j];
if (l->sidedef[0]->Flags & WALLF_POLYOBJ) continue; // don't bother with polyobjects if (l->sidedef[0]->Flags & WALLF_POLYOBJ) continue; // don't bother with polyobjects
int vtnum1 = int(l->v1 - vertexes); int vtnum1 = int(l->v1 - vertexes);

View file

@ -320,9 +320,8 @@ void GLFlat::DrawSkyboxSector(int pass, bool processlights)
float minx = FLT_MAX, miny = FLT_MAX; float minx = FLT_MAX, miny = FLT_MAX;
float maxx = -FLT_MAX, maxy = -FLT_MAX; float maxx = -FLT_MAX, maxy = -FLT_MAX;
for (int i = 0; i < sector->linecount; i++) for (auto ln : sector->Lines)
{ {
line_t *ln = sector->lines[i];
float x = ln->v1->fX(); float x = ln->v1->fX();
float y = ln->v1->fY(); float y = ln->v1->fY();
if (x < minx) minx = x; if (x < minx) minx = x;

View file

@ -756,6 +756,7 @@ xx(ResolveState)
xx(DamageFunction) xx(DamageFunction)
xx(Length) xx(Length)
xx(Unit) xx(Unit)
xx(Size)
xx(StateLabel) xx(StateLabel)
xx(SpriteID) xx(SpriteID)
xx(TextureID) xx(TextureID)

View file

@ -216,7 +216,7 @@ static void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flag
//========================================================================== //==========================================================================
static int P_Set3DFloor(line_t * line, int param, int param2, int alpha) static int P_Set3DFloor(line_t * line, int param, int param2, int alpha)
{ {
int s, i; int s;
int flags; int flags;
int tag = line->args[0]; int tag = line->args[0];
sector_t * sec = line->frontsector, *ss; sector_t * sec = line->frontsector, *ss;
@ -230,10 +230,8 @@ static int P_Set3DFloor(line_t * line, int param, int param2, int alpha)
{ {
flags = FF_EXISTS | FF_RENDERALL | FF_SOLID | FF_INVERTSECTOR; flags = FF_EXISTS | FF_RENDERALL | FF_SOLID | FF_INVERTSECTOR;
alpha = 255; alpha = 255;
for (i = 0; i < sec->linecount; i++) for (auto l: sec->Lines)
{ {
line_t * l = sec->lines[i];
if (l->special == Sector_SetContents && l->frontsector == sec) if (l->special == Sector_SetContents && l->frontsector == sec)
{ {
alpha = clamp<int>(l->args[1], 0, 100); alpha = clamp<int>(l->args[1], 0, 100);

View file

@ -167,10 +167,8 @@ void P_Attach3dMidtexLinesToSector(sector_t *sector, int lineid, int tag, bool c
int sec; int sec;
while ((sec = it.Next()) >= 0) while ((sec = it.Next()) >= 0)
{ {
for (int line = 0; line < sectors[sec].linecount; line ++) for (auto ln : sectors[sec].Lines)
{ {
line_t *ln = sectors[sec].lines[line];
if (lineid != 0 && !tagManager.LineHasID(ln, lineid)) continue; if (lineid != 0 && !tagManager.LineHasID(ln, lineid)) continue;
if (ln->frontsector == NULL || ln->backsector == NULL || !(ln->flags & ML_3DMIDTEX)) if (ln->frontsector == NULL || ln->backsector == NULL || !(ln->flags & ML_3DMIDTEX))

View file

@ -242,7 +242,7 @@ bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int t
// new door thinker // new door thinker
DCeiling *ceiling = new DCeiling (sec, speed, speed2, silent & ~4); DCeiling *ceiling = new DCeiling (sec, speed, speed2, silent & ~4);
vertex_t *spot = sec->lines[0]->v1; vertex_t *spot = sec->Lines[0]->v1;
switch (type) switch (type)
{ {

View file

@ -286,10 +286,9 @@ void DDoor::DoorSound(bool raise, DSeqNode *curseq) const
// Search the front top textures of 2-sided lines on the door sector // Search the front top textures of 2-sided lines on the door sector
// for a door sound to use. // for a door sound to use.
for (int i = 0; i < m_Sector->linecount; ++i) for (auto line : m_Sector->Lines)
{ {
const char *texname; const char *texname;
line_t *line = m_Sector->lines[i];
if (line->backsector == NULL) if (line->backsector == NULL)
continue; continue;
@ -694,14 +693,14 @@ DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay,
m_Line1 = line; m_Line1 = line;
m_Line2 = line; m_Line2 = line;
for (int i = 0; i < sec->linecount; ++i) for (auto l : sec->Lines)
{ {
if (sec->lines[i] == line) if (l == line)
continue; continue;
if (sec->lines[i]->sidedef[0]->GetTexture(side_t::top) == line->sidedef[0]->GetTexture(side_t::top)) if (l->sidedef[0]->GetTexture(side_t::top) == line->sidedef[0]->GetTexture(side_t::top))
{ {
m_Line2 = sec->lines[i]; m_Line2 = l;
break; break;
} }
} }
@ -789,9 +788,8 @@ bool EV_SlidingDoor (line_t *line, AActor *actor, int tag, int speed, int delay)
continue; continue;
} }
for (int i = 0; tag != 0 && i < sec->linecount; ++i) for (auto line : sec->Lines)
{ {
line = sec->lines[i];
if (line->backsector == NULL) if (line->backsector == NULL)
{ {
continue; continue;

View file

@ -161,10 +161,8 @@ static void P_RecursiveSound(sector_t *sec, AActor *soundtarget, bool splash, AA
bool checkabove = !sec->PortalBlocksSound(sector_t::ceiling); bool checkabove = !sec->PortalBlocksSound(sector_t::ceiling);
bool checkbelow = !sec->PortalBlocksSound(sector_t::floor); bool checkbelow = !sec->PortalBlocksSound(sector_t::floor);
for (int i = 0; i < sec->linecount; i++) for (auto check : sec->Lines)
{ {
line_t *check = sec->lines[i];
// check sector portals // check sector portals
// I wish there was a better method to do this than randomly looking through the portal at a few places... // I wish there was a better method to do this than randomly looking through the portal at a few places...
if (checkabove) if (checkabove)

View file

@ -578,7 +578,6 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line,
int osecnum; //jff 3/4/98 save old loop index int osecnum; //jff 3/4/98 save old loop index
double height; double height;
double stairstep; double stairstep;
int i;
int newsecnum = -1; int newsecnum = -1;
FTextureID texture; FTextureID texture;
int ok; int ok;
@ -669,18 +668,18 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line,
} }
else else
{ {
for (i = 0; i < sec->linecount; i++) for (auto line : sec->Lines)
{ {
if ( !((sec->lines[i])->flags & ML_TWOSIDED) ) if ( !(line->flags & ML_TWOSIDED) )
continue; continue;
tsec = (sec->lines[i])->frontsector; tsec = line->frontsector;
newsecnum = (int)(tsec-sectors); newsecnum = (int)(tsec-sectors);
if (secnum != newsecnum) if (secnum != newsecnum)
continue; continue;
tsec = (sec->lines[i])->backsector; tsec = line->backsector;
if (!tsec) continue; //jff 5/7/98 if no backside, continue if (!tsec) continue; //jff 5/7/98 if no backside, continue
newsecnum = (int)(tsec - sectors); newsecnum = (int)(tsec - sectors);
@ -765,7 +764,6 @@ bool EV_DoDonut (int tag, line_t *line, double pillarspeed, double slimespeed)
sector_t* s3; sector_t* s3;
int secnum; int secnum;
bool rtn; bool rtn;
int i;
DFloor* floor; DFloor* floor;
vertex_t* spot; vertex_t* spot;
double height; double height;
@ -782,19 +780,19 @@ bool EV_DoDonut (int tag, line_t *line, double pillarspeed, double slimespeed)
continue; // safe now, because we check that tag is non-0 in the looping condition [fdari] continue; // safe now, because we check that tag is non-0 in the looping condition [fdari]
rtn = true; rtn = true;
s2 = getNextSector (s1->lines[0], s1); // s2 is pool's sector s2 = getNextSector (s1->Lines[0], s1); // s2 is pool's sector
if (!s2) // note lowest numbered line around if (!s2) // note lowest numbered line around
continue; // pillar must be two-sided continue; // pillar must be two-sided
if (s2->PlaneMoving(sector_t::floor)) if (s2->PlaneMoving(sector_t::floor))
continue; continue;
for (i = 0; i < s2->linecount; i++) for (auto ln : s2->Lines)
{ {
if (!(s2->lines[i]->flags & ML_TWOSIDED) || if (!(ln->flags & ML_TWOSIDED) ||
(s2->lines[i]->backsector == s1)) (ln->backsector == s1))
continue; continue;
s3 = s2->lines[i]->backsector; s3 = ln->backsector;
// Spawn rising slime // Spawn rising slime
floor = new DFloor (s2); floor = new DFloor (s2);

View file

@ -540,9 +540,9 @@ void EV_TurnTagLightsOff (int tag)
sector_t *sector = sectors + secnum; sector_t *sector = sectors + secnum;
int min = sector->lightlevel; int min = sector->lightlevel;
for (int i = 0; i < sector->linecount; i++) for (auto ln : sector->Lines)
{ {
sector_t *tsec = getNextSector (sector->lines[i],sector); sector_t *tsec = getNextSector (ln, sector);
if (!tsec) if (!tsec)
continue; continue;
if (tsec->lightlevel < min) if (tsec->lightlevel < min)
@ -574,11 +574,9 @@ void EV_LightTurnOn (int tag, int bright)
// surrounding sector // surrounding sector
if (bright < 0) if (bright < 0)
{ {
int j; for (auto ln : sector->Lines)
for (j = 0; j < sector->linecount; j++)
{ {
sector_t *temp = getNextSector (sector->lines[j], sector); sector_t *temp = getNextSector(ln, sector);
if (!temp) if (!temp)
continue; continue;
@ -622,11 +620,11 @@ void EV_LightTurnOnPartway (int tag, double frac)
while ((secnum = it.Next()) >= 0) while ((secnum = it.Next()) >= 0)
{ {
sector_t *temp, *sector = &sectors[secnum]; sector_t *temp, *sector = &sectors[secnum];
int j, bright = 0, min = sector->lightlevel; int bright = 0, min = sector->lightlevel;
for (j = 0; j < sector->linecount; ++j) for (auto ln : sector->Lines)
{ {
if ((temp = getNextSector (sector->lines[j], sector)) != NULL) if ((temp = getNextSector (ln, sector)) != nullptr)
{ {
if (temp->lightlevel > bright) if (temp->lightlevel > bright)
{ {

View file

@ -45,12 +45,8 @@
sector_t *sector_t::NextSpecialSector (int type, sector_t *nogood) const sector_t *sector_t::NextSpecialSector (int type, sector_t *nogood) const
{ {
sector_t *tsec; sector_t *tsec;
int i; for (auto ln : Lines)
for (i = 0; i < linecount; i++)
{ {
line_t *ln = lines[i];
if (NULL != (tsec = getNextSector (ln, this)) && if (NULL != (tsec = getNextSector (ln, this)) &&
tsec != nogood && tsec != nogood &&
tsec->special == type) tsec->special == type)
@ -67,21 +63,18 @@ sector_t *sector_t::NextSpecialSector (int type, sector_t *nogood) const
// //
double sector_t::FindLowestFloorSurrounding (vertex_t **v) const double sector_t::FindLowestFloorSurrounding (vertex_t **v) const
{ {
int i;
sector_t *other; sector_t *other;
line_t *check;
double floor; double floor;
double ofloor; double ofloor;
vertex_t *spot; vertex_t *spot;
if (linecount == 0) return GetPlaneTexZ(sector_t::floor); if (Lines.Size() == 0) return GetPlaneTexZ(sector_t::floor);
spot = lines[0]->v1; spot = Lines[0]->v1;
floor = floorplane.ZatPoint(spot); floor = floorplane.ZatPoint(spot);
for (i = 0; i < linecount; i++) for (auto check : Lines)
{ {
check = lines[i];
if (NULL != (other = getNextSector (check, this))) if (NULL != (other = getNextSector (check, this)))
{ {
ofloor = other->floorplane.ZatPoint (check->v1); ofloor = other->floorplane.ZatPoint (check->v1);
@ -111,21 +104,18 @@ double sector_t::FindLowestFloorSurrounding (vertex_t **v) const
// //
double sector_t::FindHighestFloorSurrounding (vertex_t **v) const double sector_t::FindHighestFloorSurrounding (vertex_t **v) const
{ {
int i;
line_t *check;
sector_t *other; sector_t *other;
double floor; double floor;
double ofloor; double ofloor;
vertex_t *spot; vertex_t *spot;
if (linecount == 0) return GetPlaneTexZ(sector_t::floor); if (Lines.Size() == 0) return GetPlaneTexZ(sector_t::floor);
spot = lines[0]->v1; spot = Lines[0]->v1;
floor = -FLT_MAX; floor = -FLT_MAX;
for (i = 0; i < linecount; i++) for (auto check : Lines)
{ {
check = lines[i];
if (NULL != (other = getNextSector (check, this))) if (NULL != (other = getNextSector (check, this)))
{ {
ofloor = other->floorplane.ZatPoint (check->v1); ofloor = other->floorplane.ZatPoint (check->v1);
@ -166,18 +156,15 @@ double sector_t::FindNextHighestFloor (vertex_t **v) const
double ofloor, floor; double ofloor, floor;
sector_t *other; sector_t *other;
vertex_t *spot; vertex_t *spot;
line_t *check;
int i;
if (linecount == 0) return GetPlaneTexZ(sector_t::floor); if (Lines.Size() == 0) return GetPlaneTexZ(sector_t::floor);
spot = lines[0]->v1; spot = Lines[0]->v1;
height = floorplane.ZatPoint(spot); height = floorplane.ZatPoint(spot);
heightdiff = FLT_MAX; heightdiff = FLT_MAX;
for (i = 0; i < linecount; i++) for (auto check : Lines)
{ {
check = lines[i];
if (NULL != (other = getNextSector (check, this))) if (NULL != (other = getNextSector (check, this)))
{ {
ofloor = other->floorplane.ZatPoint (check->v1); ofloor = other->floorplane.ZatPoint (check->v1);
@ -221,18 +208,15 @@ double sector_t::FindNextLowestFloor (vertex_t **v) const
double ofloor, floor; double ofloor, floor;
sector_t *other; sector_t *other;
vertex_t *spot; vertex_t *spot;
line_t *check;
int i;
if (linecount == 0) return GetPlaneTexZ(sector_t::floor); if (Lines.Size() == 0) return GetPlaneTexZ(sector_t::floor);
spot = lines[0]->v1; spot = Lines[0]->v1;
height = floorplane.ZatPoint (spot); height = floorplane.ZatPoint (spot);
heightdiff = FLT_MAX; heightdiff = FLT_MAX;
for (i = 0; i < linecount; i++) for (auto check : Lines)
{ {
check = lines[i];
if (NULL != (other = getNextSector (check, this))) if (NULL != (other = getNextSector (check, this)))
{ {
ofloor = other->floorplane.ZatPoint (check->v1); ofloor = other->floorplane.ZatPoint (check->v1);
@ -275,19 +259,15 @@ double sector_t::FindNextLowestCeiling (vertex_t **v) const
double oceil, ceil; double oceil, ceil;
sector_t *other; sector_t *other;
vertex_t *spot; vertex_t *spot;
line_t *check;
int i;
if (Lines.Size() == 0) return GetPlaneTexZ(sector_t::floor);
if (linecount == 0) return GetPlaneTexZ(sector_t::ceiling); spot = Lines[0]->v1;
spot = lines[0]->v1;
height = ceilingplane.ZatPoint(spot); height = ceilingplane.ZatPoint(spot);
heightdiff = FLT_MAX; heightdiff = FLT_MAX;
for (i = 0; i < linecount; i++) for (auto check : Lines)
{ {
check = lines[i];
if (NULL != (other = getNextSector (check, this))) if (NULL != (other = getNextSector (check, this)))
{ {
oceil = other->ceilingplane.ZatPoint(check->v1); oceil = other->ceilingplane.ZatPoint(check->v1);
@ -330,18 +310,15 @@ double sector_t::FindNextHighestCeiling (vertex_t **v) const
double oceil, ceil; double oceil, ceil;
sector_t *other; sector_t *other;
vertex_t *spot; vertex_t *spot;
line_t *check;
int i;
if (linecount == 0) return GetPlaneTexZ(sector_t::ceiling); if (Lines.Size() == 0) return GetPlaneTexZ(sector_t::ceiling);
spot = lines[0]->v1; spot = Lines[0]->v1;
height = ceilingplane.ZatPoint(spot); height = ceilingplane.ZatPoint(spot);
heightdiff = FLT_MAX; heightdiff = FLT_MAX;
for (i = 0; i < linecount; i++) for (auto check : Lines)
{ {
check = lines[i];
if (NULL != (other = getNextSector (check, this))) if (NULL != (other = getNextSector (check, this)))
{ {
oceil = other->ceilingplane.ZatPoint(check->v1); oceil = other->ceilingplane.ZatPoint(check->v1);
@ -376,17 +353,14 @@ double sector_t::FindLowestCeilingSurrounding (vertex_t **v) const
double oceil; double oceil;
sector_t *other; sector_t *other;
vertex_t *spot; vertex_t *spot;
line_t *check;
int i;
if (linecount == 0) return GetPlaneTexZ(sector_t::ceiling); if (Lines.Size() == 0) return GetPlaneTexZ(sector_t::ceiling);
spot = lines[0]->v1; spot = Lines[0]->v1;
height = FLT_MAX; height = FLT_MAX;
for (i = 0; i < linecount; i++) for (auto check : Lines)
{ {
check = lines[i];
if (NULL != (other = getNextSector (check, this))) if (NULL != (other = getNextSector (check, this)))
{ {
oceil = other->ceilingplane.ZatPoint(check->v1); oceil = other->ceilingplane.ZatPoint(check->v1);
@ -418,17 +392,14 @@ double sector_t::FindHighestCeilingSurrounding (vertex_t **v) const
double oceil; double oceil;
sector_t *other; sector_t *other;
vertex_t *spot; vertex_t *spot;
line_t *check;
int i;
if (linecount == 0) return GetPlaneTexZ(sector_t::ceiling); if (Lines.Size() == 0) return GetPlaneTexZ(sector_t::ceiling);
spot = lines[0]->v1; spot = Lines[0]->v1;
height = -FLT_MAX; height = -FLT_MAX;
for (i = 0; i < linecount; i++) for (auto check : Lines)
{ {
check = lines[i];
if (NULL != (other = getNextSector (check, this))) if (NULL != (other = getNextSector (check, this)))
{ {
oceil = other->ceilingplane.ZatPoint(check->v1); oceil = other->ceilingplane.ZatPoint(check->v1);
@ -479,12 +450,12 @@ double sector_t::FindShortestTextureAround () const
{ {
double minsize = FLT_MAX; double minsize = FLT_MAX;
for (int i = 0; i < linecount; i++) for (auto check : Lines)
{ {
if (lines[i]->flags & ML_TWOSIDED) if (check->flags & ML_TWOSIDED)
{ {
CheckShortestTex (lines[i]->sidedef[0]->GetTexture(side_t::bottom), minsize); CheckShortestTex (check->sidedef[0]->GetTexture(side_t::bottom), minsize);
CheckShortestTex (lines[i]->sidedef[1]->GetTexture(side_t::bottom), minsize); CheckShortestTex (check->sidedef[1]->GetTexture(side_t::bottom), minsize);
} }
} }
return minsize < FLT_MAX ? minsize : TexMan[0]->GetHeight(); return minsize < FLT_MAX ? minsize : TexMan[0]->GetHeight();
@ -505,12 +476,12 @@ double sector_t::FindShortestUpperAround () const
{ {
double minsize = FLT_MAX; double minsize = FLT_MAX;
for (int i = 0; i < linecount; i++) for (auto check : Lines)
{ {
if (lines[i]->flags & ML_TWOSIDED) if (check->flags & ML_TWOSIDED)
{ {
CheckShortestTex (lines[i]->sidedef[0]->GetTexture(side_t::top), minsize); CheckShortestTex (check->sidedef[0]->GetTexture(side_t::top), minsize);
CheckShortestTex (lines[i]->sidedef[1]->GetTexture(side_t::top), minsize); CheckShortestTex (check->sidedef[1]->GetTexture(side_t::top), minsize);
} }
} }
return minsize < FLT_MAX ? minsize : TexMan[0]->GetHeight(); return minsize < FLT_MAX ? minsize : TexMan[0]->GetHeight();
@ -533,17 +504,14 @@ double sector_t::FindShortestUpperAround () const
// //
sector_t *sector_t::FindModelFloorSector (double floordestheight) const sector_t *sector_t::FindModelFloorSector (double floordestheight) const
{ {
int i;
sector_t *sec; sector_t *sec;
//jff 5/23/98 don't disturb sec->linecount while searching for (auto check : Lines)
// but allow early exit in old demos
for (i = 0; i < linecount; i++)
{ {
sec = getNextSector (lines[i], this); sec = getNextSector (check, this);
if (sec != NULL && if (sec != NULL &&
(sec->floorplane.ZatPoint(lines[i]->v1) == floordestheight || (sec->floorplane.ZatPoint(check->v1) == floordestheight ||
sec->floorplane.ZatPoint(lines[i]->v2) == floordestheight)) sec->floorplane.ZatPoint(check->v2) == floordestheight))
{ {
return sec; return sec;
} }
@ -569,17 +537,14 @@ sector_t *sector_t::FindModelFloorSector (double floordestheight) const
// //
sector_t *sector_t::FindModelCeilingSector (double floordestheight) const sector_t *sector_t::FindModelCeilingSector (double floordestheight) const
{ {
int i;
sector_t *sec; sector_t *sec;
//jff 5/23/98 don't disturb sec->linecount while searching for (auto check : Lines)
// but allow early exit in old demos
for (i = 0; i < linecount; i++)
{ {
sec = getNextSector (lines[i], this); sec = getNextSector (check, this);
if (sec != NULL && if (sec != NULL &&
(sec->ceilingplane.ZatPoint(lines[i]->v1) == floordestheight || (sec->ceilingplane.ZatPoint(check->v1) == floordestheight ||
sec->ceilingplane.ZatPoint(lines[i]->v2) == floordestheight)) sec->ceilingplane.ZatPoint(check->v2) == floordestheight))
{ {
return sec; return sec;
} }
@ -592,13 +557,10 @@ sector_t *sector_t::FindModelCeilingSector (double floordestheight) const
// //
int sector_t::FindMinSurroundingLight (int min) const int sector_t::FindMinSurroundingLight (int min) const
{ {
int i;
line_t* line;
sector_t* check; sector_t* check;
for (i = 0; i < linecount; i++) for (auto line : Lines)
{ {
line = lines[i];
if (NULL != (check = getNextSector (line, this)) && if (NULL != (check = getNextSector (line, this)) &&
check->lightlevel < min) check->lightlevel < min)
{ {
@ -613,8 +575,6 @@ int sector_t::FindMinSurroundingLight (int min) const
// //
double sector_t::FindHighestFloorPoint (vertex_t **v) const double sector_t::FindHighestFloorPoint (vertex_t **v) const
{ {
int i;
line_t *line;
double height = -FLT_MAX; double height = -FLT_MAX;
double probeheight; double probeheight;
vertex_t *spot = NULL; vertex_t *spot = NULL;
@ -623,15 +583,14 @@ double sector_t::FindHighestFloorPoint (vertex_t **v) const
{ {
if (v != NULL) if (v != NULL)
{ {
if (linecount == 0) *v = &vertexes[0]; if (Lines.Size() == 0) *v = &vertexes[0];
else *v = lines[0]->v1; else *v = Lines[0]->v1;
} }
return -floorplane.fD(); return -floorplane.fD();
} }
for (i = 0; i < linecount; i++) for (auto line : Lines)
{ {
line = lines[i];
probeheight = floorplane.ZatPoint(line->v1); probeheight = floorplane.ZatPoint(line->v1);
if (probeheight > height) if (probeheight > height)
{ {
@ -655,8 +614,6 @@ double sector_t::FindHighestFloorPoint (vertex_t **v) const
// //
double sector_t::FindLowestCeilingPoint (vertex_t **v) const double sector_t::FindLowestCeilingPoint (vertex_t **v) const
{ {
int i;
line_t *line;
double height = FLT_MAX; double height = FLT_MAX;
double probeheight; double probeheight;
vertex_t *spot = NULL; vertex_t *spot = NULL;
@ -665,15 +622,14 @@ double sector_t::FindLowestCeilingPoint (vertex_t **v) const
{ {
if (v != NULL) if (v != NULL)
{ {
if (linecount == 0) *v = &vertexes[0]; if (Lines.Size() == 0) *v = &vertexes[0];
else *v = lines[0]->v1; else *v = Lines[0]->v1;
} }
return ceilingplane.fD(); return ceilingplane.fD();
} }
for (i = 0; i < linecount; i++) for (auto line : Lines)
{ {
line = lines[i];
probeheight = ceilingplane.ZatPoint(line->v1); probeheight = ceilingplane.ZatPoint(line->v1);
if (probeheight < height) if (probeheight < height)
{ {
@ -738,15 +694,14 @@ DEFINE_ACTION_FUNCTION(_Sector, SetFade)
void sector_t::ClosestPoint(const DVector2 &in, DVector2 &out) const void sector_t::ClosestPoint(const DVector2 &in, DVector2 &out) const
{ {
int i;
double x = in.X, y = in.Y; double x = in.X, y = in.Y;
double bestdist = HUGE_VAL; double bestdist = HUGE_VAL;
double bestx = 0, besty = 0; double bestx = 0, besty = 0;
for (i = 0; i < linecount; ++i) for (auto check : Lines)
{ {
vertex_t *v1 = lines[i]->v1; vertex_t *v1 = check->v1;
vertex_t *v2 = lines[i]->v2; vertex_t *v2 = check->v2;
double a = v2->fX() - v1->fX(); double a = v2->fX() - v1->fX();
double b = v2->fY() - v1->fY(); double b = v2->fY() - v1->fY();
double den = a*a + b*b; double den = a*a + b*b;
@ -1133,9 +1088,8 @@ DEFINE_ACTION_FUNCTION(_Sector, NextLowestFloorAt)
void sector_t::RemoveForceField() void sector_t::RemoveForceField()
{ {
for (int i = 0; i < linecount; ++i) for (auto line : Lines)
{ {
line_t *line = lines[i];
if (line->backsector != NULL && line->special == ForceField) if (line->backsector != NULL && line->special == ForceField)
{ {
line->flags &= ~(ML_BLOCKING | ML_BLOCKEVERYTHING); line->flags &= ~(ML_BLOCKING | ML_BLOCKEVERYTHING);
@ -1377,8 +1331,7 @@ DEFINE_FIELD_X(Sector, sector_t, soundtraversed)
DEFINE_FIELD_X(Sector, sector_t, stairlock) DEFINE_FIELD_X(Sector, sector_t, stairlock)
DEFINE_FIELD_X(Sector, sector_t, prevsec) DEFINE_FIELD_X(Sector, sector_t, prevsec)
DEFINE_FIELD_X(Sector, sector_t, nextsec) DEFINE_FIELD_X(Sector, sector_t, nextsec)
DEFINE_FIELD_X(Sector, sector_t, linecount) DEFINE_FIELD_X(Sector, sector_t, Lines)
DEFINE_FIELD_X(Sector, sector_t, lines)
DEFINE_FIELD_X(Sector, sector_t, heightsec) DEFINE_FIELD_X(Sector, sector_t, heightsec)
DEFINE_FIELD_X(Sector, sector_t, bottommap) DEFINE_FIELD_X(Sector, sector_t, bottommap)
DEFINE_FIELD_X(Sector, sector_t, midmap) DEFINE_FIELD_X(Sector, sector_t, midmap)

View file

@ -775,16 +775,13 @@ static void SetTextureNoErr (side_t *side, int position, DWORD *color, const cha
void P_FloodZone (sector_t *sec, int zonenum) void P_FloodZone (sector_t *sec, int zonenum)
{ {
int i;
if (sec->ZoneNumber == zonenum) if (sec->ZoneNumber == zonenum)
return; return;
sec->ZoneNumber = zonenum; sec->ZoneNumber = zonenum;
for (i = 0; i < sec->linecount; ++i) for (auto check : sec->Lines)
{ {
line_t *check = sec->lines[i];
sector_t *other; sector_t *other;
if (check->sidedef[1] == NULL || (check->flags & ML_ZONEBOUNDARY)) if (check->sidedef[1] == NULL || (check->flags & ML_ZONEBOUNDARY))
@ -3093,7 +3090,6 @@ static void P_GroupLines (bool buildmap)
cycle_t times[16]; cycle_t times[16];
int* linesDoneInEachSector; int* linesDoneInEachSector;
int i; int i;
int j;
int total; int total;
line_t* li; line_t* li;
sector_t* sector; sector_t* sector;
@ -3140,13 +3136,13 @@ static void P_GroupLines (bool buildmap)
} }
else else
{ {
li->frontsector->linecount++; li->frontsector->Lines.Count++;
total++; total++;
} }
if (li->backsector && li->backsector != li->frontsector) if (li->backsector && li->backsector != li->frontsector)
{ {
li->backsector->linecount++; li->backsector->Lines.Count++;
total++; total++;
} }
} }
@ -3165,7 +3161,7 @@ static void P_GroupLines (bool buildmap)
for (sector = sectors, i = 0; i < numsectors; i++, sector++) for (sector = sectors, i = 0; i < numsectors; i++, sector++)
{ {
if (sector->linecount == 0) if (sector->Lines.Count == 0)
{ {
Printf ("Sector %i (tag %i) has no lines\n", i, tagManager.GetFirstSectorTag(sector)); Printf ("Sector %i (tag %i) has no lines\n", i, tagManager.GetFirstSectorTag(sector));
// 0 the sector's tag so that no specials can use it // 0 the sector's tag so that no specials can use it
@ -3173,8 +3169,8 @@ static void P_GroupLines (bool buildmap)
} }
else else
{ {
sector->lines = lineb_p; sector->Lines.Array = lineb_p;
lineb_p += sector->linecount; lineb_p += sector->Lines.Count;
} }
} }
@ -3182,26 +3178,25 @@ static void P_GroupLines (bool buildmap)
{ {
if (li->frontsector != NULL) if (li->frontsector != NULL)
{ {
li->frontsector->lines[linesDoneInEachSector[li->frontsector - sectors]++] = li; li->frontsector->Lines[linesDoneInEachSector[li->frontsector - sectors]++] = li;
} }
if (li->backsector != NULL && li->backsector != li->frontsector) if (li->backsector != NULL && li->backsector != li->frontsector)
{ {
li->backsector->lines[linesDoneInEachSector[li->backsector - sectors]++] = li; li->backsector->Lines[linesDoneInEachSector[li->backsector - sectors]++] = li;
} }
} }
for (i = 0, sector = sectors; i < numsectors; ++i, ++sector) for (i = 0, sector = sectors; i < numsectors; ++i, ++sector)
{ {
if (linesDoneInEachSector[i] != sector->linecount) if (linesDoneInEachSector[i] != sector->Lines.Size())
{ {
I_Error("P_GroupLines: miscounted"); I_Error("P_GroupLines: miscounted");
} }
if (sector->linecount > 3) if (sector->Lines.Size() > 3)
{ {
bbox.ClearBox(); bbox.ClearBox();
for (j = 0; j < sector->linecount; ++j) for (auto li : sector->Lines)
{ {
li = sector->lines[j];
bbox.AddToBox(li->v1->fPos()); bbox.AddToBox(li->v1->fPos());
bbox.AddToBox(li->v2->fPos()); bbox.AddToBox(li->v2->fPos());
} }
@ -3210,15 +3205,15 @@ static void P_GroupLines (bool buildmap)
sector->centerspot.X = (bbox.Right() + bbox.Left()) / 2; sector->centerspot.X = (bbox.Right() + bbox.Left()) / 2;
sector->centerspot.Y = (bbox.Top() + bbox.Bottom()) / 2; sector->centerspot.Y = (bbox.Top() + bbox.Bottom()) / 2;
} }
else if (sector->linecount > 0) else if (sector->Lines.Size() > 0)
{ {
// For triangular sectors the above does not calculate good points unless the longest of the triangle's lines is perfectly horizontal and vertical // For triangular sectors the above does not calculate good points unless the longest of the triangle's lines is perfectly horizontal and vertical
DVector2 pos = { 0,0 }; DVector2 pos = { 0,0 };
for (int i = 0; i < sector->linecount; i++) for (auto ln : sector->Lines)
{ {
pos += sector->lines[i]->v1->fPos() + sector->lines[i]->v2->fPos(); pos += ln->v1->fPos() + ln->v2->fPos();
} }
sector->centerspot = pos / (2 * sector->linecount); sector->centerspot = pos / (2 * sector->Lines.Size());
} }
} }
delete[] linesDoneInEachSector; delete[] linesDoneInEachSector;

View file

@ -201,10 +201,8 @@ void P_SetSlope (secplane_t *plane, bool setCeil, int xyangi, int zangi, const D
void P_VavoomSlope(sector_t * sec, int id, const DVector3 &pos, int which) void P_VavoomSlope(sector_t * sec, int id, const DVector3 &pos, int which)
{ {
for (int i=0;i<sec->linecount;i++) for(auto l : sec->Lines)
{ {
line_t * l=sec->lines[i];
if (l->args[0]==id) if (l->args[0]==id)
{ {
DVector3 v1, v2, cross; DVector3 v1, v2, cross;
@ -306,16 +304,16 @@ static void P_SetSlopesFromVertexHeights(FMapThing *firstmt, FMapThing *lastmt,
for (int i = 0; i < numsectors; i++) for (int i = 0; i < numsectors; i++)
{ {
sector_t *sec = &sectors[i]; sector_t *sec = &sectors[i];
if (sec->linecount != 3) continue; // only works with triangular sectors if (sec->Lines.Size() != 3) continue; // only works with triangular sectors
DVector3 vt1, vt2, vt3, cross; DVector3 vt1, vt2, vt3, cross;
DVector3 vec1, vec2; DVector3 vec1, vec2;
int vi1, vi2, vi3; int vi1, vi2, vi3;
vi1 = int(sec->lines[0]->v1 - vertexes); vi1 = int(sec->Lines[0]->v1 - vertexes);
vi2 = int(sec->lines[0]->v2 - vertexes); vi2 = int(sec->Lines[0]->v2 - vertexes);
vi3 = (sec->lines[1]->v1 == sec->lines[0]->v1 || sec->lines[1]->v1 == sec->lines[0]->v2)? vi3 = (sec->Lines[1]->v1 == sec->Lines[0]->v1 || sec->Lines[1]->v1 == sec->Lines[0]->v2)?
int(sec->lines[1]->v2 - vertexes) : int(sec->lines[1]->v1 - vertexes); int(sec->Lines[1]->v2 - vertexes) : int(sec->Lines[1]->v1 - vertexes);
vt1 = DVector3(vertexes[vi1].fPos(), 0); vt1 = DVector3(vertexes[vi1].fPos(), 0);
vt2 = DVector3(vertexes[vi2].fPos(), 0); vt2 = DVector3(vertexes[vi2].fPos(), 0);
@ -332,7 +330,7 @@ static void P_SetSlopesFromVertexHeights(FMapThing *firstmt, FMapThing *lastmt,
vt2.Z = h2? *h2 : j==0? sec->GetPlaneTexZ(sector_t::floor) : sec->GetPlaneTexZ(sector_t::ceiling); vt2.Z = h2? *h2 : j==0? sec->GetPlaneTexZ(sector_t::floor) : sec->GetPlaneTexZ(sector_t::ceiling);
vt3.Z = h3? *h3 : j==0? sec->GetPlaneTexZ(sector_t::floor) : sec->GetPlaneTexZ(sector_t::ceiling); vt3.Z = h3? *h3 : j==0? sec->GetPlaneTexZ(sector_t::floor) : sec->GetPlaneTexZ(sector_t::ceiling);
if (P_PointOnLineSidePrecise(vertexes[vi3].fX(), vertexes[vi3].fY(), sec->lines[0]) == 0) if (P_PointOnLineSidePrecise(vertexes[vi3].fX(), vertexes[vi3].fY(), sec->Lines[0]) == 0)
{ {
vec1 = vt2 - vt3; vec1 = vt2 - vt3;
vec2 = vt1 - vt3; vec2 = vt1 - vt3;
@ -451,9 +449,7 @@ static void P_AlignPlane(sector_t *sec, line_t *line, int which)
{ {
sector_t *refsec; sector_t *refsec;
double bestdist; double bestdist;
vertex_t *refvert = (*sec->lines)->v1; // Shut up, GCC vertex_t *refvert = sec->Lines[0]->v1; // Shut up, GCC
int i;
line_t **probe;
if (line->backsector == NULL) if (line->backsector == NULL)
return; return;
@ -461,22 +457,22 @@ static void P_AlignPlane(sector_t *sec, line_t *line, int which)
// Find furthest vertex from the reference line. It, along with the two ends // Find furthest vertex from the reference line. It, along with the two ends
// of the line, will define the plane. // of the line, will define the plane.
bestdist = 0; bestdist = 0;
for (i = sec->linecount * 2, probe = sec->lines; i > 0; i--) for (auto ln : sec->Lines)
{ {
double dist; for (int i = 0; i < 2; i++)
vertex_t *vert;
if (i & 1)
vert = (*probe++)->v2;
else
vert = (*probe)->v1;
dist = fabs((line->v1->fY() - vert->fY()) * line->Delta().X -
(line->v1->fX() - vert->fX()) * line->Delta().Y);
if (dist > bestdist)
{ {
bestdist = dist; double dist;
refvert = vert; vertex_t *vert;
vert = i == 0 ? ln->v1 : ln->v2;
dist = fabs((line->v1->fY() - vert->fY()) * line->Delta().X -
(line->v1->fX() - vert->fX()) * line->Delta().Y);
if (dist > bestdist)
{
bestdist = dist;
refvert = vert;
}
} }
} }

View file

@ -1038,10 +1038,8 @@ void P_SpawnSkybox(ASkyViewpoint *origin)
} }
if (Sector) if (Sector)
{ {
line_t * refline = NULL; for(auto refline : Sector->Lines)
for (short i = 0; i < Sector->linecount; i++)
{ {
refline = Sector->lines[i];
if (refline->special == Sector_SetPortal && refline->args[1] == 2) if (refline->special == Sector_SetPortal && refline->args[1] == 2)
{ {
// We found the setup linedef for this skybox, so let's use it for our init. // We found the setup linedef for this skybox, so let's use it for our init.

View file

@ -801,9 +801,8 @@ static bool CollectSectors(int groupid, sector_t *origin)
{ {
sector_t *sec = list[i]; sector_t *sec = list[i];
for (int j = 0; j < sec->linecount; j++) for (auto line : sec->Lines)
{ {
line_t *line = sec->lines[j];
sector_t *other = line->frontsector == sec ? line->backsector : line->frontsector; sector_t *other = line->frontsector == sec ? line->backsector : line->frontsector;
if (other != NULL && other != sec && other->PortalGroup != groupid) if (other != NULL && other != sec && other->PortalGroup != groupid)
{ {
@ -1096,9 +1095,9 @@ void P_CreateLinkedPortals()
// set a flag on each line connecting to a plane portal sector. This is used to reduce the amount of checks in P_CheckSight. // set a flag on each line connecting to a plane portal sector. This is used to reduce the amount of checks in P_CheckSight.
if (sectors[i].PortalIsLinked(sector_t::floor) || sectors[i].PortalIsLinked(sector_t::ceiling)) if (sectors[i].PortalIsLinked(sector_t::floor) || sectors[i].PortalIsLinked(sector_t::ceiling))
{ {
for (int j = 0; j < sectors[i].linecount; j++) for(auto ln : sectors[i].Lines)
{ {
sectors[i].lines[j]->flags |= ML_PORTALCONNECT; ln->flags |= ML_PORTALCONNECT;
} }
} }
if (sectors[i].PortalIsLinked(sector_t::ceiling) && sectors[i].PortalIsLinked(sector_t::floor)) if (sectors[i].PortalIsLinked(sector_t::ceiling) && sectors[i].PortalIsLinked(sector_t::floor))

View file

@ -1037,8 +1037,7 @@ public:
// jff 2/26/98 lockout machinery for stairbuilding // jff 2/26/98 lockout machinery for stairbuilding
SBYTE stairlock; // -2 on first locked -1 after thinker done 0 normally SBYTE stairlock; // -2 on first locked -1 after thinker done 0 normally
short linecount; TStaticPointedArray<line_t *> Lines;
struct line_t **lines; // [linecount] size
// killough 3/7/98: support flat heights drawn at another sector's heights // killough 3/7/98: support flat heights drawn at another sector's heights
sector_t *heightsec; // other sector, or NULL if no other sector sector_t *heightsec; // other sector, or NULL if no other sector

View file

@ -6620,6 +6620,7 @@ FxArrayElement::FxArrayElement(FxExpression *base, FxExpression *_index)
index = _index; index = _index;
AddressRequested = false; AddressRequested = false;
AddressWritable = false; AddressWritable = false;
SizeAddr = ~0u;
} }
//========================================================================== //==========================================================================
@ -6691,10 +6692,31 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
arraytype = static_cast<PArray*>(ptype->PointedType); arraytype = static_cast<PArray*>(ptype->PointedType);
arrayispointer = true; arrayispointer = true;
} }
if (index->isConstant())
if (Array->IsResizableArray())
{
// if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset.
if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember)
{
auto parentfield = static_cast<FxStructMember *>(Array)->membervar;
SizeAddr = unsigned(parentfield->Offset + parentfield->Type->Align);
}
else if (Array->ExprType == EFX_GlobalVariable)
{
auto parentfield = static_cast<FxGlobalVariable *>(Array)->membervar;
SizeAddr = unsigned(parentfield->Offset + parentfield->Type->Align);
}
else
{
ScriptPosition.Message(MSG_ERROR, "Invalid resizable array");
delete this;
return nullptr;
}
}
else if (index->isConstant())
{ {
unsigned indexval = static_cast<FxConstant *>(index)->GetValue().GetInt(); unsigned indexval = static_cast<FxConstant *>(index)->GetValue().GetInt();
if (indexval >= arraytype->ElementCount) if (indexval >= arraytype->ElementCount && !Array->IsResizableArray())
{ {
ScriptPosition.Message(MSG_ERROR, "Array index out of bounds"); ScriptPosition.Message(MSG_ERROR, "Array index out of bounds");
delete this; delete this;
@ -6767,21 +6789,40 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
arraytype = static_cast<PArray*>(Array->ValueType); arraytype = static_cast<PArray*>(Array->ValueType);
} }
ExpEmit start = Array->Emit(build); ExpEmit start = Array->Emit(build);
ExpEmit bound;
/* what was this for? // For resizable arrays we even need to check the bounds if if the index is constant.
if (start.Konst) if (SizeAddr != ~0u)
{ {
ExpEmit tmpstart(build, REGT_POINTER); auto f = new PField(NAME_None, TypeUInt32, 0, SizeAddr);
build->Emit(OP_LKP, tmpstart.RegNum, start.RegNum); if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember)
start.Free(build); {
start = tmpstart; static_cast<FxStructMember *>(Array)->membervar = f;
static_cast<FxStructMember *>(Array)->AddressRequested = false;
}
else if (Array->ExprType == EFX_GlobalVariable)
{
static_cast<FxGlobalVariable *>(Array)->membervar = f;
static_cast<FxGlobalVariable *>(Array)->AddressRequested = false;
}
Array->ValueType = TypeUInt32;
bound = Array->Emit(build);
} }
*/
if (index->isConstant()) if (index->isConstant())
{ {
unsigned indexval = static_cast<FxConstant *>(index)->GetValue().GetInt(); unsigned indexval = static_cast<FxConstant *>(index)->GetValue().GetInt();
assert(indexval < arraytype->ElementCount && "Array index out of bounds"); assert(SizeAddr != ~0u || (indexval < arraytype->ElementCount && "Array index out of bounds"));
if (SizeAddr != ~0u)
{
ExpEmit indexreg(build, REGT_INT);
build->EmitLoadInt(indexreg.RegNum, indexval);
build->Emit(OP_BOUND_R, indexreg.RegNum, bound.RegNum);
indexreg.Free(build);
bound.Free(build);
}
if (AddressRequested) if (AddressRequested)
{ {
if (indexval != 0) if (indexval != 0)
@ -6821,9 +6862,12 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
else else
{ {
ExpEmit indexv(index->Emit(build)); ExpEmit indexv(index->Emit(build));
// Todo: For dynamically allocated arrays (like global sector and linedef tables) we need to get the bound value in here somehow. if (SizeAddr != ~0u)
// Right now their bounds are not properly checked for. {
if (arraytype->ElementCount > 65535) build->Emit(OP_BOUND_R, indexv.RegNum, bound.RegNum);
bound.Free(build);
}
else if (arraytype->ElementCount > 65535)
{ {
build->Emit(OP_BOUND_K, indexv.RegNum, build->GetConstantInt(arraytype->ElementCount)); build->Emit(OP_BOUND_K, indexv.RegNum, build->GetConstantInt(arraytype->ElementCount));
} }
@ -7347,7 +7391,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
// Note: These builtins would better be relegated to the actual type objects, instead of polluting this file, but that's a task for later. // Note: These builtins would better be relegated to the actual type objects, instead of polluting this file, but that's a task for later.
// Texture builtins. // Texture builtins.
if (Self->ValueType == TypeTextureID) else if (Self->ValueType == TypeTextureID)
{ {
if (MethodName == NAME_IsValid || MethodName == NAME_IsNull || MethodName == NAME_Exists || MethodName == NAME_SetInvalid || MethodName == NAME_SetNull) if (MethodName == NAME_IsValid || MethodName == NAME_IsNull || MethodName == NAME_Exists || MethodName == NAME_SetInvalid || MethodName == NAME_SetNull)
{ {
@ -7390,7 +7434,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
} }
} }
if (Self->IsVector()) else if (Self->IsVector())
{ {
// handle builtins: Vectors got 2: Length and Unit. // handle builtins: Vectors got 2: Length and Unit.
if (MethodName == NAME_Length || MethodName == NAME_Unit) if (MethodName == NAME_Length || MethodName == NAME_Unit)
@ -7408,11 +7452,63 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
} }
} }
if (Self->ValueType == TypeString) else if (Self->ValueType == TypeString)
{ {
// same for String methods. It also uses a hidden struct type to define them. // same for String methods. It also uses a hidden struct type to define them.
Self->ValueType = TypeStringStruct; Self->ValueType = TypeStringStruct;
} }
else if (Self->IsArray())
{
if (MethodName == NAME_Size)
{
if (ArgList.Size() > 0)
{
ScriptPosition.Message(MSG_ERROR, "too many parameters in call to %s", MethodName.GetChars());
delete this;
return nullptr;
}
if (!Self->IsResizableArray())
{
auto atype = Self->ValueType;
if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) atype = static_cast<PPointer*>(ValueType)->PointedType;
auto size = static_cast<PArray*>(atype)->ElementCount;
auto x = new FxConstant(size, ScriptPosition);
delete this;
return x;
}
else
{
// Resizable arrays can only be defined in C code and they can only exist in pointer form to reduce their impact on the code generator.
if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember)
{
auto member = static_cast<FxStructMember*>(Self);
auto newfield = new PField(NAME_None, TypeUInt32, VARF_ReadOnly, member->membervar->Offset + member->membervar->Type->Align); // the size is stored right behind the pointer.
member->membervar = newfield;
Self = nullptr;
delete this;
member->ValueType = TypeUInt32;
return member;
}
else if (Self->ExprType == EFX_GlobalVariable)
{
auto member = static_cast<FxGlobalVariable*>(Self);
auto newfield = new PField(NAME_None, TypeUInt32, VARF_ReadOnly, member->membervar->Offset + member->membervar->Type->Align); // the size is stored right behind the pointer.
member->membervar = newfield;
Self = nullptr;
delete this;
member->ValueType = TypeUInt32;
return member;
}
else
{
// This should never happen because resizable arrays cannot be defined in scripts.
ScriptPosition.Message(MSG_ERROR, "Cannot retrieve size of array");
delete this;
return nullptr;
}
}
}
}
if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))
{ {

View file

@ -326,6 +326,8 @@ public:
bool IsVector() const { return ValueType == TypeVector2 || ValueType == TypeVector3; }; bool IsVector() const { return ValueType == TypeVector2 || ValueType == TypeVector3; };
bool IsBoolCompat() const { return ValueType->GetRegCount() == 1 && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT || ValueType->GetRegType() == REGT_POINTER); } bool IsBoolCompat() const { return ValueType->GetRegCount() == 1 && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT || ValueType->GetRegType() == REGT_POINTER); }
bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && ValueType != TypeNullPtr && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)); } bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && ValueType != TypeNullPtr && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)); }
bool IsArray() const { return ValueType->IsKindOf(RUNTIME_CLASS(PArray)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PArray))); }
bool IsResizableArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PResizableArray))); } // can only exist in pointer form.
virtual ExpEmit Emit(VMFunctionBuilder *build); virtual ExpEmit Emit(VMFunctionBuilder *build);
void EmitStatement(VMFunctionBuilder *build); void EmitStatement(VMFunctionBuilder *build);
@ -426,6 +428,13 @@ public:
isresolved = true; isresolved = true;
} }
FxConstant(unsigned int val, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos)
{
ValueType = value.Type = TypeUInt32;
value.Int = val;
isresolved = true;
}
FxConstant(double val, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) FxConstant(double val, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos)
{ {
ValueType = value.Type = TypeFloat64; ValueType = value.Type = TypeFloat64;
@ -1427,6 +1436,7 @@ class FxArrayElement : public FxExpression
public: public:
FxExpression *Array; FxExpression *Array;
FxExpression *index; FxExpression *index;
unsigned SizeAddr;
bool AddressRequested; bool AddressRequested;
bool AddressWritable; bool AddressWritable;
bool arrayispointer = false; bool arrayispointer = false;

View file

@ -710,12 +710,8 @@ static int fieldcmp(const void * a, const void * b)
void InitThingdef() void InitThingdef()
{ {
PType *TypeActor = NewPointer(RUNTIME_CLASS(AActor)); // Create all global variables here because this cannot be done on the script side and really isn't worth adding support for.
PStruct *sstruct = NewNativeStruct("Sector", nullptr);
auto sptr = NewPointer(sstruct);
sstruct->AddNativeField("soundtarget", TypeActor, myoffsetof(sector_t, SoundTarget));
// expose the global validcount variable. // expose the global validcount variable.
PField *vcf = new PField("validcount", TypeSInt32, VARF_Native | VARF_Static, (intptr_t)&validcount); PField *vcf = new PField("validcount", TypeSInt32, VARF_Native | VARF_Static, (intptr_t)&validcount);
GlobalSymbols.AddSymbol(vcf); GlobalSymbols.AddSymbol(vcf);
@ -746,7 +742,7 @@ void InitThingdef()
// set up the lines array in the sector struct. This is a bit messy because the type system is not prepared to handle a pointer to an array of pointers to a native struct even remotely well... // set up the lines array in the sector struct. This is a bit messy because the type system is not prepared to handle a pointer to an array of pointers to a native struct even remotely well...
// As a result, the size has to be set to something large and arbritrary because it can change between maps. This will need some serious improvement when things get cleaned up. // As a result, the size has to be set to something large and arbritrary because it can change between maps. This will need some serious improvement when things get cleaned up.
pstruct = NewNativeStruct("Sector", nullptr); pstruct = NewNativeStruct("Sector", nullptr);
pstruct->AddNativeField("lines", NewPointer(NewArray(NewPointer(NewNativeStruct("line", nullptr), false), 0x40000), false), myoffsetof(sector_t, lines), VARF_Native); pstruct->AddNativeField("lines", NewPointer(NewResizableArray(NewPointer(NewNativeStruct("line", nullptr), false)), false), myoffsetof(sector_t, Lines), VARF_Native);
parray = NewArray(TypeBool, MAXPLAYERS); parray = NewArray(TypeBool, MAXPLAYERS);
playerf = new PField("playeringame", parray, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&playeringame); playerf = new PField("playeringame", parray, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&playeringame);

View file

@ -467,6 +467,112 @@ public:
} }
}; };
// A non-resizable array
// This is meant for data that can be replaced but is otherwise static as long as it exists.
// The reason for it is to replace any global pointer/counter pairs with something that can
// be reliably accessed by the scripting VM and which can use 'for' iterator syntax.
// This is split into two, so that it also can be used to wrap arrays that are not directly allocated.
// This first class only gets a reference to some data but won't own it.
template <class T>
class TStaticPointedArray
{
public:
typedef TIterator<T> iterator;
typedef TIterator<const T> const_iterator;
iterator begin()
{
return &Array[0];
}
const_iterator begin() const
{
return &Array[0];
}
const_iterator cbegin() const
{
return &Array[0];
}
iterator end()
{
return &Array[Count];
}
const_iterator end() const
{
return &Array[Count];
}
const_iterator cend() const
{
return &Array[Count];
}
void Init(T *ptr, unsigned cnt)
{
Array = ptr;
Count = cnt;
}
// Return a reference to an element
T &operator[] (size_t index) const
{
return Array[index];
}
unsigned int Size() const
{
return Count;
}
// Some code needs to access these directly so they cannot be private.
T *Array;
unsigned int Count;
};
// This second type owns its data, it can delete and reallocate it, but it cannot
// resize the array or repurpose its old contents if new ones are about to be created.
template <class T>
class TStaticArray : public TStaticPointedArray<T>
{
public:
////////
// This is a dummy constructor that does nothing. The purpose of this
// is so you can create a global TArray in the data segment that gets
// used by code before startup without worrying about the constructor
// resetting it after it's already been used. You MUST NOT use it for
// heap- or stack-allocated TArrays.
enum ENoInit
{
NoInit
};
TStaticArray(ENoInit dummy)
{
}
////////
TStaticArray()
{
Count = 0;
Array = NULL;
}
// This is not supposed to be copyable.
TStaticArray(const TStaticArray<T> &other) = delete;
~TStaticArray()
{
Clear();
}
void Clear()
{
if (Array) delete[] Array;
}
void Alloc(unsigned int amount)
{
Clear();
Array = new T[amount];
Count = Amount;
}
};
// TAutoGrowArray ----------------------------------------------------------- // TAutoGrowArray -----------------------------------------------------------
// An array with accessors that automatically grow the array as needed. // An array with accessors that automatically grow the array as needed.
// It can still be used as a normal TArray if needed. ACS uses this for // It can still be used as a normal TArray if needed. ACS uses this for

View file

@ -273,8 +273,7 @@ struct Sector native
native int prevsec; native int prevsec;
native int nextsec; native int nextsec;
native readonly int16 linecount; //TStaticPointedArray<line_t *> Lines; // this is defined internally to avoid exposing some overly complicated type to the parser
//line_t **lines; // this is defined internally to avoid exposing some overly complicated type to the parser
native readonly Sector heightsec; native readonly Sector heightsec;

View file

@ -58,7 +58,7 @@ class LittleFly : Actor
return fallback; return fallback;
} }
// Try neighboring sectors // Try neighboring sectors
for (int i = 0; i < sec.linecount; ++i) for (int i = 0; i < sec.lines.Size(); ++i)
{ {
line ln = sec.lines[i]; line ln = sec.lines[i];
sector sec2 = (ln.frontsector == sec) ? ln.backsector : ln.frontsector; sector sec2 = (ln.frontsector == sec) ? ln.backsector : ln.frontsector;