// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // $Id:$ // // Copyright (C) 1993-1996 by id Software, Inc. // // This source is available for distribution and/or modification // only under the terms of the DOOM Source Code License as // published by id Software. All rights reserved. // // The source is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License // for more details. // // DESCRIPTION: // Refresh/rendering module, shared data struct definitions. // //----------------------------------------------------------------------------- #ifndef __R_DEFS_H__ #define __R_DEFS_H__ #include "doomdef.h" #include "templates.h" #include "memarena.h" #include "m_bbox.h" // Some more or less basic data types // we depend on. #include "m_fixed.h" // We rely on the thinker data struct // to handle sound origins in sectors. // SECTORS do store MObjs anyway. #include "actor.h" #include "dthinker.h" #define MAXWIDTH 5760 #define MAXHEIGHT 3600 const WORD NO_INDEX = 0xffffu; const DWORD NO_SIDE = 0xffffffffu; // Silhouette, needed for clipping Segs (mainly) // and sprites representing things. enum { SIL_NONE, SIL_BOTTOM, SIL_TOP, SIL_BOTH }; extern size_t MaxDrawSegs; struct FDisplacement; enum { SKYBOX_ANCHOR = -1, SKYBOX_SKYVIEWPOINT = 0, // a regular skybox SKYBOX_STACKEDSECTORTHING, // stacked sectors with the thing method SKYBOX_PORTAL, // stacked sectors with Sector_SetPortal SKYBOX_LINKEDPORTAL, // linked portal (interactive) SKYBOX_PLANE, // EE-style plane portal (not implemented in SW renderer) SKYBOX_HORIZON, // EE-style horizon portal (not implemented in SW renderer) }; // // INTERNAL MAP TYPES // used by play and refresh // // // Your plain vanilla vertex. // Note: transformed values not buffered locally, // like some DOOM-alikes ("wt", "WebView") did. // enum { VERTEXFLAG_ZCeilingEnabled = 0x01, VERTEXFLAG_ZFloorEnabled = 0x02 }; struct vertexdata_t { double zCeiling, zFloor; DWORD flags; }; struct vertex_t { fixed_t x, y; double fX() const { return FIXED2DBL(x); } double fY() const { return FIXED2DBL(y); } DVector2 fPos() { return{ fX(), fY() }; } bool operator== (const vertex_t &other) { return x == other.x && y == other.y; } void clear() { x = y = 0; } }; // Forward of LineDefs, for Sectors. struct line_t; class player_t; class FScanner; class FBitmap; struct FCopyInfo; class DInterpolation; class FArchive; enum { UDMF_Line, UDMF_Side, UDMF_Sector, UDMF_Thing }; struct FUDMFKey { enum { UDMF_Int, UDMF_Float, UDMF_String }; FName Key; int Type; int IntVal; double FloatVal; FString StringVal; FUDMFKey() { } FUDMFKey& operator =(int val) { Type = UDMF_Int; IntVal = val; FloatVal = val; StringVal = ""; return *this; } FUDMFKey& operator =(double val) { Type = UDMF_Float; IntVal = int(val); FloatVal = val; StringVal = ""; return *this; } FUDMFKey& operator =(const FString &val) { Type = UDMF_String; IntVal = strtol(val.GetChars(), NULL, 0); FloatVal = strtod(val.GetChars(), NULL); StringVal = val; return *this; } }; class FUDMFKeys : public TArray { public: void Sort(); FUDMFKey *Find(FName key); }; // // The SECTORS record, at runtime. // Stores things/mobjs. // class DSectorEffect; struct sector_t; struct FRemapTable; enum { SECSPAC_Enter = 1, // Trigger when player enters SECSPAC_Exit = 2, // Trigger when player exits SECSPAC_HitFloor = 4, // Trigger when player hits floor SECSPAC_HitCeiling = 8, // Trigger when player hits ceiling SECSPAC_Use = 16, // Trigger when player uses SECSPAC_UseWall = 32, // Trigger when player uses a wall SECSPAC_EyesDive = 64, // Trigger when player eyes go below fake floor SECSPAC_EyesSurface = 128, // Trigger when player eyes go above fake floor SECSPAC_EyesBelowC = 256, // Trigger when player eyes go below fake ceiling SECSPAC_EyesAboveC = 512, // Trigger when player eyes go above fake ceiling SECSPAC_HitFakeFloor= 1024, // Trigger when player hits fake floor }; class ASectorAction : public AActor { DECLARE_CLASS (ASectorAction, AActor) public: ASectorAction (bool activatedByUse = false); void Destroy (); void BeginPlay (); void Activate (AActor *source); void Deactivate (AActor *source); bool TriggerAction(AActor *triggerer, int activationType); bool CanTrigger (AActor *triggerer) const; bool IsActivatedByUse() const; protected: virtual bool DoTriggerAction(AActor *triggerer, int activationType); bool CheckTrigger(AActor *triggerer) const; private: bool ActivatedByUse; }; class ASkyViewpoint; struct secplane_t { // the plane is defined as a*x + b*y + c*z + d = 0 // ic is 1/c, for faster Z calculations fixed_t a, b, c, d, ic; double fA() const { return FIXED2FLOAT(a); } double fB() const { return FIXED2FLOAT(b); } double fC() const { return FIXED2FLOAT(c); } double fD() const { return FIXED2FLOAT(d); } bool isSlope() const { return a != 0 || b != 0; } DVector3 Normal() const { return{ FIXED2FLOAT(a), FIXED2FLOAT(b), FIXED2FLOAT(c) }; } // Returns < 0 : behind; == 0 : on; > 0 : in front int PointOnSide (fixed_t x, fixed_t y, fixed_t z) const { return TMulScale16(a,x, b,y, c,z) + d; } // Returns the value of z at (0,0) This is used by the 3D floor code which does not handle slopes fixed_t Zat0 () const { return ic < 0 ? d : -d; } fixed_t ZatPoint(const fixedvec2 &spot) const { return FixedMul(ic, -d - DMulScale16(a, spot.x, b, spot.y)); } fixed_t ZatPoint(const fixedvec3 &spot) const { return FixedMul(ic, -d - DMulScale16(a, spot.x, b, spot.y)); } double ZatPointF(const fixedvec3 &spot) const { return FIXED2DBL(FixedMul(ic, -d - DMulScale16(a, spot.x, b, spot.y))); } // Returns the value of z at (x,y) fixed_t ZatPoint (fixed_t x, fixed_t y) const { return FixedMul (ic, -d - DMulScale16 (a, x, b, y)); } double _f_ZatPointF(fixed_t x, fixed_t y) const { return FIXED2DBL(FixedMul(ic, -d - DMulScale16(a, x, b, y))); } // Returns the value of z at (x,y) as a double double ZatPoint (double x, double y) const { return (d + a*x + b*y) * ic / (-65536.0 * 65536.0); } double ZatPoint(const DVector2 &pos) const { return (d + a*pos.X + b*pos.Y) * ic / (-65536.0 * 65536.0); } // Returns the value of z at vertex v fixed_t ZatPoint (const vertex_t *v) const { return FixedMul (ic, -d - DMulScale16 (a, v->x, b, v->y)); } fixed_t ZatPoint (const AActor *ac) const { return FixedMul (ic, -d - DMulScale16 (a, ac->_f_X(), b, ac->_f_Y())); } double ZatPointF(const AActor *ac) const { return FIXED2DBL(ZatPoint(ac)); } // Returns the value of z at (x,y) if d is equal to dist fixed_t ZatPointDist (fixed_t x, fixed_t y, fixed_t dist) const { return FixedMul (ic, -dist - DMulScale16 (a, x, b, y)); } // Returns the value of z at vertex v if d is equal to dist fixed_t ZatPointDist (const vertex_t *v, fixed_t dist) { return FixedMul (ic, -dist - DMulScale16 (a, v->x, b, v->y)); } // Flips the plane's vertical orientiation, so that if it pointed up, // it will point down, and vice versa. void FlipVert () { a = -a; b = -b; c = -c; d = -d; ic = -ic; } // Returns true if 2 planes are the same bool operator== (const secplane_t &other) const { return a == other.a && b == other.b && c == other.c && d == other.d; } // Returns true if 2 planes are different bool operator!= (const secplane_t &other) const { return a != other.a || b != other.b || c != other.c || d != other.d; } // Moves a plane up/down by hdiff units void ChangeHeight (fixed_t hdiff) { d = d - FixedMul (hdiff, c); } // Moves a plane up/down by hdiff units fixed_t GetChangedHeight (fixed_t hdiff) { return d - FixedMul (hdiff, c); } // Returns how much this plane's height would change if d were set to oldd fixed_t HeightDiff (fixed_t oldd) const { return FixedMul (oldd - d, ic); } // Returns how much this plane's height would change if d were set to oldd fixed_t HeightDiff (fixed_t oldd, fixed_t newd) const { return FixedMul (oldd - newd, ic); } fixed_t PointToDist (fixed_t x, fixed_t y, fixed_t z) const { return -TMulScale16 (a, x, y, b, z, c); } fixed_t PointToDist(fixedvec2 xy, fixed_t z) const { return -TMulScale16(a, xy.x, xy.y, b, z, c); } fixed_t PointToDist (const vertex_t *v, fixed_t z) const { return -TMulScale16 (a, v->x, b, v->y, z, c); } void SetAtHeight(fixed_t height, int ceiling) { a = b = 0; if (ceiling) { c = ic = -FRACUNIT; d = height; } else { c = ic = FRACUNIT; d = -height; } } inline void SetAtHeight(double height, int ceiling) { SetAtHeight(FLOAT2FIXED(clamp(height, -32767., 32767.)), ceiling); } bool CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const; }; FArchive &operator<< (FArchive &arc, secplane_t &plane); #include "p_3dfloors.h" // Ceiling/floor flags enum { PLANEF_ABSLIGHTING = 1, // floor/ceiling light is absolute, not relative PLANEF_BLOCKED = 2, // can not be moved anymore. PLANEF_ADDITIVE = 4, // rendered additive // linked portal stuff PLANEF_NORENDER = 8, PLANEF_NOPASS = 16, PLANEF_BLOCKSOUND = 32, PLANEF_DISABLED = 64, PLANEF_OBSTRUCTED = 128, // if the portal plane is beyond the sector's floor or ceiling. }; // Internal sector flags enum { SECF_FAKEFLOORONLY = 2, // when used as heightsec in R_FakeFlat, only copies floor SECF_CLIPFAKEPLANES = 4, // as a heightsec, clip planes to target sector's planes SECF_NOFAKELIGHT = 8, // heightsec does not change lighting SECF_IGNOREHEIGHTSEC= 16, // heightsec is only for triggering sector actions SECF_UNDERWATER = 32, // sector is underwater SECF_FORCEDUNDERWATER= 64, // sector is forced to be underwater SECF_UNDERWATERMASK = 32+64, SECF_DRAWN = 128, // sector has been drawn at least once SECF_HIDDEN = 256, // Do not draw on textured automap SECF_NOFLOORSKYBOX = 512, // force use of regular sky SECF_NOCEILINGSKYBOX = 1024, // force use of regular sky (do not separate from NOFLOORSKYBOX!!!) }; enum { SECF_SILENT = 1, // actors in sector make no noise SECF_NOFALLINGDAMAGE= 2, // No falling damage in this sector SECF_FLOORDROP = 4, // all actors standing on this floor will remain on it when it lowers very fast. SECF_NORESPAWN = 8, // players can not respawn in this sector SECF_FRICTION = 16, // sector has friction enabled SECF_PUSH = 32, // pushers enabled SECF_SILENTMOVE = 64, // Sector movement makes mo sound (Eternity got this so this may be useful for an extended cross-port standard.) SECF_DMGTERRAINFX = 128, // spawns terrain splash when inflicting damage SECF_ENDGODMODE = 256, // getting damaged by this sector ends god mode SECF_ENDLEVEL = 512, // ends level when health goes below 10 SECF_HAZARD = 1024, // Change to Strife's delayed damage handling. SECF_WASSECRET = 1 << 30, // a secret that was discovered SECF_SECRET = 1 << 31, // a secret sector SECF_DAMAGEFLAGS = SECF_ENDGODMODE|SECF_ENDLEVEL|SECF_DMGTERRAINFX|SECF_HAZARD, SECF_NOMODIFY = SECF_SECRET|SECF_WASSECRET, // not modifiable by Sector_ChangeFlags SECF_SPECIALFLAGS = SECF_DAMAGEFLAGS|SECF_FRICTION|SECF_PUSH, // these flags originate from 'special and must be transferrable by floor thinkers }; enum { PL_SKYFLAT = 0x40000000 }; struct FDynamicColormap; struct FLinkedSector { sector_t *Sector; int Type; }; // this substructure contains a few sector properties that are stored in dynamic arrays // These must not be copied by R_FakeFlat etc. or bad things will happen. struct extsector_t { // Boom sector transfer information struct fakefloor { TArray Sectors; } FakeFloor; // 3DMIDTEX information struct midtex { struct plane { TArray AttachedSectors; // all sectors containing 3dMidtex lines attached to this sector TArray AttachedLines; // all 3dMidtex lines attached to this sector } Floor, Ceiling; } Midtex; // Linked sector information struct linked { struct plane { TArray Sectors; } Floor, Ceiling; } Linked; // 3D floors struct xfloor { TDeletingArray ffloors; // 3D floors in this sector TArray lightlist; // 3D light list TArray attached; // 3D floors attached to this sector } XFloor; void Serialize(FArchive &arc); }; struct FTransform { // killough 3/7/98: floor and ceiling texture offsets fixed_t xoffs, yoffs; // [RH] floor and ceiling texture scales fixed_t xscale, yscale; // [RH] floor and ceiling texture rotation angle_t angle; // base values fixed_t base_angle, base_yoffs; }; struct secspecial_t { FNameNoInit damagetype; // [RH] Means-of-death for applied damage int damageamount; // [RH] Damage to do while standing on floor short special; short damageinterval; // Interval for damage application short leakydamage; // chance of leaking through radiation suit int Flags; secspecial_t() { Clear(); } void Clear() { memset(this, 0, sizeof(*this)); } }; FArchive &operator<< (FArchive &arc, secspecial_t &p); struct sector_t { // Member functions bool IsLinked(sector_t *other, bool ceiling) const; fixed_t FindLowestFloorSurrounding (vertex_t **v) const; fixed_t FindHighestFloorSurrounding (vertex_t **v) const; fixed_t FindNextHighestFloor (vertex_t **v) const; fixed_t FindNextLowestFloor (vertex_t **v) const; fixed_t FindLowestCeilingSurrounding (vertex_t **v) const; // jff 2/04/98 fixed_t FindHighestCeilingSurrounding (vertex_t **v) const; // jff 2/04/98 fixed_t FindNextLowestCeiling (vertex_t **v) const; // jff 2/04/98 fixed_t FindNextHighestCeiling (vertex_t **v) const; // jff 2/04/98 fixed_t FindShortestTextureAround () const; // jff 2/04/98 fixed_t FindShortestUpperAround () const; // jff 2/04/98 sector_t *FindModelFloorSector (fixed_t floordestheight) const; // jff 2/04/98 sector_t *FindModelCeilingSector (fixed_t floordestheight) const; // jff 2/04/98 int FindMinSurroundingLight (int max) const; sector_t *NextSpecialSector (int type, sector_t *prev) const; // [RH] fixed_t FindLowestCeilingPoint (vertex_t **v) const; fixed_t FindHighestFloorPoint (vertex_t **v) const; void AdjustFloorClip () const; void SetColor(int r, int g, int b, int desat); void SetFade(int r, int g, int b); void ClosestPoint(fixed_t x, fixed_t y, fixed_t &ox, fixed_t &oy) const; int GetFloorLight () const; int GetCeilingLight () const; sector_t *GetHeightSec() const; double GetFriction(int plane = sector_t::floor, double *movefac = NULL) const; DInterpolation *SetInterpolation(int position, bool attach); ASkyViewpoint *GetSkyBox(int which); void CheckPortalPlane(int plane); enum { floor, ceiling }; struct splane { FTransform xform; int Flags; int Light; fixed_t alpha; FTextureID Texture; fixed_t TexZ; }; splane planes[2]; void SetXOffset(int pos, fixed_t o) { planes[pos].xform.xoffs = o; } void AddXOffset(int pos, fixed_t o) { planes[pos].xform.xoffs += o; } fixed_t GetXOffset(int pos) const { return planes[pos].xform.xoffs; } double GetXOffsetF(int pos) const { return FIXED2DBL(planes[pos].xform.xoffs); } void SetYOffset(int pos, fixed_t o) { planes[pos].xform.yoffs = o; } void AddYOffset(int pos, fixed_t o) { planes[pos].xform.yoffs += o; } fixed_t GetYOffset(int pos, bool addbase = true) const { if (!addbase) { return planes[pos].xform.yoffs; } else { return planes[pos].xform.yoffs + planes[pos].xform.base_yoffs; } } double GetYOffsetF(int pos, bool addbase = true) const { if (!addbase) { return FIXED2DBL(planes[pos].xform.yoffs); } else { return FIXED2DBL(planes[pos].xform.yoffs + planes[pos].xform.base_yoffs); } } void SetXScale(int pos, fixed_t o) { planes[pos].xform.xscale = o; } fixed_t GetXScale(int pos) const { return planes[pos].xform.xscale; } double GetXScaleF(int pos) const { return FIXED2DBL(planes[pos].xform.xscale); } void SetYScale(int pos, fixed_t o) { planes[pos].xform.yscale = o; } fixed_t GetYScale(int pos) const { return planes[pos].xform.yscale; } double GetYScaleF(int pos) const { return FIXED2DBL(planes[pos].xform.yscale); } void SetAngle(int pos, angle_t o) { planes[pos].xform.angle = o; } angle_t GetAngle(int pos, bool addbase = true) const { if (!addbase) { return planes[pos].xform.angle; } else { return planes[pos].xform.angle + planes[pos].xform.base_angle; } } DAngle GetAngleF(int pos, bool addbase = true) const { if (!addbase) { return ANGLE2DBL(planes[pos].xform.angle); } else { return ANGLE2DBL(planes[pos].xform.angle + planes[pos].xform.base_angle); } } void SetBase(int pos, fixed_t y, angle_t o) { planes[pos].xform.base_yoffs = y; planes[pos].xform.base_angle = o; } void SetAlpha(int pos, fixed_t o) { planes[pos].alpha = o; } fixed_t GetAlpha(int pos) const { return planes[pos].alpha; } int GetFlags(int pos) const { return planes[pos].Flags; } void ChangeFlags(int pos, int And, int Or) { planes[pos].Flags &= ~And; planes[pos].Flags |= Or; } int GetPlaneLight(int pos) const { return planes[pos].Light; } void SetPlaneLight(int pos, int level) { planes[pos].Light = level; } FTextureID GetTexture(int pos) const { return planes[pos].Texture; } void SetTexture(int pos, FTextureID tex, bool floorclip = true) { FTextureID old = planes[pos].Texture; planes[pos].Texture = tex; if (floorclip && pos == floor && tex != old) AdjustFloorClip(); } fixed_t GetPlaneTexZ(int pos) const { return planes[pos].TexZ; } double GetPlaneTexZF(int pos) const { return FIXED2DBL(planes[pos].TexZ); } void SetPlaneTexZ(int pos, fixed_t val) { planes[pos].TexZ = val; } void ChangePlaneTexZ(int pos, fixed_t val) { planes[pos].TexZ += val; } static inline short ClampLight(int level) { return (short)clamp(level, SHRT_MIN, SHRT_MAX); } void ChangeLightLevel(int newval) { lightlevel = ClampLight(lightlevel + newval); } void SetLightLevel(int newval) { lightlevel = ClampLight(newval); } int GetLightLevel() const { return lightlevel; } secplane_t &GetSecPlane(int pos) { return pos == floor? floorplane:ceilingplane; } bool isSecret() const { return !!(Flags & SECF_SECRET); } bool wasSecret() const { return !!(Flags & SECF_WASSECRET); } void ClearSecret() { Flags &= ~SECF_SECRET; } void ClearSpecial() { // clears all variables that originate from 'special'. Used for sector type transferring thinkers special = 0; damageamount = 0; damageinterval = 0; damagetype = NAME_None; leakydamage = 0; Flags &= ~SECF_SPECIALFLAGS; } bool PortalBlocksView(int plane) { if (SkyBoxes[plane] == NULL) return true; if (SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return false; return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); } bool PortalBlocksSight(int plane) { if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true; return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); } bool PortalBlocksMovement(int plane) { if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true; return !!(planes[plane].Flags & (PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); } bool PortalBlocksSound(int plane) { if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true; return !!(planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); } bool PortalIsLinked(int plane) { return (SkyBoxes[plane] != NULL && SkyBoxes[plane]->special1 == SKYBOX_LINKEDPORTAL); } // These may only be called if the portal has been validated DVector2 FloorDisplacement() { return Displacements.getOffset(PortalGroup, SkyBoxes[sector_t::floor]->Sector->PortalGroup); } DVector2 CeilingDisplacement() { return Displacements.getOffset(PortalGroup, SkyBoxes[sector_t::ceiling]->Sector->PortalGroup); } int GetTerrain(int pos) const; void TransferSpecial(sector_t *model); void GetSpecial(secspecial_t *spec); void SetSpecial(const secspecial_t *spec); bool PlaneMoving(int pos); // Portal-aware height calculation double HighestCeilingAt(const DVector2 &a, sector_t **resultsec = NULL); double LowestFloorAt(const DVector2 &a, sector_t **resultsec = NULL); double HighestCeilingAt(AActor *a, sector_t **resultsec = NULL) { return HighestCeilingAt(a->Pos(), resultsec); } double LowestFloorAt(AActor *a, sector_t **resultsec = NULL) { return LowestFloorAt(a->Pos(), resultsec); } fixed_t NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t bottomz, fixed_t topz, int flags = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL); fixed_t NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, int flags = 0, fixed_t steph = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL); inline double NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL) { return FIXED2DBL(NextHighestCeilingAt(FLOAT2FIXED(x), FLOAT2FIXED(y), FLOAT2FIXED(bottomz), FLOAT2FIXED(topz), flags, resultsec, resultffloor)); } double NextLowestFloorAt(double x, double y, double z, int flags = 0, double steph = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL) { return FIXED2DBL(NextLowestFloorAt(FLOAT2FIXED(x), FLOAT2FIXED(y), FLOAT2FIXED(z), flags, FLOAT2FIXED(steph), resultsec, resultffloor)); } // Member variables fixed_t CenterFloor () const { return floorplane.ZatPoint (_f_centerspot()); } fixed_t CenterCeiling () const { return ceilingplane.ZatPoint (_f_centerspot()); } // [RH] store floor and ceiling planes instead of heights secplane_t floorplane, ceilingplane; // [RH] give floor and ceiling even more properties FDynamicColormap *ColorMap; // [RH] Per-sector colormap TObjPtr SoundTarget; short special; short lightlevel; short seqType; // this sector's sound sequence int sky; FNameNoInit SeqName; // Sound sequence name. Setting seqType non-negative will override this. DVector2 centerspot; // origin for any sounds played by the sector int validcount; // if == validcount, already checked AActor* thinglist; // list of mobjs in sector fixedvec2 _f_centerspot() const { return{ FLOAT2FIXED(centerspot.X), FLOAT2FIXED(centerspot.Y) }; } // killough 8/28/98: friction is a sector property, not an mobj property. // these fields used to be in AActor, but presented performance problems // when processed as mobj properties. Fix is to make them sector properties. double friction, movefactor; int terrainnum[2]; // thinker_t for reversable actions TObjPtr floordata; // jff 2/22/98 make thinkers on TObjPtr ceilingdata; // floors, ceilings, lighting, TObjPtr lightingdata; // independent of one another enum { CeilingMove, FloorMove, CeilingScroll, FloorScroll }; TObjPtr interpolations[4]; BYTE soundtraversed; // 0 = untraversed, 1,2 = sndlines -1 // jff 2/26/98 lockout machinery for stairbuilding SBYTE stairlock; // -2 on first locked -1 after thinker done 0 normally SWORD prevsec; // -1 or number of sector for previous step SWORD nextsec; // -1 or number of next step sector short linecount; struct line_t **lines; // [linecount] size // killough 3/7/98: support flat heights drawn at another sector's heights sector_t *heightsec; // other sector, or NULL if no other sector DWORD bottommap, midmap, topmap; // killough 4/4/98: dynamic colormaps // [RH] these can also be blend values if // the alpha mask is non-zero // list of mobjs that are at least partially in the sector // thinglist is a subset of touching_thinglist struct msecnode_t *touching_thinglist; // phares 3/14/98 double gravity; // [RH] Sector gravity (1.0 is normal) FNameNoInit damagetype; // [RH] Means-of-death for applied damage int damageamount; // [RH] Damage to do while standing on floor short damageinterval; // Interval for damage application short leakydamage; // chance of leaking through radiation suit WORD ZoneNumber; // [RH] Zone this sector belongs to WORD MoreFlags; // [RH] Internal sector flags DWORD Flags; // Sector flags // [RH] Action specials for sectors. Like Skull Tag, but more // flexible in a Bloody way. SecActTarget forms a list of actors // joined by their tracer fields. When a potential sector action // occurs, SecActTarget's TriggerAction method is called. TObjPtr SecActTarget; // [RH] The sky box to render for this sector. NULL means use a // regular sky. TObjPtr SkyBoxes[2]; int PortalGroup; int sectornum; // for comparing sector copies extsector_t * e; // This stores data that requires construction/destruction. Such data must not be copied by R_FakeFlat. }; FArchive &operator<< (FArchive &arc, sector_t::splane &p); struct ReverbContainer; struct zone_t { ReverbContainer *Environment; }; // // The SideDef. // class DBaseDecal; enum { WALLF_ABSLIGHTING = 1, // Light is absolute instead of relative WALLF_NOAUTODECALS = 2, // Do not attach impact decals to this wall WALLF_NOFAKECONTRAST = 4, // Don't do fake contrast for this wall in side_t::GetLightLevel WALLF_SMOOTHLIGHTING = 8, // Similar to autocontrast but applies to all angles. WALLF_CLIP_MIDTEX = 16, // Like the line counterpart, but only for this side. WALLF_WRAP_MIDTEX = 32, // Like the line counterpart, but only for this side. WALLF_POLYOBJ = 64, // This wall belongs to a polyobject. WALLF_LIGHT_FOG = 128, // This wall's Light is used even in fog. }; struct side_t { enum ETexpart { top=0, mid=1, bottom=2 }; struct part { fixed_t xoffset; fixed_t yoffset; fixed_t xscale; fixed_t yscale; FTextureID texture; TObjPtr interpolation; //int Light; }; sector_t* sector; // Sector the SideDef is facing. DBaseDecal* AttachedDecals; // [RH] Decals bound to the wall part textures[3]; line_t *linedef; //DWORD linenum; DWORD LeftSide, RightSide; // [RH] Group walls into loops WORD TexelLength; SWORD Light; BYTE Flags; int Index; // needed to access custom UDMF fields which are stored in loading order. int GetLightLevel (bool foggy, int baselight, bool is3dlight=false, int *pfakecontrast_usedbygzdoom=NULL) const; void SetLight(SWORD l) { Light = l; } FTextureID GetTexture(int which) const { return textures[which].texture; } void SetTexture(int which, FTextureID tex) { textures[which].texture = tex; } void SetTextureXOffset(int which, fixed_t offset) { textures[which].xoffset = offset; } void SetTextureXOffset(fixed_t offset) { textures[top].xoffset = textures[mid].xoffset = textures[bottom].xoffset = offset; } fixed_t GetTextureXOffset(int which) const { return textures[which].xoffset; } double GetTextureXOffsetF(int which) const { return FIXED2DBL(textures[which].xoffset); } void AddTextureXOffset(int which, fixed_t delta) { textures[which].xoffset += delta; } void SetTextureYOffset(int which, fixed_t offset) { textures[which].yoffset = offset; } void SetTextureYOffset(fixed_t offset) { textures[top].yoffset = textures[mid].yoffset = textures[bottom].yoffset = offset; } fixed_t GetTextureYOffset(int which) const { return textures[which].yoffset; } double GetTextureYOffsetF(int which) const { return FIXED2DBL(textures[which].yoffset); } void AddTextureYOffset(int which, fixed_t delta) { textures[which].yoffset += delta; } void SetTextureXScale(int which, fixed_t scale) { textures[which].xscale = scale == 0 ? FRACUNIT : scale; } void SetTextureXScale(fixed_t scale) { textures[top].xscale = textures[mid].xscale = textures[bottom].xscale = scale == 0 ? FRACUNIT : scale; } fixed_t GetTextureXScale(int which) const { return textures[which].xscale; } void MultiplyTextureXScale(int which, fixed_t delta) { textures[which].xscale = FixedMul(textures[which].xscale, delta); } void SetTextureYScale(int which, fixed_t scale) { textures[which].yscale = scale == 0 ? FRACUNIT : scale; } void SetTextureYScale(fixed_t scale) { textures[top].yscale = textures[mid].yscale = textures[bottom].yscale = scale == 0 ? FRACUNIT : scale; } fixed_t GetTextureYScale(int which) const { return textures[which].yscale; } double GetTextureYScaleF(int which) const { return FIXED2DBL(textures[which].yscale); } void MultiplyTextureYScale(int which, fixed_t delta) { textures[which].yscale = FixedMul(textures[which].yscale, delta); } DInterpolation *SetInterpolation(int position); void StopInterpolation(int position); vertex_t *V1() const; vertex_t *V2() const; }; FArchive &operator<< (FArchive &arc, side_t::part &p); struct line_t { vertex_t *v1, *v2; // vertices, from v1 to v2 fixed_t dx, dy; // precalculated v2 - v1 for side checking DWORD flags; DWORD activation; // activation type int special; fixed_t Alpha; // <--- translucency (0=invisibile, FRACUNIT=opaque) int args[5]; // <--- hexen-style arguments (expanded to ZDoom's full width) side_t *sidedef[2]; fixed_t bbox[4]; // bounding box, for the extent of the LineDef. sector_t *frontsector, *backsector; int validcount; // if == validcount, already checked int locknumber; // [Dusk] lock number for special unsigned portalindex; DVector2 V1() const { return{ FIXED2DBL(v1->x), FIXED2DBL(v1->y) }; } DVector2 V2() const { return{ FIXED2DBL(v2->x), FIXED2DBL(v2->y) }; } DVector2 Delta() const { return{ FIXED2DBL(dx), FIXED2DBL(dy) }; } FLinePortal *getPortal() const { return portalindex >= linePortals.Size() ? (FLinePortal*)NULL : &linePortals[portalindex]; } // returns true if the portal is crossable by actors bool isLinePortal() const { return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_PASSABLE); } // returns true if the portal needs to be handled by the renderer bool isVisualPortal() const { return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_VISIBLE); } line_t *getPortalDestination() const { return portalindex >= linePortals.Size() ? (line_t*)NULL : linePortals[portalindex].mDestination; } int getPortalAlignment() const { return portalindex >= linePortals.Size() ? 0 : linePortals[portalindex].mAlign; } }; // phares 3/14/98 // // Sector list node showing all sectors an object appears in. // // There are two threads that flow through these nodes. The first thread // starts at touching_thinglist in a sector_t and flows through the m_snext // links to find all mobjs that are entirely or partially in the sector. // The second thread starts at touching_sectorlist in a AActor and flows // through the m_tnext links to find all sectors a thing touches. This is // useful when applying friction or push effects to sectors. These effects // can be done as thinkers that act upon all objects touching their sectors. // As an mobj moves through the world, these nodes are created and // destroyed, with the links changed appropriately. // // For the links, NULL means top or end of list. struct msecnode_t { sector_t *m_sector; // a sector containing this object AActor *m_thing; // this object struct msecnode_t *m_tprev; // prev msecnode_t for this thing struct msecnode_t *m_tnext; // next msecnode_t for this thing struct msecnode_t *m_sprev; // prev msecnode_t for this sector struct msecnode_t *m_snext; // next msecnode_t for this sector bool visited; // killough 4/4/98, 4/7/98: used in search algorithms }; struct FPolyNode; struct FMiniBSP; // // The LineSeg. // struct seg_t { vertex_t* v1; vertex_t* v2; side_t* sidedef; line_t* linedef; // Sector references. Could be retrieved from linedef, too. sector_t* frontsector; sector_t* backsector; // NULL for one-sided lines }; struct glsegextra_t { DWORD PartnerSeg; subsector_t *Subsector; }; // // A SubSector. // References a Sector. // Basically, this is a list of LineSegs indicating the visible walls that // define (all or some) sides of a convex BSP leaf. // enum { SSECF_DEGENERATE = 1, SSECF_DRAWN = 2, SSECF_POLYORG = 4, }; struct subsector_t { sector_t *sector; FPolyNode *polys; FMiniBSP *BSP; seg_t *firstline; sector_t *render_sector; DWORD numlines; int flags; void BuildPolyBSP(); }; // // BSP node. // struct node_t { // Partition line. fixed_t x; fixed_t y; fixed_t dx; fixed_t dy; fixed_t bbox[2][4]; // Bounding box for each child. float len; union { void *children[2]; // If bit 0 is set, it's a subsector. int intchildren[2]; // Used by nodebuilder. }; }; // An entire BSP tree. struct FMiniBSP { bool bDirty; TArray Nodes; TArray Segs; TArray Subsectors; TArray Verts; }; // // OTHER TYPES // typedef BYTE lighttable_t; // This could be wider for >8 bit display. // This encapsulates the fields of vissprite_t that can be altered by AlterWeaponSprite struct visstyle_t { lighttable_t *colormap; float Alpha; FRenderStyle RenderStyle; }; //---------------------------------------------------------------------------------- // // The playsim can use different nodes than the renderer so this is // not the same as R_PointInSubsector // //---------------------------------------------------------------------------------- subsector_t *P_PointInSubsector(fixed_t x, fixed_t y); inline sector_t *P_PointInSector(fixed_t x, fixed_t y) { return P_PointInSubsector(x, y)->sector; } inline sector_t *P_PointInSector(const DVector2 &pos) { return P_PointInSubsector(FLOAT2FIXED(pos.X), FLOAT2FIXED(pos.Y))->sector; } inline sector_t *P_PointInSector(double X, double Y) { return P_PointInSubsector(FLOAT2FIXED(X), FLOAT2FIXED(Y))->sector; } inline fixedvec3 AActor::_f_PosRelative(int portalgroup) const { return _f_Pos() + Displacements._f_getOffset(Sector->PortalGroup, portalgroup); } inline fixedvec3 AActor::_f_PosRelative(const AActor *other) const { return _f_Pos() + Displacements._f_getOffset(Sector->PortalGroup, other->Sector->PortalGroup); } inline fixedvec3 AActor::_f_PosRelative(sector_t *sec) const { return _f_Pos() + Displacements._f_getOffset(Sector->PortalGroup, sec->PortalGroup); } inline fixedvec3 AActor::_f_PosRelative(line_t *line) const { return _f_Pos() + Displacements._f_getOffset(Sector->PortalGroup, line->frontsector->PortalGroup); } inline fixedvec3 _f_PosRelative(const fixedvec3 &pos, line_t *line, sector_t *refsec = NULL) { return pos + Displacements._f_getOffset(refsec->PortalGroup, line->frontsector->PortalGroup); } inline DVector3 AActor::PosRelative(int portalgroup) const { return Pos() + Displacements.getOffset(Sector->PortalGroup, portalgroup); } inline DVector3 AActor::PosRelative(const AActor *other) const { return Pos() + Displacements.getOffset(Sector->PortalGroup, other->Sector->PortalGroup); } inline DVector3 AActor::PosRelative(sector_t *sec) const { return Pos() + Displacements.getOffset(Sector->PortalGroup, sec->PortalGroup); } inline DVector3 AActor::PosRelative(line_t *line) const { return Pos() + Displacements.getOffset(Sector->PortalGroup, line->frontsector->PortalGroup); } inline DVector3 PosRelative(const DVector3 &pos, line_t *line, sector_t *refsec = NULL) { return pos + Displacements.getOffset(refsec->PortalGroup, line->frontsector->PortalGroup); } inline void AActor::ClearInterpolation() { Prev = Pos(); PrevAngles = Angles; if (Sector) PrevPortalGroup = Sector->PortalGroup; else PrevPortalGroup = 0; } inline bool FBoundingBox::inRange(const line_t *ld) const { return (!(Left() > ld->bbox[BOXRIGHT] || Right() < ld->bbox[BOXLEFT] || Top() < ld->bbox[BOXBOTTOM] || Bottom() > ld->bbox[BOXTOP])); } #endif