- User definable dynamic lights

This hasn't been tested yet!
This commit is contained in:
Christoph Oelckers 2019-06-28 12:35:42 +02:00
parent 1b1069dc78
commit 1dcbe43d95
7 changed files with 235 additions and 6 deletions

View file

@ -56,6 +56,7 @@ class FLightDefaults;
struct FSection;
struct FLevelLocals;
struct FDynamicLight;
//
// NOTES: AActor
//
@ -1173,6 +1174,7 @@ public:
DRotator PrevAngles;
int PrevPortalGroup;
TArray<FDynamicLight *> AttachedLights;
TDeletingArray<FLightDefaults *> UserLights;
// When was this actor spawned?
int SpawnTime;

View file

@ -804,6 +804,144 @@ void AActor::DeleteAttachedLights()
AttachedLights.Clear();
}
//==========================================================================
//
//
//
//==========================================================================
extern TDeletingArray<FLightDefaults *> LightDefaults;
unsigned FindUserLight(AActor *self, FName id, bool create = false)
{
for (unsigned i = 0; i < self->UserLights.Size(); i++ )
{
if (self->UserLights[i]->GetName() == id) return i;
}
if (create)
{
auto li = new FLightDefaults(id);
return self->UserLights.Push(li);
}
return ~0u;
}
//==========================================================================
//
//
//
//==========================================================================
int AttachLightDef(AActor *self, int _lightid, int _lightname)
{
FName lightid = FName(ENamedName(_lightid));
FName lightname = FName(ENamedName(_lightname));
// Todo: Optimize. This may be too slow.
auto lightdef = LightDefaults.FindEx([=](const auto &a) {
return a->GetName() == lightid;
});
if (lightdef < LightDefaults.Size())
{
auto userlight = self->UserLights[FindUserLight(self, lightid, true)];
userlight->CopyFrom(*LightDefaults[lightdef]);
return 1;
}
return 0;
}
DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_AttachLightDef, AttachLightDef)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_NAME(lightid);
PARAM_NAME(lightname);
ACTION_RETURN_BOOL(AttachLightDef(self, lightid.GetIndex(), lightname.GetIndex()));
}
//==========================================================================
//
//
//
//==========================================================================
int AttachLightDirect(AActor *self, int _lightid, int type, int color, int radius1, int radius2, int flags, double ofs_x, double ofs_y, double ofs_z, double param, double spoti, double spoto, double spotp)
{
FName lightid = FName(ENamedName(_lightid));
auto userlight = self->UserLights[FindUserLight(self, lightid, true)];
userlight->SetType(ELightType(type));
userlight->SetArg(LIGHT_RED, RPART(color));
userlight->SetArg(LIGHT_GREEN, GPART(color));
userlight->SetArg(LIGHT_BLUE, BPART(color));
userlight->SetArg(LIGHT_INTENSITY, radius1);
userlight->SetArg(LIGHT_SECONDARY_INTENSITY, radius2);
userlight->SetFlags(LightFlags::FromInt(flags));
float of[] = { float(ofs_x), float(ofs_y), float(ofs_z)};
userlight->SetOffset(of);
userlight->SetParameter(type == PulseLight? param*TICRATE : param*360.);
userlight->SetSpotInnerAngle(spoti);
userlight->SetSpotOuterAngle(spoto);
if (spotp >= -90. && spotp <= 90.)
{
userlight->SetSpotPitch(spotp);
}
else
{
userlight->UnsetSpotPitch();
}
return 1;
}
DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_AttachLight, AttachLightDirect)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_NAME(lightid);
PARAM_INT(type);
PARAM_INT(color);
PARAM_INT(radius1);
PARAM_INT(radius2);
PARAM_INT(flags);
PARAM_FLOAT(ofs_x);
PARAM_FLOAT(ofs_y);
PARAM_FLOAT(ofs_z);
PARAM_FLOAT(parami);
PARAM_FLOAT(spoti);
PARAM_FLOAT(spoto);
PARAM_FLOAT(spotp);
ACTION_RETURN_BOOL(AttachLightDirect(self, lightid, type, color, radius1, radius2, flags, ofs_x, ofs_y, ofs_z, parami, spoti, spoto, spotp));
}
//==========================================================================
//
//
//
//==========================================================================
int RemoveLight(AActor *self, int _lightid)
{
FName lightid = FName(ENamedName(_lightid));
auto userlight = FindUserLight(self, lightid, false);
if (userlight < self->UserLights.Size())
{
delete self->UserLights[userlight];
self->UserLights.Delete(userlight);
}
return 1;
}
DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_RemoveLight, RemoveLight)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_NAME(lightid);
ACTION_RETURN_BOOL(RemoveLight(self, lightid));
}
//==========================================================================
//
//
//
//==========================================================================
//==========================================================================
//
// This is called before saving the game

View file

