mirror of
https://github.com/leozide/leocad.git
synced 2026-10-26 22:10:32 +00:00
Replace manual piece-data retain/release bookkeeping with shared copyable asset-reference handles. Pieces, models, selection, minifigs, thumbnails, and stored insertion previews retain their dependencies explicitly, while transient queries continue to borrow pointers. Separate registered lookup and acquisition from asynchronous load requests and explicit readiness waits. Keep loader-held references through work and notification delivery, resetting shared request handles on the UI thread and guarding callback-triggered library teardown. Validated with the Qt 6.10 debug build and 26 offscreen lifecycle checks, including cancellation, stale requests, copy/move operations, model/preview teardown, undo, project merge/export, and loader shutdown.
324 lines
8.3 KiB
C++
324 lines
8.3 KiB
C++
#pragma once
|
|
|
|
class lcPieceData;
|
|
|
|
#include "object.h"
|
|
#include "lc_colors.h"
|
|
#include "lc_math.h"
|
|
#include "lc_assettypes.h"
|
|
|
|
#define LC_MAX_CONTROL_POINTS 1000
|
|
|
|
enum lcPieceSection : quint32
|
|
{
|
|
LC_PIECE_SECTION_INVALID = LC_OBJECT_SECTION_INVALID,
|
|
LC_PIECE_SECTION_POSITION = 0,
|
|
LC_PIECE_SECTION_CONTROL_POINT_FIRST,
|
|
LC_PIECE_SECTION_CONTROL_POINT_LAST = LC_PIECE_SECTION_CONTROL_POINT_FIRST + LC_MAX_CONTROL_POINTS - 1,
|
|
LC_PIECE_SECTION_TRAIN_TRACK_CONNECTION_FIRST = 1
|
|
};
|
|
|
|
struct lcPieceControlPoint
|
|
{
|
|
lcMatrix44 Transform;
|
|
float Scale;
|
|
|
|
bool operator==(const lcPieceControlPoint& Other) const
|
|
{
|
|
return Transform == Other.Transform && Scale == Other.Scale;
|
|
}
|
|
};
|
|
|
|
struct lcPieceHistoryState
|
|
{
|
|
lcObjectId Id;
|
|
bool Hidden;
|
|
int FileLine;
|
|
QString PieceId;
|
|
uint32_t GroupIndex;
|
|
int ColorIndex;
|
|
quint32 ColorCode;
|
|
lcStep StepShow;
|
|
lcStep StepHide;
|
|
lcMatrix44 PivotMatrix;
|
|
bool PivotPointValid;
|
|
std::vector<lcPieceControlPoint> ControlPoints;
|
|
lcObjectProperty<lcVector3> Position;
|
|
lcObjectProperty<lcMatrix33> Rotation;
|
|
|
|
bool operator==(const lcPieceHistoryState& Other) const
|
|
{
|
|
return Id == Other.Id && Hidden == Other.Hidden && FileLine == Other.FileLine && PieceId == Other.PieceId &&
|
|
GroupIndex == Other.GroupIndex && ColorIndex == Other.ColorIndex && ColorCode == Other.ColorCode &&
|
|
StepShow == Other.StepShow && StepHide == Other.StepHide && PivotMatrix == Other.PivotMatrix &&
|
|
PivotPointValid == Other.PivotPointValid && ControlPoints == Other.ControlPoints &&
|
|
Position == Other.Position && Rotation == Other.Rotation;
|
|
}
|
|
};
|
|
|
|
class lcPiece : public lcObject
|
|
{
|
|
public:
|
|
lcPiece();
|
|
lcPiece(lcPieceData* PieceData);
|
|
lcPiece(lcPieceDataRef PieceDataRef);
|
|
lcPiece(const lcPiece& Other);
|
|
virtual ~lcPiece();
|
|
|
|
lcPiece(lcPiece&&) = delete;
|
|
lcPiece& operator=(const lcPiece&) = delete;
|
|
lcPiece& operator=(lcPiece&&) = delete;
|
|
|
|
quint32 GetAllowedTransforms() const override;
|
|
lcVector3 GetSectionPosition(quint32 Section) const override;
|
|
|
|
void SaveLDraw(QTextStream& Stream) const;
|
|
bool ParseLDrawLine(QTextStream& Stream);
|
|
|
|
void SetFileLine(int Line)
|
|
{
|
|
mFileLine = Line;
|
|
}
|
|
|
|
int GetFileLine() const
|
|
{
|
|
return mFileLine;
|
|
}
|
|
|
|
void RayTest(lcObjectRayTest& ObjectRayTest) const override;
|
|
void BoxTest(lcObjectBoxTest& ObjectBoxTest) const override;
|
|
bool MinIntersectDist(const lcVector3& Start, const lcVector3& End, float& MinDistance, lcPieceRayTest& PieceRayTest) const;
|
|
bool IntersectsPlanes(const lcMatrix44& WorldMatrix, const lcVector4 Planes[6]) const;
|
|
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;
|
|
lcPieceHistoryState GetHistoryState(const lcModel* Model) const;
|
|
void SetHistoryState(const lcPieceHistoryState& State, const lcModel* Model);
|
|
|
|
void AddMainModelRenderMeshes(lcScene* Scene, bool Highlight, bool Fade) const;
|
|
void AddSubModelRenderMeshes(lcScene* Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const;
|
|
void SubModelCompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector3& Min, lcVector3& Max) const;
|
|
void SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points, lcGeometryBoundsMode Mode) const;
|
|
|
|
void InsertTime(lcStep Start, lcStep Time);
|
|
void RemoveTime(lcStep Start, lcStep Time);
|
|
|
|
bool IsHidden() const
|
|
{
|
|
return mHidden;
|
|
}
|
|
|
|
void SetHidden(bool Hidden)
|
|
{
|
|
mHidden = Hidden;
|
|
}
|
|
|
|
const std::vector<lcPieceControlPoint>& GetControlPoints() const
|
|
{
|
|
return mControlPoints;
|
|
}
|
|
|
|
void SetControlPoints(const std::vector<lcPieceControlPoint>& ControlPoints)
|
|
{
|
|
mControlPoints = ControlPoints;
|
|
UpdateMesh();
|
|
}
|
|
|
|
void SetControlPointScale(int ControlPointIndex, float Scale)
|
|
{
|
|
mControlPoints[ControlPointIndex].Scale = Scale;
|
|
UpdateMesh();
|
|
}
|
|
|
|
bool IsTrainTrackConnected(int ConnectionIndex) const
|
|
{
|
|
return mTrainTrackConnections[ConnectionIndex];
|
|
}
|
|
|
|
void SetTrainTrackConnections(std::vector<bool>&& Connections)
|
|
{
|
|
mTrainTrackConnections = std::move(Connections);
|
|
}
|
|
|
|
const QString& GetID() const
|
|
{
|
|
return mID;
|
|
}
|
|
|
|
void UpdateID();
|
|
|
|
QString GetName() const override;
|
|
bool IsVisible(lcStep Step) const;
|
|
bool IsVisibleInSubModel() const;
|
|
|
|
bool AreTrainTrackConnectionsVisible() const
|
|
{
|
|
return IsFocused();
|
|
}
|
|
|
|
void GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, std::vector<lcModelPartsEntry>& ModelParts) const;
|
|
void Initialize(const lcMatrix44& WorldMatrix, lcStep Step);
|
|
const lcBoundingBox& GetBoundingBox() const;
|
|
void CompareBoundingBox(lcVector3& Min, lcVector3& Max) const;
|
|
void SetPieceData(lcPieceDataRef PieceDataRef, const QString& ID, bool Wait, bool UpdateSynthInfo);
|
|
bool SetPieceId(lcPieceData* PieceData);
|
|
bool FileLoad(lcFile& file, Project* Project);
|
|
|
|
void UpdatePosition(lcStep Step) override;
|
|
void MoveSelected(lcStep Step, bool AddKey, const lcVector3& Distance);
|
|
void Rotate(lcStep Step, bool AddKey, const lcMatrix33& RotationMatrix, const lcVector3& Center, const lcMatrix33& RotationFrame);
|
|
void MovePivotPoint(const lcVector3& Distance);
|
|
void RotatePivotPoint(const lcMatrix33& RotationMatrix);
|
|
|
|
bool CanAddControlPoint() const;
|
|
bool CanRemoveControlPoint() const;
|
|
|
|
bool InsertControlPoint(const lcVector3& WorldStart, const lcVector3& WorldEnd);
|
|
bool RemoveFocusedControlPoint();
|
|
void VerifyControlPoints(std::vector<lcPieceControlPoint>& ControlPoints) const;
|
|
bool IsGeneratedMeshPending() const { return mSynthPending; }
|
|
// An older mesh may remain visible while its replacement is pending.
|
|
bool HasGeneratedMesh() const { return mMesh != nullptr && !mSynthPending; }
|
|
void SetGeneratedMesh(lcMesh* Mesh);
|
|
void RefreshGeneratedMesh();
|
|
|
|
lcGroup* GetTopGroup();
|
|
|
|
void SetGroup(lcGroup* Group)
|
|
{
|
|
mGroup = Group;
|
|
}
|
|
|
|
lcGroup* GetGroup() const
|
|
{
|
|
return mGroup;
|
|
}
|
|
|
|
lcStep GetStepShow() const
|
|
{
|
|
return mStepShow;
|
|
}
|
|
|
|
lcStep GetStepHide() const
|
|
{
|
|
return mStepHide;
|
|
}
|
|
|
|
void SetStepHide(lcStep Step)
|
|
{
|
|
if (Step < 2)
|
|
Step = 2;
|
|
|
|
mStepHide = Step;
|
|
|
|
if (mStepHide <= mStepShow)
|
|
SetStepShow(mStepHide - 1);
|
|
}
|
|
|
|
void SetStepShow(lcStep Step)
|
|
{
|
|
if (Step == LC_STEP_MAX)
|
|
Step = LC_STEP_MAX - 1;
|
|
|
|
if (mStepShow != Step)
|
|
{
|
|
mFileLine = -1;
|
|
mStepShow = Step;
|
|
}
|
|
|
|
if (mStepHide <= mStepShow)
|
|
mStepHide = mStepShow + 1;
|
|
}
|
|
|
|
quint32 GetColorCode() const
|
|
{
|
|
return mColorCode;
|
|
}
|
|
|
|
void SetColorCode(quint32 ColorCode)
|
|
{
|
|
mColorCode = ColorCode;
|
|
mColorIndex = lcGetColorIndex(ColorCode);
|
|
}
|
|
|
|
int GetColorIndex() const
|
|
{
|
|
return mColorIndex;
|
|
}
|
|
|
|
bool SetColorIndex(int ColorIndex)
|
|
{
|
|
if (mColorIndex == ColorIndex)
|
|
return false;
|
|
|
|
mColorIndex = ColorIndex;
|
|
mColorCode = lcGetColorCode(ColorIndex);
|
|
|
|
return true;
|
|
}
|
|
|
|
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;
|
|
lcMatrix33 GetRelativeRotation() const;
|
|
|
|
void ResetPivotPoint()
|
|
{
|
|
mPivotPointValid = false;
|
|
mPivotMatrix = lcMatrix44Identity();
|
|
}
|
|
|
|
public:
|
|
lcPieceDataRef mPieceData;
|
|
|
|
lcMatrix44 mModelWorld;
|
|
lcMatrix44 mPivotMatrix = lcMatrix44Identity();
|
|
|
|
protected:
|
|
void UpdateMesh();
|
|
lcMesh* GetDisplayMesh() const;
|
|
|
|
bool IsPivotPointVisible() const
|
|
{
|
|
return mPivotPointValid && IsFocused();
|
|
}
|
|
|
|
bool AreControlPointsVisible() const
|
|
{
|
|
return IsSelected();
|
|
}
|
|
|
|
void DrawSynthInterface(lcContext* Context, const lcMatrix44& WorldMatrix) const;
|
|
|
|
lcObjectProperty<lcVector3> mPosition = lcObjectProperty<lcVector3>(lcVector3(0.0f, 0.0f, 0.0f));
|
|
lcObjectProperty<lcMatrix33> mRotation = lcObjectProperty<lcMatrix33>(lcMatrix33Identity());
|
|
|
|
int mFileLine = -1;
|
|
QString mID;
|
|
|
|
lcGroup* mGroup = nullptr;
|
|
|
|
int mColorIndex;
|
|
quint32 mColorCode;
|
|
|
|
lcStep mStepShow = 1;
|
|
lcStep mStepHide = LC_STEP_MAX;
|
|
|
|
bool mPivotPointValid = false;
|
|
std::vector<lcPieceControlPoint> mControlPoints;
|
|
std::vector<bool> mTrainTrackConnections;
|
|
lcMesh* mMesh = nullptr;
|
|
bool mSynthPending = false;
|
|
};
|