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.
This commit is contained in:
Leonardo Zide committed 2026-10-21 10:48:24 -07:00
1 parent 3d1091492e
commit 851eecee50
15 files changed
+324 -131

No files matched your search

+2 -2
View File
@@ -921,7 +921,7 @@ void lcCamera::RemoveKeyFrames()
mUpVector.RemoveAllKeys();
}
lcCameraHistoryState lcCamera::GetHistoryState([[maybe_unused]] const lcModel* Model) const
lcCameraHistoryState lcCamera::GetHistoryState() const
{
lcCameraHistoryState State;
@@ -940,7 +940,7 @@ lcCameraHistoryState lcCamera::GetHistoryState([[maybe_unused]] const lcModel* M
return State;
}
void lcCamera::SetHistoryState(const lcCameraHistoryState& State, [[maybe_unused]] const lcModel* Model)
void lcCamera::SetHistoryState(const lcCameraHistoryState& State)
{
mId = State.Id;
mHidden = State.Hidden;
+2 -2
View File
@@ -191,8 +191,8 @@ public:
bool HasKeyFrame(lcObjectPropertyId PropertyId, lcStep Time) const override;
bool SetKeyFrame(lcObjectPropertyId PropertyId, lcStep Time, bool KeyFrame) override;
void RemoveKeyFrames() override;
lcCameraHistoryState GetHistoryState(const lcModel* Model) const;
void SetHistoryState(const lcCameraHistoryState& State, const lcModel* Model);
lcCameraHistoryState GetHistoryState() const;
void SetHistoryState(const lcCameraHistoryState& State);
void InsertTime(lcStep Start, lcStep Time);
void RemoveTime(lcStep Start, lcStep Time);
+4 -21
View File
@@ -1,7 +1,6 @@
#include "lc_global.h"
#include <stdlib.h>
#include "group.h"
#include "lc_model.h"
#include "lc_file.h"
lcGroupId lcGroup::mNextId;
@@ -63,36 +62,20 @@ void lcGroup::CreateName(const std::vector<std::unique_ptr<lcGroup>>& Groups)
mName = Prefix + QString::number(Max + 1);
}
lcGroupHistoryState lcGroup::GetHistoryState(const lcModel* Model) const
lcGroupHistoryState lcGroup::GetHistoryState() const
{
lcGroupHistoryState State;
State.Id = mId;
State.ParentIndex = ~0U;
State.ParentId = mGroup ? static_cast<uint32_t>(mGroup->GetId()) : LC_GROUP_ID_INVALID;
State.Name = mName;
if (mGroup)
{
const std::vector<std::unique_ptr<lcGroup>>& Groups = Model->GetGroups();
for (size_t GroupIndex = 0; GroupIndex < Groups.size(); GroupIndex++)
{
if (Groups[GroupIndex].get() == mGroup)
{
State.ParentIndex = static_cast<uint32_t>(GroupIndex);
break;
}
}
}
return State;
}
void lcGroup::SetHistoryState(const lcGroupHistoryState& State, const lcModel* Model)
void lcGroup::SetHistoryState(const lcGroupHistoryState& State, lcGroup* Parent)
{
const std::vector<std::unique_ptr<lcGroup>>& Groups = Model->GetGroups();
mId = State.Id;
mName = State.Name;
mGroup = (State.ParentIndex < Groups.size()) ? Groups[State.ParentIndex].get() : nullptr;
mGroup = Parent;
}
+6 -4
View File
@@ -4,15 +4,17 @@
enum class lcGroupId : uint32_t;
constexpr uint32_t LC_GROUP_ID_INVALID = std::numeric_limits<uint32_t>::max();
struct lcGroupHistoryState
{
lcGroupId Id;
uint32_t ParentIndex;
uint32_t ParentId;
QString Name;
bool operator==(const lcGroupHistoryState& Other) const
{
return Id == Other.Id && ParentIndex == Other.ParentIndex && Name == Other.Name;
return Id == Other.Id && ParentId == Other.ParentId && Name == Other.Name;
}
};
@@ -34,8 +36,8 @@ public:
void FileLoad(lcFile* File);
void CreateName(const std::vector<std::unique_ptr<lcGroup>>& Groups);
lcGroupHistoryState GetHistoryState(const lcModel* Model) const;
void SetHistoryState(const lcGroupHistoryState& State, const lcModel* Model);
lcGroupHistoryState GetHistoryState() const;
void SetHistoryState(const lcGroupHistoryState& State, lcGroup* Parent);
lcGroup* mGroup = nullptr;
QString mName;
+75 -37
View File
@@ -2262,43 +2262,43 @@ void lcModel::RemoveFromSelection(const std::vector<lcObject*>& Objects)
AddSelectionHistory([this, &Objects](){ SetObjectsSelected(Objects, false); });
}
template<typename StateType, typename ObjectType>
void lcModel::LoadObjectHistoryState(const std::vector<StateType>& ObjectStates, std::vector<std::unique_ptr<ObjectType>>& Objects)
{
std::vector<std::unique_ptr<ObjectType>> NewObjects;
std::unordered_map<uint32_t, size_t> ObjectIndices;
NewObjects.reserve(ObjectStates.size());
ObjectIndices.reserve(Objects.size());
for (size_t ObjectIndex = 0; ObjectIndex < Objects.size(); ObjectIndex++)
ObjectIndices.emplace(static_cast<uint32_t>(Objects[ObjectIndex]->GetId()), ObjectIndex);
for (const StateType& ObjectState : ObjectStates)
{
const auto ObjectIt = ObjectIndices.find(static_cast<uint32_t>(ObjectState.Id));
if (ObjectIt != ObjectIndices.end())
NewObjects.emplace_back(std::move(Objects[ObjectIt->second]));
else
NewObjects.emplace_back(new ObjectType());
}
if constexpr(std::is_same_v<ObjectType, lcCamera>)
for (const std::unique_ptr<lcCamera>& Camera : Objects)
if (Camera)
RemoveCameraFromViews(Camera.get());
Objects = std::move(NewObjects);
for (size_t ObjectIndex = 0; ObjectIndex < Objects.size(); ObjectIndex++)
Objects[ObjectIndex]->SetHistoryState(ObjectStates[ObjectIndex], this);
}
void lcModel::LoadEditHistoryState(const lcModelHistoryEditState& HistoryState)
{
LoadObjectHistoryState(HistoryState.Groups, mGroups);
LoadObjectHistoryState(HistoryState.Pieces, mPieces);
const std::unordered_map<uint32_t, lcGroup*> GroupsById = RestoreGroups(HistoryState.Groups);
RestorePieces(HistoryState.Pieces, GroupsById);
RestoreCameras(HistoryState.Cameras);
RestoreLights(HistoryState.Lights);
}
std::unordered_map<uint32_t, lcGroup*> lcModel::RestoreGroups(const lcObjectHistory<lcGroupHistoryState>& History)
{
const std::unordered_map<uint32_t, lcGroup*> GroupsById = History.RestoreObjects(mGroups);
// The lookup uses saved IDs, so a parent can be linked before its state is restored.
for (const lcGroupHistoryState& State : History.States)
{
const auto Group = GroupsById.find(static_cast<uint32_t>(State.Id));
const auto Parent = GroupsById.find(State.ParentId);
if (Group != GroupsById.end())
Group->second->SetHistoryState(State, Parent != GroupsById.end() ? Parent->second : nullptr);
}
return GroupsById;
}
void lcModel::RestorePieces(const lcObjectHistory<lcPieceHistoryState>& History, const std::unordered_map<uint32_t, lcGroup*>& GroupsById)
{
const std::unordered_map<uint32_t, lcPiece*> PiecesById = History.RestoreObjects(mPieces);
for (const lcPieceHistoryState& State : History.States)
{
const auto Piece = PiecesById.find(static_cast<uint32_t>(State.Id));
const auto Group = GroupsById.find(State.GroupId);
if (Piece != PiecesById.end())
Piece->second->SetHistoryState(State, mProject, Group != GroupsById.end() ? Group->second : nullptr);
}
// Model-list changes are not undoable, but older edit states can still name
// a submodel that was replaced. Do not restore references that now recurse.
@@ -2306,9 +2306,47 @@ void lcModel::LoadEditHistoryState(const lcModelHistoryEditState& HistoryState)
{
return Piece->mPieceData && Piece->mPieceData->IncludesModel(this);
}), mPieces.end());
}
LoadObjectHistoryState(HistoryState.Cameras, mCameras);
LoadObjectHistoryState(HistoryState.Lights, mLights);
void lcModel::RestoreCameras(const lcObjectHistory<lcCameraHistoryState>& History)
{
if (History.IsEmpty())
return;
if (History.Order)
{
const std::unordered_set<uint32_t> CameraIds(History.Order->begin(), History.Order->end());
for (const std::unique_ptr<lcCamera>& Camera : mCameras)
if (CameraIds.find(static_cast<uint32_t>(Camera->GetId())) == CameraIds.end())
RemoveCameraFromViews(Camera.get());
}
const std::unordered_map<uint32_t, lcCamera*> CamerasById = History.RestoreObjects(mCameras);
for (const lcCameraHistoryState& State : History.States)
{
const auto Camera = CamerasById.find(static_cast<uint32_t>(State.Id));
if (Camera != CamerasById.end())
Camera->second->SetHistoryState(State);
}
}
void lcModel::RestoreLights(const lcObjectHistory<lcLightHistoryState>& History)
{
if (History.IsEmpty())
return;
const std::unordered_map<uint32_t, lcLight*> LightsById = History.RestoreObjects(mLights);
for (const lcLightHistoryState& State : History.States)
{
const auto Light = LightsById.find(static_cast<uint32_t>(State.Id));
if (Light != LightsById.end())
Light->second->SetHistoryState(State);
}
}
void lcModel::BeginEditHistory()
+10 -2
View File
@@ -15,6 +15,11 @@ enum class lcGeometryBoundsMode
enum class lcCameraProjection;
struct lcSetInventoryItem;
struct lcModelHistoryEditState;
struct lcGroupHistoryState;
struct lcPieceHistoryState;
struct lcCameraHistoryState;
struct lcLightHistoryState;
template<typename StateType> struct lcObjectHistory;
class lcModelHistory;
class lcModelHistorySelect;
class lcModelHistoryEdit;
@@ -291,8 +296,6 @@ public:
void InsertStepAction(lcStep Step);
void RemoveStepAction(lcStep Step);
template<typename StateType, typename ObjectType>
void LoadObjectHistoryState(const std::vector<StateType>& ObjectStates, std::vector<std::unique_ptr<ObjectType>>& Objects);
void LoadEditHistoryState(const lcModelHistoryEditState& HistoryState);
void LoadModelPropertiesState(const lcModelProperties& ModelProperties);
@@ -478,6 +481,11 @@ protected:
void DeleteModel();
std::unordered_map<uint32_t, lcGroup*> RestoreGroups(const lcObjectHistory<lcGroupHistoryState>& History);
void RestorePieces(const lcObjectHistory<lcPieceHistoryState>& History, const std::unordered_map<uint32_t, lcGroup*>& GroupsById);
void RestoreCameras(const lcObjectHistory<lcCameraHistoryState>& History);
void RestoreLights(const lcObjectHistory<lcLightHistoryState>& History);
void AddSelectionHistory(std::function<void()> Callback);
void ClearSelection();
void SetFocus(lcObject* FocusObject, uint32_t FocusSection, lcSelectionMode SelectionMode);
+18 -28
View File
@@ -142,11 +142,6 @@ void lcModelHistorySelect::LoadState(const lcModelHistorySelectState& State, lcM
}
}
bool operator!=(const lcModelHistoryEditState& a, const lcModelHistoryEditState& b)
{
return a.Groups != b.Groups || a.Pieces != b.Pieces || a.Cameras != b.Cameras || a.Lights != b.Lights;
}
lcModelHistoryEdit::lcModelHistoryEdit(lcModelHistoryEditMergeKey MergeKey)
: mMergeKey(MergeKey)
{
@@ -158,25 +153,10 @@ lcModelHistoryEdit::~lcModelHistoryEdit()
void lcModelHistoryEdit::SaveState(lcModelHistoryEditState& State, const lcModel* Model)
{
const std::vector<std::unique_ptr<lcGroup>>& Groups = Model->GetGroups();
for (const std::unique_ptr<lcGroup>& Group : Groups)
State.Groups.emplace_back(Group->GetHistoryState(Model));
const std::vector<std::unique_ptr<lcPiece>>& Pieces = Model->GetPieces();
for (const std::unique_ptr<lcPiece>& Piece : Pieces)
State.Pieces.emplace_back(Piece->GetHistoryState(Model));
const std::vector<std::unique_ptr<lcCamera>>& Cameras = Model->GetCameras();
for (const std::unique_ptr<lcCamera>& Camera : Cameras)
State.Cameras.emplace_back(Camera->GetHistoryState(Model));
const std::vector<std::unique_ptr<lcLight>>& Lights = Model->GetLights();
for (const std::unique_ptr<lcLight>& Light : Lights)
State.Lights.emplace_back(Light->GetHistoryState(Model));
State.Groups.Save(Model->GetGroups());
State.Pieces.Save(Model->GetPieces());
State.Cameras.Save(Model->GetCameras());
State.Lights.Save(Model->GetLights());
}
void lcModelHistoryEdit::LoadState(const lcModelHistoryEditState& State, lcModel* Model)
@@ -192,6 +172,11 @@ void lcModelHistoryEdit::SaveStartState(const lcModel* Model)
void lcModelHistoryEdit::SaveEndState(const lcModel* Model)
{
SaveState(mEndState, Model);
lcObjectHistory<lcGroupHistoryState>::Compact(mStartState.Groups, mEndState.Groups);
lcObjectHistory<lcPieceHistoryState>::Compact(mStartState.Pieces, mEndState.Pieces);
lcObjectHistory<lcCameraHistoryState>::Compact(mStartState.Cameras, mEndState.Cameras);
lcObjectHistory<lcLightHistoryState>::Compact(mStartState.Lights, mEndState.Lights);
}
void lcModelHistoryEdit::LoadStartState(lcModel* Model) const
@@ -206,7 +191,7 @@ void lcModelHistoryEdit::LoadEndState(lcModel* Model) const
bool lcModelHistoryEdit::StateChanged() const
{
return mStartState != mEndState;
return !mStartState.IsEmpty() || !mEndState.IsEmpty();
}
void lcModelHistoryEdit::RenamePieces(const std::vector<lcModelPieceRename>& Renames, const lcPieceData* ModelPieceData)
@@ -215,7 +200,7 @@ void lcModelHistoryEdit::RenamePieces(const std::vector<lcModelPieceRename>& Ren
auto RenamePieceIds = [&Renames](lcModelHistoryEditState& State)
{
for (lcPieceHistoryState& Piece : State.Pieces)
for (lcPieceHistoryState& Piece : State.Pieces.States)
{
for (const lcModelPieceRename& Rename : Renames)
{
@@ -243,8 +228,13 @@ void lcModelHistoryEdit::MergeWith(lcModelHistory* Other)
{
lcModelHistoryEdit* OtherModelHistoryEdit = dynamic_cast<lcModelHistoryEdit*>(Other);
if (OtherModelHistoryEdit)
mEndState = std::move(OtherModelHistoryEdit->mEndState);
if (!OtherModelHistoryEdit)
return;
lcObjectHistory<lcGroupHistoryState>::Merge(mStartState.Groups, mEndState.Groups, OtherModelHistoryEdit->mStartState.Groups, OtherModelHistoryEdit->mEndState.Groups);
lcObjectHistory<lcPieceHistoryState>::Merge(mStartState.Pieces, mEndState.Pieces, OtherModelHistoryEdit->mStartState.Pieces, OtherModelHistoryEdit->mEndState.Pieces);
lcObjectHistory<lcCameraHistoryState>::Merge(mStartState.Cameras, mEndState.Cameras, OtherModelHistoryEdit->mStartState.Cameras, OtherModelHistoryEdit->mEndState.Cameras);
lcObjectHistory<lcLightHistoryState>::Merge(mStartState.Lights, mEndState.Lights, OtherModelHistoryEdit->mStartState.Lights, OtherModelHistoryEdit->mEndState.Lights);
}
void lcModelHistoryProperties::SaveStartState(const lcModel* Model)
+10 -6
View File
@@ -1,6 +1,7 @@
#pragma once
#include "lc_model.h"
#include "lc_objecthistory.h"
enum class lcObjectType;
enum class lcSelectionMode;
@@ -78,13 +79,16 @@ struct lcLightHistoryState;
struct lcModelHistoryEditState
{
std::vector<lcGroupHistoryState> Groups;
std::vector<lcPieceHistoryState> Pieces;
std::vector<lcCameraHistoryState> Cameras;
std::vector<lcLightHistoryState> Lights;
};
lcObjectHistory<lcGroupHistoryState> Groups;
lcObjectHistory<lcPieceHistoryState> Pieces;
lcObjectHistory<lcCameraHistoryState> Cameras;
lcObjectHistory<lcLightHistoryState> Lights;
bool operator!=(const lcModelHistoryEditState& a, const lcModelHistoryEditState& b);
bool IsEmpty() const
{
return Groups.IsEmpty() && Pieces.IsEmpty() && Cameras.IsEmpty() && Lights.IsEmpty();
}
};
enum class lcModelHistoryEditMerge
{
+173
View File
@@ -0,0 +1,173 @@
#pragma once
// Object states are captured while an edit is in progress, then reduced to the
// changed objects. Ordering is only retained for insertions, deletions or reordering.
template<typename StateType>
struct lcObjectHistory
{
std::vector<StateType> States;
std::optional<std::vector<uint32_t>> Order;
template<typename ObjectType>
void Save(const std::vector<std::unique_ptr<ObjectType>>& Objects)
{
States.clear();
States.reserve(Objects.size());
Order.emplace();
Order->reserve(Objects.size());
for (const std::unique_ptr<ObjectType>& Object : Objects)
{
States.emplace_back(Object->GetHistoryState());
Order->emplace_back(static_cast<uint32_t>(Object->GetId()));
}
}
bool IsEmpty() const
{
return States.empty() && !Order;
}
static void Compact(lcObjectHistory& Start, lcObjectHistory& End)
{
std::unordered_map<uint32_t, const StateType*> StartStates;
std::unordered_map<uint32_t, const StateType*> EndStates;
StartStates.reserve(Start.States.size());
EndStates.reserve(End.States.size());
for (const StateType& State : Start.States)
StartStates.emplace(static_cast<uint32_t>(State.Id), &State);
for (const StateType& State : End.States)
EndStates.emplace(static_cast<uint32_t>(State.Id), &State);
std::unordered_set<uint32_t> Changed;
for (const StateType& State : Start.States)
{
const auto Other = EndStates.find(static_cast<uint32_t>(State.Id));
if (Other == EndStates.end() || !(State == *Other->second))
Changed.emplace(static_cast<uint32_t>(State.Id));
}
for (const StateType& State : End.States)
if (StartStates.find(static_cast<uint32_t>(State.Id)) == StartStates.end())
Changed.emplace(static_cast<uint32_t>(State.Id));
auto KeepChanges = [&Changed](std::vector<StateType>& States)
{
std::vector<StateType> Changes;
Changes.reserve(std::min(States.size(), Changed.size()));
for (StateType& State : States)
if (Changed.find(static_cast<uint32_t>(State.Id)) != Changed.end())
Changes.emplace_back(std::move(State));
States = std::move(Changes);
};
KeepChanges(Start.States);
KeepChanges(End.States);
if (Start.Order == End.Order)
{
Start.Order.reset();
End.Order.reset();
}
}
static void Merge(lcObjectHistory& Start, lcObjectHistory& End, lcObjectHistory& NextStart, lcObjectHistory& NextEnd)
{
std::map<uint32_t, StateType> Before;
std::map<uint32_t, StateType> After;
for (StateType& State : Start.States)
Before.emplace(static_cast<uint32_t>(State.Id), std::move(State));
for (StateType& State : End.States)
After.emplace(static_cast<uint32_t>(State.Id), std::move(State));
for (StateType& State : NextStart.States)
{
const uint32_t Id = static_cast<uint32_t>(State.Id);
if (After.find(Id) == After.end())
Before.emplace(Id, std::move(State));
}
for (const StateType& State : NextStart.States)
After.erase(static_cast<uint32_t>(State.Id));
for (StateType& State : NextEnd.States)
After.insert_or_assign(static_cast<uint32_t>(State.Id), std::move(State));
Start.States.clear();
End.States.clear();
for (auto& [Id, State] : Before)
Start.States.emplace_back(std::move(State));
for (auto& [Id, State] : After)
End.States.emplace_back(std::move(State));
if (!Start.Order)
Start.Order = std::move(NextStart.Order);
if (NextEnd.Order)
End.Order = std::move(NextEnd.Order);
Compact(Start, End);
}
template<typename ObjectType>
std::unordered_map<uint32_t, ObjectType*> RestoreObjects(std::vector<std::unique_ptr<ObjectType>>& Objects) const
{
std::unordered_map<uint32_t, ObjectType*> ObjectsById;
if (!Order)
{
ObjectsById.reserve(Objects.size());
for (const std::unique_ptr<ObjectType>& Object : Objects)
ObjectsById.emplace(static_cast<uint32_t>(Object->GetId()), Object.get());
return ObjectsById;
}
std::unordered_map<uint32_t, size_t> ObjectIndices;
ObjectIndices.reserve(Objects.size());
for (size_t Index = 0; Index < Objects.size(); Index++)
ObjectIndices.emplace(static_cast<uint32_t>(Objects[Index]->GetId()), Index);
std::unordered_set<uint32_t> StateIds;
std::vector<std::unique_ptr<ObjectType>> NewObjects;
for (const StateType& State : States)
StateIds.emplace(static_cast<uint32_t>(State.Id));
NewObjects.reserve(Order->size());
ObjectsById.reserve(Order->size());
for (uint32_t Id : *Order)
{
const auto Object = ObjectIndices.find(Id);
if (Object != ObjectIndices.end())
NewObjects.emplace_back(std::move(Objects[Object->second]));
else if (StateIds.find(Id) != StateIds.end())
NewObjects.emplace_back(std::make_unique<ObjectType>());
else
continue; // A non-undoable model-list change may have removed it.
// New objects do not have their saved IDs until their state is restored.
ObjectsById.emplace(Id, NewObjects.back().get());
}
Objects = std::move(NewObjects);
return ObjectsById;
}
};
+10
View File
@@ -61,6 +61,11 @@ struct lcObjectPropertyKey
{
lcStep Step;
T Value;
bool operator==(const lcObjectPropertyKey& Other) const
{
return Step == Other.Step && Value == Other.Value;
}
};
template<typename T>
@@ -79,6 +84,11 @@ public:
return mValue;
}
bool operator==(const lcObjectProperty& Other) const
{
return mValue == Other.mValue && mKeys == Other.mKeys;
}
void SetValue(const T& Value)
{
mValue = Value;
+2 -2
View File
@@ -1511,7 +1511,7 @@ void lcLight::RemoveKeyFrames()
mPOVRayFadePower.RemoveAllKeys();
}
lcLightHistoryState lcLight::GetHistoryState([[maybe_unused]] const lcModel* Model) const
lcLightHistoryState lcLight::GetHistoryState() const
{
lcLightHistoryState State;
@@ -1541,7 +1541,7 @@ lcLightHistoryState lcLight::GetHistoryState([[maybe_unused]] const lcModel* Mod
return State;
}
void lcLight::SetHistoryState(const lcLightHistoryState& State, [[maybe_unused]] const lcModel* Model)
void lcLight::SetHistoryState(const lcLightHistoryState& State)
{
mId = State.Id;
mHidden = State.Hidden;
+2 -2
View File
@@ -197,8 +197,8 @@ public:
bool HasKeyFrame(lcObjectPropertyId PropertyId, lcStep Time) const override;
bool SetKeyFrame(lcObjectPropertyId PropertyId, lcStep Time, bool KeyFrame) override;
void RemoveKeyFrames() override;
lcLightHistoryState GetHistoryState(const lcModel* Model) const;
void SetHistoryState(const lcLightHistoryState& State, const lcModel* Model);
lcLightHistoryState GetHistoryState() const;
void SetHistoryState(const lcLightHistoryState& State);
void InsertTime(lcStep Start, lcStep Time);
void RemoveTime(lcStep Start, lcStep Time);
+5 -21
View File
@@ -988,7 +988,7 @@ void lcPiece::RemoveKeyFrames()
mRotation.RemoveAllKeys();
}
lcPieceHistoryState lcPiece::GetHistoryState(const lcModel* Model) const
lcPieceHistoryState lcPiece::GetHistoryState() const
{
lcPieceHistoryState State;
@@ -996,7 +996,7 @@ lcPieceHistoryState lcPiece::GetHistoryState(const lcModel* Model) const
State.Hidden = mHidden;
State.FileLine = mFileLine;
State.PieceId = mID;
State.GroupIndex = ~0U;
State.GroupId = mGroup ? static_cast<uint32_t>(mGroup->GetId()) : LC_GROUP_ID_INVALID;
State.ColorIndex = mColorIndex;
State.ColorCode = mColorCode;
State.StepShow = mStepShow;
@@ -1007,32 +1007,16 @@ lcPieceHistoryState lcPiece::GetHistoryState(const lcModel* Model) const
State.Position = mPosition;
State.Rotation = mRotation;
const std::vector<std::unique_ptr<lcGroup>>& Groups = Model->GetGroups();
if (mGroup)
{
for (size_t GroupIndex = 0; GroupIndex < Groups.size(); GroupIndex++)
{
if (mGroup == Groups[GroupIndex].get())
{
State.GroupIndex = static_cast<uint32_t>(GroupIndex);
break;
}
}
}
return State;
}
void lcPiece::SetHistoryState(const lcPieceHistoryState& State, const lcModel* Model)
void lcPiece::SetHistoryState(const lcPieceHistoryState& State, Project* Project, lcGroup* Group)
{
const std::vector<std::unique_ptr<lcGroup>>& Groups = Model->GetGroups();
mId = State.Id;
mHidden = State.Hidden;
mFileLine = State.FileLine;
mID = State.PieceId;
mGroup = (State.GroupIndex < Groups.size()) ? Groups[State.GroupIndex].get() : nullptr;
mGroup = Group;
mColorIndex = State.ColorIndex;
mColorCode = State.ColorCode;
mStepShow = State.StepShow;
@@ -1043,7 +1027,7 @@ void lcPiece::SetHistoryState(const lcPieceHistoryState& State, const lcModel* M
mPosition = State.Position;
mRotation = State.Rotation;
lcPieceDataRef RestoredData = lcGetPiecesLibrary()->AcquirePieceData(mID.toLatin1(), Model->GetProject(), true, true);
lcPieceDataRef RestoredData = lcGetPiecesLibrary()->AcquirePieceData(mID.toLatin1(), Project, true, true);
if (mPieceData != RestoredData)
{
+4 -4
View File
@@ -35,7 +35,7 @@ struct lcPieceHistoryState
bool Hidden;
int FileLine;
QString PieceId;
uint32_t GroupIndex;
uint32_t GroupId;
int ColorIndex;
quint32 ColorCode;
lcStep StepShow;
@@ -49,7 +49,7 @@ struct lcPieceHistoryState
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 &&
GroupId == Other.GroupId && 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;
@@ -95,8 +95,8 @@ public:
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);
lcPieceHistoryState GetHistoryState() const;
void SetHistoryState(const lcPieceHistoryState& State, Project* Project, lcGroup* Group);
void AddMainModelRenderMeshes(lcScene* Scene, bool Highlight, bool Fade) const;
void AddSubModelRenderMeshes(lcScene* Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const;
+1
View File
@@ -304,6 +304,7 @@ HEADERS += \
common/lc_minifigdialog.h \
common/lc_model.h \
common/lc_modellistdialog.h \
common/lc_objecthistory.h \
common/lc_objectproperty.h \
common/lc_pagesetupdialog.h \
common/lc_partpalettedialog.h \