keyframes: implemented copying/pasting

This commit is contained in:
itsmattkc
2022-05-10 15:42:09 -07:00
parent af9e54504c
commit 182e1599af
24 changed files with 567 additions and 160 deletions
+5
View File
@@ -41,6 +41,11 @@ NodeKeyframe::NodeKeyframe(const rational &time, const QVariant &value, Type typ
setParent(parent);
}
NodeKeyframe::NodeKeyframe()
{
type_ = NodeKeyframe::kLinear;
}
NodeKeyframe::~NodeKeyframe()
{
setParent(nullptr);
+8 -12
View File
@@ -64,6 +64,7 @@ public:
* @brief NodeKeyframe Constructor
*/
NodeKeyframe(const rational& time, const QVariant& value, Type type, int track, int element, const QString& input, QObject* parent = nullptr);
NodeKeyframe();
virtual ~NodeKeyframe() override;
@@ -71,10 +72,9 @@ public:
NodeKeyframe* copy(QObject* parent = nullptr) const;
Node* parent() const;
const QString& input() const
{
return input_;
}
const QString& input() const { return input_; }
void set_input(const QString& input) { input_ = input; }
NodeKeyframeTrackReference key_track_ref() const
{
@@ -141,15 +141,11 @@ public:
* For the majority of keyfreames, this will be 0, but for some types, such as kVec2, this will be 0 for X keyframes
* and 1 for Y keyframes, etc.
*/
int track() const
{
return track_;
}
int track() const { return track_; }
void set_track(int t) { track_ = t; }
int element() const
{
return element_;
}
int element() const { return element_; }
void set_element(int e) { element_ = e; }
/**
* @brief Convenience function for getting the opposite handle type (e.g. kInHandle <-> kOutHandle)
+9 -1
View File
@@ -55,6 +55,7 @@ public:
};
using SerializedProperties = QHash<Node*, QMap<QString, QString> >;
using SerializedKeyframes = QHash<QString, QVector<NodeKeyframe*> >;
class LoadData
{
@@ -65,6 +66,8 @@ public:
std::vector<TimelineMarker*> markers;
SerializedKeyframes keyframes;
};
class Result
@@ -105,7 +108,7 @@ public:
class SaveData
{
public:
SaveData(Project *project, const QString &filename = QString())
SaveData(Project *project = nullptr, const QString &filename = QString())
{
project_ = project;
filename_ = filename;
@@ -128,6 +131,9 @@ public:
const std::vector<TimelineMarker*> &GetOnlySerializeMarkers() const { return only_serialize_markers_; }
void SetOnlySerializeMarkers(const std::vector<TimelineMarker*> &only) { only_serialize_markers_ = only; }
const std::vector<NodeKeyframe*> &GetOnlySerializeKeyframes() const { return only_serialize_keyframes_; }
void SetOnlySerializeKeyframes(const std::vector<NodeKeyframe*> &only) { only_serialize_keyframes_ = only; }
const SerializedProperties &GetProperties() const { return properties_; }
void SetProperties(const SerializedProperties &p) { properties_ = p; }
@@ -142,6 +148,8 @@ public:
std::vector<TimelineMarker*> only_serialize_markers_;
std::vector<NodeKeyframe*> only_serialize_keyframes_;
};
static void Initialize();
+210 -46
View File
@@ -99,6 +99,102 @@ ProjectSerializer220403::LoadData ProjectSerializer220403::Load(Project *project
}
}
} else if (reader->name() == QStringLiteral("keyframes")) {
while (XMLReadNextStartElement(reader)) {
if (reader->name() == QStringLiteral("node")) {
QString node_id;
XMLAttributeLoop(reader, attr) {
if (attr.name() == QStringLiteral("id")) {
node_id = attr.value().toString();
break;
}
}
Node *n = nullptr;
if (!node_id.isEmpty()) {
n = NodeFactory::CreateFromID(node_id);
}
if (!n) {
reader->skipCurrentElement();
} else {
while (XMLReadNextStartElement(reader)) {
if (reader->name() == QStringLiteral("input")) {
QString input_id;
XMLAttributeLoop(reader, attr) {
if (attr.name() == QStringLiteral("id")) {
input_id = attr.value().toString();
break;
}
}
if (input_id.isEmpty()) {
reader->skipCurrentElement();
} else {
while (XMLReadNextStartElement(reader)) {
if (reader->name() == QStringLiteral("element")) {
QString element_id;
XMLAttributeLoop(reader, attr) {
if (attr.name() == QStringLiteral("id")) {
element_id = attr.value().toString();
break;
}
}
if (element_id.isEmpty()) {
reader->skipCurrentElement();
} else {
while (XMLReadNextStartElement(reader)) {
if (reader->name() == QStringLiteral("track")) {
QString track_id;
XMLAttributeLoop(reader, attr) {
if (attr.name() == QStringLiteral("id")) {
track_id = attr.value().toString();
break;
}
}
if (track_id.isEmpty()) {
reader->skipCurrentElement();
} else {
while (XMLReadNextStartElement(reader)) {
if (reader->name() == QStringLiteral("key")) {
NodeKeyframe *key = new NodeKeyframe();
key->set_input(input_id);
key->set_element(element_id.toInt());
key->set_track(track_id.toInt());
LoadKeyframe(reader, key, n->GetInputDataType(input_id));
load_data.keyframes[node_id].append(key);
} else {
reader->skipCurrentElement();
}
}
}
} else {
reader->skipCurrentElement();
}
}
}
} else {
reader->skipCurrentElement();
}
}
}
} else {
reader->skipCurrentElement();
}
}
}
delete n;
} else {
reader->skipCurrentElement();
}
}
} else if (reader->name() == QStringLiteral("markers")) {
while (XMLReadNextStartElement(reader)) {
@@ -221,8 +317,6 @@ ProjectSerializer220403::LoadData ProjectSerializer220403::Load(Project *project
void ProjectSerializer220403::Save(QXmlStreamWriter *writer, const SaveData &data, void *reserved) const
{
Project *project = data.GetProject();
if (!data.GetOnlySerializeMarkers().empty()) {
writer->writeStartElement(QStringLiteral("markers"));
@@ -239,9 +333,63 @@ void ProjectSerializer220403::Save(QXmlStreamWriter *writer, const SaveData &dat
writer->writeEndElement(); // markers
} else {
} else if (!data.GetOnlySerializeKeyframes().empty()) {
writer->writeTextElement(QStringLiteral("uuid"), data.GetProject()->GetUuid().toString());
writer->writeStartElement(QStringLiteral("keyframes"));
// Organize keyframes into node+input
QHash<QString, QHash<QString, QMap<int, QMap<int, QVector<NodeKeyframe*> > > > > organized;
for (auto it=data.GetOnlySerializeKeyframes().cbegin(); it!=data.GetOnlySerializeKeyframes().cend(); it++) {
NodeKeyframe *key = *it;
organized[key->parent()->id()][key->input()][key->element()][key->track()].append(key);
}
for (auto it=organized.cbegin(); it!=organized.cend(); it++) {
writer->writeStartElement(QStringLiteral("node"));
writer->writeAttribute(QStringLiteral("id"), it.key());
for (auto jt=it.value().cbegin(); jt!=it.value().cend(); jt++) {
writer->writeStartElement(QStringLiteral("input"));
writer->writeAttribute(QStringLiteral("id"), jt.key());
for (auto kt=jt.value().cbegin(); kt!=jt.value().cend(); kt++) {
writer->writeStartElement(QStringLiteral("element"));
writer->writeAttribute(QStringLiteral("id"), QString::number(kt.key()));
for (auto lt=kt.value().cbegin(); lt!=kt.value().cend(); lt++) {
const QVector<NodeKeyframe *> &keys = lt.value();
writer->writeStartElement(QStringLiteral("track"));
writer->writeAttribute(QStringLiteral("id"), QString::number(lt.key()));
for (NodeKeyframe *key : keys) {
writer->writeStartElement(QStringLiteral("key"));
SaveKeyframe(writer, key, key->parent()->GetInputDataType(key->input()));
writer->writeEndElement(); // key
}
writer->writeEndElement(); // track
}
writer->writeEndElement(); // element
}
writer->writeEndElement(); // input
}
writer->writeEndElement(); // node;
}
writer->writeEndElement(); // keyframes
} else if (Project *project = data.GetProject()) {
writer->writeTextElement(QStringLiteral("uuid"), project->GetUuid().toString());
writer->writeStartElement(QStringLiteral("nodes"));
@@ -310,6 +458,10 @@ void ProjectSerializer220403::Save(QXmlStreamWriter *writer, const SaveData &dat
// Save main window project layout
project->GetLayoutInfo().toXml(writer);
} else {
qCritical() << "Cannot save nodes without project object";
}
}
@@ -601,40 +753,13 @@ void ProjectSerializer220403::LoadImmediate(QXmlStreamReader *reader, Node *node
}
if (reader->name() == QStringLiteral("key")) {
QString key_input;
rational key_time;
NodeKeyframe::Type key_type = NodeKeyframe::kLinear;
QVariant key_value;
QPointF key_in_handle;
QPointF key_out_handle;
NodeKeyframe* key = new NodeKeyframe();
key->set_input(input);
key->set_element(element);
key->set_track(track);
XMLAttributeLoop(reader, attr) {
if (IsCancelled()) {
return;
}
if (attr.name() == QStringLiteral("input")) {
key_input = attr.value().toString();
} else if (attr.name() == QStringLiteral("time")) {
key_time = rational::fromString(attr.value().toString());
} else if (attr.name() == QStringLiteral("type")) {
key_type = static_cast<NodeKeyframe::Type>(attr.value().toInt());
} else if (attr.name() == QStringLiteral("inhandlex")) {
key_in_handle.setX(attr.value().toDouble());
} else if (attr.name() == QStringLiteral("inhandley")) {
key_in_handle.setY(attr.value().toDouble());
} else if (attr.name() == QStringLiteral("outhandlex")) {
key_out_handle.setX(attr.value().toDouble());
} else if (attr.name() == QStringLiteral("outhandley")) {
key_out_handle.setY(attr.value().toDouble());
}
}
key_value = NodeValue::StringToValue(data_type, reader->readElementText(), true);
NodeKeyframe* key = new NodeKeyframe(key_time, key_value, key_type, track, element, key_input, node);
key->set_bezier_control_in(key_in_handle);
key->set_bezier_control_out(key_out_handle);
LoadKeyframe(reader, key, data_type);
key->setParent(node);
} else {
reader->skipCurrentElement();
}
@@ -695,15 +820,7 @@ void ProjectSerializer220403::SaveImmediate(QXmlStreamWriter *writer, Node *node
for (NodeKeyframe* key : track) {
writer->writeStartElement(QStringLiteral("key"));
writer->writeAttribute(QStringLiteral("input"), key->input());
writer->writeAttribute(QStringLiteral("time"), key->time().toString());
writer->writeAttribute(QStringLiteral("type"), QString::number(key->type()));
writer->writeAttribute(QStringLiteral("inhandlex"), QString::number(key->bezier_control_in().x()));
writer->writeAttribute(QStringLiteral("inhandley"), QString::number(key->bezier_control_in().y()));
writer->writeAttribute(QStringLiteral("outhandlex"), QString::number(key->bezier_control_out().x()));
writer->writeAttribute(QStringLiteral("outhandley"), QString::number(key->bezier_control_out().y()));
writer->writeCharacters(NodeValue::ValueToString(data_type, key->value(), true));
SaveKeyframe(writer, key, data_type);
writer->writeEndElement(); // key
}
@@ -722,6 +839,53 @@ void ProjectSerializer220403::SaveImmediate(QXmlStreamWriter *writer, Node *node
}
}
void ProjectSerializer220403::LoadKeyframe(QXmlStreamReader *reader, NodeKeyframe *key, NodeValue::Type data_type) const
{
QString key_input;
QPointF key_in_handle;
QPointF key_out_handle;
XMLAttributeLoop(reader, attr) {
if (IsCancelled()) {
return;
}
if (attr.name() == QStringLiteral("input")) {
key_input = attr.value().toString();
} else if (attr.name() == QStringLiteral("time")) {
key->set_time(rational::fromString(attr.value().toString()));
} else if (attr.name() == QStringLiteral("type")) {
key->set_type(static_cast<NodeKeyframe::Type>(attr.value().toInt()));
} else if (attr.name() == QStringLiteral("inhandlex")) {
key_in_handle.setX(attr.value().toDouble());
} else if (attr.name() == QStringLiteral("inhandley")) {
key_in_handle.setY(attr.value().toDouble());
} else if (attr.name() == QStringLiteral("outhandlex")) {
key_out_handle.setX(attr.value().toDouble());
} else if (attr.name() == QStringLiteral("outhandley")) {
key_out_handle.setY(attr.value().toDouble());
}
}
key->set_value(NodeValue::StringToValue(data_type, reader->readElementText(), true));
key->set_bezier_control_in(key_in_handle);
key->set_bezier_control_out(key_out_handle);
}
void ProjectSerializer220403::SaveKeyframe(QXmlStreamWriter *writer, NodeKeyframe *key, NodeValue::Type data_type) const
{
writer->writeAttribute(QStringLiteral("input"), key->input());
writer->writeAttribute(QStringLiteral("time"), key->time().toString());
writer->writeAttribute(QStringLiteral("type"), QString::number(key->type()));
writer->writeAttribute(QStringLiteral("inhandlex"), QString::number(key->bezier_control_in().x()));
writer->writeAttribute(QStringLiteral("inhandley"), QString::number(key->bezier_control_in().y()));
writer->writeAttribute(QStringLiteral("outhandlex"), QString::number(key->bezier_control_out().x()));
writer->writeAttribute(QStringLiteral("outhandley"), QString::number(key->bezier_control_out().y()));
writer->writeCharacters(NodeValue::ValueToString(data_type, key->value(), true));
}
bool ProjectSerializer220403::LoadPosition(QXmlStreamReader *reader, quintptr *node_ptr, Node::Position *pos) const
{
bool got_node_ptr = false;
@@ -86,6 +86,10 @@ private:
void SaveImmediate(QXmlStreamWriter *writer, Node *node, const QString &input, int element) const;
void LoadKeyframe(QXmlStreamReader *reader, NodeKeyframe *key, NodeValue::Type data_type) const;
void SaveKeyframe(QXmlStreamWriter *writer, NodeKeyframe *key, NodeValue::Type data_type) const;
bool LoadPosition(QXmlStreamReader *reader, quintptr *node_ptr, Node::Position *pos) const;
void SavePosition(QXmlStreamWriter *writer, Node *node, const Node::Position &pos) const;