mirror of
https://github.com/leozide/leocad
synced 2025-01-30 20:34:56 +01:00
Blender lights - lcLight
This commit is contained in:
parent
1dd08401d7
commit
07a268ed32
4 changed files with 655 additions and 19 deletions
|
@ -105,6 +105,7 @@ struct lcMeshSection;
|
|||
struct lcRenderMesh;
|
||||
struct lcObjectSection;
|
||||
struct lcPieceInfoRayTest;
|
||||
struct lcLightProperties;
|
||||
class lcTexture;
|
||||
class lcScene;
|
||||
class lcViewManipulator;
|
||||
|
|
570
common/light.cpp
570
common/light.cpp
|
@ -11,36 +11,81 @@
|
|||
#define LC_LIGHT_POSITION_EDGE 7.5f
|
||||
#define LC_LIGHT_TARGET_EDGE 5.0f
|
||||
#define LC_LIGHT_SPHERE_RADIUS 5.0f
|
||||
#define LC_LIGHT_BASEFACE_EDGE 12.5f
|
||||
|
||||
// New omni light.
|
||||
lcLight::lcLight(float px, float py, float pz)
|
||||
: lcObject(lcObjectType::Light)
|
||||
{
|
||||
Initialize(lcVector3(px, py, pz), lcVector3(0.0f, 0.0f, 0.0f));
|
||||
Initialize(lcVector3(px, py, pz), lcVector3(0.0f, 0.0f, 0.0f), LC_POINTLIGHT);
|
||||
UpdatePosition(1);
|
||||
}
|
||||
|
||||
// New directional or spot light.
|
||||
lcLight::lcLight(float px, float py, float pz, float tx, float ty, float tz)
|
||||
lcLight::lcLight(float px, float py, float pz, float tx, float ty, float tz, int LightType)
|
||||
: lcObject(lcObjectType::Light)
|
||||
{
|
||||
Initialize(lcVector3(px, py, pz), lcVector3(tx, ty, tz));
|
||||
mState |= LC_LIGHT_SPOT;
|
||||
Initialize(lcVector3(px, py, pz), lcVector3(tx, ty, tz), LightType);
|
||||
if (LightType == LC_SPOTLIGHT)
|
||||
mState |= LC_LIGHT_SPOT;
|
||||
else
|
||||
mState |= LC_LIGHT_DIRECTIONAL;
|
||||
UpdatePosition(1);
|
||||
}
|
||||
|
||||
void lcLight::Initialize(const lcVector3& Position, const lcVector3& TargetPosition)
|
||||
void lcLight::SetLightState(int LightType)
|
||||
{
|
||||
mState = 0;
|
||||
|
||||
mPositionKeys.ChangeKey(Position, 1, true);
|
||||
mTargetPositionKeys.ChangeKey(TargetPosition, 1, true);
|
||||
mAmbientColorKeys.ChangeKey(lcVector4(0.0f, 0.0f, 0.0f, 1.0f), 1, true);
|
||||
mDiffuseColorKeys.ChangeKey(lcVector4(0.8f, 0.8f, 0.8f, 1.0f), 1, true);
|
||||
mSpecularColorKeys.ChangeKey(lcVector4(1.0f, 1.0f, 1.0f, 1.0f), 1, true);
|
||||
mAttenuationKeys.ChangeKey(lcVector3(1.0f, 0.0f, 0.0f), 1, true);
|
||||
mSpotCutoffKeys.ChangeKey(30.0f, 1, true);
|
||||
mSpotExponentKeys.ChangeKey(0.0f, 1, true);
|
||||
switch (LightType)
|
||||
{
|
||||
case LC_AREALIGHT:
|
||||
case LC_SUNLIGHT:
|
||||
mState |= LC_LIGHT_DIRECTIONAL;
|
||||
break;
|
||||
case LC_SPOTLIGHT:
|
||||
mState |= LC_LIGHT_SPOT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void lcLight::Initialize(const lcVector3& Position, const lcVector3& TargetPosition, int LightType)
|
||||
{
|
||||
SetLightState(LightType);
|
||||
|
||||
mEnableCutoff = false;
|
||||
mPosition = Position;
|
||||
mTargetPosition = TargetPosition;
|
||||
mAmbientColor = lcVector4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
mDiffuseColor = lcVector4(0.8f, 0.8f, 0.8f, 1.0f);
|
||||
mSpecularColor = lcVector4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
mAttenuation = lcVector3(1.0f, 0.0f, 0.0f);
|
||||
mLightColor = lcVector3(1.0f, 1.0f, 1.0f); //RGB - White
|
||||
mLightType = LightType ? LightType : int(LC_POINTLIGHT);
|
||||
mLightFactor[0] = LightType ? LightType == LC_SUNLIGHT ? 11.4f : 0.25f : 0.0f;
|
||||
mLightFactor[1] = LightType == LC_AREALIGHT ? 0.25f : LightType == LC_SPOTLIGHT ? 0.150f : 0.0f;
|
||||
mLightSpecular = 1.0f;
|
||||
mSpotSize = 75.0f;
|
||||
mLightShape = 0 /*Square*/;
|
||||
mSpotCutoff = LightType ? LightType != LC_SUNLIGHT ? 40.0f : 0.0f : 30.0f;
|
||||
mSpotExponent = 10.0f; /*Energy/Power*/
|
||||
|
||||
mPositionKeys.ChangeKey(mPosition, 1, true);
|
||||
mTargetPositionKeys.ChangeKey(mTargetPosition, 1, true);
|
||||
mAmbientColorKeys.ChangeKey(mAmbientColor, 1, true);
|
||||
mDiffuseColorKeys.ChangeKey(mDiffuseColor, 1, true);
|
||||
mSpecularColorKeys.ChangeKey(mSpecularColor, 1, true);
|
||||
mAttenuationKeys.ChangeKey(mAttenuation, 1, true);
|
||||
mLightShapeKeys.ChangeKey(mLightShape, 1, true);
|
||||
mLightColorKeys.ChangeKey(mLightColor, 1, true);
|
||||
mLightTypeKeys.ChangeKey(mLightType, 1, true);
|
||||
mLightFactorKeys.ChangeKey(mLightFactor, 1, true);
|
||||
mLightSpecularKeys.ChangeKey(mLightSpecular, 1, true);
|
||||
mSpotCutoffKeys.ChangeKey(mSpotCutoff, 1, true);
|
||||
mSpotExponentKeys.ChangeKey(mSpotExponent, 1, true);
|
||||
mLightSpotSizeKeys.ChangeKey(mSpotSize, 1, true);
|
||||
}
|
||||
|
||||
lcLight::~lcLight()
|
||||
|
@ -49,7 +94,139 @@ lcLight::~lcLight()
|
|||
|
||||
void lcLight::SaveLDraw(QTextStream& Stream) const
|
||||
{
|
||||
Q_UNUSED(Stream);
|
||||
const QLatin1String LineEnding("\r\n");
|
||||
|
||||
if (mPositionKeys.GetSize() > 1)
|
||||
mPositionKeys.SaveKeysLDraw(Stream, "LIGHT POSITION_KEY ");
|
||||
else
|
||||
Stream << QLatin1String("0 !LEOCAD LIGHT POSITION ") << mPosition[0] << ' ' << mPosition[1] << ' ' << mPosition[2] << LineEnding;
|
||||
|
||||
if (mTargetPositionKeys.GetSize() > 1)
|
||||
mTargetPositionKeys.SaveKeysLDraw(Stream, "LIGHT TARGET_POSITION_KEY ");
|
||||
else
|
||||
Stream << QLatin1String("0 !LEOCAD LIGHT TARGET_POSITION ") << mTargetPosition[0] << ' ' << mTargetPosition[1] << ' ' << mTargetPosition[2] << LineEnding;
|
||||
|
||||
if (mLightColorKeys.GetSize() > 1)
|
||||
mLightColorKeys.SaveKeysLDraw(Stream, "LIGHT COLOR_RGB_KEY ");
|
||||
else
|
||||
Stream << QLatin1String("0 !LEOCAD LIGHT COLOR_RGB ") << mLightColor[0] << ' ' << mLightColor[1] << ' ' << mLightColor[2] << LineEnding;
|
||||
|
||||
if (mLightSpecularKeys.GetSize() > 1)
|
||||
mLightSpecularKeys.SaveKeysLDraw(Stream, "LIGHT SPECULAR_KEY ");
|
||||
else
|
||||
Stream << QLatin1String("0 !LEOCAD LIGHT SPECULAR ") << mLightSpecular << LineEnding;
|
||||
|
||||
if (mLightType == LC_SUNLIGHT)
|
||||
{
|
||||
if (mSpotExponentKeys.GetSize() > 1)
|
||||
mSpotExponentKeys.SaveKeysLDraw(Stream, "LIGHT STRENGTH_KEY ");
|
||||
else
|
||||
Stream << QLatin1String("0 !LEOCAD LIGHT STRENGTH ") << mSpotExponent << LineEnding;
|
||||
|
||||
if (mLightFactorKeys.GetSize() > 1)
|
||||
mLightFactorKeys.SaveKeysLDraw(Stream, "LIGHT ANGLE_KEY ");
|
||||
else
|
||||
Stream << QLatin1String("0 !LEOCAD LIGHT ANGLE ") << mLightFactor[0] << LineEnding;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mSpotExponentKeys.GetSize() > 1)
|
||||
mSpotExponentKeys.SaveKeysLDraw(Stream, "LIGHT POWER_KEY ");
|
||||
else
|
||||
Stream << QLatin1String("0 !LEOCAD LIGHT POWER ") << mSpotExponent << LineEnding;
|
||||
|
||||
if (mEnableCutoff)
|
||||
{
|
||||
if (mSpotCutoffKeys.GetSize() > 1)
|
||||
mSpotCutoffKeys.SaveKeysLDraw(Stream, "LIGHT CUTOFF_DISTANCE_KEY ");
|
||||
else
|
||||
Stream << QLatin1String("0 !LEOCAD LIGHT CUTOFF_DISTANCE ") << mSpotCutoff << LineEnding;
|
||||
}
|
||||
|
||||
switch (mLightType)
|
||||
{
|
||||
case LC_POINTLIGHT:
|
||||
if (mLightFactorKeys.GetSize() > 1)
|
||||
mLightFactorKeys.SaveKeysLDraw(Stream, "LIGHT RADIUS_KEY ");
|
||||
else
|
||||
Stream << QLatin1String("0 !LEOCAD LIGHT RADIUS ") << mLightFactor[0] << LineEnding;
|
||||
break;
|
||||
case LC_SPOTLIGHT:
|
||||
if (mLightFactorKeys.GetSize() > 1) {
|
||||
mLightFactorKeys.SaveKeysLDraw(Stream, "LIGHT RADIUS_AND_SPOT_BLEND_KEY ");
|
||||
} else {
|
||||
Stream << QLatin1String("0 !LEOCAD LIGHT RADIUS ") << mLightFactor[0] << LineEnding;
|
||||
Stream << QLatin1String("0 !LEOCAD LIGHT SPOT_BLEND ") << mLightFactor[1] << LineEnding;
|
||||
}
|
||||
if (mLightSpotSizeKeys.GetSize() > 1)
|
||||
mLightSpotSizeKeys.SaveKeysLDraw(Stream, "LIGHT SPOT_SIZE_KEY ");
|
||||
else
|
||||
Stream << QLatin1String("0 !LEOCAD LIGHT SPOT_SIZE ") << mSpotSize << LineEnding;
|
||||
break;
|
||||
case LC_AREALIGHT:
|
||||
if (mLightFactorKeys.GetSize() > 1) {
|
||||
mLightFactorKeys.SaveKeysLDraw(Stream, "LIGHT SIZE_KEY ");
|
||||
} else {
|
||||
if (mLightShape == LC_LIGHT_SHAPE_RECTANGLE || mLightShape == LC_LIGHT_SHAPE_ELLIPSE)
|
||||
Stream << QLatin1String("0 !LEOCAD LIGHT WIDTH ") << mLightFactor[0] << QLatin1String(" HEIGHT ") << mLightFactor[1] << LineEnding;
|
||||
else
|
||||
Stream << QLatin1String("0 !LEOCAD LIGHT SIZE ") << mLightFactor[0] << LineEnding;
|
||||
}
|
||||
if (mLightShapeKeys.GetSize() > 1) {
|
||||
mLightShapeKeys.SaveKeysLDraw(Stream, "LIGHT SHAPE_KEY ");
|
||||
} else {
|
||||
Stream << QLatin1String("0 !LEOCAD LIGHT SHAPE ");
|
||||
|
||||
QString Shape = QLatin1String("Undefined ");
|
||||
switch(mLightShape)
|
||||
{
|
||||
case LC_LIGHT_SHAPE_SQUARE:
|
||||
Shape = QLatin1String("Square ");
|
||||
break;
|
||||
case LC_LIGHT_SHAPE_DISK:
|
||||
Shape = QLatin1String("Disk ");
|
||||
break;
|
||||
case LC_LIGHT_SHAPE_RECTANGLE:
|
||||
Shape = QLatin1String("Rectangle ");
|
||||
break;
|
||||
case LC_LIGHT_SHAPE_ELLIPSE:
|
||||
Shape = QLatin1String("Ellipse ");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Stream << QLatin1String(Shape.toLatin1()) << LineEnding;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mLightTypeKeys.GetSize() > 1)
|
||||
{
|
||||
mLightTypeKeys.SaveKeysLDraw(Stream, "LIGHT TYPE_KEY ");
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream << QLatin1String("0 !LEOCAD LIGHT TYPE ");
|
||||
|
||||
QString Type = QLatin1String("Undefined ");
|
||||
switch(mLightType){
|
||||
case LC_POINTLIGHT:
|
||||
Type = QLatin1String("Point ");
|
||||
break;
|
||||
case LC_SUNLIGHT:
|
||||
Type = QLatin1String("Sun ");
|
||||
break;
|
||||
case LC_AREALIGHT:
|
||||
Type = QLatin1String("Area ");
|
||||
break;
|
||||
case LC_SPOTLIGHT:
|
||||
Type = QLatin1String("Spot ");
|
||||
break;
|
||||
}
|
||||
Stream << QLatin1String(Type.toLatin1()) << QLatin1String("NAME ") << mName << LineEnding;
|
||||
}
|
||||
}
|
||||
|
||||
void lcLight::CreateName(const lcArray<lcLight*>& Lights)
|
||||
|
@ -72,7 +249,8 @@ void lcLight::CreateName(const lcArray<lcLight*>& Lights)
|
|||
}
|
||||
|
||||
int MaxLightNumber = 0;
|
||||
const QLatin1String Prefix("Light ");
|
||||
|
||||
const QLatin1String Prefix(mLightType == LC_POINTLIGHT ? "Pointlight " : mLightType == LC_AREALIGHT ? "Arealight " : mLightType == LC_SUNLIGHT ? "Sunlight " : "Spotlight ");
|
||||
|
||||
for (const lcLight* Light : Lights)
|
||||
{
|
||||
|
@ -91,6 +269,142 @@ void lcLight::CreateName(const lcArray<lcLight*>& Lights)
|
|||
mName = Prefix + QString::number(MaxLightNumber + 1);
|
||||
}
|
||||
|
||||
bool lcLight::ParseLDrawLine(QTextStream& Stream)
|
||||
{
|
||||
while (!Stream.atEnd())
|
||||
{
|
||||
QString Token;
|
||||
Stream >> Token;
|
||||
if (Token == QLatin1String("COLOR_RGB"))
|
||||
{
|
||||
Stream >> mLightColor[0] >> mLightColor[1] >> mLightColor[2];
|
||||
mLightColorKeys.ChangeKey(mLightColor, 1, true);
|
||||
}
|
||||
else if (Token == QLatin1String("POWER") || Token == QLatin1String("STRENGTH"))
|
||||
{
|
||||
Stream >> mSpotExponent;
|
||||
mSpotExponentKeys.ChangeKey(mSpotExponent, 1, true);
|
||||
}
|
||||
else if (Token == QLatin1String("RADIUS") || Token == QLatin1String("SIZE") || Token == QLatin1String("WIDTH") || (mHeightSet = Token == QLatin1String("HEIGHT")) || (mSpotBlendSet = Token == QLatin1String("SPOT_BLEND")) || (mAngleSet = Token == QLatin1String("ANGLE")))
|
||||
{
|
||||
if(Token == QLatin1String("HEIGHT") || Token == QLatin1String("SPOT_BLEND"))
|
||||
Stream >> mLightFactor[1];
|
||||
else
|
||||
Stream >> mLightFactor[0];
|
||||
mLightFactorKeys.ChangeKey(mLightFactor, 1, true);
|
||||
}
|
||||
else if (Token == QLatin1String("SPOT_SIZE"))
|
||||
{
|
||||
Stream >> mSpotSize;
|
||||
mLightSpotSizeKeys.ChangeKey(mSpotSize, 1, true);
|
||||
}
|
||||
else if (Token == QLatin1String("SHAPE"))
|
||||
{
|
||||
QString Shape;
|
||||
Stream >> Shape;
|
||||
Shape = Shape.replace("\"", "").toLower();
|
||||
if (Shape == QLatin1String("square"))
|
||||
mLightShape = LC_LIGHT_SHAPE_SQUARE;
|
||||
else if (Shape == QLatin1String("disk") || Shape == QLatin1String("circle"))
|
||||
mLightShape = LC_LIGHT_SHAPE_DISK;
|
||||
else if (Shape == QLatin1String("rectangle"))
|
||||
mLightShape = LC_LIGHT_SHAPE_RECTANGLE;
|
||||
else if (Shape == QLatin1String("ellipse"))
|
||||
mLightShape = LC_LIGHT_SHAPE_ELLIPSE;
|
||||
mLightShapeKeys.ChangeKey(mLightShape, 1, true);
|
||||
}
|
||||
else if (Token == QLatin1String("SPECULAR"))
|
||||
{
|
||||
Stream >>mLightSpecular;
|
||||
mLightSpecularKeys.ChangeKey(mLightSpecular, 1, true);
|
||||
}
|
||||
else if ((mSpotCutoffSet = Token == QLatin1String("CUTOFF_DISTANCE")))
|
||||
{
|
||||
mEnableCutoff = true;
|
||||
Stream >> mSpotCutoff;
|
||||
mSpotCutoffKeys.ChangeKey(mSpotCutoff, 1, true);
|
||||
}
|
||||
else if (Token == QLatin1String("TYPE"))
|
||||
{
|
||||
QString Type;
|
||||
Stream >> Type;
|
||||
Type = Type.replace("\"", "").toLower();
|
||||
if (Type == QLatin1String("point"))
|
||||
mLightType = LC_POINTLIGHT;
|
||||
else if (Type == QLatin1String("sun"))
|
||||
mLightType = LC_SUNLIGHT;
|
||||
else if (Type == QLatin1String("spot"))
|
||||
mLightType = LC_SPOTLIGHT;
|
||||
else if (Type == QLatin1String("area"))
|
||||
mLightType = LC_AREALIGHT;
|
||||
SetLightState(mLightType);
|
||||
mLightTypeKeys.ChangeKey(mLightType, 1, true);
|
||||
}
|
||||
else if (Token == QLatin1String("POSITION"))
|
||||
{
|
||||
Stream >> mPosition[0] >> mPosition[1] >> mPosition[2];
|
||||
mPositionKeys.ChangeKey(mPosition, 1, true);
|
||||
}
|
||||
else if (Token == QLatin1String("TARGET_POSITION"))
|
||||
{
|
||||
Stream >> mTargetPosition[0] >> mTargetPosition[1] >> mTargetPosition[2];
|
||||
mTargetPositionKeys.ChangeKey(mTargetPosition, 1, true);
|
||||
}
|
||||
else if (Token == QLatin1String("COLOR_RGB_KEY"))
|
||||
mLightColorKeys.LoadKeysLDraw(Stream);
|
||||
else if ((Token == QLatin1String("POWER_KEY")) || (Token == QLatin1String("STRENGTH_KEY")))
|
||||
mSpotExponentKeys.LoadKeysLDraw(Stream);
|
||||
else if ((Token == QLatin1String("ANGLE_KEY")) || (Token == QLatin1String("RADIUS_KEY")) || (Token == QLatin1String("SIZE_KEY")) || (Token == QLatin1String("RADIUS_AND_SPOT_BLEND_KEY")))
|
||||
mLightFactorKeys.LoadKeysLDraw(Stream);
|
||||
else if (Token == QLatin1String("SPOT_SIZE_KEY"))
|
||||
mLightSpotSizeKeys.LoadKeysLDraw(Stream);
|
||||
else if (Token == QLatin1String("SHAPE_KEY"))
|
||||
mLightShapeKeys.LoadKeysLDraw(Stream);
|
||||
else if (Token == QLatin1String("SPECULAR_KEY"))
|
||||
mLightSpecularKeys.LoadKeysLDraw(Stream);
|
||||
else if (Token == QLatin1String("CUTOFF_DISTANCE_KEY"))
|
||||
mSpotCutoffKeys.LoadKeysLDraw(Stream);
|
||||
else if (Token == QLatin1String("TYPE_KEY"))
|
||||
mLightTypeKeys.LoadKeysLDraw(Stream);
|
||||
else if (Token == QLatin1String("POSITION_KEY"))
|
||||
mPositionKeys.LoadKeysLDraw(Stream);
|
||||
else if (Token == QLatin1String("TARGET_POSITION_KEY"))
|
||||
mTargetPositionKeys.LoadKeysLDraw(Stream);
|
||||
else if (Token == QLatin1String("NAME"))
|
||||
{
|
||||
mName = Stream.readAll().trimmed();
|
||||
mName.replace("\"", "");
|
||||
|
||||
// Set default settings per light type
|
||||
if (mLightType == LC_SPOTLIGHT) {
|
||||
if (!mSpotBlendSet) {
|
||||
mLightFactor[1] = 0.15f;
|
||||
mLightFactorKeys.ChangeKey(mLightFactor, 1, true);
|
||||
}
|
||||
}
|
||||
if (mLightType == LC_AREALIGHT && (mLightShape == LC_LIGHT_SHAPE_RECTANGLE || mLightShape == LC_LIGHT_SHAPE_ELLIPSE)) {
|
||||
if (!mHeightSet) {
|
||||
mLightFactor[1] = 0.25f;
|
||||
mLightFactorKeys.ChangeKey(mLightFactor, 1, true);
|
||||
}
|
||||
}
|
||||
if (mLightType == LC_SUNLIGHT) {
|
||||
if (!mAngleSet) {
|
||||
mLightFactor[0] = 11.4f;
|
||||
mLightFactorKeys.ChangeKey(mLightFactor, 1, true);
|
||||
}
|
||||
if (!mSpotCutoffSet) {
|
||||
mSpotCutoff = 0.0f;
|
||||
mSpotCutoffKeys.ChangeKey(mSpotCutoff, 1, true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void lcLight::CompareBoundingBox(lcVector3& Min, lcVector3& Max)
|
||||
{
|
||||
const lcVector3 Points[2] =
|
||||
|
@ -109,6 +423,44 @@ void lcLight::CompareBoundingBox(lcVector3& Min, lcVector3& Max)
|
|||
}
|
||||
}
|
||||
|
||||
void lcLight::UpdateLight(lcStep Step, lcLightProperties Props, int Property)
|
||||
{
|
||||
switch(Property){
|
||||
case LC_LIGHT_SHAPE:
|
||||
mLightShape = Props.mLightShape;
|
||||
mLightShapeKeys.ChangeKey(mLightShape, Step, false);
|
||||
break;
|
||||
case LC_LIGHT_COLOR:
|
||||
mLightColor = Props.mLightColor;
|
||||
mLightColorKeys.ChangeKey(mLightColor, Step, false);
|
||||
break;
|
||||
case LC_LIGHT_FACTOR:
|
||||
mLightFactor = Props.mLightFactor;
|
||||
mLightFactorKeys.ChangeKey(mLightFactor, Step, false);
|
||||
break;
|
||||
case LC_LIGHT_SPECULAR:
|
||||
mLightSpecular = Props.mLightSpecular;
|
||||
mLightSpecularKeys.ChangeKey(mLightSpecular, Step, false);
|
||||
break;
|
||||
case LC_LIGHT_EXPONENT:
|
||||
mSpotExponent = Props.mSpotExponent;
|
||||
mSpotExponentKeys.ChangeKey(mSpotExponent, Step, false);
|
||||
break;
|
||||
case LC_LIGHT_SPOT_SIZE:
|
||||
mSpotSize = Props.mSpotSize;
|
||||
mLightSpotSizeKeys.ChangeKey(mSpotSize, Step, false);
|
||||
break;
|
||||
case LC_LIGHT_CUTOFF:
|
||||
mSpotCutoff = Props.mSpotCutoff;
|
||||
mSpotCutoffKeys.ChangeKey(mSpotCutoff, Step, false);
|
||||
break;
|
||||
case LC_LIGHT_USE_CUTOFF:
|
||||
mEnableCutoff = Props.mEnableCutoff;
|
||||
break;
|
||||
}
|
||||
UpdatePosition(Step);
|
||||
}
|
||||
|
||||
void lcLight::RayTest(lcObjectRayTest& ObjectRayTest) const
|
||||
{
|
||||
if (IsPointLight())
|
||||
|
@ -231,6 +583,12 @@ void lcLight::InsertTime(lcStep Start, lcStep Time)
|
|||
mDiffuseColorKeys.InsertTime(Start, Time);
|
||||
mSpecularColorKeys.InsertTime(Start, Time);
|
||||
mAttenuationKeys.InsertTime(Start, Time);
|
||||
mLightShapeKeys.InsertTime(Start, Time);
|
||||
mLightColorKeys.InsertTime(Start, Time);
|
||||
mLightTypeKeys.InsertTime(Start, Time);
|
||||
mLightFactorKeys.InsertTime(Start, Time);
|
||||
mLightSpecularKeys.InsertTime(Start, Time);
|
||||
mLightSpotSizeKeys.InsertTime(Start, Time);
|
||||
mSpotCutoffKeys.InsertTime(Start, Time);
|
||||
mSpotExponentKeys.InsertTime(Start, Time);
|
||||
}
|
||||
|
@ -243,6 +601,12 @@ void lcLight::RemoveTime(lcStep Start, lcStep Time)
|
|||
mDiffuseColorKeys.RemoveTime(Start, Time);
|
||||
mSpecularColorKeys.RemoveTime(Start, Time);
|
||||
mAttenuationKeys.RemoveTime(Start, Time);
|
||||
mLightShapeKeys.RemoveTime(Start, Time);
|
||||
mLightColorKeys.RemoveTime(Start, Time);
|
||||
mLightTypeKeys.RemoveTime(Start, Time);
|
||||
mLightFactorKeys.RemoveTime(Start, Time);
|
||||
mLightSpecularKeys.RemoveTime(Start, Time);
|
||||
mLightSpotSizeKeys.RemoveTime(Start, Time);
|
||||
mSpotCutoffKeys.RemoveTime(Start, Time);
|
||||
mSpotExponentKeys.RemoveTime(Start, Time);
|
||||
}
|
||||
|
@ -255,6 +619,12 @@ void lcLight::UpdatePosition(lcStep Step)
|
|||
mDiffuseColor = mDiffuseColorKeys.CalculateKey(Step);
|
||||
mSpecularColor = mSpecularColorKeys.CalculateKey(Step);
|
||||
mAttenuation = mAttenuationKeys.CalculateKey(Step);
|
||||
mLightShape = mLightShapeKeys.CalculateKey(Step);
|
||||
mLightColor = mLightColorKeys.CalculateKey(Step);
|
||||
mLightType = mLightTypeKeys.CalculateKey(Step);
|
||||
mLightFactor = mLightFactorKeys.CalculateKey(Step);
|
||||
mLightSpecular = mLightSpecularKeys.CalculateKey(Step);
|
||||
mSpotSize = mLightSpotSizeKeys.CalculateKey(Step);
|
||||
mSpotCutoff = mSpotCutoffKeys.CalculateKey(Step);
|
||||
mSpotExponent = mSpotExponentKeys.CalculateKey(Step);
|
||||
|
||||
|
@ -294,10 +664,160 @@ void lcLight::DrawInterface(lcContext* Context, const lcScene& Scene) const
|
|||
|
||||
if (IsPointLight())
|
||||
DrawPointLight(Context);
|
||||
else if (IsDirectionalLight())
|
||||
DrawDirectionalLight(Context);
|
||||
else
|
||||
DrawSpotLight(Context);
|
||||
}
|
||||
|
||||
void lcLight::DrawDirectionalLight(lcContext* Context) const
|
||||
{
|
||||
lcVector3 FrontVector(mTargetPosition - mPosition);
|
||||
lcVector3 UpVector(1, 1, 1);
|
||||
|
||||
if (fabs(FrontVector[0]) < fabs(FrontVector[1]))
|
||||
{
|
||||
if (fabs(FrontVector[0]) < fabs(FrontVector[2]))
|
||||
UpVector[0] = -(UpVector[1] * FrontVector[1] + UpVector[2] * FrontVector[2]);
|
||||
else
|
||||
UpVector[2] = -(UpVector[0] * FrontVector[0] + UpVector[1] * FrontVector[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fabs(FrontVector[1]) < fabs(FrontVector[2]))
|
||||
UpVector[1] = -(UpVector[0] * FrontVector[0] + UpVector[2] * FrontVector[2]);
|
||||
else
|
||||
UpVector[2] = -(UpVector[0] * FrontVector[0] + UpVector[1] * FrontVector[1]);
|
||||
}
|
||||
|
||||
lcMatrix44 LightMatrix = lcMatrix44LookAt(mPosition, mTargetPosition, UpVector);
|
||||
LightMatrix = lcMatrix44AffineInverse(LightMatrix);
|
||||
LightMatrix.SetTranslation(lcVector3(0, 0, 0));
|
||||
|
||||
lcMatrix44 LightViewMatrix = lcMul(LightMatrix, lcMatrix44Translation(mPosition));
|
||||
Context->SetWorldMatrix(LightViewMatrix);
|
||||
|
||||
float Verts[(20 + 8 + 2 + 16) * 3];
|
||||
float* CurVert = Verts;
|
||||
|
||||
for (int EdgeIdx = 0; EdgeIdx < 8; EdgeIdx++)
|
||||
{
|
||||
float c = cosf(float(EdgeIdx) / 4 * LC_PI) * LC_LIGHT_POSITION_EDGE;
|
||||
float s = sinf(float(EdgeIdx) / 4 * LC_PI) * LC_LIGHT_POSITION_EDGE;
|
||||
|
||||
*CurVert++ = c;
|
||||
*CurVert++ = s;
|
||||
*CurVert++ = LC_LIGHT_POSITION_EDGE;
|
||||
*CurVert++ = c;
|
||||
*CurVert++ = s;
|
||||
*CurVert++ = -LC_LIGHT_POSITION_EDGE;
|
||||
}
|
||||
|
||||
if (mLightType == LC_SUNLIGHT) {
|
||||
|
||||
// set base face to same size (LC_LIGHT_TARGET_EDGE) as body - was 12.5f
|
||||
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
|
||||
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
|
||||
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
|
||||
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
|
||||
|
||||
} else {
|
||||
|
||||
*CurVert++ = -LC_LIGHT_BASEFACE_EDGE; *CurVert++ = -LC_LIGHT_BASEFACE_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
|
||||
*CurVert++ = LC_LIGHT_BASEFACE_EDGE; *CurVert++ = -LC_LIGHT_BASEFACE_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
|
||||
*CurVert++ = LC_LIGHT_BASEFACE_EDGE; *CurVert++ = LC_LIGHT_BASEFACE_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
|
||||
*CurVert++ = -LC_LIGHT_BASEFACE_EDGE; *CurVert++ = LC_LIGHT_BASEFACE_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
|
||||
}
|
||||
|
||||
|
||||
float Length = FrontVector.Length();
|
||||
|
||||
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE - Length;
|
||||
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE - Length;
|
||||
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE - Length;
|
||||
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE - Length;
|
||||
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE - Length;
|
||||
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE - Length;
|
||||
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE - Length;
|
||||
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE - Length;
|
||||
|
||||
*CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = 0.0f;
|
||||
*CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = -Length;
|
||||
|
||||
const GLushort Indices[56 + 24 + 2 + 40] =
|
||||
{
|
||||
// base body
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14, 0,
|
||||
1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15, 1,
|
||||
// base face
|
||||
16, 17, 17, 18, 18, 19, 19, 16,
|
||||
// targe box
|
||||
20, 21, 21, 22, 22, 23, 23, 20,
|
||||
24, 25, 25, 26, 26, 27, 27, 24,
|
||||
20, 24, 21, 25, 22, 26, 23, 27,
|
||||
// target line - from base to target
|
||||
28, 29,
|
||||
};
|
||||
|
||||
Context->SetVertexBufferPointer(Verts);
|
||||
Context->SetVertexFormatPosition(3);
|
||||
Context->SetIndexBufferPointer(Indices);
|
||||
|
||||
const lcPreferences& Preferences = lcGetPreferences();
|
||||
const float LineWidth = Preferences.mLineWidth;
|
||||
const lcVector4 SelectedColor = lcVector4FromColor(Preferences.mObjectSelectedColor);
|
||||
const lcVector4 FocusedColor = lcVector4FromColor(Preferences.mObjectFocusedColor);
|
||||
const lcVector4 LightColor = lcVector4FromColor(Preferences.mLightColor);
|
||||
|
||||
if (!IsSelected())
|
||||
{
|
||||
Context->SetLineWidth(LineWidth);
|
||||
Context->SetColor(LightColor);
|
||||
|
||||
Context->DrawIndexedPrimitives(GL_LINES, 56 + 24 + 2, GL_UNSIGNED_SHORT, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsSelected(LC_LIGHT_SECTION_POSITION))
|
||||
{
|
||||
Context->SetLineWidth(2.0f * LineWidth);
|
||||
if (IsFocused(LC_LIGHT_SECTION_POSITION))
|
||||
Context->SetColor(FocusedColor);
|
||||
else
|
||||
Context->SetColor(SelectedColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context->SetLineWidth(LineWidth);
|
||||
Context->SetColor(LightColor);
|
||||
}
|
||||
|
||||
Context->DrawIndexedPrimitives(GL_LINES, 56, GL_UNSIGNED_SHORT, 0);
|
||||
|
||||
if (IsSelected(LC_LIGHT_SECTION_TARGET))
|
||||
{
|
||||
Context->SetLineWidth(2.0f * LineWidth);
|
||||
if (IsFocused(LC_LIGHT_SECTION_TARGET))
|
||||
Context->SetColor(FocusedColor);
|
||||
else
|
||||
Context->SetColor(SelectedColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context->SetLineWidth(LineWidth);
|
||||
Context->SetColor(LightColor);
|
||||
}
|
||||
|
||||
Context->DrawIndexedPrimitives(GL_LINES, 24, GL_UNSIGNED_SHORT, 56 * 2);
|
||||
|
||||
Context->SetLineWidth(LineWidth);
|
||||
Context->SetColor(LightColor);
|
||||
|
||||
Context->DrawIndexedPrimitives(GL_LINES, 2 + 40, GL_UNSIGNED_SHORT, (56 + 24) * 2);
|
||||
}
|
||||
}
|
||||
|
||||
void lcLight::DrawSpotLight(lcContext* Context) const
|
||||
{
|
||||
lcVector3 FrontVector(mTargetPosition - mPosition);
|
||||
|
@ -360,7 +880,7 @@ void lcLight::DrawSpotLight(lcContext* Context) const
|
|||
*CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = 0.0f;
|
||||
*CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = -Length;
|
||||
|
||||
const GLushort Indices[56 + 24 + 2 + 40] =
|
||||
const GLushort Indices[56 + 24 + 2 + 40] =
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14, 0,
|
||||
|
@ -565,6 +1085,24 @@ void lcLight::RemoveKeyFrames()
|
|||
mAttenuationKeys.RemoveAll();
|
||||
mAttenuationKeys.ChangeKey(mAttenuation, 1, true);
|
||||
|
||||
mLightShapeKeys.RemoveAll();
|
||||
mLightShapeKeys.ChangeKey(mLightShape, 1, false);
|
||||
|
||||
mLightColorKeys.RemoveAll();
|
||||
mLightColorKeys.ChangeKey(mLightColor, 1, true);
|
||||
|
||||
mLightFactorKeys.RemoveAll();
|
||||
mLightFactorKeys.ChangeKey(mLightFactor, 1, true);
|
||||
|
||||
mLightTypeKeys.RemoveAll();
|
||||
mLightTypeKeys.ChangeKey(mLightType, 1, true);
|
||||
|
||||
mLightSpecularKeys.RemoveAll();
|
||||
mLightSpecularKeys.ChangeKey(mLightSpecular, 1, true);
|
||||
|
||||
mLightSpotSizeKeys.RemoveAll();
|
||||
mLightSpotSizeKeys.ChangeKey(mSpotSize, 1, false);
|
||||
|
||||
mSpotCutoffKeys.RemoveAll();
|
||||
mSpotCutoffKeys.ChangeKey(mSpotCutoff, 1, true);
|
||||
|
||||
|
|
|
@ -21,11 +21,55 @@ enum lcLightSection
|
|||
LC_LIGHT_SECTION_TARGET
|
||||
};
|
||||
|
||||
enum lcLightType
|
||||
{
|
||||
LC_UNDEFINED_LIGHT,
|
||||
LC_POINTLIGHT,
|
||||
LC_AREALIGHT,
|
||||
LC_SUNLIGHT,
|
||||
LC_SPOTLIGHT
|
||||
};
|
||||
|
||||
enum lcLightShape
|
||||
{
|
||||
LC_LIGHT_SHAPE_UNDEFINED = -1,
|
||||
LC_LIGHT_SHAPE_SQUARE,
|
||||
LC_LIGHT_SHAPE_DISK,
|
||||
LC_LIGHT_SHAPE_RECTANGLE,
|
||||
LC_LIGHT_SHAPE_ELLIPSE
|
||||
};
|
||||
|
||||
enum lcLightProperty
|
||||
{
|
||||
LC_LIGHT_NONE,
|
||||
LC_LIGHT_SHAPE,
|
||||
LC_LIGHT_COLOR,
|
||||
LC_LIGHT_TYPE,
|
||||
LC_LIGHT_FACTOR,
|
||||
LC_LIGHT_SPECULAR,
|
||||
LC_LIGHT_EXPONENT,
|
||||
LC_LIGHT_SPOT_SIZE,
|
||||
LC_LIGHT_CUTOFF,
|
||||
LC_LIGHT_USE_CUTOFF
|
||||
};
|
||||
|
||||
struct lcLightProperties
|
||||
{
|
||||
lcVector3 mLightColor;
|
||||
lcVector2 mLightFactor;
|
||||
float mLightSpecular;
|
||||
float mSpotExponent;
|
||||
float mSpotCutoff;
|
||||
float mSpotSize;
|
||||
bool mEnableCutoff;
|
||||
int mLightShape;
|
||||
};
|
||||
|
||||
class lcLight : public lcObject
|
||||
{
|
||||
public:
|
||||
lcLight(float px, float py, float pz);
|
||||
lcLight(float px, float py, float pz, float tx, float ty, float tz);
|
||||
lcLight(float px, float py, float pz, float tx, float ty, float tz, int LightType);
|
||||
~lcLight();
|
||||
|
||||
lcLight(const lcLight&) = delete;
|
||||
|
@ -178,6 +222,7 @@ public:
|
|||
}
|
||||
|
||||
void SaveLDraw(QTextStream& Stream) const;
|
||||
bool ParseLDrawLine(QTextStream& Stream);
|
||||
|
||||
public:
|
||||
void RayTest(lcObjectRayTest& ObjectRayTest) const override;
|
||||
|
@ -191,6 +236,11 @@ public:
|
|||
bool IsVisible() const
|
||||
{ return (mState & LC_LIGHT_HIDDEN) == 0; }
|
||||
|
||||
void SetName(const QString& Name)
|
||||
{
|
||||
mName = Name;
|
||||
}
|
||||
|
||||
QString GetName() const override
|
||||
{
|
||||
return mName;
|
||||
|
@ -201,6 +251,20 @@ public:
|
|||
void MoveSelected(lcStep Step, bool AddKey, const lcVector3& Distance);
|
||||
bool Setup(int LightIndex);
|
||||
void CreateName(const lcArray<lcLight*>& Lights);
|
||||
void UpdateLight(lcStep Step, lcLightProperties Props, int Property);
|
||||
lcLightProperties GetLightProperties() const
|
||||
{
|
||||
lcLightProperties props;
|
||||
props.mLightColor = mLightColor;
|
||||
props.mLightFactor = mLightFactor;
|
||||
props.mLightSpecular = mLightSpecular;
|
||||
props.mSpotExponent = mSpotExponent;
|
||||
props.mSpotCutoff = mSpotCutoff;
|
||||
props.mSpotSize = mSpotSize;
|
||||
props.mEnableCutoff = mEnableCutoff;
|
||||
props.mLightShape = mLightShape;
|
||||
return props;
|
||||
}
|
||||
|
||||
// Temporary parameters
|
||||
lcMatrix44 mWorldLight;
|
||||
|
@ -210,8 +274,20 @@ public:
|
|||
lcVector4 mDiffuseColor;
|
||||
lcVector4 mSpecularColor;
|
||||
lcVector3 mAttenuation;
|
||||
lcVector3 mLightColor;
|
||||
lcVector2 mLightFactor;
|
||||
bool mAngleSet;
|
||||
bool mSpotBlendSet;
|
||||
bool mSpotCutoffSet;
|
||||
bool mHeightSet;
|
||||
bool mEnableCutoff;
|
||||
int mLightType;
|
||||
int mLightShape;
|
||||
float mLightSpecular;
|
||||
float mSpotSize;
|
||||
float mSpotCutoff;
|
||||
float mSpotExponent;
|
||||
QString mName;
|
||||
|
||||
protected:
|
||||
lcObjectKeyArray<lcVector3> mPositionKeys;
|
||||
|
@ -220,14 +296,21 @@ protected:
|
|||
lcObjectKeyArray<lcVector4> mDiffuseColorKeys;
|
||||
lcObjectKeyArray<lcVector4> mSpecularColorKeys;
|
||||
lcObjectKeyArray<lcVector3> mAttenuationKeys;
|
||||
lcObjectKeyArray<lcVector3> mLightColorKeys;
|
||||
lcObjectKeyArray<lcVector2> mLightFactorKeys;
|
||||
lcObjectKeyArray<int> mLightTypeKeys;
|
||||
lcObjectKeyArray<int> mLightShapeKeys;
|
||||
lcObjectKeyArray<float> mLightSpecularKeys;
|
||||
lcObjectKeyArray<float> mLightSpotSizeKeys;
|
||||
lcObjectKeyArray<float> mSpotCutoffKeys;
|
||||
lcObjectKeyArray<float> mSpotExponentKeys;
|
||||
|
||||
void Initialize(const lcVector3& Position, const lcVector3& TargetPosition);
|
||||
void Initialize(const lcVector3& Position, const lcVector3& TargetPosition, int LightType);
|
||||
|
||||
void DrawDirectionalLight(lcContext* Context) const;
|
||||
void DrawPointLight(lcContext* Context) const;
|
||||
void DrawSpotLight(lcContext* Context) const;
|
||||
void SetLightState(int LightType);
|
||||
|
||||
QString mName;
|
||||
quint32 mState;
|
||||
};
|
||||
|
|
|
@ -38,6 +38,20 @@ template void lcObjectKeyArray<lcMatrix33>::ChangeKey(const lcMatrix33& Value, l
|
|||
template void lcObjectKeyArray<lcMatrix33>::InsertTime(lcStep Start, lcStep Time);
|
||||
template void lcObjectKeyArray<lcMatrix33>::RemoveTime(lcStep Start, lcStep Time);
|
||||
|
||||
template void lcObjectKeyArray<int>::SaveKeysLDraw(QTextStream& Stream, const char* KeyName) const;
|
||||
template void lcObjectKeyArray<int>::LoadKeysLDraw(QTextStream& Stream);
|
||||
template const int& lcObjectKeyArray<int>::CalculateKey(lcStep Step) const;
|
||||
template void lcObjectKeyArray<int>::ChangeKey(const int& Value, lcStep Step, bool AddKey);
|
||||
template void lcObjectKeyArray<int>::InsertTime(lcStep Start, lcStep Time);
|
||||
template void lcObjectKeyArray<int>::RemoveTime(lcStep Start, lcStep Time);
|
||||
|
||||
template void lcObjectKeyArray<lcVector2>::SaveKeysLDraw(QTextStream& Stream, const char* KeyName) const;
|
||||
template void lcObjectKeyArray<lcVector2>::LoadKeysLDraw(QTextStream& Stream);
|
||||
template const lcVector2& lcObjectKeyArray<lcVector2>::CalculateKey(lcStep Step) const;
|
||||
template void lcObjectKeyArray<lcVector2>::ChangeKey(const lcVector2& Value, lcStep Step, bool AddKey);
|
||||
template void lcObjectKeyArray<lcVector2>::InsertTime(lcStep Start, lcStep Time);
|
||||
template void lcObjectKeyArray<lcVector2>::RemoveTime(lcStep Start, lcStep Time);
|
||||
|
||||
template<typename T>
|
||||
void lcObjectKeyArray<T>::SaveKeysLDraw(QTextStream& Stream, const char* KeyName) const
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue