diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 15331c7934..9a1c9f83a9 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -560,6 +560,7 @@ void PType::StaticInit() RUNTIME_CLASS(PClassPointer)->TypeTableType = RUNTIME_CLASS(PClassPointer); RUNTIME_CLASS(PEnum)->TypeTableType = RUNTIME_CLASS(PEnum); RUNTIME_CLASS(PArray)->TypeTableType = RUNTIME_CLASS(PArray); + RUNTIME_CLASS(PResizableArray)->TypeTableType = RUNTIME_CLASS(PResizableArray); RUNTIME_CLASS(PDynArray)->TypeTableType = RUNTIME_CLASS(PDynArray); RUNTIME_CLASS(PMap)->TypeTableType = RUNTIME_CLASS(PMap); RUNTIME_CLASS(PStruct)->TypeTableType = RUNTIME_CLASS(PStruct); @@ -2050,6 +2051,80 @@ PArray *NewArray(PType *type, unsigned int count) 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 **************************************************************/ IMPLEMENT_CLASS(PDynArray, false, true) diff --git a/src/dobjtype.h b/src/dobjtype.h index c310f9863b..a6dd69a6ec 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -660,6 +660,20 @@ protected: 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 { 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. PMap *NewMap(PType *keytype, PType *valuetype); PArray *NewArray(PType *type, unsigned int count); +PResizableArray *NewResizableArray(PType *type); PDynArray *NewDynArray(PType *type); PPointer *NewPointer(PType *type, bool isconst = false); PClassPointer *NewClassPointer(PClass *restrict); diff --git a/src/gl/data/gl_setup.cpp b/src/gl/data/gl_setup.cpp index 37f5c370ea..376b4aa6d2 100644 --- a/src/gl/data/gl_setup.cpp +++ b/src/gl/data/gl_setup.cpp @@ -305,7 +305,6 @@ static void PrepareTransparentDoors(sector_t * sector) int notextures=0; int nobtextures=0; int selfref=0; - int i; sector_t * nextsec=NULL; #ifdef _DEBUG @@ -323,15 +322,15 @@ static void PrepareTransparentDoors(sector_t * sector) if (sector->transdoor) { - for (i=0; ilinecount; i++) + for (auto ln : sector->Lines) { - if (sector->lines[i]->frontsector==sector->lines[i]->backsector) + if (ln->frontsector == ln->backsector) { selfref++; continue; } - sector_t * sec=getNextSector(sector->lines[i], sector); + sector_t * sec=getNextSector(ln, sector); if (sec==NULL) { solidwall=true; @@ -341,15 +340,15 @@ static void PrepareTransparentDoors(sector_t * sector) { 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()) { sector->transdoor=false; return; } - if (!sector->lines[i]->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::top).isValid()) notextures++; + if (!ln->sidedef[1-side]->GetTexture(side_t::bottom).isValid()) nobtextures++; } } if (sector->GetTexture(sector_t::ceiling)==skyflatnum) @@ -358,19 +357,19 @@ static void PrepareTransparentDoors(sector_t * sector) return; } - if (selfref+nobtextures!=sector->linecount) + if (selfref+nobtextures!=sector->Lines.Size()) { 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 // 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. if (solidwall) { - if (solidwall+nobtextures+selfref==sector->linecount && nextsec) + if (solidwall+nobtextures+selfref==sector->Lines.Size() && nextsec) { sector->heightsec=nextsec; sector->heightsec->MoreFlags=0; @@ -604,9 +603,8 @@ void gl_PreprocessLevel() PrepareTransparentDoors(§ors[i]); // 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 int vtnum1 = int(l->v1 - vertexes); diff --git a/src/gl/scene/gl_flats.cpp b/src/gl/scene/gl_flats.cpp index bc47e448b6..62a96157a9 100644 --- a/src/gl/scene/gl_flats.cpp +++ b/src/gl/scene/gl_flats.cpp @@ -320,9 +320,8 @@ void GLFlat::DrawSkyboxSector(int pass, bool processlights) float minx = FLT_MAX, miny = 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 y = ln->v1->fY(); if (x < minx) minx = x; diff --git a/src/namedef.h b/src/namedef.h index 45e1e67f28..778d1c3274 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -756,6 +756,7 @@ xx(ResolveState) xx(DamageFunction) xx(Length) xx(Unit) +xx(Size) xx(StateLabel) xx(SpriteID) xx(TextureID) diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index c2d011be95..7c25276734 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -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) { - int s, i; + int s; int flags; int tag = line->args[0]; 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; 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) { alpha = clamp(l->args[1], 0, 100); diff --git a/src/p_3dmidtex.cpp b/src/p_3dmidtex.cpp index 39263dd91d..7e7e1591a0 100644 --- a/src/p_3dmidtex.cpp +++ b/src/p_3dmidtex.cpp @@ -167,10 +167,8 @@ void P_Attach3dMidtexLinesToSector(sector_t *sector, int lineid, int tag, bool c int sec; 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 (ln->frontsector == NULL || ln->backsector == NULL || !(ln->flags & ML_3DMIDTEX)) diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index 4da81db46d..4af4186518 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -242,7 +242,7 @@ bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int t // new door thinker 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) { diff --git a/src/p_doors.cpp b/src/p_doors.cpp index aa59e5463f..b85bdb1076 100644 --- a/src/p_doors.cpp +++ b/src/p_doors.cpp @@ -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 // for a door sound to use. - for (int i = 0; i < m_Sector->linecount; ++i) + for (auto line : m_Sector->Lines) { const char *texname; - line_t *line = m_Sector->lines[i]; if (line->backsector == NULL) continue; @@ -694,14 +693,14 @@ DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay, m_Line1 = 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; - 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; } } @@ -789,9 +788,8 @@ bool EV_SlidingDoor (line_t *line, AActor *actor, int tag, int speed, int delay) continue; } - for (int i = 0; tag != 0 && i < sec->linecount; ++i) + for (auto line : sec->Lines) { - line = sec->lines[i]; if (line->backsector == NULL) { continue; diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 326c0dca4c..a3d48a7ace 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -161,10 +161,8 @@ static void P_RecursiveSound(sector_t *sec, AActor *soundtarget, bool splash, AA bool checkabove = !sec->PortalBlocksSound(sector_t::ceiling); 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 // I wish there was a better method to do this than randomly looking through the portal at a few places... if (checkabove) diff --git a/src/p_floor.cpp b/src/p_floor.cpp index fbfa70f2e7..c16720c4f1 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -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 double height; double stairstep; - int i; int newsecnum = -1; FTextureID texture; int ok; @@ -669,18 +668,18 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line, } 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; - tsec = (sec->lines[i])->frontsector; + tsec = line->frontsector; newsecnum = (int)(tsec-sectors); if (secnum != newsecnum) continue; - tsec = (sec->lines[i])->backsector; + tsec = line->backsector; if (!tsec) continue; //jff 5/7/98 if no backside, continue newsecnum = (int)(tsec - sectors); @@ -765,7 +764,6 @@ bool EV_DoDonut (int tag, line_t *line, double pillarspeed, double slimespeed) sector_t* s3; int secnum; bool rtn; - int i; DFloor* floor; vertex_t* spot; 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] 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 continue; // pillar must be two-sided if (s2->PlaneMoving(sector_t::floor)) continue; - for (i = 0; i < s2->linecount; i++) + for (auto ln : s2->Lines) { - if (!(s2->lines[i]->flags & ML_TWOSIDED) || - (s2->lines[i]->backsector == s1)) + if (!(ln->flags & ML_TWOSIDED) || + (ln->backsector == s1)) continue; - s3 = s2->lines[i]->backsector; + s3 = ln->backsector; // Spawn rising slime floor = new DFloor (s2); diff --git a/src/p_lights.cpp b/src/p_lights.cpp index a05199b91a..873368166a 100644 --- a/src/p_lights.cpp +++ b/src/p_lights.cpp @@ -540,9 +540,9 @@ void EV_TurnTagLightsOff (int tag) sector_t *sector = sectors + secnum; 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) continue; if (tsec->lightlevel < min) @@ -574,11 +574,9 @@ void EV_LightTurnOn (int tag, int bright) // surrounding sector if (bright < 0) { - int j; - - for (j = 0; j < sector->linecount; j++) + for (auto ln : sector->Lines) { - sector_t *temp = getNextSector (sector->lines[j], sector); + sector_t *temp = getNextSector(ln, sector); if (!temp) continue; @@ -622,11 +620,11 @@ void EV_LightTurnOnPartway (int tag, double frac) while ((secnum = it.Next()) >= 0) { sector_t *temp, *sector = §ors[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) { diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 22ef883580..2850f22645 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -45,12 +45,8 @@ sector_t *sector_t::NextSpecialSector (int type, sector_t *nogood) const { sector_t *tsec; - int i; - - for (i = 0; i < linecount; i++) + for (auto ln : Lines) { - line_t *ln = lines[i]; - if (NULL != (tsec = getNextSector (ln, this)) && tsec != nogood && 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 { - int i; sector_t *other; - line_t *check; double floor; double ofloor; 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); - for (i = 0; i < linecount; i++) + for (auto check : Lines) { - check = lines[i]; if (NULL != (other = getNextSector (check, this))) { 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 { - int i; - line_t *check; sector_t *other; double floor; double ofloor; 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; - for (i = 0; i < linecount; i++) + for (auto check : Lines) { - check = lines[i]; if (NULL != (other = getNextSector (check, this))) { ofloor = other->floorplane.ZatPoint (check->v1); @@ -166,18 +156,15 @@ double sector_t::FindNextHighestFloor (vertex_t **v) const double ofloor, floor; sector_t *other; 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); heightdiff = FLT_MAX; - for (i = 0; i < linecount; i++) + for (auto check : Lines) { - check = lines[i]; if (NULL != (other = getNextSector (check, this))) { ofloor = other->floorplane.ZatPoint (check->v1); @@ -221,18 +208,15 @@ double sector_t::FindNextLowestFloor (vertex_t **v) const double ofloor, floor; sector_t *other; 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); heightdiff = FLT_MAX; - for (i = 0; i < linecount; i++) + for (auto check : Lines) { - check = lines[i]; if (NULL != (other = getNextSector (check, this))) { ofloor = other->floorplane.ZatPoint (check->v1); @@ -275,19 +259,15 @@ double sector_t::FindNextLowestCeiling (vertex_t **v) const double oceil, ceil; sector_t *other; 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); heightdiff = FLT_MAX; - for (i = 0; i < linecount; i++) + for (auto check : Lines) { - check = lines[i]; if (NULL != (other = getNextSector (check, this))) { oceil = other->ceilingplane.ZatPoint(check->v1); @@ -330,18 +310,15 @@ double sector_t::FindNextHighestCeiling (vertex_t **v) const double oceil, ceil; sector_t *other; 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); heightdiff = FLT_MAX; - for (i = 0; i < linecount; i++) + for (auto check : Lines) { - check = lines[i]; if (NULL != (other = getNextSector (check, this))) { oceil = other->ceilingplane.ZatPoint(check->v1); @@ -376,17 +353,14 @@ double sector_t::FindLowestCeilingSurrounding (vertex_t **v) const double oceil; sector_t *other; 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; - for (i = 0; i < linecount; i++) + for (auto check : Lines) { - check = lines[i]; if (NULL != (other = getNextSector (check, this))) { oceil = other->ceilingplane.ZatPoint(check->v1); @@ -418,17 +392,14 @@ double sector_t::FindHighestCeilingSurrounding (vertex_t **v) const double oceil; sector_t *other; 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; - for (i = 0; i < linecount; i++) + for (auto check : Lines) { - check = lines[i]; if (NULL != (other = getNextSector (check, this))) { oceil = other->ceilingplane.ZatPoint(check->v1); @@ -479,12 +450,12 @@ double sector_t::FindShortestTextureAround () const { 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 (lines[i]->sidedef[1]->GetTexture(side_t::bottom), minsize); + CheckShortestTex (check->sidedef[0]->GetTexture(side_t::bottom), minsize); + CheckShortestTex (check->sidedef[1]->GetTexture(side_t::bottom), minsize); } } return minsize < FLT_MAX ? minsize : TexMan[0]->GetHeight(); @@ -505,12 +476,12 @@ double sector_t::FindShortestUpperAround () const { 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 (lines[i]->sidedef[1]->GetTexture(side_t::top), minsize); + CheckShortestTex (check->sidedef[0]->GetTexture(side_t::top), minsize); + CheckShortestTex (check->sidedef[1]->GetTexture(side_t::top), minsize); } } 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 { - int i; sector_t *sec; - //jff 5/23/98 don't disturb sec->linecount while searching - // but allow early exit in old demos - for (i = 0; i < linecount; i++) + for (auto check : Lines) { - sec = getNextSector (lines[i], this); + sec = getNextSector (check, this); if (sec != NULL && - (sec->floorplane.ZatPoint(lines[i]->v1) == floordestheight || - sec->floorplane.ZatPoint(lines[i]->v2) == floordestheight)) + (sec->floorplane.ZatPoint(check->v1) == floordestheight || + sec->floorplane.ZatPoint(check->v2) == floordestheight)) { return sec; } @@ -569,17 +537,14 @@ sector_t *sector_t::FindModelFloorSector (double floordestheight) const // sector_t *sector_t::FindModelCeilingSector (double floordestheight) const { - int i; sector_t *sec; - //jff 5/23/98 don't disturb sec->linecount while searching - // but allow early exit in old demos - for (i = 0; i < linecount; i++) + for (auto check : Lines) { - sec = getNextSector (lines[i], this); + sec = getNextSector (check, this); if (sec != NULL && - (sec->ceilingplane.ZatPoint(lines[i]->v1) == floordestheight || - sec->ceilingplane.ZatPoint(lines[i]->v2) == floordestheight)) + (sec->ceilingplane.ZatPoint(check->v1) == floordestheight || + sec->ceilingplane.ZatPoint(check->v2) == floordestheight)) { return sec; } @@ -592,13 +557,10 @@ sector_t *sector_t::FindModelCeilingSector (double floordestheight) const // int sector_t::FindMinSurroundingLight (int min) const { - int i; - line_t* line; sector_t* check; - for (i = 0; i < linecount; i++) + for (auto line : Lines) { - line = lines[i]; if (NULL != (check = getNextSector (line, this)) && check->lightlevel < min) { @@ -613,8 +575,6 @@ int sector_t::FindMinSurroundingLight (int min) const // double sector_t::FindHighestFloorPoint (vertex_t **v) const { - int i; - line_t *line; double height = -FLT_MAX; double probeheight; vertex_t *spot = NULL; @@ -623,15 +583,14 @@ double sector_t::FindHighestFloorPoint (vertex_t **v) const { if (v != NULL) { - if (linecount == 0) *v = &vertexes[0]; - else *v = lines[0]->v1; + if (Lines.Size() == 0) *v = &vertexes[0]; + else *v = Lines[0]->v1; } return -floorplane.fD(); } - for (i = 0; i < linecount; i++) + for (auto line : Lines) { - line = lines[i]; probeheight = floorplane.ZatPoint(line->v1); if (probeheight > height) { @@ -655,8 +614,6 @@ double sector_t::FindHighestFloorPoint (vertex_t **v) const // double sector_t::FindLowestCeilingPoint (vertex_t **v) const { - int i; - line_t *line; double height = FLT_MAX; double probeheight; vertex_t *spot = NULL; @@ -665,15 +622,14 @@ double sector_t::FindLowestCeilingPoint (vertex_t **v) const { if (v != NULL) { - if (linecount == 0) *v = &vertexes[0]; - else *v = lines[0]->v1; + if (Lines.Size() == 0) *v = &vertexes[0]; + else *v = Lines[0]->v1; } return ceilingplane.fD(); } - for (i = 0; i < linecount; i++) + for (auto line : Lines) { - line = lines[i]; probeheight = ceilingplane.ZatPoint(line->v1); if (probeheight < height) { @@ -738,15 +694,14 @@ DEFINE_ACTION_FUNCTION(_Sector, SetFade) void sector_t::ClosestPoint(const DVector2 &in, DVector2 &out) const { - int i; double x = in.X, y = in.Y; double bestdist = HUGE_VAL; double bestx = 0, besty = 0; - for (i = 0; i < linecount; ++i) + for (auto check : Lines) { - vertex_t *v1 = lines[i]->v1; - vertex_t *v2 = lines[i]->v2; + vertex_t *v1 = check->v1; + vertex_t *v2 = check->v2; double a = v2->fX() - v1->fX(); double b = v2->fY() - v1->fY(); double den = a*a + b*b; @@ -1133,9 +1088,8 @@ DEFINE_ACTION_FUNCTION(_Sector, NextLowestFloorAt) 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) { 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, prevsec) 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, bottommap) DEFINE_FIELD_X(Sector, sector_t, midmap) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 43d1833afe..de83577642 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -775,16 +775,13 @@ static void SetTextureNoErr (side_t *side, int position, DWORD *color, const cha void P_FloodZone (sector_t *sec, int zonenum) { - int i; - if (sec->ZoneNumber == zonenum) return; sec->ZoneNumber = zonenum; - for (i = 0; i < sec->linecount; ++i) + for (auto check : sec->Lines) { - line_t *check = sec->lines[i]; sector_t *other; if (check->sidedef[1] == NULL || (check->flags & ML_ZONEBOUNDARY)) @@ -3093,7 +3090,6 @@ static void P_GroupLines (bool buildmap) cycle_t times[16]; int* linesDoneInEachSector; int i; - int j; int total; line_t* li; sector_t* sector; @@ -3140,13 +3136,13 @@ static void P_GroupLines (bool buildmap) } else { - li->frontsector->linecount++; + li->frontsector->Lines.Count++; total++; } if (li->backsector && li->backsector != li->frontsector) { - li->backsector->linecount++; + li->backsector->Lines.Count++; total++; } } @@ -3165,7 +3161,7 @@ static void P_GroupLines (bool buildmap) 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)); // 0 the sector's tag so that no specials can use it @@ -3173,8 +3169,8 @@ static void P_GroupLines (bool buildmap) } else { - sector->lines = lineb_p; - lineb_p += sector->linecount; + sector->Lines.Array = lineb_p; + lineb_p += sector->Lines.Count; } } @@ -3182,26 +3178,25 @@ static void P_GroupLines (bool buildmap) { 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) { - 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) { - if (linesDoneInEachSector[i] != sector->linecount) + if (linesDoneInEachSector[i] != sector->Lines.Size()) { I_Error("P_GroupLines: miscounted"); } - if (sector->linecount > 3) + if (sector->Lines.Size() > 3) { 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->v2->fPos()); } @@ -3210,15 +3205,15 @@ static void P_GroupLines (bool buildmap) sector->centerspot.X = (bbox.Right() + bbox.Left()) / 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 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; diff --git a/src/p_slopes.cpp b/src/p_slopes.cpp index 7413922e25..2e6a448329 100644 --- a/src/p_slopes.cpp +++ b/src/p_slopes.cpp @@ -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) { - for (int i=0;ilinecount;i++) + for(auto l : sec->Lines) { - line_t * l=sec->lines[i]; - if (l->args[0]==id) { DVector3 v1, v2, cross; @@ -306,16 +304,16 @@ static void P_SetSlopesFromVertexHeights(FMapThing *firstmt, FMapThing *lastmt, for (int i = 0; i < numsectors; i++) { sector_t *sec = §ors[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 vec1, vec2; int vi1, vi2, vi3; - vi1 = int(sec->lines[0]->v1 - 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)? - int(sec->lines[1]->v2 - vertexes) : int(sec->lines[1]->v1 - vertexes); + vi1 = int(sec->Lines[0]->v1 - 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)? + int(sec->Lines[1]->v2 - vertexes) : int(sec->Lines[1]->v1 - vertexes); vt1 = DVector3(vertexes[vi1].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); 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; vec2 = vt1 - vt3; @@ -451,9 +449,7 @@ static void P_AlignPlane(sector_t *sec, line_t *line, int which) { sector_t *refsec; double bestdist; - vertex_t *refvert = (*sec->lines)->v1; // Shut up, GCC - int i; - line_t **probe; + vertex_t *refvert = sec->Lines[0]->v1; // Shut up, GCC if (line->backsector == NULL) 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 // of the line, will define the plane. bestdist = 0; - for (i = sec->linecount * 2, probe = sec->lines; i > 0; i--) + for (auto ln : sec->Lines) { - double dist; - 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) + for (int i = 0; i < 2; i++) { - bestdist = dist; - refvert = vert; + double dist; + 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; + } } } diff --git a/src/p_spec.cpp b/src/p_spec.cpp index ccfafedaca..72211897d6 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1038,10 +1038,8 @@ void P_SpawnSkybox(ASkyViewpoint *origin) } if (Sector) { - line_t * refline = NULL; - for (short i = 0; i < Sector->linecount; i++) + for(auto refline : Sector->Lines) { - refline = Sector->lines[i]; 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. diff --git a/src/portal.cpp b/src/portal.cpp index 0a21f19149..1d6e7accab 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -801,9 +801,8 @@ static bool CollectSectors(int groupid, sector_t *origin) { 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; 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. 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)) diff --git a/src/r_defs.h b/src/r_defs.h index 4015103966..80edeeebd6 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -1036,8 +1036,7 @@ public: // jff 2/26/98 lockout machinery for stairbuilding SBYTE stairlock; // -2 on first locked -1 after thinker done 0 normally - short linecount; - struct line_t **lines; // [linecount] size + TStaticPointedArray Lines; // killough 3/7/98: support flat heights drawn at another sector's heights sector_t *heightsec; // other sector, or NULL if no other sector diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 6a1bc8717d..dc28f953c5 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -208,6 +208,10 @@ ExpEmit::ExpEmit(VMFunctionBuilder *build, int type, int count) void ExpEmit::Free(VMFunctionBuilder *build) { + if (RegType == REGT_INT && RegNum == 0) + { + int a = 0; + } if (!Fixed && !Konst && RegType <= REGT_TYPE) { build->Registers[RegType].Return(RegNum, RegCount); @@ -4584,8 +4588,14 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build) else { // Use the register returned by the true condition as the - // target for the false condition. - out = trueop; + // target for the false condition, if temporary. + // If this is a local variable we need another register for the result. + if (trueop.Fixed) + { + out = ExpEmit(build, trueop.RegType); + build->Emit(truex->ValueType->GetMoveOp(), out.RegNum, trueop.RegNum, 0); + } + else out = trueop; } } // Make sure to skip the false path. @@ -6620,6 +6630,7 @@ FxArrayElement::FxArrayElement(FxExpression *base, FxExpression *_index) index = _index; AddressRequested = false; AddressWritable = false; + SizeAddr = ~0u; } //========================================================================== @@ -6691,10 +6702,31 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) arraytype = static_cast(ptype->PointedType); 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(Array)->membervar; + SizeAddr = unsigned(parentfield->Offset + parentfield->Type->Align); + } + else if (Array->ExprType == EFX_GlobalVariable) + { + auto parentfield = static_cast(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(index)->GetValue().GetInt(); - if (indexval >= arraytype->ElementCount) + if (indexval >= arraytype->ElementCount && !Array->IsResizableArray()) { ScriptPosition.Message(MSG_ERROR, "Array index out of bounds"); delete this; @@ -6767,21 +6799,40 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) arraytype = static_cast(Array->ValueType); } ExpEmit start = Array->Emit(build); + ExpEmit bound; - /* what was this for? - if (start.Konst) + // For resizable arrays we even need to check the bounds if if the index is constant. + if (SizeAddr != ~0u) { - ExpEmit tmpstart(build, REGT_POINTER); - build->Emit(OP_LKP, tmpstart.RegNum, start.RegNum); - start.Free(build); - start = tmpstart; + auto f = new PField(NAME_None, TypeUInt32, 0, SizeAddr); + if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) + { + static_cast(Array)->membervar = f; + static_cast(Array)->AddressRequested = false; + } + else if (Array->ExprType == EFX_GlobalVariable) + { + static_cast(Array)->membervar = f; + static_cast(Array)->AddressRequested = false; + } + + Array->ValueType = TypeUInt32; + bound = Array->Emit(build); } - */ + if (index->isConstant()) { unsigned indexval = static_cast(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 (indexval != 0) @@ -6821,9 +6872,12 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) else { 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. - // Right now their bounds are not properly checked for. - if (arraytype->ElementCount > 65535) + if (SizeAddr != ~0u) + { + 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)); } @@ -7347,7 +7401,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. // 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) { @@ -7390,7 +7444,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) } } - if (Self->IsVector()) + else if (Self->IsVector()) { // handle builtins: Vectors got 2: Length and Unit. if (MethodName == NAME_Length || MethodName == NAME_Unit) @@ -7408,11 +7462,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. 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(ValueType)->PointedType; + auto size = static_cast(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(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(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))) { diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index c18754cb85..08afa6d93e 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -326,6 +326,8 @@ public: 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 IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && ValueType != TypeNullPtr && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)); } + bool IsArray() const { return ValueType->IsKindOf(RUNTIME_CLASS(PArray)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PArray))); } + bool IsResizableArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PResizableArray))); } // can only exist in pointer form. virtual ExpEmit Emit(VMFunctionBuilder *build); void EmitStatement(VMFunctionBuilder *build); @@ -426,6 +428,13 @@ public: 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) { ValueType = value.Type = TypeFloat64; @@ -1427,6 +1436,7 @@ class FxArrayElement : public FxExpression public: FxExpression *Array; FxExpression *index; + unsigned SizeAddr; bool AddressRequested; bool AddressWritable; bool arrayispointer = false; diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 2244600dc2..95dc3a668e 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -710,12 +710,8 @@ static int fieldcmp(const void * a, const void * b) 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. PField *vcf = new PField("validcount", TypeSInt32, VARF_Native | VARF_Static, (intptr_t)&validcount); 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... // 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->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); playerf = new PField("playeringame", parray, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&playeringame); diff --git a/src/tarray.h b/src/tarray.h index 6e37ea0398..ca24649677 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -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 TStaticPointedArray +{ +public: + + typedef TIterator iterator; + typedef TIterator 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 TStaticArray : public TStaticPointedArray +{ +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 &other) = delete; + + ~TStaticArray() + { + Clear(); + } + void Clear() + { + if (Array) delete[] Array; + } + void Alloc(unsigned int amount) + { + Clear(); + Array = new T[amount]; + Count = Amount; + } +}; + + // TAutoGrowArray ----------------------------------------------------------- // 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 diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 10e13cf508..e609610e6c 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -273,8 +273,7 @@ struct Sector native native int prevsec; native int nextsec; - native readonly int16 linecount; - //line_t **lines; // this is defined internally to avoid exposing some overly complicated type to the parser + //TStaticPointedArray Lines; // this is defined internally to avoid exposing some overly complicated type to the parser native readonly Sector heightsec; diff --git a/wadsrc/static/zscript/hexen/flies.txt b/wadsrc/static/zscript/hexen/flies.txt index d9800552ba..35dd90e911 100644 --- a/wadsrc/static/zscript/hexen/flies.txt +++ b/wadsrc/static/zscript/hexen/flies.txt @@ -58,7 +58,7 @@ class LittleFly : Actor return fallback; } // 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]; sector sec2 = (ln.frontsector == sec) ? ln.backsector : ln.frontsector;