@ -54,7 +54,11 @@ DEFINE_TFLAGS_OPERATORS(LightFlags)
class FLightDefaults
{
public:
FLightDefaults(FName name, ELightType type);
FLightDefaults(FName name, ELightType type = PointLight)
{
m_Name = name;
m_type = type;
}
void ApplyProperties(FDynamicLight * light) const;
FName GetName() const { return m_Name; }
@ -72,6 +76,28 @@ public:
void SetSpot(bool spot) { if (spot) m_lightFlags |= LF_SPOT; else m_lightFlags &= ~LF_SPOT; }
void SetSpotInnerAngle(double angle) { m_spotInnerAngle = angle; }
void SetSpotOuterAngle(double angle) { m_spotOuterAngle = angle; }
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);
}
static void SetAttenuationForLevel(bool);
void OrderIntensities()
@ -88,7 +114,7 @@ protected:
int m_Args[5] = { 0,0,0,0,0 };
double m_Param = 0;
DVector3 m_Pos = { 0,0,0 };
ELightType m_type;
int m_type;
int8_t m_attenuate = -1;
LightFlags m_lightFlags = 0;
bool m_swapped = false;
@ -97,8 +123,12 @@ protected:
DAngle m_spotInnerAngle = 10.0;
DAngle m_spotOuterAngle = 25.0;
DAngle m_pitch = 0.0;
friend FSerializer &Serialize(FSerializer &arc, const char *key, FLightDefaults &value, FLightDefaults *def);
};
FSerializer &Serialize(FSerializer &arc, const char *key, TDeletingArray<FLightDefaults *> &value, TDeletingArray<FLightDefaults *> *def);
//==========================================================================
//
// Light associations (intermediate parser data)
@ -247,3 +277,5 @@ public:
bool explicitpitch;
};

View file

@ -186,6 +186,8 @@ AActor::~AActor ()
//
//==========================================================================
#define A(a,b) ((a), (b), def->b)
void AActor::Serialize(FSerializer &arc)
@ -364,7 +366,8 @@ void AActor::Serialize(FSerializer &arc)
A("friendlyseeblocks", friendlyseeblocks)
A("spawntime", SpawnTime)
A("spawnorder", SpawnOrder)
A("friction", Friction);
A("friction", Friction)
A("userlights", UserLights);
}
#undef A

View file

@ -36,6 +36,7 @@
#include "r_state.h"
#include "g_levellocals.h"
#include "a_dynlight.h"
#include "serializer.h"
//==========================================================================
@ -63,12 +64,60 @@ int AttenuationIsSet = -1;
//
//-----------------------------------------------------------------------------
FLightDefaults::FLightDefaults(FName name, ELightType type)
FSerializer &Serialize(FSerializer &arc, const char *key, FLightDefaults &value, FLightDefaults *def)
{
m_Name = name;
m_type = type;
if (arc.BeginObject(key))
{
arc("name", value.m_Name)
.Array("args", value.m_Args, 5, nullptr)
("param", value.m_Param)
("pos", value.m_Pos)
("type", value.m_type)
("attenuate", value.m_attenuate)
("flags", value.m_lightFlags)
("swapped", value.m_swapped)
("spot", value.m_spot)
("explicitpitch", value.m_explicitPitch)
("spotinner", value.m_spotInnerAngle)
("spotouter", value.m_spotOuterAngle)
("pitch", value.m_pitch)
.EndObject();
}
return arc;
}
FSerializer &Serialize(FSerializer &arc, const char *key, TDeletingArray<FLightDefaults *> &value, TDeletingArray<FLightDefaults *> *def)
{
if (arc.isWriting())
{
if (value.Size() == 0) return arc; // do not save empty arrays
}
bool res = arc.BeginArray(key);
if (arc.isReading())
{
if (!res)
{
value.Clear();
return arc;
}
value.Resize(arc.ArraySize());
for (auto &entry : value) entry = new FLightDefaults(NAME_None);
}
for (unsigned i = 0; i < value.Size(); i++)
{
Serialize(arc, nullptr, *value[i], nullptr);
}
arc.EndArray();
return arc;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FLightDefaults::ApplyProperties(FDynamicLight * light) const
{
auto oldtype = light->lighttype;

View file

@ -593,6 +593,7 @@ struct DirectNativeDesc
template<typename Ret, TP(1), TP(2), TP(3), TP(4), TP(5), TP(6), TP(7), TP(8), TP(9), TP(10), TP(11)> DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); VP(10); VP(11); }
template<typename Ret, TP(1), TP(2), TP(3), TP(4), TP(5), TP(6), TP(7), TP(8), TP(9), TP(10), TP(11), TP(12)> DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); VP(10); VP(11); VP(12); }
template<typename Ret, TP(1), TP(2), TP(3), TP(4), TP(5), TP(6), TP(7), TP(8), TP(9), TP(10), TP(11), TP(12), TP(13)> DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); VP(10); VP(11); VP(12); VP(13); }
template<typename Ret, TP(1), TP(2), TP(3), TP(4), TP(5), TP(6), TP(7), TP(8), TP(9), TP(10), TP(11), TP(12), TP(13), TP(14)> DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); VP(10); VP(11); VP(12); VP(13), VP(14); }
#undef TP
#undef VP

View file

@ -1162,6 +1162,10 @@ class Actor : Thinker native
action native void A_OverlayFlags(int layer, int flags, bool set);
action native void A_OverlayAlpha(int layer, double alph);
action native void A_OverlayRenderStyle(int layer, int style);
action native bool A_AttachLightDef(Name lightid, Name lightdef);
action native bool A_AttachLight(Name lightid, int type, Color lightcolor, int radius1, int radius2, int flags, Vector3 ofs, double param, double spoti, double spoto, double spotp);
action mative bool A_RemoveLight(Name lightid);
int ACS_NamedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0)
{