mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-12-02 08:53:42 +00:00
68630d6782
This included half the game state and lots of unneeded parts of the software renderer. The two modules that are shared between softpoly and the classic software renderer have been moved to a neutral place.
1733 lines
43 KiB
C++
1733 lines
43 KiB
C++
//-----------------------------------------------------------------------------
|
|
//
|
|
// Copyright 1993-1996 id Software
|
|
// Copyright 1994-1996 Raven Software
|
|
// Copyright 1998-1998 Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
|
|
// Copyright 1999-2016 Randy Heit
|
|
// Copyright 2002-2016 Christoph Oelckers
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see http://www.gnu.org/licenses/
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// DESCRIPTION:
|
|
// Refresh/rendering module, shared data struct definitions.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
#ifndef __R_DEFS_H__
|
|
#define __R_DEFS_H__
|
|
|
|
#include "doomdef.h"
|
|
#include "templates.h"
|
|
#include "m_bbox.h"
|
|
#include "dobjgc.h"
|
|
#include "r_data/r_translate.h"
|
|
#include "texmanip.h"
|
|
#include "fcolormap.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.
|
|
struct FLightNode;
|
|
struct FGLSection;
|
|
class FSerializer;
|
|
struct FSectorPortalGroup;
|
|
struct FSectorPortal;
|
|
struct FLinePortal;
|
|
struct seg_t;
|
|
struct sector_t;
|
|
class AActor;
|
|
struct FSection;
|
|
struct FLevelLocals;
|
|
|
|
const uint16_t NO_INDEX = 0xffffu;
|
|
const uint32_t NO_SIDE = 0xffffffffu;
|
|
|
|
// Silhouette, needed for clipping Segs (mainly)
|
|
// and sprites representing things.
|
|
enum
|
|
{
|
|
SIL_NONE,
|
|
SIL_BOTTOM,
|
|
SIL_TOP,
|
|
SIL_BOTH
|
|
};
|
|
|
|
struct FDisplacement;
|
|
|
|
//
|
|
// 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;
|
|
uint32_t flags;
|
|
};
|
|
|
|
struct vertex_t
|
|
{
|
|
DVector2 p;
|
|
|
|
int vertexnum;
|
|
angle_t viewangle; // precalculated angle for clipping
|
|
int angletime; // recalculation time for view angle
|
|
bool dirty; // something has changed and needs to be recalculated
|
|
int numheights;
|
|
int numsectors;
|
|
sector_t ** sectors;
|
|
float * heightlist;
|
|
|
|
void set(fixed_t x, fixed_t y)
|
|
{
|
|
p.X = x / 65536.;
|
|
p.Y = y / 65536.;
|
|
}
|
|
|
|
void set(double x, double y)
|
|
{
|
|
p.X = x;
|
|
p.Y = y;
|
|
}
|
|
|
|
void set(const DVector2 &pos)
|
|
{
|
|
p = pos;
|
|
}
|
|
|
|
double fX() const
|
|
{
|
|
return p.X;
|
|
}
|
|
|
|
double fY() const
|
|
{
|
|
return p.Y;
|
|
}
|
|
|
|
fixed_t fixX() const
|
|
{
|
|
return FLOAT2FIXED(p.X);
|
|
}
|
|
|
|
fixed_t fixY() const
|
|
{
|
|
return FLOAT2FIXED(p.Y);
|
|
}
|
|
|
|
DVector2 fPos() const
|
|
{
|
|
return p;
|
|
}
|
|
|
|
int Index() const { return vertexnum; }
|
|
void RecalcVertexHeights();
|
|
|
|
|
|
vertex_t()
|
|
{
|
|
p = { 0,0 };
|
|
angletime = 0;
|
|
viewangle = 0;
|
|
dirty = true;
|
|
numheights = numsectors = 0;
|
|
sectors = NULL;
|
|
heightlist = NULL;
|
|
}
|
|
|
|
~vertex_t()
|
|
{
|
|
if (sectors != nullptr) delete[] sectors;
|
|
if (heightlist != nullptr) delete[] heightlist;
|
|
}
|
|
|
|
bool operator== (const vertex_t &other)
|
|
{
|
|
return p == other.p;
|
|
}
|
|
|
|
bool operator!= (const vertex_t &other)
|
|
{
|
|
return p != other.p;
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
p.Zero();
|
|
}
|
|
};
|
|
|
|
// Forward of LineDefs, for Sectors.
|
|
struct line_t;
|
|
|
|
class player_t;
|
|
class FScanner;
|
|
class FBitmap;
|
|
struct FCopyInfo;
|
|
class DInterpolation;
|
|
|
|
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 = (int)strtoll(val.GetChars(), NULL, 0);
|
|
FloatVal = strtod(val.GetChars(), NULL);
|
|
StringVal = val;
|
|
return *this;
|
|
}
|
|
|
|
};
|
|
|
|
class FUDMFKeys : public TArray<FUDMFKey>
|
|
{
|
|
bool mSorted = false;
|
|
public:
|
|
void Sort();
|
|
FUDMFKey *Find(FName key);
|
|
};
|
|
|
|
//
|
|
// The SECTORS record, at runtime.
|
|
// Stores things/mobjs.
|
|
//
|
|
class DSectorEffect;
|
|
struct FRemapTable;
|
|
|
|
enum
|
|
{
|
|
SECSPAC_Enter = 1<< 0, // Trigger when player enters
|
|
SECSPAC_Exit = 1<< 1, // Trigger when player exits
|
|
SECSPAC_HitFloor = 1<< 2, // Trigger when player hits floor
|
|
SECSPAC_HitCeiling = 1<< 3, // Trigger when player hits ceiling
|
|
SECSPAC_Use = 1<< 4, // Trigger when player uses
|
|
SECSPAC_UseWall = 1<< 5, // Trigger when player uses a wall
|
|
SECSPAC_EyesDive = 1<< 6, // Trigger when player eyes go below fake floor
|
|
SECSPAC_EyesSurface = 1<< 7, // Trigger when player eyes go above fake floor
|
|
SECSPAC_EyesBelowC = 1<< 8, // Trigger when player eyes go below fake ceiling
|
|
SECSPAC_EyesAboveC = 1<< 9, // Trigger when player eyes go above fake ceiling
|
|
SECSPAC_HitFakeFloor= 1<<10, // Trigger when player hits fake floor
|
|
SECSPAC_DamageFloor = 1<<11, // Trigger when floor is damaged
|
|
SECSPAC_DamageCeiling=1<<12, // Trigger when ceiling is damaged
|
|
SECSPAC_DeathFloor = 1<<13, // Trigger when floor has 0 hp
|
|
SECSPAC_DeathCeiling= 1<<14, // Trigger when ceiling has 0 hp
|
|
SECSPAC_Damage3D = 1<<15, // Trigger when controlled 3d floor is damaged
|
|
SECSPAC_Death3D = 1<<16 // Trigger when controlled 3d floor has 0 hp
|
|
};
|
|
|
|
struct secplane_t
|
|
{
|
|
// the plane is defined as a*x + b*y + c*z + d = 0
|
|
// ic is 1/c, for faster Z calculations
|
|
|
|
//private:
|
|
DVector3 normal;
|
|
double D, negiC; // negative iC because that also saves a negation in all methods using this.
|
|
public:
|
|
friend FSerializer &Serialize(FSerializer &arc, const char *key, secplane_t &p, secplane_t *def);
|
|
|
|
void set(double aa, double bb, double cc, double dd)
|
|
{
|
|
normal.X = aa;
|
|
normal.Y = bb;
|
|
normal.Z = cc;
|
|
D = dd;
|
|
negiC = -1 / cc;
|
|
}
|
|
|
|
void setD(double dd)
|
|
{
|
|
D = dd;
|
|
}
|
|
|
|
double fC() const
|
|
{
|
|
return normal.Z;
|
|
}
|
|
double fD() const
|
|
{
|
|
return D;
|
|
}
|
|
|
|
bool isSlope() const
|
|
{
|
|
return !normal.XY().isZero();
|
|
}
|
|
|
|
const DVector3 &Normal() const
|
|
{
|
|
return normal;
|
|
}
|
|
|
|
// Returns < 0 : behind; == 0 : on; > 0 : in front
|
|
int PointOnSide(const DVector3 &pos) const
|
|
{
|
|
double v = (normal | pos) + D;
|
|
return v < -EQUAL_EPSILON ? -1 : v > EQUAL_EPSILON ? 1 : 0;
|
|
}
|
|
|
|
// Returns the value of z at (0,0) This is used by the 3D floor code which does not handle slopes
|
|
double Zat0() const
|
|
{
|
|
return negiC*D;
|
|
}
|
|
|
|
// Returns the value of z at (x,y)
|
|
fixed_t ZatPoint(fixed_t x, fixed_t y) const = delete; // it is not allowed to call this.
|
|
|
|
// Returns the value of z at (x,y) as a double
|
|
double ZatPoint (double x, double y) const
|
|
{
|
|
return (D + normal.X*x + normal.Y*y) * negiC;
|
|
}
|
|
|
|
double ZatPoint(const DVector2 &pos) const
|
|
{
|
|
return (D + normal.X*pos.X + normal.Y*pos.Y) * negiC;
|
|
}
|
|
|
|
double ZatPoint(const FVector2 &pos) const
|
|
{
|
|
return (D + normal.X*pos.X + normal.Y*pos.Y) * negiC;
|
|
}
|
|
|
|
double ZatPoint(const vertex_t *v) const
|
|
{
|
|
return (D + normal.X*v->fX() + normal.Y*v->fY()) * negiC;
|
|
}
|
|
|
|
// Returns the value of z at vertex v if d is equal to dist
|
|
double ZatPointDist(const vertex_t *v, double dist)
|
|
{
|
|
return (dist + normal.X*v->fX() + normal.Y*v->fY()) * negiC;
|
|
}
|
|
// Flips the plane's vertical orientiation, so that if it pointed up,
|
|
// it will point down, and vice versa.
|
|
void FlipVert ()
|
|
{
|
|
normal = -normal;
|
|
D = -D;
|
|
negiC = -negiC;
|
|
}
|
|
|
|
// Returns true if 2 planes are the same
|
|
bool operator== (const secplane_t &other) const
|
|
{
|
|
return normal == other.normal && D == other.D;
|
|
}
|
|
|
|
// Returns true if 2 planes are different
|
|
bool operator!= (const secplane_t &other) const
|
|
{
|
|
return normal != other.normal || D != other.D;
|
|
}
|
|
|
|
// Moves a plane up/down by hdiff units
|
|
void ChangeHeight(double hdiff)
|
|
{
|
|
D = D - hdiff * normal.Z;
|
|
}
|
|
|
|
// Moves a plane up/down by hdiff units
|
|
double GetChangedHeight(double hdiff) const
|
|
{
|
|
return D - hdiff * normal.Z;
|
|
}
|
|
|
|
// Returns how much this plane's height would change if d were set to oldd
|
|
double HeightDiff(double oldd) const
|
|
{
|
|
return (D - oldd) * negiC;
|
|
}
|
|
|
|
// Returns how much this plane's height would change if d were set to oldd
|
|
double HeightDiff(double oldd, double newd) const
|
|
{
|
|
return (newd - oldd) * negiC;
|
|
}
|
|
|
|
double PointToDist(const DVector2 &xy, double z) const
|
|
{
|
|
return -(normal.X * xy.X + normal.Y * xy.Y + normal.Z * z);
|
|
}
|
|
|
|
double PointToDist(const vertex_t *v, double z) const
|
|
{
|
|
return -(normal.X * v->fX() + normal.Y * v->fY() + normal.Z * z);
|
|
}
|
|
|
|
void SetAtHeight(double height, int ceiling)
|
|
{
|
|
normal.X = normal.Y = 0;
|
|
if (ceiling)
|
|
{
|
|
normal.Z = -1;
|
|
negiC = 1;
|
|
D = height;
|
|
}
|
|
else
|
|
{
|
|
normal.Z = 1;
|
|
negiC = -1;
|
|
D = -height;
|
|
}
|
|
}
|
|
|
|
bool CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const;
|
|
inline double ZatPoint(const AActor *ac) const;
|
|
|
|
};
|
|
|
|
#include "p_3dfloors.h"
|
|
struct subsector_t;
|
|
struct side_t;
|
|
extern bool gl_plane_reflection_i;
|
|
|
|
// 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.
|
|
PLANEF_LINKED = 256 // plane is flagged as a linked portal
|
|
};
|
|
|
|
// Internal sector flags
|
|
enum
|
|
{
|
|
SECMF_FAKEFLOORONLY = 2, // when used as heightsec in R_FakeFlat, only copies floor
|
|
SECMF_CLIPFAKEPLANES = 4, // as a heightsec, clip planes to target sector's planes
|
|
SECMF_NOFAKELIGHT = 8, // heightsec does not change lighting
|
|
SECMF_IGNOREHEIGHTSEC = 16, // heightsec is only for triggering sector actions
|
|
SECMF_UNDERWATER = 32, // sector is underwater
|
|
SECMF_FORCEDUNDERWATER = 64, // sector is forced to be underwater
|
|
SECMF_UNDERWATERMASK = 32+64,
|
|
SECMF_DRAWN = 128, // sector has been drawn at least once
|
|
SECMF_HIDDEN = 256, // Do not draw on textured automap
|
|
SECMF_OVERLAPPING = 512, // floor and ceiling overlap and require special renderer action.
|
|
SECMF_NOSKYWALLS = 1024, // Do not draw "sky walls"
|
|
};
|
|
|
|
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_NOATTACK = 2048, // monsters cannot start attacks in this sector.
|
|
|
|
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<sector_t *> Sectors;
|
|
} FakeFloor;
|
|
|
|
// 3DMIDTEX information
|
|
struct midtex
|
|
{
|
|
struct plane
|
|
{
|
|
TArray<sector_t *> AttachedSectors; // all sectors containing 3dMidtex lines attached to this sector
|
|
TArray<line_t *> AttachedLines; // all 3dMidtex lines attached to this sector
|
|
} Floor, Ceiling;
|
|
} Midtex;
|
|
|
|
// Linked sector information
|
|
struct linked
|
|
{
|
|
struct plane
|
|
{
|
|
TArray<FLinkedSector> Sectors;
|
|
} Floor, Ceiling;
|
|
} Linked;
|
|
|
|
// 3D floors
|
|
struct xfloor
|
|
{
|
|
TDeletingArray<F3DFloor *> ffloors; // 3D floors in this sector
|
|
TArray<lightlist_t> lightlist; // 3D light list
|
|
TArray<sector_t*> attached; // 3D floors attached to this sector
|
|
} XFloor;
|
|
|
|
TArray<vertex_t *> vertices;
|
|
};
|
|
|
|
struct FTransform
|
|
{
|
|
// killough 3/7/98: floor and ceiling texture offsets
|
|
double xOffs, yOffs, baseyOffs;
|
|
|
|
// [RH] floor and ceiling texture scales
|
|
double xScale, yScale;
|
|
|
|
// [RH] floor and ceiling texture rotation
|
|
DAngle Angle, baseAngle;
|
|
|
|
finline bool operator == (const FTransform &other) const
|
|
{
|
|
return xOffs == other.xOffs && yOffs + baseyOffs == other.yOffs + other.baseyOffs &&
|
|
xScale == other.xScale && yScale == other.yScale && Angle + baseAngle == other.Angle + other.baseAngle;
|
|
}
|
|
finline bool operator != (const FTransform &other) const
|
|
{
|
|
return !(*this == other);
|
|
}
|
|
|
|
};
|
|
|
|
struct secspecial_t
|
|
{
|
|
FName 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;
|
|
};
|
|
|
|
FSerializer &Serialize(FSerializer &arc, const char *key, secspecial_t &spec, secspecial_t *def);
|
|
|
|
enum class EMoveResult { ok, crushed, pastdest };
|
|
|
|
struct sector_t
|
|
{
|
|
|
|
enum
|
|
{
|
|
floor,
|
|
ceiling,
|
|
// only used for specialcolors array
|
|
walltop,
|
|
wallbottom,
|
|
sprites
|
|
|
|
};
|
|
|
|
enum
|
|
{
|
|
CeilingMove,
|
|
FloorMove,
|
|
CeilingScroll,
|
|
FloorScroll
|
|
};
|
|
|
|
enum
|
|
{
|
|
vbo_fakefloor = floor + 2,
|
|
vbo_fakeceiling = ceiling + 2,
|
|
};
|
|
|
|
enum
|
|
{
|
|
INVALIDATE_PLANES = 1,
|
|
INVALIDATE_OTHER = 2
|
|
};
|
|
|
|
struct splane
|
|
{
|
|
FTransform xform;
|
|
int Flags;
|
|
int Light;
|
|
double alpha;
|
|
double TexZ;
|
|
PalEntry GlowColor;
|
|
float GlowHeight;
|
|
FTextureID Texture;
|
|
TextureManipulation TextureFx;
|
|
};
|
|
|
|
|
|
splane planes[2];
|
|
|
|
FLevelLocals *Level;
|
|
extsector_t * e; // This stores data that requires construction/destruction. Such data must not be copied by R_FakeFlat.
|
|
|
|
secplane_t floorplane, ceilingplane; // [RH] store floor and ceiling planes instead of heights
|
|
DVector2 centerspot; // origin for any sounds played by the sector
|
|
TStaticPointedArray<line_t *> Lines;
|
|
sector_t *heightsec; // killough 3/7/98: support flat heights drawn at another sector's heights other sector, or NULL if no other sector
|
|
|
|
struct msecnode_t *sectorportal_thinglist; // for cross-portal rendering.
|
|
struct msecnode_t *touching_renderthings; // this is used to allow wide things to be rendered not only from their main sector.
|
|
|
|
PalEntry SpecialColors[5]; // Doom64 style colors
|
|
PalEntry AdditiveColors[5];
|
|
|
|
FColormap Colormap; // Sector's own color/fog info.
|
|
|
|
short special; // map-defined sector special type
|
|
short lightlevel;
|
|
|
|
int sky; // MBF sky transfer info.
|
|
int validcount; // if == validcount, already checked
|
|
|
|
uint32_t bottommap, midmap, topmap; // killough 4/4/98: dynamic colormaps
|
|
// [RH] these can also be blend values if
|
|
// the alpha mask is non-zero
|
|
|
|
bool transdoor; // For transparent door hacks
|
|
uint16_t MoreFlags; // [RH] Internal sector flags
|
|
uint32_t Flags; // Sector flags
|
|
|
|
// [RH] The portal or skybox to render for this sector.
|
|
unsigned Portals[2];
|
|
int PortalGroup;
|
|
|
|
int sectornum; // for comparing sector copies
|
|
|
|
// GL only stuff starts here
|
|
float reflect[2];
|
|
|
|
int subsectorcount; // list of subsectors
|
|
double transdoorheight; // for transparent door hacks
|
|
subsector_t ** subsectors;
|
|
FSectorPortalGroup * portals[2]; // floor and ceiling portals
|
|
|
|
int vboindex[4]; // VBO indices of the 4 planes this sector uses during rendering. This is only needed for updating plane heights.
|
|
int iboindex[4]; // IBO indices of the 4 planes this sector uses during rendering
|
|
double vboheight[2]; // Last calculated height for the 2 planes of this actual sector
|
|
int vbocount[2]; // Total count of vertices belonging to this sector's planes. This is used when a sector height changes and also contains all attached planes.
|
|
int ibocount; // number of indices per plane (identical for all planes.) If this is -1 the index buffer is not in use.
|
|
|
|
// Below are all properties which are not used by the renderer.
|
|
|
|
TObjPtr<AActor*> SoundTarget;
|
|
AActor* thinglist; // list of actors in sector
|
|
double gravity; // [RH] Sector gravity (1.0 is normal)
|
|
|
|
// thinker_t for reversable actions
|
|
TObjPtr<DSectorEffect*> floordata; // jff 2/22/98 make thinkers on
|
|
TObjPtr<DSectorEffect*> ceilingdata; // floors, ceilings, lighting,
|
|
TObjPtr<DSectorEffect*> lightingdata; // independent of one another
|
|
|
|
TObjPtr<DInterpolation*> interpolations[4];
|
|
|
|
// 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
|
|
|
|
// [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<AActor*> SecActTarget;
|
|
|
|
// killough 8/28/98: friction is a sector property, not an actor 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];
|
|
FName SeqName; // Sound sequence name. Setting seqType non-negative will override this.
|
|
|
|
short seqType; // this sector's sound sequence
|
|
uint8_t soundtraversed; // 0 = untraversed, 1,2 = sndlines -1
|
|
int8_t stairlock; // jff 2/26/98 lockout machinery for stairbuilding: -2 on first locked, -1 after thinker done, 0 normally
|
|
|
|
int prevsec; // -1 or number of sector for previous step
|
|
int nextsec; // -1 or number of next step sector
|
|
|
|
FName 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
|
|
|
|
uint16_t ZoneNumber; // [RH] Zone this sector belongs to
|
|
|
|
// [ZZ] these are for destructible sectors.
|
|
// default is 0, which means no special behavior
|
|
int healthfloor;
|
|
int healthceiling;
|
|
int health3d;
|
|
int healthfloorgroup;
|
|
int healthceilinggroup;
|
|
int health3dgroup;
|
|
|
|
// Member functions
|
|
|
|
private:
|
|
bool MoveAttached(int crush, double move, int floorOrCeiling, bool resetfailed, bool instant = false);
|
|
public:
|
|
EMoveResult MoveFloor(double speed, double dest, int crush, int direction, bool hexencrush, bool instant = false);
|
|
EMoveResult MoveCeiling(double speed, double dest, int crush, int direction, bool hexencrush);
|
|
|
|
inline EMoveResult MoveFloor(double speed, double dest, int direction)
|
|
{
|
|
return MoveFloor(speed, dest, -1, direction, false);
|
|
}
|
|
|
|
inline EMoveResult MoveCeiling(double speed, double dest, int direction)
|
|
{
|
|
return MoveCeiling(speed, dest, -1, direction, false);
|
|
}
|
|
|
|
bool IsLinked(sector_t *other, bool ceiling) const;
|
|
|
|
sector_t *NextSpecialSector (int type, sector_t *prev) const; // [RH]
|
|
void RemoveForceField();
|
|
int Index() const { return sectornum; }
|
|
|
|
void AdjustFloorClip () const;
|
|
void SetColor(PalEntry pe, int desat);
|
|
void SetFade(PalEntry pe);
|
|
void SetFogDensity(int dens);
|
|
void ClosestPoint(const DVector2 &pos, DVector2 &out) const;
|
|
|
|
int GetFloorLight() const;
|
|
int GetCeilingLight() const;
|
|
|
|
sector_t *GetHeightSec() const
|
|
{
|
|
return (MoreFlags & SECMF_IGNOREHEIGHTSEC)? nullptr : heightsec;
|
|
}
|
|
|
|
double GetFriction(int plane = sector_t::floor, double *movefac = NULL) const;
|
|
bool TriggerSectorActions(AActor *thing, int activation);
|
|
|
|
DInterpolation *SetInterpolation(int position, bool attach);
|
|
|
|
FSectorPortal *ValidatePortal(int which);
|
|
void CheckPortalPlane(int plane);
|
|
|
|
int CheckSpriteGlow(int lightlevel, const DVector3 &pos);
|
|
bool GetWallGlow(float *topglowcolor, float *bottomglowcolor);
|
|
|
|
|
|
void SetXOffset(int pos, double o)
|
|
{
|
|
planes[pos].xform.xOffs = o;
|
|
}
|
|
|
|
void AddXOffset(int pos, double o)
|
|
{
|
|
planes[pos].xform.xOffs += o;
|
|
}
|
|
|
|
double GetXOffset(int pos) const
|
|
{
|
|
return planes[pos].xform.xOffs;
|
|
}
|
|
|
|
void SetYOffset(int pos, double o)
|
|
{
|
|
planes[pos].xform.yOffs = o;
|
|
}
|
|
|
|
void AddYOffset(int pos, double o)
|
|
{
|
|
planes[pos].xform.yOffs += o;
|
|
}
|
|
|
|
double GetYOffset(int pos, bool addbase = true) const
|
|
{
|
|
if (!addbase)
|
|
{
|
|
return planes[pos].xform.yOffs;
|
|
}
|
|
else
|
|
{
|
|
return planes[pos].xform.yOffs + planes[pos].xform.baseyOffs;
|
|
}
|
|
}
|
|
|
|
void SetXScale(int pos, double o)
|
|
{
|
|
planes[pos].xform.xScale = o;
|
|
}
|
|
|
|
double GetXScale(int pos) const
|
|
{
|
|
return planes[pos].xform.xScale;
|
|
}
|
|
|
|
void SetYScale(int pos, double o)
|
|
{
|
|
planes[pos].xform.yScale = o;
|
|
}
|
|
|
|
double GetYScale(int pos) const
|
|
{
|
|
return planes[pos].xform.yScale;
|
|
}
|
|
|
|
void SetAngle(int pos, DAngle o)
|
|
{
|
|
planes[pos].xform.Angle = o;
|
|
}
|
|
|
|
DAngle GetAngle(int pos, bool addbase = true) const
|
|
{
|
|
if (!addbase)
|
|
{
|
|
return planes[pos].xform.Angle;
|
|
}
|
|
else
|
|
{
|
|
return planes[pos].xform.Angle + planes[pos].xform.baseAngle;
|
|
}
|
|
}
|
|
|
|
void SetBase(int pos, double y, DAngle o)
|
|
{
|
|
planes[pos].xform.baseyOffs = y;
|
|
planes[pos].xform.baseAngle = o;
|
|
}
|
|
|
|
void SetAlpha(int pos, double o)
|
|
{
|
|
planes[pos].alpha = o;
|
|
}
|
|
|
|
double GetAlpha(int pos) const
|
|
{
|
|
return planes[pos].alpha;
|
|
}
|
|
|
|
int GetFlags(int pos) const
|
|
{
|
|
return planes[pos].Flags;
|
|
}
|
|
|
|
// like the previous one but masks out all flags which are not relevant for rendering.
|
|
int GetVisFlags(int pos) const
|
|
{
|
|
return planes[pos].Flags & ~(PLANEF_BLOCKED | PLANEF_NOPASS | PLANEF_BLOCKSOUND | PLANEF_LINKED);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
double GetGlowHeight(int pos)
|
|
{
|
|
return planes[pos].GlowHeight;
|
|
}
|
|
|
|
PalEntry GetGlowColor(int pos)
|
|
{
|
|
return planes[pos].GlowColor;
|
|
}
|
|
|
|
void SetGlowHeight(int pos, float height)
|
|
{
|
|
planes[pos].GlowHeight = height;
|
|
}
|
|
|
|
void SetGlowColor(int pos, PalEntry color)
|
|
{
|
|
planes[pos].GlowColor = color;
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
double GetPlaneTexZ(int pos) const
|
|
{
|
|
return planes[pos].TexZ;
|
|
}
|
|
|
|
void SetPlaneTexZQuick(int pos, double val) // For the *FakeFlat functions which do not need to have the overlap checked.
|
|
{
|
|
planes[pos].TexZ = val;
|
|
}
|
|
|
|
void SetPlaneTexZ(int pos, double val, bool dirtify = false) // This mainly gets used by init code. The only place where it must set the vertex to dirty is the interpolation code.
|
|
{
|
|
planes[pos].TexZ = val;
|
|
if (dirtify) SetAllVerticesDirty();
|
|
CheckOverlap();
|
|
}
|
|
|
|
void ChangePlaneTexZ(int pos, double val)
|
|
{
|
|
planes[pos].TexZ += val;
|
|
SetAllVerticesDirty();
|
|
CheckOverlap();
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
void CheckExColorFlag();
|
|
|
|
void InitAllExcolors()
|
|
{
|
|
if (SpecialColors[sector_t::wallbottom] != 0xffffffff || SpecialColors[sector_t::walltop] != 0xffffffff || AdditiveColors[sector_t::walltop] != 0xffffffff) CheckExColorFlag();
|
|
}
|
|
|
|
void SetSpecialColor(int slot, int r, int g, int b)
|
|
{
|
|
SpecialColors[slot] = PalEntry(255, r, g, b);
|
|
if ((slot == sector_t::wallbottom || slot == sector_t::walltop) && SpecialColors[slot] != 0xffffffff) CheckExColorFlag();
|
|
}
|
|
|
|
void SetSpecialColor(int slot, PalEntry rgb)
|
|
{
|
|
rgb.a = 255;
|
|
SpecialColors[slot] = rgb;
|
|
if ((slot == sector_t::wallbottom || slot == sector_t::walltop) && rgb != 0xffffffff) CheckExColorFlag();
|
|
}
|
|
|
|
void SetAdditiveColor(int slot, PalEntry rgb)
|
|
{
|
|
rgb.a = 255;
|
|
AdditiveColors[slot] = rgb;
|
|
if ((slot == sector_t::walltop) && AdditiveColors[slot] != 0xffffffff) CheckExColorFlag(); // Wallbottom of this is not used.
|
|
|
|
}
|
|
|
|
// TextureFX parameters
|
|
|
|
void SetTextureFx(int slot, const TextureManipulation *tm)
|
|
{
|
|
if (tm) planes[slot].TextureFx = *tm; // this is for getting the data from a texture.
|
|
else planes[slot].TextureFx = {};
|
|
}
|
|
|
|
|
|
inline bool PortalBlocksView(int plane);
|
|
inline bool PortalBlocksSight(int plane);
|
|
inline bool PortalBlocksMovement(int plane);
|
|
inline bool PortalBlocksSound(int plane);
|
|
inline bool PortalIsLinked(int plane);
|
|
|
|
void ClearPortal(int plane)
|
|
{
|
|
Portals[plane] = 0;
|
|
portals[plane] = nullptr;
|
|
}
|
|
|
|
FSectorPortal *GetPortal(int plane);
|
|
double GetPortalPlaneZ(int plane);
|
|
DVector2 GetPortalDisplacement(int plane);
|
|
int GetPortalType(int plane);
|
|
int GetOppositePortalGroup(int plane);
|
|
void CheckOverlap();
|
|
|
|
void SetVerticesDirty()
|
|
{
|
|
for (unsigned i = 0; i < e->vertices.Size(); i++) e->vertices[i]->dirty = true;
|
|
}
|
|
|
|
void SetAllVerticesDirty()
|
|
{
|
|
SetVerticesDirty();
|
|
for (unsigned i = 0; i < e->FakeFloor.Sectors.Size(); i++) e->FakeFloor.Sectors[i]->SetVerticesDirty();
|
|
for (unsigned i = 0; i < e->XFloor.attached.Size(); i++) e->XFloor.attached[i]->SetVerticesDirty();
|
|
}
|
|
|
|
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);
|
|
|
|
inline double HighestCeilingAt(AActor *a, sector_t **resultsec = NULL);
|
|
inline double LowestFloorAt(AActor *a, sector_t **resultsec = NULL);
|
|
|
|
bool isClosed() const
|
|
{
|
|
return floorplane.Normal() == -ceilingplane.Normal() && floorplane.D == -ceilingplane.D;
|
|
}
|
|
|
|
// Member variables
|
|
double CenterFloor() const { return floorplane.ZatPoint(centerspot); }
|
|
double CenterCeiling() const { return ceilingplane.ZatPoint(centerspot); }
|
|
|
|
void CopyColors(sector_t *other)
|
|
{
|
|
memcpy(SpecialColors, other->SpecialColors, sizeof(SpecialColors));
|
|
Colormap = other->Colormap;
|
|
}
|
|
|
|
float GetReflect(int pos) { return gl_plane_reflection_i ? reflect[pos] : 0; }
|
|
FSectorPortalGroup *GetPortalGroup(int plane) { return portals[plane]; }
|
|
|
|
};
|
|
|
|
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.
|
|
WALLF_EXTCOLOR = 256, // enables the extended color options (flagged to allow the renderer to easily skip the relevant code)
|
|
};
|
|
|
|
struct side_t
|
|
{
|
|
enum ETexpart
|
|
{
|
|
top=0,
|
|
mid=1,
|
|
bottom=2,
|
|
none = 1, // this is just for clarification in a mapping table
|
|
};
|
|
enum EColorSlot
|
|
{
|
|
walltop = 0,
|
|
wallbottom = 1,
|
|
};
|
|
struct part
|
|
{
|
|
enum EPartFlags
|
|
{
|
|
NoGradient = 1,
|
|
FlipGradient = 2,
|
|
ClampGradient = 4,
|
|
UseOwnSpecialColors = 8,
|
|
UseOwnAdditiveColor = 16,
|
|
};
|
|
double xOffset;
|
|
double yOffset;
|
|
double xScale;
|
|
double yScale;
|
|
TObjPtr<DInterpolation*> interpolation;
|
|
int flags;
|
|
FTextureID texture;
|
|
TextureManipulation TextureFx;
|
|
PalEntry SpecialColors[2];
|
|
PalEntry AdditiveColor;
|
|
|
|
|
|
void InitFrom(const part &other)
|
|
{
|
|
if (texture.isNull()) texture = other.texture;
|
|
if (0.0 == xOffset) xOffset = other.xOffset;
|
|
if (0.0 == yOffset) yOffset = other.yOffset;
|
|
if (1.0 == xScale && 0.0 != other.xScale) xScale = other.xScale;
|
|
if (1.0 == yScale && 0.0 != other.yScale) yScale = other.yScale;
|
|
}
|
|
|
|
};
|
|
|
|
sector_t* sector; // Sector the SideDef is facing.
|
|
DBaseDecal* AttachedDecals; // [RH] Decals bound to the wall
|
|
part textures[3];
|
|
line_t *linedef;
|
|
uint32_t LeftSide, RightSide; // [RH] Group walls into loops
|
|
uint16_t TexelLength;
|
|
int16_t Light;
|
|
uint16_t Flags;
|
|
int UDMFIndex; // needed to access custom UDMF fields which are stored in loading order.
|
|
FLightNode * lighthead; // all dynamic lights that may affect this wall
|
|
seg_t **segs; // all segs belonging to this sidedef in ascending order. Used for precise rendering
|
|
int numsegs;
|
|
int sidenum;
|
|
|
|
int GetLightLevel (bool foggy, int baselight, bool is3dlight=false, int *pfakecontrast_usedbygzdoom=NULL) const;
|
|
|
|
void SetLight(int16_t l)
|
|
{
|
|
Light = l;
|
|
}
|
|
|
|
FLevelLocals *GetLevel()
|
|
{
|
|
return sector->Level;
|
|
}
|
|
|
|
FTextureID GetTexture(int which) const
|
|
{
|
|
return textures[which].texture;
|
|
}
|
|
void SetTexture(int which, FTextureID tex)
|
|
{
|
|
textures[which].texture = tex;
|
|
}
|
|
|
|
void SetTextureXOffset(int which, double offset)
|
|
{
|
|
textures[which].xOffset = offset;;
|
|
}
|
|
|
|
void SetTextureXOffset(double offset)
|
|
{
|
|
textures[top].xOffset =
|
|
textures[mid].xOffset =
|
|
textures[bottom].xOffset = offset;
|
|
}
|
|
|
|
double GetTextureXOffset(int which) const
|
|
{
|
|
return textures[which].xOffset;
|
|
}
|
|
|
|
void AddTextureXOffset(int which, double delta)
|
|
{
|
|
textures[which].xOffset += delta;
|
|
}
|
|
|
|
void SetTextureYOffset(int which, double offset)
|
|
{
|
|
textures[which].yOffset = offset;
|
|
}
|
|
|
|
void SetTextureYOffset(double offset)
|
|
{
|
|
textures[top].yOffset =
|
|
textures[mid].yOffset =
|
|
textures[bottom].yOffset = offset;
|
|
}
|
|
|
|
double GetTextureYOffset(int which) const
|
|
{
|
|
return textures[which].yOffset;
|
|
}
|
|
|
|
void AddTextureYOffset(int which, double delta)
|
|
{
|
|
textures[which].yOffset += delta;
|
|
}
|
|
|
|
void SetTextureXScale(int which, double scale)
|
|
{
|
|
textures[which].xScale = scale == 0 ? 1. : scale;
|
|
}
|
|
|
|
void SetTextureXScale(double scale)
|
|
{
|
|
textures[top].xScale = textures[mid].xScale = textures[bottom].xScale = scale == 0 ? 1. : scale;
|
|
}
|
|
|
|
double GetTextureXScale(int which) const
|
|
{
|
|
return textures[which].xScale;
|
|
}
|
|
|
|
void MultiplyTextureXScale(int which, double delta)
|
|
{
|
|
textures[which].xScale *= delta;
|
|
}
|
|
|
|
void SetTextureYScale(int which, double scale)
|
|
{
|
|
textures[which].yScale = scale == 0 ? 1. : scale;
|
|
}
|
|
|
|
void SetTextureYScale(double scale)
|
|
{
|
|
textures[top].yScale = textures[mid].yScale = textures[bottom].yScale = scale == 0 ? 1. : scale;
|
|
}
|
|
|
|
double GetTextureYScale(int which) const
|
|
{
|
|
return textures[which].yScale;
|
|
}
|
|
|
|
void MultiplyTextureYScale(int which, double delta)
|
|
{
|
|
textures[which].yScale *= delta;
|
|
}
|
|
|
|
void SetSpecialColor(int which, int slot, int r, int g, int b)
|
|
{
|
|
textures[which].SpecialColors[slot] = PalEntry(255, r, g, b);
|
|
}
|
|
|
|
void SetSpecialColor(int which, int slot, PalEntry rgb)
|
|
{
|
|
rgb.a = 255;
|
|
textures[which].SpecialColors[slot] = rgb;
|
|
}
|
|
|
|
// Note that the sector being passed in here may not be the actual sector this sidedef belongs to
|
|
// (either for polyobjects or FakeFlat'ed temporaries.)
|
|
PalEntry GetSpecialColor(int which, int slot, sector_t *frontsector) const
|
|
{
|
|
auto &part = textures[which];
|
|
if (part.flags & part::NoGradient) slot = 0;
|
|
if (part.flags & part::FlipGradient) slot ^= 1;
|
|
return (part.flags & part::UseOwnSpecialColors) ? part.SpecialColors[slot] : frontsector->SpecialColors[sector_t::walltop + slot];
|
|
}
|
|
|
|
void EnableAdditiveColor(int which, bool enable)
|
|
{
|
|
const int flag = part::UseOwnAdditiveColor;
|
|
if (enable)
|
|
{
|
|
textures[which].flags |= flag;
|
|
Flags |= WALLF_EXTCOLOR;
|
|
}
|
|
else
|
|
{
|
|
textures[which].flags &= (~flag);
|
|
}
|
|
}
|
|
|
|
void SetAdditiveColor(int which, PalEntry rgb)
|
|
{
|
|
rgb.a = 255;
|
|
textures[which].AdditiveColor = rgb;
|
|
}
|
|
|
|
void SetTextureFx(int slot, const TextureManipulation* tm)
|
|
{
|
|
if (tm)
|
|
{
|
|
textures[slot].TextureFx = *tm; // this is for getting the data from a texture.
|
|
if (tm->AddColor.a) Flags |= WALLF_EXTCOLOR;
|
|
}
|
|
else
|
|
{
|
|
textures[slot].TextureFx = {};
|
|
}
|
|
}
|
|
|
|
PalEntry GetAdditiveColor(int which, sector_t *frontsector) const
|
|
{
|
|
if (textures[which].flags & part::UseOwnAdditiveColor) {
|
|
return textures[which].AdditiveColor;
|
|
}
|
|
else
|
|
{
|
|
return frontsector->AdditiveColors[sector_t::walltop]; // Used as additive color for all walls
|
|
}
|
|
}
|
|
|
|
|
|
DInterpolation *SetInterpolation(int position);
|
|
void StopInterpolation(int position);
|
|
|
|
vertex_t *V1() const;
|
|
vertex_t *V2() const;
|
|
|
|
int Index() const { return sidenum; }
|
|
};
|
|
|
|
enum AutomapLineStyle : int
|
|
{
|
|
AMLS_Default,
|
|
AMLS_OneSided,
|
|
AMLS_TwoSided,
|
|
AMLS_FloorDiff,
|
|
AMLS_CeilingDiff,
|
|
AMLS_ExtraFloor,
|
|
AMLS_Special,
|
|
AMLS_Secret,
|
|
AMLS_NotSeen,
|
|
AMLS_Locked,
|
|
AMLS_IntraTeleport,
|
|
AMLS_InterTeleport,
|
|
AMLS_UnexploredSecret,
|
|
AMLS_Portal,
|
|
|
|
AMLS_COUNT
|
|
};
|
|
|
|
struct line_t
|
|
{
|
|
vertex_t *v1, *v2; // vertices, from v1 to v2
|
|
DVector2 delta; // precalculated v2 - v1 for side checking
|
|
uint32_t flags;
|
|
uint32_t activation; // activation type
|
|
int special;
|
|
int args[5]; // <--- hexen-style arguments (expanded to ZDoom's full width)
|
|
double alpha; // <--- translucency (0=invisibile, FRACUNIT=opaque)
|
|
side_t *sidedef[2];
|
|
double 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;
|
|
unsigned portaltransferred;
|
|
AutomapLineStyle automapstyle;
|
|
int health; // [ZZ] for destructible geometry (0 = no special behavior)
|
|
int healthgroup; // [ZZ] this is the "destructible object" id
|
|
int linenum;
|
|
|
|
DVector2 Delta() const
|
|
{
|
|
return delta;
|
|
}
|
|
|
|
void setDelta(double x, double y)
|
|
{
|
|
delta = { x, y };
|
|
}
|
|
|
|
void setAlpha(double a)
|
|
{
|
|
alpha = a;
|
|
}
|
|
|
|
FSectorPortal *GetTransferredPortal();
|
|
void AdjustLine();
|
|
|
|
inline FLevelLocals *GetLevel() const;
|
|
inline FLinePortal *getPortal() const;
|
|
inline bool isLinePortal() const;
|
|
inline bool isVisualPortal() const;
|
|
inline line_t *getPortalDestination() const;
|
|
inline int getPortalAlignment() const;
|
|
inline bool hitSkyWall(AActor* mo) const;
|
|
|
|
int Index() const { return linenum; }
|
|
};
|
|
|
|
inline vertex_t *side_t::V1() const
|
|
{
|
|
return this == linedef->sidedef[0] ? linedef->v1 : linedef->v2;
|
|
}
|
|
|
|
inline vertex_t *side_t::V2() const
|
|
{
|
|
return this == linedef->sidedef[0] ? linedef->v2 : linedef->v1;
|
|
}
|
|
|
|
// 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
|
|
};
|
|
|
|
// use the same memory layout as msecnode_t so both can be used from the same freelist.
|
|
struct portnode_t
|
|
{
|
|
FLinePortal *m_sector; // a portal containing this object (no, this isn't a sector, but if we want to use templates it needs the same variable names as msecnode_t.)
|
|
AActor *m_thing; // this object
|
|
struct portnode_t *m_tprev; // prev msecnode_t for this thing
|
|
struct portnode_t *m_tnext; // next msecnode_t for this thing
|
|
struct portnode_t *m_sprev; // prev msecnode_t for this portal
|
|
struct portnode_t *m_snext; // next msecnode_t for this portal
|
|
bool visited;
|
|
};
|
|
|
|
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
|
|
|
|
seg_t* PartnerSeg;
|
|
subsector_t* Subsector;
|
|
|
|
float sidefrac; // relative position of seg's ending vertex on owning sidedef
|
|
int segnum;
|
|
|
|
int Index() const { return segnum; }
|
|
|
|
FLevelLocals *GetLevel() const
|
|
{
|
|
return frontsector->Level;
|
|
}
|
|
};
|
|
|
|
//extern seg_t *segs;
|
|
|
|
|
|
//
|
|
// 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,
|
|
SSECMF_DRAWN = 2,
|
|
SSECF_POLYORG = 4,
|
|
SSECF_HOLE = 8,
|
|
};
|
|
|
|
struct FPortalCoverage
|
|
{
|
|
uint32_t * subsectors;
|
|
int sscount;
|
|
};
|
|
|
|
void BuildPortalCoverage(FLevelLocals *Level, FPortalCoverage *coverage, subsector_t *subsector, const DVector2 &displacement);
|
|
|
|
struct subsector_t
|
|
{
|
|
sector_t *sector;
|
|
FPolyNode *polys;
|
|
FMiniBSP *BSP;
|
|
seg_t *firstline;
|
|
sector_t *render_sector;
|
|
FSection *section;
|
|
int subsectornum;
|
|
uint32_t numlines;
|
|
uint16_t flags;
|
|
short mapsection;
|
|
|
|
// subsector related GL data
|
|
int validcount;
|
|
char hacked; // 1: is part of a render hack
|
|
|
|
void BuildPolyBSP();
|
|
int Index() const { return subsectornum; }
|
|
// 2: has one-sided walls
|
|
FPortalCoverage portalcoverage[2];
|
|
};
|
|
|
|
|
|
|
|
|
|
//
|
|
// BSP node.
|
|
//
|
|
struct node_t
|
|
{
|
|
// Partition line.
|
|
fixed_t x;
|
|
fixed_t y;
|
|
fixed_t dx;
|
|
fixed_t dy;
|
|
union
|
|
{
|
|
float bbox[2][4]; // Bounding box for each child.
|
|
fixed_t nb_bbox[2][4]; // Used by nodebuilder.
|
|
};
|
|
float len;
|
|
int nodenum;
|
|
union
|
|
{
|
|
void *children[2]; // If bit 0 is set, it's a subsector.
|
|
int intchildren[2]; // Used by nodebuilder.
|
|
};
|
|
|
|
int Index() const { return nodenum; }
|
|
};
|
|
|
|
|
|
// An entire BSP tree.
|
|
|
|
struct FMiniBSP
|
|
{
|
|
bool bDirty;
|
|
|
|
TArray<node_t> Nodes;
|
|
TArray<seg_t> Segs;
|
|
TArray<subsector_t> Subsectors;
|
|
TArray<vertex_t> Verts;
|
|
};
|
|
|
|
//
|
|
// OTHER TYPES
|
|
//
|
|
|
|
typedef uint8_t lighttable_t; // This could be wider for >8 bit display.
|
|
|
|
//----------------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------------
|
|
|
|
inline bool inRange(const FBoundingBox &box, const line_t *ld)
|
|
{
|
|
return box.Left() < ld->bbox[BOXRIGHT] &&
|
|
box.Right() > ld->bbox[BOXLEFT] &&
|
|
box.Top() > ld->bbox[BOXBOTTOM] &&
|
|
box.Bottom() < ld->bbox[BOXTOP];
|
|
}
|
|
|
|
|
|
inline void CopyFrom3DLight(FColormap &cm, lightlist_t *light)
|
|
{
|
|
cm.CopyLight(light->extra_colormap);
|
|
if (light->caster && (light->caster->flags&FF_FADEWALLS) && light->extra_colormap.FadeColor != 0)
|
|
{
|
|
cm.CopyFog(light->extra_colormap);
|
|
}
|
|
}
|
|
|
|
double FindLowestFloorSurrounding(const sector_t *sec, vertex_t **v);
|
|
double FindHighestFloorSurrounding(const sector_t *sec, vertex_t **v);
|
|
double FindNextHighestFloor(const sector_t *sec, vertex_t **v);
|
|
double FindNextLowestFloor(const sector_t *sec, vertex_t **v);
|
|
double FindLowestCeilingSurrounding(const sector_t *sec, vertex_t **v); // jff 2/04/98
|
|
double FindHighestCeilingSurrounding(const sector_t *sec, vertex_t **v); // jff 2/04/98
|
|
double FindNextLowestCeiling(const sector_t *sec, vertex_t **v); // jff 2/04/98
|
|
double FindNextHighestCeiling(const sector_t *sec, vertex_t **v); // jff 2/04/98
|
|
int FindMinSurroundingLight (const sector_t *sec, int max);
|
|
double FindHighestFloorPoint(const sector_t *sec, vertex_t **v);
|
|
|
|
double FindShortestTextureAround(sector_t *sector); // jff 2/04/98
|
|
double FindShortestUpperAround(sector_t *sector); // jff 2/04/98
|
|
sector_t *FindModelFloorSector(sector_t *sec, double floordestheight); // jff 2/04/98
|
|
sector_t *FindModelCeilingSector(sector_t *sec, double floordestheight); // jff 2/04/98
|
|
double FindLowestCeilingPoint(const sector_t *sec, vertex_t **v);
|
|
|
|
double NextHighestCeilingAt(sector_t *sec, double x, double y, double bottomz, double topz, int flags = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL);
|
|
double NextLowestFloorAt(sector_t *sec, double x, double y, double z, int flags = 0, double steph = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL);
|
|
|
|
// This setup is to allow the VM call directily into the implementation.
|
|
// With a member function this may be subject to OS implementation details, e.g. on Windows 32 bit members use a different calling convention than regular functions.
|
|
void RemoveForceField(sector_t *sec);
|
|
int PlaneMoving(sector_t *sector, int pos);
|
|
void TransferSpecial(sector_t *self, sector_t *model);
|
|
void GetSpecial(sector_t *self, secspecial_t *spec);
|
|
void SetSpecial(sector_t *self, const secspecial_t *spec);
|
|
int GetTerrain(const sector_t *, int pos);
|
|
void CheckPortalPlane(sector_t *sector, int plane);
|
|
void AdjustFloorClip(const sector_t *sector);
|
|
void SetColor(sector_t *sector, int color, int desat);
|
|
void SetFade(sector_t *sector, int color);
|
|
int GetFloorLight(const sector_t *);
|
|
int GetCeilingLight(const sector_t *);
|
|
double GetFriction(const sector_t *self, int plane, double *movefac);
|
|
double HighestCeilingAt(sector_t *sec, double x, double y, sector_t **resultsec = nullptr);
|
|
double LowestFloorAt(sector_t *sec, double x, double y, sector_t **resultsec = nullptr);
|
|
|
|
inline void sector_t::RemoveForceField() { return ::RemoveForceField(this); }
|
|
inline bool sector_t::PlaneMoving(int pos) { return !!::PlaneMoving(this, pos); }
|
|
inline void sector_t::TransferSpecial(sector_t *model) { return ::TransferSpecial(this, model); }
|
|
inline void sector_t::GetSpecial(secspecial_t *spec) { ::GetSpecial(this, spec); }
|
|
inline void sector_t::SetSpecial(const secspecial_t *spec) { ::SetSpecial(this, spec); }
|
|
inline int sector_t::GetTerrain(int pos) const { return ::GetTerrain(this, pos); }
|
|
inline void sector_t::CheckPortalPlane(int plane) { return ::CheckPortalPlane(this, plane); }
|
|
inline void sector_t::AdjustFloorClip() const { ::AdjustFloorClip(this); }
|
|
inline void sector_t::SetColor(PalEntry pe, int desat) { ::SetColor(this, pe, desat); }
|
|
inline void sector_t::SetFade(PalEntry pe) { ::SetFade(this, pe); }
|
|
inline int sector_t::GetFloorLight() const { return ::GetFloorLight(this); }
|
|
inline int sector_t::GetCeilingLight() const { return ::GetCeilingLight(this); }
|
|
inline double sector_t::GetFriction(int plane, double *movefac) const { return ::GetFriction(this, plane, movefac); }
|
|
|
|
inline void sector_t::CheckExColorFlag()
|
|
{
|
|
for (auto ld : Lines)
|
|
{
|
|
if (ld->frontsector == this) ld->sidedef[0]->Flags |= WALLF_EXTCOLOR;
|
|
if (ld->backsector == this) ld->sidedef[1]->Flags |= WALLF_EXTCOLOR;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#endif
|