Files
leocad/common/light.h
T
Leonardo Zide 851eecee50 Store only changed objects in edit undo history
Full before-and-after model snapshots accumulate large amounts of memory during editing, even when an operation changes only one object. Compact completed edits to retain only added, removed, or modified object states, with ordering metadata kept only for structural changes.

Restore objects by stable IDs, including group relationships, and detach views before removing cameras. Compose merged edits from their deltas and compare animation keys as well as current property values so keyframe-only edits remain undoable.
2026-10-21 10:48:24 -07:00

374 lines
10 KiB
C++

#pragma once
#include "object.h"
#include "lc_math.h"
enum lcLightSection : quint32
{
LC_LIGHT_SECTION_INVALID = LC_OBJECT_SECTION_INVALID,
LC_LIGHT_SECTION_POSITION = 0,
LC_LIGHT_SECTION_TARGET
};
enum class lcLightType
{
Point,
Spot,
Directional,
Area,
Count
};
enum class lcLightAreaShape
{
Rectangle,
Square,
Disk,
Ellipse,
Count
};
struct lcLightHistoryState
{
lcObjectId Id;
bool Hidden;
QString Name;
lcLightType LightType;
bool CastShadow;
lcObjectProperty<lcVector3> Position;
lcObjectProperty<lcMatrix33> Rotation;
lcObjectProperty<lcVector3> Color;
lcObjectProperty<float> BlenderPower;
lcObjectProperty<float> BlenderRadius;
lcObjectProperty<float> BlenderAngle;
lcObjectProperty<float> POVRayPower;
lcObjectProperty<float> POVRayFadeDistance;
lcObjectProperty<float> POVRayFadePower;
lcObjectProperty<float> SpotConeAngle;
lcObjectProperty<float> SpotPenumbraAngle;
lcObjectProperty<float> POVRaySpotTightness;
lcLightAreaShape AreaShape;
lcObjectProperty<float> AreaSizeX;
lcObjectProperty<float> AreaSizeY;
lcObjectProperty<int> POVRayAreaGridX;
lcObjectProperty<int> POVRayAreaGridY;
bool operator==(const lcLightHistoryState& Other) const
{
return Id == Other.Id && Hidden == Other.Hidden && Name == Other.Name && LightType == Other.LightType &&
CastShadow == Other.CastShadow && Position == Other.Position && Rotation == Other.Rotation && Color == Other.Color &&
BlenderPower == Other.BlenderPower && BlenderRadius == Other.BlenderRadius && BlenderAngle == Other.BlenderAngle &&
POVRayPower == Other.POVRayPower && POVRayFadeDistance == Other.POVRayFadeDistance && POVRayFadePower == Other.POVRayFadePower &&
SpotConeAngle == Other.SpotConeAngle && SpotPenumbraAngle == Other.SpotPenumbraAngle &&
POVRaySpotTightness == Other.POVRaySpotTightness && AreaShape == Other.AreaShape && AreaSizeX == Other.AreaSizeX &&
AreaSizeY == Other.AreaSizeY && POVRayAreaGridX == Other.POVRayAreaGridX && POVRayAreaGridY == Other.POVRayAreaGridY;
}
};
class lcLight : public lcObject
{
public:
lcLight();
lcLight(const lcVector3& Position, lcLightType LightType);
virtual ~lcLight() = default;
lcLight(const lcLight&) = delete;
lcLight(lcLight&&) = delete;
lcLight& operator=(const lcLight&) = delete;
lcLight& operator=(lcLight&&) = delete;
static QString GetLightTypeString(lcLightType LightType);
static QStringList GetLightTypeStrings();
static QString GetAreaShapeString(lcLightAreaShape LightAreaShape);
static QStringList GetAreaShapeStrings();
bool IsPointLight() const
{
return mLightType == lcLightType::Point;
}
bool IsSpotLight() const
{
return mLightType == lcLightType::Spot;
}
bool IsDirectionalLight() const
{
return mLightType == lcLightType::Directional;
}
bool IsAreaLight() const
{
return mLightType == lcLightType::Area;
}
lcLightType GetLightType() const
{
return mLightType;
}
bool SetLightType(lcLightType LightType);
quint32 GetAllowedTransforms() const override
{
if (IsPointLight())
return LC_OBJECT_TRANSFORM_MOVE_XYZ;
const quint32 Section = GetFocusSection();
if (Section == LC_LIGHT_SECTION_POSITION || Section == LC_LIGHT_SECTION_INVALID)
return LC_OBJECT_TRANSFORM_MOVE_XYZ | LC_OBJECT_TRANSFORM_ROTATE_XYZ;
if (Section == LC_LIGHT_SECTION_TARGET)
return LC_OBJECT_TRANSFORM_MOVE_XYZ;
return 0;
}
lcMatrix33 GetRelativeRotation() const
{
const quint32 Section = GetFocusSection();
if (Section == LC_LIGHT_SECTION_POSITION)
return lcMatrix33(mWorldMatrix);
else
return lcMatrix33Identity();
}
lcVector3 GetSectionPosition(quint32 Section) const override
{
if (Section == LC_LIGHT_SECTION_POSITION)
return mWorldMatrix.GetTranslation();
if (Section == LC_LIGHT_SECTION_TARGET)
return lcMul31(lcVector3(0.0f, 0.0f, -mTargetDistance), mWorldMatrix);
return lcVector3(0.0f, 0.0f, 0.0f);
}
void SetPosition(const lcVector3& Position, lcStep Step, bool AddKey)
{
mPosition.ChangeKey(Position, Step, AddKey);
}
void SetRotation(const lcMatrix33& Rotation, lcStep Step, bool AddKey)
{
mRotation.ChangeKey(Rotation, Step, AddKey);
}
lcVector3 GetRotationCenter() const
{
const quint32 Section = GetFocusSection();
if (Section == LC_LIGHT_SECTION_POSITION || Section == LC_LIGHT_SECTION_INVALID)
{
return mWorldMatrix.GetTranslation();
}
else
{
return lcMul31(lcVector3(0.0f, 0.0f, -mTargetDistance), mWorldMatrix);
}
}
lcVector3 GetPosition() const
{
return mWorldMatrix.GetTranslation();
}
lcVector3 GetDirection() const
{
return -lcVector3(mWorldMatrix[2]);
}
const lcMatrix44& GetWorldMatrix() const
{
return mWorldMatrix;
}
void SaveLDraw(QTextStream& Stream) const;
bool ParseLDrawLine(QTextStream& Stream);
public:
void RayTest(lcObjectRayTest& ObjectRayTest) const override;
void BoxTest(lcObjectBoxTest& ObjectBoxTest) const override;
void DrawInterface(lcContext* Context, const lcScene& Scene) const override;
QVariant GetPropertyValue(lcObjectPropertyId PropertyId) const override;
bool SetPropertyValue(lcObjectPropertyId PropertyId, lcStep Step, bool AddKey, QVariant Value) override;
bool HasKeyFrame(lcObjectPropertyId PropertyId, lcStep Time) const override;
bool SetKeyFrame(lcObjectPropertyId PropertyId, lcStep Time, bool KeyFrame) override;
void RemoveKeyFrames() override;
lcLightHistoryState GetHistoryState() const;
void SetHistoryState(const lcLightHistoryState& State);
void InsertTime(lcStep Start, lcStep Time);
void RemoveTime(lcStep Start, lcStep Time);
bool IsVisible() const
{
return !mHidden;
}
bool SetColor(const lcVector3& Color, lcStep Step, bool AddKey);
lcVector3 GetColor() const
{
return mColor;
}
bool SetPOVRayFadeDistance(float Distance, lcStep Step, bool AddKey);
float GetPOVRayFadeDistance() const
{
return mPOVRayFadeDistance;
}
bool SetPOVRayFadePower(float Power, lcStep Step, bool AddKey);
float GetPOVRayFadePower() const
{
return mPOVRayFadePower;
}
bool SetSpotConeAngle(float Angle, lcStep Step, bool AddKey);
float GetSpotConeAngle() const
{
return mSpotConeAngle;
}
bool SetSpotPenumbraAngle(float Angle, lcStep Step, bool AddKey);
float GetSpotPenumbraAngle() const
{
return mSpotPenumbraAngle;
}
bool SetSpotPOVRayTightness(float Angle, lcStep Step, bool AddKey);
float GetSpotPOVRayTightness() const
{
return mPOVRaySpotTightness;
}
bool SetAreaShape(lcLightAreaShape LightAreaShape);
lcLightAreaShape GetAreaShape() const
{
return mAreaShape;
}
bool SetAreaPOVRayGridX(int AreaGrid, lcStep Step, bool AddKey);
int GetAreaPOVRayGridX() const
{
return mPOVRayAreaGridX;
}
bool SetAreaPOVRayGridY(int AreaGrid, lcStep Step, bool AddKey);
int GetAreaPOVRayGridY() const
{
return mPOVRayAreaGridY;
}
bool SetBlenderRadius(float Radius, lcStep Step, bool AddKey);
float GetBlenderRadius() const
{
return mBlenderRadius;
}
bool SetBlenderAngle(float Angle, lcStep Step, bool AddKey);
float GetBlenderAngle() const
{
return mBlenderAngle * LC_RTOD;
}
bool SetAreaSizeX(float Size, lcStep Step, bool AddKey);
float GetAreaSizeX() const
{
return mAreaSizeX;
}
bool SetAreaSizeY(float Size, lcStep Step, bool AddKey);
float GetAreaSizeY() const
{
return mAreaSizeY;
}
bool SetBlenderPower(float Power, lcStep Step, bool AddKey);
float GetBlenderPower() const
{
return mBlenderPower;
}
bool SetPOVRayPower(float Power, lcStep Step, bool AddKey);
float GetPOVRayPower() const
{
return mPOVRayPower;
}
bool SetCastShadow(bool CastShadow);
bool GetCastShadow() const
{
return mCastShadow;
}
bool SetName(const QString& Name);
QString GetName() const override
{
return mName;
}
void CompareBoundingBox(lcVector3& Min, lcVector3& Max);
void UpdatePosition(lcStep Step) override;
void MoveSelected(lcStep Step, bool AddKey, const lcVector3& Distance, bool FirstMove);
void Rotate(lcStep Step, bool AddKey, const lcMatrix33& RotationMatrix, const lcVector3& Center, const lcMatrix33& RotationFrame);
void CreateName(const std::vector<std::unique_ptr<lcLight>>& Lights);
protected:
void DrawPointLight(lcContext* Context) const;
void DrawSpotLight(lcContext* Context) const;
void DrawDirectionalLight(lcContext* Context) const;
void DrawAreaLight(lcContext* Context) const;
void SetupLightMatrix(lcContext* Context) const;
void DrawSphere(lcContext* Context, const lcVector3& Center, float Radius) const;
void DrawCylinder(lcContext* Context, float Radius, float Height) const;
void DrawTarget(lcContext* Context) const;
void DrawCone(lcContext* Context, float TargetDistance) const;
QString mName;
lcLightType mLightType = lcLightType::Point;
bool mCastShadow = true;
lcObjectProperty<lcVector3> mPosition = lcObjectProperty<lcVector3>(lcVector3(0.0f, 0.0f, 0.0f));
lcObjectProperty<lcMatrix33> mRotation = lcObjectProperty<lcMatrix33>(lcMatrix33Identity());
lcObjectProperty<lcVector3> mColor = lcObjectProperty<lcVector3>(lcVector3(1.0f, 1.0f, 1.0f));
lcObjectProperty<float> mBlenderPower = lcObjectProperty<float>(10.0f);
lcObjectProperty<float> mBlenderRadius = lcObjectProperty<float>(0.0f);
lcObjectProperty<float> mBlenderAngle = lcObjectProperty<float>(0.526f * LC_DTOR);
lcObjectProperty<float> mPOVRayPower = lcObjectProperty<float>(1.0f);
lcObjectProperty<float> mPOVRayFadeDistance = lcObjectProperty<float>(0.0f);
lcObjectProperty<float> mPOVRayFadePower = lcObjectProperty<float>(0.0f);
lcObjectProperty<float> mSpotConeAngle = lcObjectProperty<float>(80.0f);
lcObjectProperty<float> mSpotPenumbraAngle = lcObjectProperty<float>(0.0f);
lcObjectProperty<float> mPOVRaySpotTightness = lcObjectProperty<float>(0.0f);
lcLightAreaShape mAreaShape = lcLightAreaShape::Rectangle;
lcObjectProperty<float> mAreaSizeX = lcObjectProperty<float>(250.0f);
lcObjectProperty<float> mAreaSizeY = lcObjectProperty<float>(250.0f);
lcObjectProperty<int> mPOVRayAreaGridX = lcObjectProperty<int>(2);
lcObjectProperty<int> mPOVRayAreaGridY = lcObjectProperty<int>(2);
lcVector3 mTargetMovePosition = lcVector3(0.0f, 0.0f, 0.0f);
lcMatrix44 mWorldMatrix;
static constexpr float mTargetDistance = 50.0f;
};