2017-03-12 15:56:00 +00:00
|
|
|
#pragma once
|
|
|
|
#include "c_cvars.h"
|
|
|
|
#include "actor.h"
|
2019-02-23 17:57:49 +00:00
|
|
|
#include "r_data/cycler.h"
|
2019-01-01 18:35:55 +00:00
|
|
|
#include "g_levellocals.h"
|
2017-03-12 15:56:00 +00:00
|
|
|
|
2018-04-19 07:20:21 +00:00
|
|
|
struct side_t;
|
|
|
|
struct seg_t;
|
|
|
|
|
2017-03-12 15:56:00 +00:00
|
|
|
class FSerializer;
|
2018-11-05 23:13:23 +00:00
|
|
|
struct FSectionLine;
|
2017-03-12 15:56:00 +00:00
|
|
|
|
2018-04-02 10:28:20 +00:00
|
|
|
enum ELightType
|
|
|
|
{
|
|
|
|
PointLight,
|
|
|
|
PulseLight,
|
|
|
|
FlickerLight,
|
|
|
|
RandomFlickerLight,
|
|
|
|
SectorLight,
|
|
|
|
DummyLight,
|
|
|
|
ColorPulseLight,
|
|
|
|
ColorFlickerLight,
|
|
|
|
RandomColorFlickerLight
|
|
|
|
};
|
2017-03-12 15:56:00 +00:00
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
2018-04-02 10:28:20 +00:00
|
|
|
LIGHT_RED = 0,
|
|
|
|
LIGHT_GREEN = 1,
|
|
|
|
LIGHT_BLUE = 2,
|
|
|
|
LIGHT_INTENSITY = 3,
|
|
|
|
LIGHT_SECONDARY_INTENSITY = 4,
|
2017-03-12 15:56:00 +00:00
|
|
|
};
|
|
|
|
|
2017-06-18 08:15:31 +00:00
|
|
|
enum LightFlag
|
|
|
|
{
|
|
|
|
LF_SUBTRACTIVE = 1,
|
|
|
|
LF_ADDITIVE = 2,
|
|
|
|
LF_DONTLIGHTSELF = 4,
|
|
|
|
LF_ATTENUATE = 8,
|
|
|
|
LF_NOSHADOWMAP = 16,
|
2018-01-04 16:58:11 +00:00
|
|
|
LF_DONTLIGHTACTORS = 32,
|
|
|
|
LF_SPOT = 64
|
2017-06-18 08:15:31 +00:00
|
|
|
};
|
|
|
|
|
2019-01-03 08:24:22 +00:00
|
|
|
typedef TFlags<LightFlag> LightFlags;
|
|
|
|
DEFINE_TFLAGS_OPERATORS(LightFlags)
|
|
|
|
|
2018-04-02 10:28:20 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Light definitions
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
class FLightDefaults
|
|
|
|
{
|
|
|
|
public:
|
2019-06-28 10:35:42 +00:00
|
|
|
FLightDefaults(FName name, ELightType type = PointLight)
|
|
|
|
{
|
|
|
|
m_Name = name;
|
|
|
|
m_type = type;
|
|
|
|
}
|
2017-06-18 08:15:31 +00:00
|
|
|
|
2019-01-01 18:35:55 +00:00
|
|
|
void ApplyProperties(FDynamicLight * light) const;
|
2018-04-02 10:28:20 +00:00
|
|
|
FName GetName() const { return m_Name; }
|
|
|
|
void SetParameter(double p) { m_Param = p; }
|
|
|
|
void SetArg(int arg, int val) { m_Args[arg] = val; }
|
|
|
|
int GetArg(int arg) { return m_Args[arg]; }
|
|
|
|
uint8_t GetAttenuate() const { return m_attenuate; }
|
|
|
|
void SetOffset(float* ft) { m_Pos.X = ft[0]; m_Pos.Z = ft[1]; m_Pos.Y = ft[2]; }
|
2019-01-03 08:24:22 +00:00
|
|
|
void SetSubtractive(bool subtract) { if (subtract) m_lightFlags |= LF_SUBTRACTIVE; else m_lightFlags &= ~LF_SUBTRACTIVE; }
|
|
|
|
void SetAdditive(bool add) { if (add) m_lightFlags |= LF_ADDITIVE; else m_lightFlags &= ~LF_ADDITIVE; }
|
|
|
|
void SetDontLightSelf(bool add) { if (add) m_lightFlags |= LF_DONTLIGHTSELF; else m_lightFlags &= ~LF_DONTLIGHTSELF; }
|
|
|
|
void SetAttenuate(bool on) { m_attenuate = on; if (on) m_lightFlags |= LF_ATTENUATE; else m_lightFlags &= ~LF_ATTENUATE; }
|
|
|
|
void SetDontLightActors(bool on) { if (on) m_lightFlags |= LF_DONTLIGHTACTORS; else m_lightFlags &= ~LF_DONTLIGHTACTORS; }
|
|
|
|
void SetNoShadowmap(bool on) { if (on) m_lightFlags |= LF_NOSHADOWMAP; else m_lightFlags &= ~LF_NOSHADOWMAP; }
|
|
|
|
void SetSpot(bool spot) { if (spot) m_lightFlags |= LF_SPOT; else m_lightFlags &= ~LF_SPOT; }
|
2018-04-02 10:28:20 +00:00
|
|
|
void SetSpotInnerAngle(double angle) { m_spotInnerAngle = angle; }
|
|
|
|
void SetSpotOuterAngle(double angle) { m_spotOuterAngle = angle; }
|
2019-06-28 10:35:42 +00:00
|
|
|
void SetSpotPitch(double pitch)
|
|
|
|
{
|
|
|
|
m_pitch = pitch;
|
|
|
|
m_explicitPitch = true;
|
|
|
|
}
|
|
|
|
void UnsetSpotPitch()
|
|
|
|
{
|
|
|
|
m_pitch = 0.;
|
|
|
|
m_explicitPitch = false;
|
|
|
|
}
|
|
|
|
void SetType(ELightType type) { m_type = type; }
|
|
|
|
void CopyFrom(const FLightDefaults &other)
|
|
|
|
{
|
|
|
|
auto n = m_Name;
|
|
|
|
*this = other;
|
|
|
|
m_Name = n;
|
|
|
|
}
|
|
|
|
void SetFlags(LightFlags lf)
|
|
|
|
{
|
|
|
|
m_lightFlags = lf;
|
|
|
|
m_attenuate = !!(m_lightFlags & LF_ATTENUATE);
|
|
|
|
}
|
2019-01-29 19:09:06 +00:00
|
|
|
static void SetAttenuationForLevel(bool);
|
2017-03-12 15:56:00 +00:00
|
|
|
|
2018-04-02 10:28:20 +00:00
|
|
|
void OrderIntensities()
|
|
|
|
{
|
|
|
|
if (m_Args[LIGHT_INTENSITY] > m_Args[LIGHT_SECONDARY_INTENSITY])
|
|
|
|
{
|
|
|
|
std::swap(m_Args[LIGHT_INTENSITY], m_Args[LIGHT_SECONDARY_INTENSITY]);
|
|
|
|
m_swapped = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
2018-12-15 14:36:43 +00:00
|
|
|
FName m_Name = NAME_None;
|
2018-04-02 10:28:20 +00:00
|
|
|
int m_Args[5] = { 0,0,0,0,0 };
|
|
|
|
double m_Param = 0;
|
|
|
|
DVector3 m_Pos = { 0,0,0 };
|
2019-06-28 10:35:42 +00:00
|
|
|
int m_type;
|
2018-04-02 10:28:20 +00:00
|
|
|
int8_t m_attenuate = -1;
|
2019-01-03 08:24:22 +00:00
|
|
|
LightFlags m_lightFlags = 0;
|
2018-04-02 10:28:20 +00:00
|
|
|
bool m_swapped = false;
|
|
|
|
bool m_spot = false;
|
2019-01-01 18:35:55 +00:00
|
|
|
bool m_explicitPitch = false;
|
|
|
|
DAngle m_spotInnerAngle = 10.0;
|
|
|
|
DAngle m_spotOuterAngle = 25.0;
|
|
|
|
DAngle m_pitch = 0.0;
|
2019-06-28 10:35:42 +00:00
|
|
|
|
|
|
|
friend FSerializer &Serialize(FSerializer &arc, const char *key, FLightDefaults &value, FLightDefaults *def);
|
2018-04-02 10:28:20 +00:00
|
|
|
};
|
|
|
|
|
2019-06-28 10:35:42 +00:00
|
|
|
FSerializer &Serialize(FSerializer &arc, const char *key, TDeletingArray<FLightDefaults *> &value, TDeletingArray<FLightDefaults *> *def);
|
|
|
|
|
2018-04-02 10:28:20 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Light associations (intermediate parser data)
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
class FLightAssociation
|
2017-03-12 15:56:00 +00:00
|
|
|
{
|
2018-04-02 10:28:20 +00:00
|
|
|
public:
|
|
|
|
//FLightAssociation();
|
|
|
|
FLightAssociation(FName actorName, const char *frameName, FName lightName)
|
|
|
|
: m_ActorName(actorName), m_AssocLight(lightName)
|
|
|
|
{
|
|
|
|
strncpy(m_FrameName, frameName, 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
FName ActorName() { return m_ActorName; }
|
|
|
|
const char *FrameName() { return m_FrameName; }
|
|
|
|
FName Light() { return m_AssocLight; }
|
|
|
|
void ReplaceLightName(FName newName) { m_AssocLight = newName; }
|
|
|
|
protected:
|
|
|
|
char m_FrameName[8];
|
|
|
|
FName m_ActorName, m_AssocLight;
|
2017-03-12 15:56:00 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-04-02 10:28:20 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Light associations per actor class
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
class FInternalLightAssociation
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
FInternalLightAssociation(FLightAssociation * asso);
|
|
|
|
int Sprite() const { return m_sprite; }
|
|
|
|
int Frame() const { return m_frame; }
|
|
|
|
const FLightDefaults *Light() const { return m_AssocLight; }
|
|
|
|
protected:
|
|
|
|
int m_sprite;
|
|
|
|
int m_frame;
|
|
|
|
FLightDefaults * m_AssocLight;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-03-12 15:56:00 +00:00
|
|
|
struct FLightNode
|
|
|
|
{
|
|
|
|
FLightNode ** prevTarget;
|
|
|
|
FLightNode * nextTarget;
|
|
|
|
FLightNode ** prevLight;
|
|
|
|
FLightNode * nextLight;
|
2019-01-01 18:35:55 +00:00
|
|
|
FDynamicLight * lightsource;
|
2017-03-12 15:56:00 +00:00
|
|
|
union
|
|
|
|
{
|
|
|
|
side_t * targLine;
|
|
|
|
subsector_t * targSubsector;
|
|
|
|
void * targ;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2019-01-01 18:35:55 +00:00
|
|
|
struct FDynamicLight
|
2017-03-12 15:56:00 +00:00
|
|
|
{
|
|
|
|
friend class FLightDefaults;
|
2019-01-01 18:35:55 +00:00
|
|
|
|
|
|
|
inline DVector3 PosRelative(int portalgroup) const
|
|
|
|
{
|
2019-01-28 00:25:52 +00:00
|
|
|
return Pos + Level->Displacements.getOffset(Sector->PortalGroup, portalgroup);
|
2019-01-01 18:35:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ShouldLightActor(AActor *check)
|
|
|
|
{
|
2019-01-03 08:24:22 +00:00
|
|
|
return visibletoplayer && IsActive() && (!((*pLightFlags) & LF_DONTLIGHTSELF) || target != check) && !((*pLightFlags) & LF_DONTLIGHTACTORS);
|
2019-01-01 18:35:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SetOffset(const DVector3 &pos)
|
|
|
|
{
|
|
|
|
m_off = pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool IsActive() const { return m_active; }
|
2017-03-12 15:56:00 +00:00
|
|
|
float GetRadius() const { return (IsActive() ? m_currentRadius * 2.f : 0.f); }
|
2019-01-01 18:35:55 +00:00
|
|
|
int GetRed() const { return pArgs[LIGHT_RED]; }
|
|
|
|
int GetGreen() const { return pArgs[LIGHT_GREEN]; }
|
|
|
|
int GetBlue() const { return pArgs[LIGHT_BLUE]; }
|
|
|
|
int GetIntensity() const { return pArgs[LIGHT_INTENSITY]; }
|
|
|
|
int GetSecondaryIntensity() const { return pArgs[LIGHT_SECONDARY_INTENSITY]; }
|
|
|
|
|
2019-01-03 08:24:22 +00:00
|
|
|
bool IsSubtractive() const { return !!((*pLightFlags) & LF_SUBTRACTIVE); }
|
|
|
|
bool IsAdditive() const { return !!((*pLightFlags) & LF_ADDITIVE); }
|
|
|
|
bool IsSpot() const { return !!((*pLightFlags) & LF_SPOT); }
|
|
|
|
bool IsAttenuated() const { return !!((*pLightFlags) & LF_ATTENUATE); }
|
|
|
|
bool DontShadowmap() const { return !!((*pLightFlags) & LF_NOSHADOWMAP); }
|
|
|
|
bool DontLightSelf() const { return !!((*pLightFlags) & (LF_DONTLIGHTSELF|LF_DONTLIGHTACTORS)); } // dontlightactors implies dontlightself.
|
|
|
|
bool DontLightActors() const { return !!((*pLightFlags) & LF_DONTLIGHTACTORS); }
|
2019-01-01 18:35:55 +00:00
|
|
|
void Deactivate() { m_active = false; }
|
|
|
|
void Activate();
|
|
|
|
|
|
|
|
void SetActor(AActor *ac, bool isowned) { target = ac; owned = isowned; }
|
|
|
|
double X() const { return Pos.X; }
|
|
|
|
double Y() const { return Pos.Y; }
|
|
|
|
double Z() const { return Pos.Z; }
|
|
|
|
|
|
|
|
void Tick();
|
|
|
|
void UpdateLocation();
|
2017-03-12 15:56:00 +00:00
|
|
|
void LinkLight();
|
|
|
|
void UnlinkLight();
|
2019-01-01 18:35:55 +00:00
|
|
|
void ReleaseLight();
|
2017-03-12 15:56:00 +00:00
|
|
|
|
|
|
|
private:
|
2018-11-05 23:47:43 +00:00
|
|
|
double DistToSeg(const DVector3 &pos, vertex_t *start, vertex_t *end);
|
2018-11-05 23:13:23 +00:00
|
|
|
void CollectWithinRadius(const DVector3 &pos, FSection *section, float radius);
|
2017-03-12 15:56:00 +00:00
|
|
|
|
2019-01-01 18:35:55 +00:00
|
|
|
public:
|
2017-03-12 15:56:00 +00:00
|
|
|
FCycler m_cycler;
|
2019-01-01 18:35:55 +00:00
|
|
|
DVector3 Pos;
|
|
|
|
DVector3 m_off;
|
2017-03-12 15:56:00 +00:00
|
|
|
|
2019-01-01 18:35:55 +00:00
|
|
|
// This date can either come from the owning actor or from a light definition
|
|
|
|
// To avoid having to copy these around every tic, these are pointers to the source data.
|
|
|
|
const DAngle *pSpotInnerAngle;
|
|
|
|
const DAngle *pSpotOuterAngle;
|
|
|
|
const DAngle *pPitch; // This is to handle pitch overrides through GLDEFS, it can either point to the target's pitch or the light definition.
|
|
|
|
const int *pArgs;
|
2019-01-03 08:24:22 +00:00
|
|
|
const LightFlags *pLightFlags;
|
2019-01-01 18:35:55 +00:00
|
|
|
|
|
|
|
double specialf1;
|
|
|
|
FDynamicLight *next, *prev;
|
|
|
|
sector_t *Sector;
|
2019-01-27 18:16:14 +00:00
|
|
|
FLevelLocals *Level;
|
2019-01-01 18:35:55 +00:00
|
|
|
TObjPtr<AActor *> target;
|
|
|
|
FLightNode * touching_sides;
|
|
|
|
FLightNode * touching_sector;
|
|
|
|
float radius; // The maximum size the light can be with its current settings.
|
|
|
|
float m_currentRadius; // The current light size.
|
2017-03-12 15:56:00 +00:00
|
|
|
int m_tickCount;
|
2019-01-01 18:35:55 +00:00
|
|
|
int m_lastUpdate;
|
|
|
|
int mShadowmapIndex;
|
|
|
|
bool m_active;
|
|
|
|
bool visibletoplayer;
|
|
|
|
bool shadowmapped;
|
2017-03-12 15:56:00 +00:00
|
|
|
uint8_t lighttype;
|
|
|
|
bool owned;
|
|
|
|
bool swapped;
|
2019-01-01 18:35:55 +00:00
|
|
|
bool explicitpitch;
|
2017-03-12 15:56:00 +00:00
|
|
|
|
|
|
|
};
|
2019-06-28 10:35:42 +00:00
|
|
|
|
|
|
|
|