leocad/common/light.cpp

1576 lines
46 KiB
C++
Raw Normal View History

#include "lc_global.h"
2012-03-29 03:10:55 +02:00
#include "lc_math.h"
#include "lc_colors.h"
2011-09-07 23:06:51 +02:00
#include <string.h>
#include <stdio.h>
#include <math.h>
#include "light.h"
2014-04-14 05:20:16 +02:00
#include "lc_application.h"
#include "lc_context.h"
2011-09-07 23:06:51 +02:00
2014-11-24 01:43:13 +01:00
#define LC_LIGHT_SPHERE_RADIUS 5.0f
2023-08-26 21:41:16 +02:00
#define LC_LIGHT_TARGET_EDGE 5.0f
#define LC_LIGHT_SPOT_CONE_HEIGHT 10.0f
#define LC_LIGHT_SPOT_CONE_RADIUS 7.5f
#define LC_LIGHT_DIRECTIONAL_RADIUS 5.0f
#define LC_LIGHT_DIRECTIONAL_HEIGHT 7.5f
#define LC_LIGHT_POSITION_EDGE 7.5f
2014-11-24 01:43:13 +01:00
2023-09-02 05:46:29 +02:00
static const std::array<QLatin1String, static_cast<int>(lcLightType::Count)> gLightTypes = { QLatin1String("POINT"), QLatin1String("SPOT"), QLatin1String("DIRECTIONAL"), QLatin1String("AREA") };
2011-09-07 23:06:51 +02:00
2023-08-13 15:15:52 +02:00
lcLight::lcLight(const lcVector3& Position, const lcVector3& TargetPosition, lcLightType LightType)
2023-08-27 04:43:08 +02:00
: lcObject(lcObjectType::Light), mLightType(LightType)
2011-09-07 23:06:51 +02:00
{
mState = 0;
2012-08-17 01:50:40 +02:00
2023-08-27 04:43:08 +02:00
mPosition = Position;
mTargetPosition = TargetPosition;
mUpVector = lcVector3(0, 0, 1);
if (IsAreaLight())
{
lcVector3 FrontVector = lcNormalize(TargetPosition - Position), SideVector;
if (FrontVector == mUpVector)
SideVector = lcVector3(1, 0, 0);
else
SideVector = lcCross(FrontVector, mUpVector);
mUpVector = lcCross(SideVector, FrontVector);
mUpVector.Normalize();
}
2023-08-07 13:22:59 +02:00
mPOVRayLight = false;
2023-08-07 11:31:33 +02:00
mEnableCutoff = false;
mAttenuation = lcVector3(1.0f, 0.0f, 0.0f);
2023-08-13 15:15:52 +02:00
mLightFactor[0] = LightType == lcLightType::Directional ? 11.4f : 0.25f;
mLightFactor[1] = LightType == lcLightType::Area ? 0.25f : LightType == lcLightType::Spot ? 0.150f : 0.0f;
2023-08-07 13:22:59 +02:00
mLightDiffuse = 1.0f;
2023-08-07 11:31:33 +02:00
mLightSpecular = 1.0f;
2023-08-07 13:22:59 +02:00
mSpotExponent = 10.0f;
mPOVRayExponent = 1.0f;
2023-08-07 11:31:33 +02:00
mSpotSize = 75.0f;
2023-08-13 15:15:52 +02:00
mSpotCutoff = LightType != lcLightType::Directional ? 40.0f : 0.0f;
2023-08-07 13:22:59 +02:00
mSpotFalloff = 45.0f;
mSpotTightness = 0;
mAreaGrid = lcVector2(10.0f, 10.0f);
mAreaSize = lcVector2(200.0f, 200.0f);
mLightShape = LC_LIGHT_SHAPE_SQUARE;
2023-08-07 11:31:33 +02:00
mPositionKeys.ChangeKey(mPosition, 1, true);
mTargetPositionKeys.ChangeKey(mTargetPosition, 1, true);
2023-08-27 04:43:08 +02:00
mUpVectorKeys.ChangeKey(mUpVector, 1, true);
2023-08-27 20:17:07 +02:00
mColorKeys.ChangeKey(mColor, 1, true);
2023-08-07 11:31:33 +02:00
mAttenuationKeys.ChangeKey(mAttenuation, 1, true);
mLightFactorKeys.ChangeKey(mLightFactor, 1, true);
2023-08-07 13:22:59 +02:00
mLightDiffuseKeys.ChangeKey(mLightDiffuse, 1, true);
2023-08-07 11:31:33 +02:00
mLightSpecularKeys.ChangeKey(mLightSpecular, 1, true);
mSpotCutoffKeys.ChangeKey(mSpotCutoff, 1, true);
2023-08-07 13:22:59 +02:00
mSpotFalloffKeys.ChangeKey(mSpotFalloff, 1, true);
2023-08-07 11:31:33 +02:00
mSpotExponentKeys.ChangeKey(mSpotExponent, 1, true);
2023-08-07 13:22:59 +02:00
mSpotSizeKeys.ChangeKey(mSpotSize, 1, true);
mSpotTightnessKeys.ChangeKey(mSpotTightness, 1, true);
mAreaGridKeys.ChangeKey(mAreaGrid, 1, true);
2011-09-07 23:06:51 +02:00
2023-08-13 15:15:52 +02:00
UpdatePosition(1);
2011-09-07 23:06:51 +02:00
}
2023-09-02 05:46:29 +02:00
QString lcLight::GetLightTypeString(lcLightType LightType)
{
switch (LightType)
{
case lcLightType::Point:
return QT_TRANSLATE_NOOP("Light Names", "Point Light");
case lcLightType::Spot:
return QT_TRANSLATE_NOOP("Light Names", "Spotlight");
case lcLightType::Directional:
return QT_TRANSLATE_NOOP("Light Names", "Directional Light");
case lcLightType::Area:
return QT_TRANSLATE_NOOP("Light Names", "Area Light");
case lcLightType::Count:
break;
}
return QString();
}
2014-09-05 02:24:28 +02:00
void lcLight::SaveLDraw(QTextStream& Stream) const
{
2023-08-07 11:31:33 +02:00
const QLatin1String LineEnding("\r\n");
2023-08-07 13:22:59 +02:00
if (mPOVRayLight)
Stream << QLatin1String("0 !LEOCAD LIGHT POV_RAY") << LineEnding;
2023-09-02 19:40:52 +02:00
if (!mCastShadow)
2023-08-07 13:22:59 +02:00
Stream << QLatin1String("0 !LEOCAD LIGHT SHADOWLESS") << LineEnding;
2023-08-07 11:31:33 +02:00
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 (mLightType != lcLightType::Point)
2023-08-07 13:22:59 +02:00
{
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;
}
2023-08-07 11:31:33 +02:00
2023-08-27 04:43:08 +02:00
if (mLightType == lcLightType::Area)
{
if (mUpVectorKeys.GetSize() > 1)
mUpVectorKeys.SaveKeysLDraw(Stream, "LIGHT UP_VECTOR_KEY ");
else
Stream << QLatin1String("0 !LEOCAD LIGHT UP_VECTOR ") << mUpVector[0] << ' ' << mUpVector[1] << ' ' << mUpVector[2] << LineEnding;
}
2023-08-27 20:17:07 +02:00
if (mColorKeys.GetSize() > 1)
mColorKeys.SaveKeysLDraw(Stream, "LIGHT COLOR_KEY ");
2023-08-07 11:31:33 +02:00
else
2023-08-27 20:17:07 +02:00
Stream << QLatin1String("0 !LEOCAD LIGHT COLOR ") << mColor[0] << ' ' << mColor[1] << ' ' << mColor[2] << LineEnding;
2023-08-07 11:31:33 +02:00
2023-08-07 13:22:59 +02:00
if (!mPOVRayLight)
{
if (mLightDiffuseKeys.GetSize() > 1)
mLightDiffuseKeys.SaveKeysLDraw(Stream, "LIGHT DIFFUSE_KEY ");
else
Stream << QLatin1String("0 !LEOCAD LIGHT DIFFUSE ") << mLightDiffuse << LineEnding;
if (mLightSpecularKeys.GetSize() > 1)
mLightSpecularKeys.SaveKeysLDraw(Stream, "LIGHT SPECULAR_KEY ");
else
Stream << QLatin1String("0 !LEOCAD LIGHT SPECULAR ") << mLightSpecular << LineEnding;
}
2023-08-07 11:31:33 +02:00
2023-08-13 15:15:52 +02:00
if (mSpotExponentKeys.GetSize() > 1)
mSpotExponentKeys.SaveKeysLDraw(Stream, "LIGHT POWER_KEY ");
else
Stream << QLatin1String("0 !LEOCAD LIGHT POWER ") << (mPOVRayLight ? mPOVRayExponent : mSpotExponent) << LineEnding;
if (mEnableCutoff && !mPOVRayLight)
2023-08-07 11:31:33 +02:00
{
2023-08-13 15:15:52 +02:00
if (mSpotCutoffKeys.GetSize() > 1)
mSpotCutoffKeys.SaveKeysLDraw(Stream, "LIGHT CUTOFF_DISTANCE_KEY ");
2023-08-07 11:31:33 +02:00
else
2023-08-13 15:15:52 +02:00
Stream << QLatin1String("0 !LEOCAD LIGHT CUTOFF_DISTANCE ") << mSpotCutoff << LineEnding;
}
2023-08-07 11:31:33 +02:00
2023-08-13 15:15:52 +02:00
switch (mLightType)
{
2023-09-02 05:46:29 +02:00
case lcLightType::Count:
break;
2023-08-13 15:15:52 +02:00
case lcLightType::Point:
2023-08-07 13:22:59 +02:00
if (!mPOVRayLight)
{
if (mLightFactorKeys.GetSize() > 1)
2023-08-13 15:15:52 +02:00
mLightFactorKeys.SaveKeysLDraw(Stream, "LIGHT RADIUS_KEY ");
2023-08-07 13:22:59 +02:00
else
2023-08-13 15:15:52 +02:00
Stream << QLatin1String("0 !LEOCAD LIGHT RADIUS ") << mLightFactor[0] << LineEnding;
2023-08-07 13:22:59 +02:00
}
2023-08-13 15:15:52 +02:00
break;
2023-08-07 11:31:33 +02:00
2023-08-13 15:15:52 +02:00
case lcLightType::Spot:
if (mPOVRayLight)
2023-08-07 11:31:33 +02:00
{
2023-08-13 15:15:52 +02:00
if (mLightFactorKeys.GetSize() > 1)
mLightFactorKeys.SaveKeysLDraw(Stream, "LIGHT RADIUS_KEY ");
else
Stream << QLatin1String("0 !LEOCAD LIGHT RADIUS ") << (mSpotSize - mSpotFalloff) << LineEnding;
if (mSpotFalloffKeys.GetSize() > 1)
mSpotFalloffKeys.SaveKeysLDraw(Stream, "LIGHT SPOT_FALLOFF_KEY ");
else
Stream << QLatin1String("0 !LEOCAD LIGHT SPOT_FALLOFF ") << mSpotFalloff << LineEnding;
if (mSpotTightnessKeys.GetSize() > 1)
mSpotTightnessKeys.SaveKeysLDraw(Stream, "SPOT_TIGHTNESS_KEY ");
2023-08-07 11:31:33 +02:00
else
2023-08-13 15:15:52 +02:00
Stream << QLatin1String("0 !LEOCAD LIGHT SPOT_TIGHTNESS ") << mSpotTightness << LineEnding;
2023-08-07 11:31:33 +02:00
}
2023-08-13 15:15:52 +02:00
else
2023-08-07 11:31:33 +02:00
{
2023-08-13 15:15:52 +02:00
if (mSpotSizeKeys.GetSize() > 1)
mSpotSizeKeys.SaveKeysLDraw(Stream, "LIGHT SPOT_SIZE_KEY ");
2023-08-07 11:31:33 +02:00
else
2023-08-13 15:15:52 +02:00
Stream << QLatin1String("0 !LEOCAD LIGHT SPOT_SIZE ") << mSpotSize << LineEnding;
2023-08-07 13:22:59 +02:00
2023-08-13 15:15:52 +02:00
if (mLightFactorKeys.GetSize() > 1)
mLightFactorKeys.SaveKeysLDraw(Stream, "LIGHT RADIUS_AND_SPOT_BLEND_KEY ");
else
2023-08-07 13:22:59 +02:00
{
2023-08-13 15:15:52 +02:00
Stream << QLatin1String("0 !LEOCAD LIGHT RADIUS ") << mLightFactor[0] << LineEnding;
Stream << QLatin1String("0 !LEOCAD LIGHT SPOT_BLEND ") << mLightFactor[1] << LineEnding;
2023-08-07 13:22:59 +02:00
}
2023-08-13 15:15:52 +02:00
}
break;
case lcLightType::Directional:
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;
break;
case lcLightType::Area:
if (mPOVRayLight)
{
if (mAreaGridKeys.GetSize() > 1)
mAreaGridKeys.SaveKeysLDraw(Stream, "LIGHT AREA_GRID_KEY ");
else
2023-08-13 15:15:52 +02:00
Stream << QLatin1String("0 !LEOCAD LIGHT AREA_ROWS ") << mAreaGrid[0] << QLatin1String(" AREA_COLUMNS ") << mAreaGrid[1] << LineEnding;
}
if (mLightFactorKeys.GetSize() > 1)
mLightFactorKeys.SaveKeysLDraw(Stream, "LIGHT SIZE_KEY ");
else
{
if (mPOVRayLight)
{
2023-08-13 15:15:52 +02:00
Stream << QLatin1String("0 !LEOCAD LIGHT WIDTH ") << mAreaSize[0] << QLatin1String(" HEIGHT ") << mAreaSize[1] << LineEnding;
2023-08-07 11:31:33 +02:00
}
else
{
2023-08-13 15:15:52 +02:00
if (mLightShape == LC_LIGHT_SHAPE_RECTANGLE || mLightShape == LC_LIGHT_SHAPE_ELLIPSE || mLightFactor[1] > 0)
Stream << QLatin1String("0 !LEOCAD LIGHT WIDTH ") << mLightFactor[0] << QLatin1String(" HEIGHT ") << mLightFactor[1] << LineEnding;
else
Stream << QLatin1String("0 !LEOCAD LIGHT SIZE ") << mLightFactor[0] << LineEnding;
2023-08-07 11:31:33 +02:00
}
}
2023-08-13 15:15:52 +02:00
Stream << QLatin1String("0 !LEOCAD LIGHT SHAPE ");
2023-08-07 11:31:33 +02:00
2023-08-13 15:15:52 +02:00
QString Shape = QLatin1String("UNDEFINED ");
2023-09-02 05:46:29 +02:00
2023-08-13 15:15:52 +02:00
switch (mLightShape)
{
2023-08-13 15:15:52 +02:00
case LC_LIGHT_SHAPE_SQUARE:
Shape = QLatin1String("SQUARE ");
2023-08-07 11:31:33 +02:00
break;
2023-08-13 15:15:52 +02:00
case LC_LIGHT_SHAPE_DISK:
Shape = QLatin1String("DISK ");
2023-08-07 11:31:33 +02:00
break;
2023-08-13 15:15:52 +02:00
case LC_LIGHT_SHAPE_RECTANGLE:
Shape = QLatin1String("RECTANGLE ");
2023-08-07 11:31:33 +02:00
break;
2023-08-13 15:15:52 +02:00
case LC_LIGHT_SHAPE_ELLIPSE:
Shape = QLatin1String("ELLIPSE ");
2023-08-07 11:31:33 +02:00
break;
}
2023-08-13 15:15:52 +02:00
Stream << QLatin1String("0 !LEOCAD LIGHT SHAPE ") << Shape << LineEnding;
break;
2023-08-07 11:31:33 +02:00
}
2023-08-13 15:15:52 +02:00
Stream << QLatin1String("0 !LEOCAD LIGHT TYPE ") << gLightTypes[static_cast<int>(mLightType)] << QLatin1String(" NAME ") << mName << LineEnding;
}
2014-08-07 17:22:33 +02:00
void lcLight::CreateName(const lcArray<lcLight*>& Lights)
2011-09-07 23:06:51 +02:00
{
2020-12-14 01:27:21 +01:00
if (!mName.isEmpty())
2014-12-16 00:55:17 +01:00
{
bool Found = false;
2019-03-29 01:59:58 +01:00
2021-11-15 03:34:24 +01:00
for (const lcLight* Light : Lights)
2014-12-16 00:55:17 +01:00
{
2020-12-14 01:27:21 +01:00
if (Light->GetName() == mName)
2014-12-16 00:55:17 +01:00
{
Found = true;
break;
}
}
if (!Found)
return;
}
2020-12-14 01:27:21 +01:00
int MaxLightNumber = 0;
2023-08-07 11:31:33 +02:00
2023-08-13 15:15:52 +02:00
QString Prefix;
switch (mLightType)
{
case lcLightType::Point:
2023-09-02 05:46:29 +02:00
Prefix = QLatin1String("Point Light ");
2023-08-13 15:15:52 +02:00
break;
case lcLightType::Spot:
Prefix = QLatin1String("Spotlight ");
break;
case lcLightType::Directional:
2023-09-02 05:46:29 +02:00
Prefix = QLatin1String("Directional Light ");
2023-08-13 15:15:52 +02:00
break;
case lcLightType::Area:
2023-09-02 05:46:29 +02:00
Prefix = QLatin1String("Area Light ");
break;
case lcLightType::Count:
2023-08-13 15:15:52 +02:00
break;
}
2011-09-07 23:06:51 +02:00
2021-11-15 03:34:24 +01:00
for (const lcLight* Light : Lights)
2011-09-07 23:06:51 +02:00
{
2020-12-14 01:27:21 +01:00
QString LightName = Light->GetName();
if (LightName.startsWith(Prefix))
2011-09-07 23:06:51 +02:00
{
2020-12-14 01:27:21 +01:00
bool Ok = false;
2021-07-06 02:07:24 +02:00
int LightNumber = LightName.mid(Prefix.size()).toInt(&Ok);
2020-12-14 01:27:21 +01:00
if (Ok && LightNumber > MaxLightNumber)
MaxLightNumber = LightNumber;
2011-09-07 23:06:51 +02:00
}
}
2020-12-14 01:27:21 +01:00
mName = Prefix + QString::number(MaxLightNumber + 1);
2011-09-07 23:06:51 +02:00
}
2023-08-07 11:31:33 +02:00
bool lcLight::ParseLDrawLine(QTextStream& Stream)
{
while (!Stream.atEnd())
{
QString Token;
Stream >> Token;
2023-08-27 04:43:08 +02:00
if (Token == QLatin1String("POSITION"))
{
Stream >> mPosition[0] >> mPosition[1] >> mPosition[2];
mPositionKeys.ChangeKey(mPosition, 1, true);
}
2023-08-27 20:17:07 +02:00
else if (Token == QLatin1String("POSITION_KEY"))
mPositionKeys.LoadKeysLDraw(Stream);
2023-08-27 04:43:08 +02:00
else if (Token == QLatin1String("TARGET_POSITION"))
{
Stream >> mTargetPosition[0] >> mTargetPosition[1] >> mTargetPosition[2];
mTargetPositionKeys.ChangeKey(mTargetPosition, 1, true);
}
2023-08-27 20:17:07 +02:00
else if (Token == QLatin1String("TARGET_POSITION_KEY"))
mTargetPositionKeys.LoadKeysLDraw(Stream);
2023-08-27 04:43:08 +02:00
else if (Token == QLatin1String("UP_VECTOR"))
{
Stream >> mUpVector[0] >> mUpVector[1] >> mUpVector[2];
mUpVectorKeys.ChangeKey(mUpVector, 1, true);
}
else if (Token == QLatin1String("UP_VECTOR_KEY"))
mUpVectorKeys.LoadKeysLDraw(Stream);
2023-08-27 20:17:07 +02:00
else if (Token == QLatin1String("COLOR"))
2023-08-07 11:31:33 +02:00
{
2023-08-27 20:17:07 +02:00
Stream >> mColor[0] >> mColor[1] >> mColor[2];
mColorKeys.ChangeKey(mColor, 1, true);
2023-08-07 11:31:33 +02:00
}
2023-08-27 20:17:07 +02:00
else if (Token == QLatin1String("COLOR_KEY"))
mColorKeys.LoadKeysLDraw(Stream);
2023-08-07 11:31:33 +02:00
else if (Token == QLatin1String("POWER") || Token == QLatin1String("STRENGTH"))
{
2023-08-07 13:22:59 +02:00
if (mPOVRayLight)
{
Stream >> mPOVRayExponent;
mSpotExponentKeys.ChangeKey(mPOVRayExponent, 1, true);
}
else
{
Stream >> mSpotExponent;
mSpotExponentKeys.ChangeKey(mSpotExponent, 1, true);
}
2023-08-07 11:31:33 +02:00
}
else if (Token == QLatin1String("RADIUS") || Token == QLatin1String("SIZE") || Token == QLatin1String("WIDTH") || (mHeightSet = Token == QLatin1String("HEIGHT")) || (mSpotBlendSet = Token == QLatin1String("SPOT_BLEND")) || (mAngleSet = Token == QLatin1String("ANGLE")))
{
2023-08-07 13:22:59 +02:00
if (mPOVRayLight)
{
if (Token == QLatin1String("WIDTH"))
Stream >> mAreaSize[0];
else if (Token == QLatin1String("HEIGHT"))
Stream >> mAreaSize[1];
mLightFactorKeys.ChangeKey(mAreaSize, 1, true);
}
2023-08-07 11:31:33 +02:00
else
2023-08-07 13:22:59 +02:00
{
if(Token == QLatin1String("HEIGHT") || Token == QLatin1String("SPOT_BLEND"))
Stream >> mLightFactor[1];
else
Stream >> mLightFactor[0];
mLightFactorKeys.ChangeKey(mLightFactor, 1, true);
}
}
else if (Token == QLatin1String("AREA_ROWS"))
{
mPOVRayLight = true;
Stream >> mAreaGrid[0];
mAreaGridKeys.ChangeKey(mAreaGrid, 1, true);
}
else if (Token == QLatin1String("AREA_COLUMNS"))
{
mPOVRayLight = true;
Stream >> mAreaGrid[1];
mAreaGridKeys.ChangeKey(mAreaGrid, 1, true);
}
else if (Token == QLatin1String("SPOT_FALLOFF"))
{
mPOVRayLight = true;
Stream >> mSpotFalloff;
mSpotFalloffKeys.ChangeKey(mSpotFalloff, 1, true);
}
else if (Token == QLatin1String("SPOT_TIGHTNESS"))
{
mPOVRayLight = true;
Stream >> mSpotTightness;
mSpotTightnessKeys.ChangeKey(mSpotTightness, 1, true);
2023-08-07 11:31:33 +02:00
}
else if (Token == QLatin1String("SPOT_SIZE"))
{
Stream >> mSpotSize;
2023-08-07 13:22:59 +02:00
mSpotSizeKeys.ChangeKey(mSpotSize, 1, true);
2023-08-07 11:31:33 +02:00
}
else if (Token == QLatin1String("SHAPE"))
{
QString Shape;
Stream >> Shape;
2023-08-13 15:15:52 +02:00
Shape.replace("\"", "");
if (Shape == QLatin1String("SQUARE"))
2023-08-07 11:31:33 +02:00
mLightShape = LC_LIGHT_SHAPE_SQUARE;
2023-08-13 15:15:52 +02:00
else if (Shape == QLatin1String("DISK") || Shape == QLatin1String("CIRCLE"))
2023-08-07 11:31:33 +02:00
mLightShape = LC_LIGHT_SHAPE_DISK;
2023-08-13 15:15:52 +02:00
else if (Shape == QLatin1String("RECTANGLE"))
2023-08-07 11:31:33 +02:00
mLightShape = LC_LIGHT_SHAPE_RECTANGLE;
2023-08-13 15:15:52 +02:00
else if (Shape == QLatin1String("ELLIPSE"))
2023-08-07 11:31:33 +02:00
mLightShape = LC_LIGHT_SHAPE_ELLIPSE;
}
2023-08-07 13:22:59 +02:00
else if (Token == QLatin1String("DIFFUSE"))
{
Stream >>mLightDiffuse;
mLightDiffuseKeys.ChangeKey(mLightDiffuse, 1, true);
}
2023-08-07 11:31:33 +02:00
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;
2023-08-13 15:15:52 +02:00
for (size_t TypeIndex = 0; TypeIndex < gLightTypes.size(); TypeIndex++)
{
if (Type == gLightTypes[TypeIndex])
{
mLightType = static_cast<lcLightType>(TypeIndex);
break;
}
}
2023-08-07 11:31:33 +02:00
}
2023-08-07 13:22:59 +02:00
else if (Token == QLatin1String("POV_RAY"))
{
mPOVRayLight = true;
}
else if (Token == QLatin1String("SHADOWLESS"))
{
2023-09-02 19:40:52 +02:00
mCastShadow = false;
2023-08-07 13:22:59 +02:00
}
2023-08-07 11:31:33 +02:00
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"))
2023-08-07 13:22:59 +02:00
mSpotSizeKeys.LoadKeysLDraw(Stream);
else if (Token == QLatin1String("SPOT_FALLOFF_KEY"))
mSpotFalloffKeys.LoadKeysLDraw(Stream);
else if (Token == QLatin1String("SPOT_TIGHTNESS_KEY"))
mSpotTightnessKeys.LoadKeysLDraw(Stream);
else if (Token == QLatin1String("AREA_GRID_KEY"))
mAreaGridKeys.LoadKeysLDraw(Stream);
else if (Token == QLatin1String("DIFFUSE_KEY"))
mLightDiffuseKeys.LoadKeysLDraw(Stream);
2023-08-07 11:31:33 +02:00
else if (Token == QLatin1String("SPECULAR_KEY"))
mLightSpecularKeys.LoadKeysLDraw(Stream);
else if (Token == QLatin1String("CUTOFF_DISTANCE_KEY"))
mSpotCutoffKeys.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
2023-08-13 15:15:52 +02:00
switch (mLightType)
{
2023-08-13 15:15:52 +02:00
case lcLightType::Point:
break;
case lcLightType::Spot:
if (!mSpotBlendSet)
{
2023-08-07 11:31:33 +02:00
mLightFactor[1] = 0.15f;
mLightFactorKeys.ChangeKey(mLightFactor, 1, true);
}
2023-08-13 15:15:52 +02:00
break;
case lcLightType::Directional:
if (!mAngleSet)
{
2023-08-07 11:31:33 +02:00
mLightFactor[0] = 11.4f;
mLightFactorKeys.ChangeKey(mLightFactor, 1, true);
}
2023-08-13 15:15:52 +02:00
if (!mSpotCutoffSet)
{
2023-08-13 15:15:52 +02:00
mSpotCutoff = 0.0f;
2023-08-07 11:31:33 +02:00
mSpotCutoffKeys.ChangeKey(mSpotCutoff, 1, true);
}
2023-08-13 15:15:52 +02:00
break;
case lcLightType::Area:
if (mLightShape == LC_LIGHT_SHAPE_RECTANGLE || mLightShape == LC_LIGHT_SHAPE_ELLIPSE)
{
if (!mHeightSet)
{
mLightFactor[1] = 0.25f;
mLightFactorKeys.ChangeKey(mLightFactor, 1, true);
}
}
break;
2023-09-02 05:46:29 +02:00
case lcLightType::Count:
break;
2023-08-07 11:31:33 +02:00
}
2023-08-13 15:15:52 +02:00
2023-08-07 11:31:33 +02:00
return true;
}
}
return false;
}
2016-02-19 18:53:54 +01:00
void lcLight::CompareBoundingBox(lcVector3& Min, lcVector3& Max)
2014-11-10 01:06:11 +01:00
{
const lcVector3 Points[2] =
{
mPosition, mTargetPosition
};
for (int i = 0; i < (IsPointLight() ? 1 : 2); i++)
{
const lcVector3& Point = Points[i];
2016-02-19 18:53:54 +01:00
// TODO: this should check the entire mesh
Min = lcMin(Point, Min);
Max = lcMax(Point, Max);
2014-11-10 01:06:11 +01:00
}
}
2023-08-07 11:31:33 +02:00
void lcLight::UpdateLight(lcStep Step, lcLightProperties Props, int Property)
{
switch(Property)
{
2023-08-07 11:31:33 +02:00
case LC_LIGHT_SHAPE:
mLightShape = Props.mLightShape;
break;
case LC_LIGHT_FACTOR:
2023-08-13 15:15:52 +02:00
if (Props.mPOVRayLight && mLightType == lcLightType::Area)
2023-08-07 13:22:59 +02:00
{
mAreaSize = Props.mLightFactor;
mLightFactorKeys.ChangeKey(mAreaSize, 1, true);
}
else
{
mLightFactor = Props.mLightFactor;
mLightFactorKeys.ChangeKey(mLightFactor, 1, true);
}
break;
case LC_LIGHT_DIFFUSE:
mLightDiffuse = Props.mLightDiffuse;
mLightDiffuseKeys.ChangeKey(mLightDiffuse, Step, false);
2023-08-07 11:31:33 +02:00
break;
case LC_LIGHT_SPECULAR:
mLightSpecular = Props.mLightSpecular;
mLightSpecularKeys.ChangeKey(mLightSpecular, Step, false);
break;
case LC_LIGHT_EXPONENT:
2023-08-07 13:22:59 +02:00
if (Props.mPOVRayLight)
{
mPOVRayExponent = Props.mSpotExponent;
mSpotExponentKeys.ChangeKey(mPOVRayExponent, Step, false);
}
else
{
mSpotExponent = Props.mSpotExponent;
mSpotExponentKeys.ChangeKey(mSpotExponent, Step, false);
}
break;
case LC_LIGHT_AREA_GRID:
mAreaGrid = Props.mAreaGrid;
mAreaGridKeys.ChangeKey(mAreaGrid, Step, false);
2023-08-07 11:31:33 +02:00
break;
case LC_LIGHT_SPOT_SIZE:
mSpotSize = Props.mSpotSize;
2023-08-07 13:22:59 +02:00
mSpotSizeKeys.ChangeKey(mSpotSize, Step, false);
break;
case LC_LIGHT_SPOT_FALLOFF:
mSpotFalloff = Props.mSpotFalloff;
mSpotFalloffKeys.ChangeKey(mSpotFalloff, Step, false);
break;
case LC_LIGHT_SPOT_TIGHTNESS:
mSpotTightness = Props.mSpotTightness;
mSpotTightnessKeys.ChangeKey(mSpotTightness, Step, false);
2023-08-07 11:31:33 +02:00
break;
case LC_LIGHT_CUTOFF:
mSpotCutoff = Props.mSpotCutoff;
mSpotCutoffKeys.ChangeKey(mSpotCutoff, Step, false);
break;
case LC_LIGHT_USE_CUTOFF:
mEnableCutoff = Props.mEnableCutoff;
break;
2023-08-07 13:22:59 +02:00
case LC_LIGHT_POVRAY:
mPOVRayLight = Props.mPOVRayLight;
break;
2023-08-07 11:31:33 +02:00
}
UpdatePosition(Step);
}
2014-05-01 20:42:11 +02:00
void lcLight::RayTest(lcObjectRayTest& ObjectRayTest) const
2011-09-07 23:06:51 +02:00
{
if (IsPointLight())
2012-09-10 01:42:57 +02:00
{
float Distance;
2012-09-10 01:42:57 +02:00
2023-08-26 21:41:16 +02:00
if (lcSphereRayMinIntersectDistance(mPosition, LC_LIGHT_SPHERE_RADIUS, ObjectRayTest.Start, ObjectRayTest.End, &Distance) && (Distance < ObjectRayTest.Distance))
{
2014-08-07 17:22:33 +02:00
ObjectRayTest.ObjectSection.Object = const_cast<lcLight*>(this);
ObjectRayTest.ObjectSection.Section = LC_LIGHT_SECTION_POSITION;
ObjectRayTest.Distance = Distance;
2012-09-10 01:42:57 +02:00
}
return;
2012-09-10 01:42:57 +02:00
}
2023-08-26 21:41:16 +02:00
if (mLightType == lcLightType::Spot)
{
float Distance;
lcVector3 Direction = lcNormalize(mTargetPosition - mPosition);
if (lcConeRayMinIntersectDistance(mPosition - Direction * LC_LIGHT_SPOT_CONE_HEIGHT, Direction, LC_LIGHT_SPOT_CONE_RADIUS, LC_LIGHT_SPOT_CONE_HEIGHT, ObjectRayTest.Start, ObjectRayTest.End, &Distance) && (Distance < ObjectRayTest.Distance))
{
ObjectRayTest.ObjectSection.Object = const_cast<lcLight*>(this);
ObjectRayTest.ObjectSection.Section = LC_LIGHT_SECTION_POSITION;
ObjectRayTest.Distance = Distance;
}
}
else if (mLightType == lcLightType::Area)
{
lcVector3 FrontVector = mTargetPosition - mPosition;
lcVector4 Plane(FrontVector, -lcDot(FrontVector, mPosition));
lcVector3 Intersection;
if (lcLineSegmentPlaneIntersection(&Intersection, ObjectRayTest.Start, ObjectRayTest.End, Plane))
{
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]);
}
lcVector3 XAxis = lcNormalize(lcCross(FrontVector, UpVector));
lcVector3 YAxis = lcNormalize(lcCross(FrontVector, XAxis));
lcVector3 IntersectionDirection = Intersection - mPosition;
float x = lcDot(IntersectionDirection, XAxis);
float y = lcDot(IntersectionDirection, YAxis);
if (fabsf(x) < mAreaSize.x / 2.0f && fabsf(y) < mAreaSize.y / 2.0f)
{
float Distance = lcLength(Intersection - ObjectRayTest.Start);
if (Distance < ObjectRayTest.Distance)
{
ObjectRayTest.ObjectSection.Object = const_cast<lcLight*>(this);
ObjectRayTest.ObjectSection.Section = LC_LIGHT_SECTION_POSITION;
ObjectRayTest.Distance = Distance;
}
}
}
}
lcVector3 Start = lcMul31(ObjectRayTest.Start, mWorldLight);
lcVector3 End = lcMul31(ObjectRayTest.End, mWorldLight);
float Distance;
lcVector3 Plane;
2023-08-26 21:41:16 +02:00
if (mLightType == lcLightType::Directional)
2012-09-10 01:42:57 +02:00
{
2023-08-26 21:41:16 +02:00
if (lcCylinderRayMinIntersectDistance(LC_LIGHT_DIRECTIONAL_RADIUS, LC_LIGHT_DIRECTIONAL_HEIGHT, Start, End, &Distance) && (Distance < ObjectRayTest.Distance))
{
ObjectRayTest.ObjectSection.Object = const_cast<lcLight*>(this);
ObjectRayTest.ObjectSection.Section = LC_LIGHT_SECTION_POSITION;
ObjectRayTest.Distance = Distance;
ObjectRayTest.PieceInfoRayTest.Plane = Plane;
}
}
2023-08-26 21:41:16 +02:00
lcVector3 Min = lcVector3(-LC_LIGHT_TARGET_EDGE, -LC_LIGHT_TARGET_EDGE, -LC_LIGHT_TARGET_EDGE);
lcVector3 Max = lcVector3( LC_LIGHT_TARGET_EDGE, LC_LIGHT_TARGET_EDGE, LC_LIGHT_TARGET_EDGE);
lcMatrix44 WorldTarget = mWorldLight;
WorldTarget.SetTranslation(lcMul30(-mTargetPosition, WorldTarget));
Start = lcMul31(ObjectRayTest.Start, WorldTarget);
End = lcMul31(ObjectRayTest.End, WorldTarget);
if (lcBoundingBoxRayIntersectDistance(Min, Max, Start, End, &Distance, nullptr, &Plane) && (Distance < ObjectRayTest.Distance))
{
2014-08-07 17:22:33 +02:00
ObjectRayTest.ObjectSection.Object = const_cast<lcLight*>(this);
ObjectRayTest.ObjectSection.Section = LC_LIGHT_SECTION_TARGET;
ObjectRayTest.Distance = Distance;
ObjectRayTest.PieceInfoRayTest.Plane = Plane;
}
2023-08-27 04:43:08 +02:00
if (IsAreaLight())
{
const lcMatrix44 LightWorld = lcMatrix44AffineInverse(mWorldLight);
const lcVector3 UpVectorPosition = lcMul31(lcVector3(0, 25, 0), LightWorld);
lcMatrix44 WorldLight = mWorldLight;
WorldLight.SetTranslation(lcMul30(-UpVectorPosition, WorldLight));
Start = lcMul31(ObjectRayTest.Start, WorldLight);
End = lcMul31(ObjectRayTest.End, WorldLight);
if (lcBoundingBoxRayIntersectDistance(Min, Max, Start, End, &Distance, nullptr, &Plane) && (Distance < ObjectRayTest.Distance))
{
ObjectRayTest.ObjectSection.Object = const_cast<lcLight*>(this);
ObjectRayTest.ObjectSection.Section = LC_LIGHT_SECTION_UPVECTOR;
ObjectRayTest.Distance = Distance;
ObjectRayTest.PieceInfoRayTest.Plane = Plane;
}
}
2011-09-07 23:06:51 +02:00
}
2014-05-01 20:42:11 +02:00
void lcLight::BoxTest(lcObjectBoxTest& ObjectBoxTest) const
2011-09-07 23:06:51 +02:00
{
if (IsPointLight())
2012-09-10 01:42:57 +02:00
{
for (int PlaneIdx = 0; PlaneIdx < 6; PlaneIdx++)
2014-11-24 01:43:13 +01:00
if (lcDot3(mPosition, ObjectBoxTest.Planes[PlaneIdx]) + ObjectBoxTest.Planes[PlaneIdx][3] > LC_LIGHT_SPHERE_RADIUS)
return;
2012-09-10 01:42:57 +02:00
2014-11-29 03:55:58 +01:00
ObjectBoxTest.Objects.Add(const_cast<lcLight*>(this));
return;
2012-09-10 01:42:57 +02:00
}
2023-08-26 21:41:16 +02:00
lcVector3 Min(-LC_LIGHT_POSITION_EDGE, -LC_LIGHT_POSITION_EDGE, -LC_LIGHT_POSITION_EDGE); // todo: fix light box test
2014-11-24 01:43:13 +01:00
lcVector3 Max(LC_LIGHT_POSITION_EDGE, LC_LIGHT_POSITION_EDGE, LC_LIGHT_POSITION_EDGE);
lcVector4 LocalPlanes[6];
for (int PlaneIdx = 0; PlaneIdx < 6; PlaneIdx++)
2012-09-10 01:42:57 +02:00
{
2021-11-15 03:34:24 +01:00
const lcVector3 Normal = lcMul30(ObjectBoxTest.Planes[PlaneIdx], mWorldLight);
LocalPlanes[PlaneIdx] = lcVector4(Normal, ObjectBoxTest.Planes[PlaneIdx][3] - lcDot3(mWorldLight[3], Normal));
}
2011-09-07 23:06:51 +02:00
if (lcBoundingBoxIntersectsVolume(Min, Max, LocalPlanes))
2012-08-17 01:50:40 +02:00
{
2014-11-29 03:55:58 +01:00
ObjectBoxTest.Objects.Add(const_cast<lcLight*>(this));
return;
}
2011-09-07 23:06:51 +02:00
2014-11-24 01:43:13 +01:00
Min = lcVector3(-LC_LIGHT_TARGET_EDGE, -LC_LIGHT_TARGET_EDGE, -LC_LIGHT_TARGET_EDGE);
Max = lcVector3(LC_LIGHT_TARGET_EDGE, LC_LIGHT_TARGET_EDGE, LC_LIGHT_TARGET_EDGE);
2011-09-07 23:06:51 +02:00
lcMatrix44 WorldTarget = mWorldLight;
WorldTarget.SetTranslation(lcMul30(-mTargetPosition, WorldTarget));
2011-09-07 23:06:51 +02:00
for (int PlaneIdx = 0; PlaneIdx < 6; PlaneIdx++)
{
2021-11-15 03:34:24 +01:00
const lcVector3 Normal = lcMul30(ObjectBoxTest.Planes[PlaneIdx], WorldTarget);
LocalPlanes[PlaneIdx] = lcVector4(Normal, ObjectBoxTest.Planes[PlaneIdx][3] - lcDot3(WorldTarget[3], Normal));
2012-08-17 01:50:40 +02:00
}
if (lcBoundingBoxIntersectsVolume(Min, Max, LocalPlanes))
2012-08-17 01:50:40 +02:00
{
2014-11-29 03:55:58 +01:00
ObjectBoxTest.Objects.Add(const_cast<lcLight*>(this));
return;
2012-08-17 01:50:40 +02:00
}
2011-09-07 23:06:51 +02:00
}
void lcLight::MoveSelected(lcStep Step, bool AddKey, const lcVector3& Distance)
2011-09-07 23:06:51 +02:00
{
if (IsSelected(LC_LIGHT_SECTION_POSITION))
2012-06-07 02:08:59 +02:00
{
2014-06-22 19:39:15 +02:00
mPosition += Distance;
mPositionKeys.ChangeKey(mPosition, Step, AddKey);
2012-06-07 02:08:59 +02:00
}
2011-09-07 23:06:51 +02:00
if (IsSelected(LC_LIGHT_SECTION_TARGET))
2012-06-07 02:08:59 +02:00
{
2014-06-22 19:39:15 +02:00
mTargetPosition += Distance;
mTargetPositionKeys.ChangeKey(mTargetPosition, Step, AddKey);
2012-06-07 02:08:59 +02:00
}
2023-08-27 04:43:08 +02:00
else if (IsSelected(LC_LIGHT_SECTION_UPVECTOR))
{
mUpVector += Distance;
mUpVector.Normalize();
mUpVectorKeys.ChangeKey(mUpVector, Step, AddKey);
}
if (IsAreaLight())
{
const lcVector3 FrontVector(mTargetPosition - mPosition);
lcVector3 SideVector = lcCross(FrontVector, mUpVector);
if (fabsf(lcDot(mUpVector, SideVector)) > 0.99f)
SideVector = lcVector3(1, 0, 0);
mUpVector = lcCross(SideVector, FrontVector);
mUpVector.Normalize();
}
2011-09-07 23:06:51 +02:00
}
2023-09-04 19:59:16 +02:00
void lcLight::Rotate(lcStep Step, bool AddKey, const lcMatrix33& RotationMatrix, const lcMatrix33& RotationFrame)
{
if (IsPointLight())
return;
if (GetFocusSection() != LC_LIGHT_SECTION_POSITION)
return;
// lcVector3 Direction = mTargetPosition - mPosition;
//
// Direction = lcMul(Direction, RotationMatrix);
//
// mTargetPosition = mPosition + Direction;
// mTargetPositionKeys.ChangeKey(mTargetPosition, Step, AddKey);
const lcMatrix33 LocalToWorldMatrix = lcMatrix33AffineInverse(lcMatrix33(mWorldLight));
const lcMatrix33 LocalToFocusMatrix = lcMul(LocalToWorldMatrix, RotationFrame);
lcMatrix33 NewLocalToWorldMatrix = lcMul(LocalToFocusMatrix, RotationMatrix);
const lcMatrix33 WorldToLocalMatrix = lcMatrix33AffineInverse(LocalToWorldMatrix);
NewLocalToWorldMatrix.Orthonormalize();
lcVector3 Target = lcMul(lcVector3(0.0f, 0.0f, lcLength(mTargetPosition - mPosition)), NewLocalToWorldMatrix);
mTargetPosition = mPosition - Target;
mTargetPositionKeys.ChangeKey(mTargetPosition, Step, AddKey);
if (IsAreaLight())
{
const lcVector3 FrontVector(mTargetPosition - mPosition);
lcVector3 SideVector = lcCross(FrontVector, mUpVector);
if (fabsf(lcDot(mUpVector, SideVector)) > 0.99f)
SideVector = lcVector3(1, 0, 0);
mUpVector = lcCross(SideVector, FrontVector);
mUpVector.Normalize();
}
}
2023-09-02 05:46:29 +02:00
void lcLight::SetLightType(lcLightType LightType)
{
if (static_cast<int>(LightType) < 0 || LightType >= lcLightType::Count)
return;
mLightType = LightType;
}
2023-08-27 20:17:07 +02:00
void lcLight::SetColor(const lcVector3& Color, lcStep Step, bool AddKey)
{
mColorKeys.ChangeKey(Color, Step, AddKey);
}
2023-09-02 19:40:52 +02:00
void lcLight::SetCastShadow(bool CastShadow)
{
mCastShadow = CastShadow;
}
2014-08-31 02:53:12 +02:00
void lcLight::InsertTime(lcStep Start, lcStep Time)
{
mPositionKeys.InsertTime(Start, Time);
mTargetPositionKeys.InsertTime(Start, Time);
2023-08-27 04:43:08 +02:00
mUpVectorKeys.InsertTime(Start, Time);
2023-08-27 20:17:07 +02:00
mColorKeys.InsertTime(Start, Time);
mAttenuationKeys.InsertTime(Start, Time);
2023-08-07 11:31:33 +02:00
mLightFactorKeys.InsertTime(Start, Time);
2023-08-07 13:22:59 +02:00
mLightDiffuseKeys.InsertTime(Start, Time);
2023-08-07 11:31:33 +02:00
mLightSpecularKeys.InsertTime(Start, Time);
2023-08-07 13:22:59 +02:00
mSpotSizeKeys.InsertTime(Start, Time);
mSpotCutoffKeys.InsertTime(Start, Time);
mSpotExponentKeys.InsertTime(Start, Time);
2023-08-07 13:22:59 +02:00
mSpotFalloffKeys.InsertTime(Start, Time);
mSpotTightnessKeys.InsertTime(Start, Time);
mAreaGridKeys.InsertTime(Start, Time);
2014-08-31 02:53:12 +02:00
}
void lcLight::RemoveTime(lcStep Start, lcStep Time)
{
mPositionKeys.RemoveTime(Start, Time);
mTargetPositionKeys.RemoveTime(Start, Time);
2023-08-27 04:43:08 +02:00
mUpVectorKeys.RemoveTime(Start, Time);
2023-08-27 20:17:07 +02:00
mColorKeys.RemoveTime(Start, Time);
mAttenuationKeys.RemoveTime(Start, Time);
2023-08-07 11:31:33 +02:00
mLightFactorKeys.RemoveTime(Start, Time);
2023-08-07 13:22:59 +02:00
mLightDiffuseKeys.RemoveTime(Start, Time);
2023-08-07 11:31:33 +02:00
mLightSpecularKeys.RemoveTime(Start, Time);
2023-08-07 13:22:59 +02:00
mSpotSizeKeys.RemoveTime(Start, Time);
mSpotCutoffKeys.RemoveTime(Start, Time);
mSpotExponentKeys.RemoveTime(Start, Time);
2023-08-07 13:22:59 +02:00
mSpotFalloffKeys.RemoveTime(Start, Time);
mSpotTightnessKeys.RemoveTime(Start, Time);
mAreaGridKeys.RemoveTime(Start, Time);
2014-08-31 02:53:12 +02:00
}
2014-07-06 08:04:09 +02:00
void lcLight::UpdatePosition(lcStep Step)
2011-09-07 23:06:51 +02:00
{
mPosition = mPositionKeys.CalculateKey(Step);
mTargetPosition = mTargetPositionKeys.CalculateKey(Step);
2023-08-27 04:43:08 +02:00
mUpVector = mUpVectorKeys.CalculateKey(Step);
2023-08-27 20:17:07 +02:00
mColor = mColorKeys.CalculateKey(Step);
mAttenuation = mAttenuationKeys.CalculateKey(Step);
2023-08-07 11:31:33 +02:00
mLightFactor = mLightFactorKeys.CalculateKey(Step);
2023-08-07 13:22:59 +02:00
mLightDiffuse = mLightDiffuseKeys.CalculateKey(Step);
2023-08-07 11:31:33 +02:00
mLightSpecular = mLightSpecularKeys.CalculateKey(Step);
2023-08-07 13:22:59 +02:00
mSpotSize = mSpotSizeKeys.CalculateKey(Step);
mSpotCutoff = mSpotCutoffKeys.CalculateKey(Step);
mSpotExponent = mSpotExponentKeys.CalculateKey(Step);
2023-08-07 13:22:59 +02:00
mSpotFalloff = mSpotFalloffKeys.CalculateKey(Step);
mSpotTightness = mSpotTightnessKeys.CalculateKey(Step);
mAreaGrid = mAreaGridKeys.CalculateKey(Step);
2011-09-07 23:06:51 +02:00
if (IsPointLight())
2012-03-29 03:10:55 +02:00
{
mWorldLight = lcMatrix44Identity();
mWorldLight.SetTranslation(-mPosition);
}
2023-08-27 04:43:08 +02:00
else if (IsAreaLight())
{
2023-09-04 19:59:16 +02:00
lcVector3 UpVector(0, 0, 1), FrontVector(mPosition), SideVector;
FrontVector.Normalize();
if (fabsf(lcDot(UpVector, FrontVector)) > 0.99f)
SideVector = lcVector3(-1, 0, 0);
else
SideVector = lcCross(FrontVector, UpVector);
UpVector = lcCross(SideVector, FrontVector);
UpVector.Normalize();
mUpVector = UpVector;
2023-08-27 04:43:08 +02:00
mWorldLight = lcMatrix44LookAt(mPosition, mTargetPosition, mUpVector);
}
else
{
lcVector3 FrontVector(mTargetPosition - mPosition);
lcVector3 UpVector(1, 1, 1);
2011-09-07 23:06:51 +02:00
if (fabs(FrontVector[0]) < fabs(FrontVector[1]))
2012-08-17 01:50:40 +02:00
{
if (fabs(FrontVector[0]) < fabs(FrontVector[2]))
UpVector[0] = -(UpVector[1] * FrontVector[1] + UpVector[2] * FrontVector[2]);
2012-08-17 01:50:40 +02:00
else
UpVector[2] = -(UpVector[0] * FrontVector[0] + UpVector[1] * FrontVector[1]);
2012-08-17 01:50:40 +02:00
}
else
{
if (fabs(FrontVector[1]) < fabs(FrontVector[2]))
UpVector[1] = -(UpVector[0] * FrontVector[0] + UpVector[2] * FrontVector[2]);
2012-08-17 01:50:40 +02:00
else
UpVector[2] = -(UpVector[0] * FrontVector[0] + UpVector[1] * FrontVector[1]);
2012-08-17 01:50:40 +02:00
}
mWorldLight = lcMatrix44LookAt(mPosition, mTargetPosition, UpVector);
2012-08-17 01:50:40 +02:00
}
2011-09-07 23:06:51 +02:00
}
void lcLight::DrawInterface(lcContext* Context, const lcScene& Scene) const
2011-09-07 23:06:51 +02:00
{
Q_UNUSED(Scene);
2020-03-22 21:44:20 +01:00
Context->SetMaterial(lcMaterialType::UnlitColor);
2023-08-26 21:41:16 +02:00
switch (mLightType)
{
case lcLightType::Point:
2015-05-17 01:04:35 +02:00
DrawPointLight(Context);
2023-08-26 21:41:16 +02:00
break;
case lcLightType::Spot:
DrawSpotLight(Context);
break;
case lcLightType::Directional:
DrawDirectionalLight(Context);
2023-08-26 21:41:16 +02:00
break;
case lcLightType::Area:
DrawAreaLight(Context);
break;
2023-09-02 05:46:29 +02:00
case lcLightType::Count:
break;
2023-08-26 21:41:16 +02:00
}
2015-04-19 03:10:01 +02:00
}
2023-08-26 21:41:16 +02:00
void lcLight::DrawPointLight(lcContext* Context) const
2023-08-07 11:31:33 +02:00
{
2023-08-26 21:41:16 +02:00
Context->SetWorldMatrix(lcMatrix44Translation(mPosition));
2023-08-07 11:31:33 +02:00
2023-08-26 21:41:16 +02:00
const lcPreferences& Preferences = lcGetPreferences();
if (IsFocused(LC_LIGHT_SECTION_POSITION))
2023-08-07 11:31:33 +02:00
{
2023-08-26 21:41:16 +02:00
const lcVector4 FocusedColor = lcVector4FromColor(Preferences.mObjectFocusedColor);
Context->SetColor(FocusedColor);
}
else if (IsSelected(LC_LIGHT_SECTION_POSITION))
{
const lcVector4 SelectedColor = lcVector4FromColor(Preferences.mObjectSelectedColor);
Context->SetColor(SelectedColor);
2023-08-07 11:31:33 +02:00
}
else
{
2023-08-26 21:41:16 +02:00
const lcVector4 LightColor = lcVector4FromColor(Preferences.mLightColor);
Context->SetColor(LightColor);
2023-08-07 11:31:33 +02:00
}
2023-08-26 21:41:16 +02:00
DrawSphere(Context, LC_LIGHT_SPHERE_RADIUS);
}
2023-08-07 11:31:33 +02:00
2023-08-26 21:41:16 +02:00
void lcLight::DrawSpotLight(lcContext* Context) const
{
constexpr int ConeEdges = 8;
float TargetDistance = SetupLightMatrix(Context);
2023-08-26 21:41:16 +02:00
float Verts[(ConeEdges + 1) * 3];
2023-08-07 11:31:33 +02:00
float* CurVert = Verts;
2023-08-26 21:41:16 +02:00
for (int EdgeIndex = 0; EdgeIndex < ConeEdges; EdgeIndex++)
2023-08-07 11:31:33 +02:00
{
2023-08-26 21:41:16 +02:00
float c = cosf((float)EdgeIndex / ConeEdges * LC_2PI) * LC_LIGHT_SPOT_CONE_RADIUS;
float s = sinf((float)EdgeIndex / ConeEdges * LC_2PI) * LC_LIGHT_SPOT_CONE_RADIUS;
2023-08-07 11:31:33 +02:00
2023-08-26 21:41:16 +02:00
*CurVert++ = c;
*CurVert++ = s;
*CurVert++ = 0.0f;
2023-08-07 11:31:33 +02:00
}
2023-08-26 21:41:16 +02:00
*CurVert++ = 0.0f;
*CurVert++ = 0.0f;
*CurVert++ = LC_LIGHT_SPOT_CONE_HEIGHT;
2023-08-07 11:31:33 +02:00
2023-08-26 21:41:16 +02:00
Context->SetVertexBufferPointer(Verts);
Context->SetVertexFormatPosition(3);
2023-08-07 11:31:33 +02:00
2023-08-26 21:41:16 +02:00
const GLushort Indices[(ConeEdges + 4) * 2] =
2023-08-07 11:31:33 +02:00
{
2023-08-26 21:41:16 +02:00
0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 0,
0, 8, 2, 8, 4, 8, 6, 8,
};
2023-08-07 11:31:33 +02:00
2023-08-26 21:41:16 +02:00
Context->SetIndexBufferPointer(Indices);
2023-08-07 11:31:33 +02:00
2023-08-26 21:41:16 +02:00
Context->DrawIndexedPrimitives(GL_LINES, (ConeEdges + 4) * 2, GL_UNSIGNED_SHORT, 0);
2023-08-07 11:31:33 +02:00
2023-08-26 21:41:16 +02:00
DrawTarget(Context, TargetDistance);
2023-08-26 21:41:16 +02:00
if (IsSelected())
DrawCone(Context, TargetDistance);
}
2023-08-26 21:41:16 +02:00
void lcLight::DrawDirectionalLight(lcContext* Context) const
{
float TargetDistance = SetupLightMatrix(Context);
2023-08-26 21:41:16 +02:00
DrawCylinder(Context, LC_LIGHT_DIRECTIONAL_RADIUS, LC_LIGHT_DIRECTIONAL_HEIGHT);
2023-08-07 11:31:33 +02:00
2023-08-26 21:41:16 +02:00
DrawTarget(Context, TargetDistance);
}
2023-08-07 11:31:33 +02:00
2023-08-26 21:41:16 +02:00
void lcLight::DrawAreaLight(lcContext* Context) const
{
float TargetDistance = SetupLightMatrix(Context);
2023-08-07 11:31:33 +02:00
2023-08-26 21:41:16 +02:00
if (mLightShape == LC_LIGHT_SHAPE_SQUARE || mLightShape == LC_LIGHT_SHAPE_RECTANGLE)
{
float Verts[4 * 3];
float* CurVert = Verts;
2023-08-07 11:31:33 +02:00
2023-08-26 21:41:16 +02:00
*CurVert++ = -mAreaSize.x / 2.0f;
*CurVert++ = -mAreaSize.y / 2.0f;
*CurVert++ = 0.0f;
2015-04-19 03:10:01 +02:00
2023-08-26 21:41:16 +02:00
*CurVert++ = mAreaSize.x / 2.0f;
*CurVert++ = -mAreaSize.y / 2.0f;
*CurVert++ = 0.0f;
2015-04-19 03:10:01 +02:00
2023-08-26 21:41:16 +02:00
*CurVert++ = mAreaSize.x / 2.0f;
*CurVert++ = mAreaSize.y / 2.0f;
*CurVert++ = 0.0f;
2015-04-19 03:10:01 +02:00
2023-08-26 21:41:16 +02:00
*CurVert++ = -mAreaSize.x / 2.0f;
*CurVert++ = mAreaSize.y / 2.0f;
*CurVert++ = 0.0f;
2015-04-19 03:10:01 +02:00
2023-08-26 21:41:16 +02:00
Context->SetVertexBufferPointer(Verts);
Context->SetVertexFormatPosition(3);
2015-04-19 03:10:01 +02:00
2023-08-26 21:41:16 +02:00
const GLushort Indices[(4 + 2) * 2] =
{
2023-08-26 21:41:16 +02:00
0, 1, 1, 2, 2, 3, 3, 0,
0, 2, 1, 3,
};
2015-04-19 03:10:01 +02:00
2023-08-26 21:41:16 +02:00
Context->SetIndexBufferPointer(Indices);
2015-04-19 03:10:01 +02:00
2023-08-26 21:41:16 +02:00
Context->DrawIndexedPrimitives(GL_LINES, (4 + 2) * 2, GL_UNSIGNED_SHORT, 0);
}
else
{
constexpr int CircleEdges = 16;
2015-04-19 03:10:01 +02:00
2023-08-26 21:41:16 +02:00
float Verts[CircleEdges * 3];
float* CurVert = Verts;
2015-04-19 03:10:01 +02:00
2023-08-26 21:41:16 +02:00
for (int EdgeIndex = 0; EdgeIndex < CircleEdges; EdgeIndex++)
{
float c = cosf((float)EdgeIndex / CircleEdges * LC_2PI) * mAreaSize.x / 2.0f;
float s = sinf((float)EdgeIndex / CircleEdges * LC_2PI) * mAreaSize.y / 2.0f;
2023-08-26 21:41:16 +02:00
*CurVert++ = c;
*CurVert++ = s;
*CurVert++ = 0.0f;
}
2023-08-26 21:41:16 +02:00
Context->SetVertexBufferPointer(Verts);
Context->SetVertexFormatPosition(3);
2023-08-26 21:41:16 +02:00
const GLushort Indices[(CircleEdges + 2) * 2] =
{
0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8,
8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 0,
0, 8, 4, 12
};
Context->SetIndexBufferPointer(Indices);
2023-08-26 21:41:16 +02:00
Context->DrawIndexedPrimitives(GL_LINES, (CircleEdges + 2) * 2, GL_UNSIGNED_SHORT, 0);
}
2023-08-26 21:41:16 +02:00
DrawTarget(Context, TargetDistance);
2023-08-27 04:43:08 +02:00
float Verts[10 * 3];
float* CurVert = Verts;
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE + 25.0f; *CurVert++ = LC_LIGHT_TARGET_EDGE;
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE + 25.0f; *CurVert++ = LC_LIGHT_TARGET_EDGE;
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE + 25.0f; *CurVert++ = LC_LIGHT_TARGET_EDGE;
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE + 25.0f; *CurVert++ = LC_LIGHT_TARGET_EDGE;
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE + 25.0f; *CurVert++ = -LC_LIGHT_TARGET_EDGE;
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE + 25.0f; *CurVert++ = -LC_LIGHT_TARGET_EDGE;
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE + 25.0f; *CurVert++ = -LC_LIGHT_TARGET_EDGE;
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE + 25.0f; *CurVert++ = -LC_LIGHT_TARGET_EDGE;
*CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = 0.0f;
*CurVert++ = 0.0f; *CurVert++ = 25.0f; *CurVert++ = 0.0f;
Context->SetVertexBufferPointer(Verts);
Context->SetVertexFormatPosition(3);
const GLushort Indices[(12 + 1) * 2] =
{
0, 1, 1, 2, 2, 3, 3, 0,
4, 5, 5, 6, 6, 7, 7, 4,
0, 4, 1, 5, 2, 6, 3, 7,
8, 9
};
Context->SetIndexBufferPointer(Indices);
const lcPreferences& Preferences = lcGetPreferences();
const float LineWidth = Preferences.mLineWidth;
const lcVector4 LightColor = lcVector4FromColor(Preferences.mLightColor);
if (IsSelected(LC_LIGHT_SECTION_UPVECTOR))
{
const lcVector4 SelectedColor = lcVector4FromColor(Preferences.mObjectSelectedColor);
const lcVector4 FocusedColor = lcVector4FromColor(Preferences.mObjectFocusedColor);
Context->SetLineWidth(2.0f * LineWidth);
if (IsFocused(LC_LIGHT_SECTION_UPVECTOR))
Context->SetColor(FocusedColor);
else
Context->SetColor(SelectedColor);
}
else
{
Context->SetLineWidth(LineWidth);
Context->SetColor(LightColor);
}
Context->DrawIndexedPrimitives(GL_LINES, 12 * 2, GL_UNSIGNED_SHORT, 0);
Context->SetLineWidth(LineWidth);
Context->SetColor(LightColor);
Context->DrawIndexedPrimitives(GL_LINES, 2, GL_UNSIGNED_SHORT, 12 * 2 * 2);
2023-08-26 21:41:16 +02:00
}
2015-04-19 03:10:01 +02:00
2023-08-26 21:41:16 +02:00
float lcLight::SetupLightMatrix(lcContext* Context) const
{
lcVector3 FrontVector(mTargetPosition - mPosition);
lcVector3 UpVector(1, 1, 1);
2015-04-19 03:10:01 +02:00
2023-08-27 04:43:08 +02:00
if (IsAreaLight())
2023-08-26 21:41:16 +02:00
{
2023-08-27 04:43:08 +02:00
UpVector = mUpVector;
}
else
2012-06-07 02:08:59 +02:00
{
2023-08-27 04:43:08 +02:00
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]);
}
2012-06-07 02:08:59 +02:00
else
2023-08-27 04:43:08 +02:00
{
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]);
}
2023-08-26 21:41:16 +02:00
}
2011-09-07 23:06:51 +02:00
2023-08-26 21:41:16 +02:00
lcMatrix44 LightMatrix = lcMatrix44LookAt(mPosition, mTargetPosition, UpVector);
LightMatrix = lcMatrix44AffineInverse(LightMatrix);
LightMatrix.SetTranslation(lcVector3(0, 0, 0));
2012-09-10 01:42:57 +02:00
2023-08-26 21:41:16 +02:00
const lcMatrix44 LightViewMatrix = lcMul(LightMatrix, lcMatrix44Translation(mPosition));
Context->SetWorldMatrix(LightViewMatrix);
2012-09-10 01:42:57 +02:00
2023-08-26 21:41:16 +02:00
const lcPreferences& Preferences = lcGetPreferences();
const float LineWidth = Preferences.mLineWidth;
2012-09-10 01:42:57 +02:00
2023-08-26 21:41:16 +02:00
if (IsSelected(LC_LIGHT_SECTION_POSITION))
{
const lcVector4 SelectedColor = lcVector4FromColor(Preferences.mObjectSelectedColor);
const lcVector4 FocusedColor = lcVector4FromColor(Preferences.mObjectFocusedColor);
2023-08-26 21:41:16 +02:00
Context->SetLineWidth(2.0f * LineWidth);
2023-08-26 21:41:16 +02:00
if (IsFocused(LC_LIGHT_SECTION_POSITION))
Context->SetColor(FocusedColor);
else
Context->SetColor(SelectedColor);
}
else
{
const lcVector4 LightColor = lcVector4FromColor(Preferences.mLightColor);
2012-09-10 01:42:57 +02:00
2023-08-26 21:41:16 +02:00
Context->SetLineWidth(LineWidth);
Context->SetColor(LightColor);
2012-09-10 01:42:57 +02:00
}
2023-08-26 21:41:16 +02:00
return FrontVector.Length();
2012-09-10 01:42:57 +02:00
}
2023-08-26 21:41:16 +02:00
void lcLight::DrawSphere(lcContext* Context, float Radius) const
2012-09-10 01:42:57 +02:00
{
2021-11-15 03:34:24 +01:00
constexpr int Slices = 6;
constexpr int NumIndices = 3 * Slices + 6 * Slices * (Slices - 2) + 3 * Slices;
constexpr int NumVertices = (Slices - 1) * Slices + 2;
2012-09-10 01:42:57 +02:00
lcVector3 Vertices[NumVertices];
2017-12-02 21:22:04 +01:00
quint16 Indices[NumIndices];
2012-09-10 01:42:57 +02:00
lcVector3* Vertex = Vertices;
2017-12-02 21:22:04 +01:00
quint16* Index = Indices;
2012-09-10 01:42:57 +02:00
*Vertex++ = lcVector3(0, 0, Radius);
2023-08-26 21:41:16 +02:00
for (int i = 1; i < Slices; i++)
2012-09-10 01:42:57 +02:00
{
2021-11-15 03:34:24 +01:00
const float r0 = Radius * sinf(i * (LC_PI / Slices));
const float z0 = Radius * cosf(i * (LC_PI / Slices));
2012-09-10 01:42:57 +02:00
for (int j = 0; j < Slices; j++)
{
2021-11-15 03:34:24 +01:00
const float x0 = r0 * sinf(j * (LC_2PI / Slices));
const float y0 = r0 * cosf(j * (LC_2PI / Slices));
2012-09-10 01:42:57 +02:00
*Vertex++ = lcVector3(x0, y0, z0);
2012-06-07 02:08:59 +02:00
}
2012-09-10 01:42:57 +02:00
}
*Vertex++ = lcVector3(0, 0, -Radius);
2011-09-07 23:06:51 +02:00
2023-08-26 21:41:16 +02:00
for (quint16 i = 0; i < Slices - 1; i++)
2012-09-10 01:42:57 +02:00
{
*Index++ = 0;
*Index++ = 1 + i;
*Index++ = 1 + i + 1;
2012-06-07 02:08:59 +02:00
}
2012-09-10 01:42:57 +02:00
*Index++ = 0;
*Index++ = 1;
*Index++ = 1 + Slices - 1;
2023-08-26 21:41:16 +02:00
for (quint16 i = 0; i < Slices - 2; i++)
2012-09-10 01:42:57 +02:00
{
2021-07-06 02:00:41 +02:00
quint16 Row1 = 1 + i * Slices;
quint16 Row2 = 1 + (i + 1) * Slices;
2012-09-10 01:42:57 +02:00
2023-08-26 21:41:16 +02:00
for (quint16 j = 0; j < Slices - 1; j++)
2012-09-10 01:42:57 +02:00
{
*Index++ = Row1 + j;
*Index++ = Row2 + j + 1;
*Index++ = Row2 + j;
*Index++ = Row1 + j;
*Index++ = Row1 + j + 1;
*Index++ = Row2 + j + 1;
}
*Index++ = Row1 + Slices - 1;
*Index++ = Row2 + 0;
*Index++ = Row2 + Slices - 1;
*Index++ = Row1 + Slices - 1;
*Index++ = Row2 + 0;
*Index++ = Row1 + 0;
}
2023-08-26 21:41:16 +02:00
for (quint16 i = 0; i < Slices - 1; i++)
2012-09-10 01:42:57 +02:00
{
*Index++ = (Slices - 1) * Slices + 1;
*Index++ = (Slices - 1) * (Slices - 1) + i;
*Index++ = (Slices - 1) * (Slices - 1) + i + 1;
}
*Index++ = (Slices - 1) * Slices + 1;
*Index++ = (Slices - 1) * (Slices - 1) + (Slices - 2) + 1;
*Index++ = (Slices - 1) * (Slices - 1);
2023-08-26 21:41:16 +02:00
Context->SetVertexBufferPointer(Vertices);
Context->SetVertexFormatPosition(3);
Context->SetIndexBufferPointer(Indices);
2015-04-19 03:10:01 +02:00
2023-08-26 21:41:16 +02:00
Context->DrawIndexedPrimitives(GL_TRIANGLES, NumIndices, GL_UNSIGNED_SHORT, 0);
}
2021-11-25 00:20:08 +01:00
2023-08-26 21:41:16 +02:00
void lcLight::DrawCylinder(lcContext* Context, float Radius, float Height) const
{
constexpr int Slices = 8;
float Verts[(Slices * 2) * 3];
float* CurVert = Verts;
for (int EdgeIndex = 0; EdgeIndex < Slices; EdgeIndex++)
2021-11-25 00:20:08 +01:00
{
2023-08-26 21:41:16 +02:00
float c = cosf((float)EdgeIndex / Slices * LC_2PI) * Radius;
float s = sinf((float)EdgeIndex / Slices * LC_2PI) * Radius;
*CurVert++ = c;
*CurVert++ = s;
*CurVert++ = Height;
*CurVert++ = c;
*CurVert++ = s;
*CurVert++ = 0.0f;
2021-11-25 00:20:08 +01:00
}
2023-08-26 21:41:16 +02:00
const GLushort Indices[48] =
{
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,
};
Context->SetVertexBufferPointer(Verts);
Context->SetVertexFormatPosition(3);
Context->SetIndexBufferPointer(Indices);
Context->DrawIndexedPrimitives(GL_LINES, 48, GL_UNSIGNED_SHORT, 0);
}
void lcLight::DrawTarget(lcContext* Context, float TargetDistance) const
{
float Verts[10 * 3];
float* CurVert = Verts;
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE - TargetDistance;
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE - TargetDistance;
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE - TargetDistance;
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE - TargetDistance;
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE - TargetDistance;
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE - TargetDistance;
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE - TargetDistance;
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE - TargetDistance;
*CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = 0.0f;
*CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = -TargetDistance;
Context->SetVertexBufferPointer(Verts);
Context->SetVertexFormatPosition(3);
const GLushort Indices[(12 + 1) * 2] =
{
0, 1, 1, 2, 2, 3, 3, 0,
4, 5, 5, 6, 6, 7, 7, 4,
0, 4, 1, 5, 2, 6, 3, 7,
8, 9
};
Context->SetIndexBufferPointer(Indices);
const lcPreferences& Preferences = lcGetPreferences();
const float LineWidth = Preferences.mLineWidth;
const lcVector4 LightColor = lcVector4FromColor(Preferences.mLightColor);
if (IsSelected(LC_LIGHT_SECTION_TARGET))
2021-11-25 00:20:08 +01:00
{
const lcVector4 SelectedColor = lcVector4FromColor(Preferences.mObjectSelectedColor);
2023-08-26 21:41:16 +02:00
const lcVector4 FocusedColor = lcVector4FromColor(Preferences.mObjectFocusedColor);
Context->SetLineWidth(2.0f * LineWidth);
if (IsFocused(LC_LIGHT_SECTION_TARGET))
Context->SetColor(FocusedColor);
else
Context->SetColor(SelectedColor);
2021-11-25 00:20:08 +01:00
}
2015-04-19 03:10:01 +02:00
else
2021-11-25 00:20:08 +01:00
{
2023-08-26 21:41:16 +02:00
Context->SetLineWidth(LineWidth);
2021-11-25 00:20:08 +01:00
Context->SetColor(LightColor);
}
2015-04-19 03:10:01 +02:00
2023-08-26 21:41:16 +02:00
Context->DrawIndexedPrimitives(GL_LINES, 12 * 2, GL_UNSIGNED_SHORT, 0);
Context->SetLineWidth(LineWidth);
Context->SetColor(LightColor);
Context->DrawIndexedPrimitives(GL_LINES, 2, GL_UNSIGNED_SHORT, 12 * 2 * 2);
}
void lcLight::DrawCone(lcContext* Context, float TargetDistance) const
{
constexpr int ConeEdges = 16;
const float Radius = tanf(LC_DTOR * mSpotCutoff) * TargetDistance;
float Verts[(ConeEdges + 1) * 3];
float* CurVert = Verts;
for (int EdgeIndex = 0; EdgeIndex < ConeEdges; EdgeIndex++)
{
float c = cosf((float)EdgeIndex / ConeEdges * LC_2PI) * Radius;
float s = sinf((float)EdgeIndex / ConeEdges * LC_2PI) * Radius;
*CurVert++ = c;
*CurVert++ = s;
*CurVert++ = -TargetDistance;
}
*CurVert++ = 0.0f;
*CurVert++ = 0.0f;
*CurVert++ = 0.0f;
Context->SetVertexBufferPointer(Verts);
2017-03-24 17:34:53 +01:00
Context->SetVertexFormatPosition(3);
2023-08-26 21:41:16 +02:00
const GLushort Indices[(ConeEdges + 4) * 2] =
{
0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8,
8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 0,
16, 0, 16, 4, 16, 8, 16, 12
};
2015-05-17 01:04:35 +02:00
Context->SetIndexBufferPointer(Indices);
2023-08-26 21:41:16 +02:00
Context->DrawIndexedPrimitives(GL_LINES, (ConeEdges + 4) * 2, GL_UNSIGNED_SHORT, 0);
2011-09-07 23:06:51 +02:00
}
void lcLight::RemoveKeyFrames()
{
mPositionKeys.RemoveAll();
mPositionKeys.ChangeKey(mPosition, 1, true);
mTargetPositionKeys.RemoveAll();
mTargetPositionKeys.ChangeKey(mTargetPosition, 1, true);
2023-08-27 04:43:08 +02:00
mUpVectorKeys.RemoveAll();
mUpVectorKeys.ChangeKey(mUpVector, 1, true);
2023-08-27 20:17:07 +02:00
mColorKeys.RemoveAll();
mColorKeys.ChangeKey(mColor, 1, true);
mAttenuationKeys.RemoveAll();
mAttenuationKeys.ChangeKey(mAttenuation, 1, true);
2023-08-07 11:31:33 +02:00
mLightFactorKeys.RemoveAll();
mLightFactorKeys.ChangeKey(mLightFactor, 1, true);
2023-08-07 13:22:59 +02:00
mLightDiffuseKeys.RemoveAll();
mLightDiffuseKeys.ChangeKey(mLightDiffuse, 1, true);
2023-08-07 11:31:33 +02:00
mLightSpecularKeys.RemoveAll();
mLightSpecularKeys.ChangeKey(mLightSpecular, 1, true);
2023-08-07 13:22:59 +02:00
mSpotSizeKeys.RemoveAll();
mSpotSizeKeys.ChangeKey(mSpotSize, 1, false);
2023-08-07 11:31:33 +02:00
mSpotCutoffKeys.RemoveAll();
mSpotCutoffKeys.ChangeKey(mSpotCutoff, 1, true);
mSpotExponentKeys.RemoveAll();
mSpotExponentKeys.ChangeKey(mSpotExponent, 1, true);
2023-08-07 13:22:59 +02:00
mSpotFalloffKeys.RemoveAll();
mSpotFalloffKeys.ChangeKey(mSpotFalloff, 1, true);
mSpotTightnessKeys.RemoveAll();
mSpotTightnessKeys.ChangeKey(mSpotTightness, 1, true);
mAreaGridKeys.RemoveAll();
mAreaGridKeys.ChangeKey(mAreaGrid, 1, true);
}
2014-05-01 20:42:11 +02:00
bool lcLight::Setup(int LightIndex)
2011-09-07 23:06:51 +02:00
{
2017-04-27 07:24:54 +02:00
Q_UNUSED(LightIndex);
return true;
2011-09-07 23:06:51 +02:00
}