Merge branch 'master' into gizmos
This commit is contained in:
@@ -234,6 +234,18 @@ void Block::SaveInternal(QXmlStreamWriter *writer) const
|
||||
}
|
||||
}
|
||||
|
||||
QList<NodeInput *> Block::GetInputsToHash() const
|
||||
{
|
||||
QList<NodeInput*> inputs = Node::GetInputsToHash();
|
||||
|
||||
// Ignore these inputs
|
||||
inputs.removeOne(media_in_input_);
|
||||
inputs.removeOne(speed_input_);
|
||||
inputs.removeOne(length_input_);
|
||||
|
||||
return inputs;
|
||||
}
|
||||
|
||||
void Block::LengthInputChanged()
|
||||
{
|
||||
emit LengthChanged(length());
|
||||
|
||||
@@ -126,6 +126,8 @@ protected:
|
||||
|
||||
virtual void SaveInternal(QXmlStreamWriter* writer) const override;
|
||||
|
||||
virtual QList<NodeInput*> GetInputsToHash() const override;
|
||||
|
||||
Block* previous_;
|
||||
Block* next_;
|
||||
|
||||
|
||||
@@ -40,6 +40,11 @@ QString ExternalTransition::Name() const
|
||||
return meta_.Name();
|
||||
}
|
||||
|
||||
QString ExternalTransition::ShortName() const
|
||||
{
|
||||
return meta_.ShortName();
|
||||
}
|
||||
|
||||
QString ExternalTransition::id() const
|
||||
{
|
||||
return meta_.id();
|
||||
|
||||
@@ -35,6 +35,7 @@ public:
|
||||
virtual Node* copy() const override;
|
||||
|
||||
virtual QString Name() const override;
|
||||
virtual QString ShortName() const override;
|
||||
virtual QString id() const override;
|
||||
virtual QString Category() const override;
|
||||
virtual QString Description() const override;
|
||||
|
||||
@@ -129,6 +129,19 @@ double TransitionBlock::GetInProgress(const rational &time) const
|
||||
return clamp((GetInternalTransitionTime(time) - out_offset().toDouble()) / in_offset().toDouble(), 0.0, 1.0);
|
||||
}
|
||||
|
||||
void TransitionBlock::Hash(QCryptographicHash &hash, const rational &time) const
|
||||
{
|
||||
Block::Hash(hash, time);
|
||||
|
||||
double all_prog = GetTotalProgress(time);
|
||||
double in_prog = GetInProgress(time);
|
||||
double out_prog = GetOutProgress(time);
|
||||
|
||||
hash.addData(reinterpret_cast<const char*>(&all_prog), sizeof(double));
|
||||
hash.addData(reinterpret_cast<const char*>(&in_prog), sizeof(double));
|
||||
hash.addData(reinterpret_cast<const char*>(&out_prog), sizeof(double));
|
||||
}
|
||||
|
||||
double TransitionBlock::GetInternalTransitionTime(const rational &time) const
|
||||
{
|
||||
return time.toDouble() - in().toDouble();
|
||||
|
||||
@@ -47,6 +47,8 @@ public:
|
||||
double GetOutProgress(const rational& time) const;
|
||||
double GetInProgress(const rational& time) const;
|
||||
|
||||
virtual void Hash(QCryptographicHash& hash, const rational &time) const override;
|
||||
|
||||
private:
|
||||
double GetInternalTransitionTime(const rational& time) const;
|
||||
|
||||
|
||||
@@ -42,6 +42,11 @@ QString ExternalNode::Name() const
|
||||
return meta_.Name();
|
||||
}
|
||||
|
||||
QString ExternalNode::ShortName() const
|
||||
{
|
||||
return meta_.ShortName();
|
||||
}
|
||||
|
||||
QString ExternalNode::id() const
|
||||
{
|
||||
return meta_.id();
|
||||
|
||||
@@ -39,6 +39,7 @@ public:
|
||||
virtual Node* copy() const override;
|
||||
|
||||
virtual QString Name() const override;
|
||||
virtual QString ShortName() const override;
|
||||
virtual QString id() const override;
|
||||
virtual QString Category() const override;
|
||||
virtual QString Description() const override;
|
||||
|
||||
@@ -59,6 +59,11 @@ QString MatrixGenerator::Name() const
|
||||
return tr("Orthographic Matrix");
|
||||
}
|
||||
|
||||
QString MatrixGenerator::ShortName() const
|
||||
{
|
||||
return tr("Ortho");
|
||||
}
|
||||
|
||||
QString MatrixGenerator::id() const
|
||||
{
|
||||
return QStringLiteral("org.olivevideoeditor.Olive.transform");
|
||||
|
||||
@@ -34,6 +34,7 @@ public:
|
||||
virtual Node* copy() const override;
|
||||
|
||||
virtual QString Name() const override;
|
||||
virtual QString ShortName() const override;
|
||||
virtual QString id() const override;
|
||||
virtual QString Category() const override;
|
||||
virtual QString Description() const override;
|
||||
|
||||
@@ -737,6 +737,19 @@ void NodeInput::remove_keyframe(NodeKeyframePtr key)
|
||||
emit_time_range(time_affected);
|
||||
}
|
||||
|
||||
NodeKeyframePtr NodeInput::get_keyframe_shared_ptr_from_raw(NodeKeyframe* raw) const
|
||||
{
|
||||
foreach (const KeyframeTrack& track, keyframe_tracks_) {
|
||||
foreach (NodeKeyframePtr key, track) {
|
||||
if (key.get() == raw) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void NodeInput::KeyframeTimeChanged()
|
||||
{
|
||||
NodeKeyframe* key = static_cast<NodeKeyframe*>(sender());
|
||||
|
||||
+6
-1
@@ -172,6 +172,11 @@ public:
|
||||
*/
|
||||
void remove_keyframe(NodeKeyframePtr key);
|
||||
|
||||
/**
|
||||
* @brief Hacky convenience function to turn a raw pointer into a shared pointer
|
||||
*/
|
||||
NodeKeyframePtr get_keyframe_shared_ptr_from_raw(NodeKeyframe *raw) const;
|
||||
|
||||
/**
|
||||
* @brief Return whether a keyframe exists at this time
|
||||
*
|
||||
@@ -279,7 +284,7 @@ public:
|
||||
QList<Node*> GetImmediateDependencies() const;
|
||||
|
||||
signals:
|
||||
void ValueChanged(const TimeRange& range);
|
||||
void ValueChanged(const OLIVE_NAMESPACE::TimeRange& range);
|
||||
|
||||
void KeyframeEnableChanged(bool);
|
||||
|
||||
|
||||
@@ -62,4 +62,12 @@ NodeValueTable TimeInput::Value(NodeValueDatabase &value) const
|
||||
return table;
|
||||
}
|
||||
|
||||
void TimeInput::Hash(QCryptographicHash &hash, const rational &time) const
|
||||
{
|
||||
Node::Hash(hash, time);
|
||||
|
||||
// Make sure time is hashed
|
||||
hash.addData(NodeParam::ValueToBytes(NodeParam::kRational, QVariant::fromValue(time)));
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -40,6 +40,8 @@ public:
|
||||
|
||||
virtual NodeValueTable Value(NodeValueDatabase& value) const override;
|
||||
|
||||
virtual void Hash(QCryptographicHash& hash, const rational& time) const override;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -57,6 +57,15 @@ QString NodeMetaReader::Name() const
|
||||
return GetStringForCurrentLanguage(&names_);
|
||||
}
|
||||
|
||||
QString NodeMetaReader::ShortName() const
|
||||
{
|
||||
if (short_names_.isEmpty()) {
|
||||
return Name();
|
||||
} else {
|
||||
return GetStringForCurrentLanguage(&short_names_);
|
||||
}
|
||||
}
|
||||
|
||||
const QString &NodeMetaReader::id() const
|
||||
{
|
||||
return id_;
|
||||
@@ -173,6 +182,9 @@ void NodeMetaReader::XMLReadEffect(QXmlStreamReader* reader)
|
||||
if (reader->name() == QStringLiteral("name")) {
|
||||
// Pick up name
|
||||
XMLReadLanguageString(reader, &names_);
|
||||
} else if (reader->name() == QStringLiteral("shortnames")) {
|
||||
// Pick up short name
|
||||
XMLReadLanguageString(reader, &short_names_);
|
||||
} else if (reader->name() == QStringLiteral("category")) {
|
||||
// Pick up category
|
||||
XMLReadLanguageString(reader, &categories_);
|
||||
|
||||
@@ -35,6 +35,7 @@ public:
|
||||
NodeMetaReader(const QString& xml_meta_filename);
|
||||
|
||||
QString Name() const;
|
||||
QString ShortName() const;
|
||||
const QString& id() const;
|
||||
QString Category() const;
|
||||
QString Description() const;
|
||||
@@ -67,6 +68,7 @@ private:
|
||||
QString xml_filename_;
|
||||
|
||||
LanguageMap names_;
|
||||
LanguageMap short_names_;
|
||||
LanguageMap descriptions_;
|
||||
LanguageMap categories_;
|
||||
QMap<QString, LanguageMap > param_names_;
|
||||
|
||||
+103
-1
@@ -25,6 +25,9 @@
|
||||
#include <QFile>
|
||||
|
||||
#include "common/xmlutils.h"
|
||||
#include "project/project.h"
|
||||
#include "project/item/footage/footage.h"
|
||||
#include "project/item/footage/imagestream.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
@@ -103,6 +106,13 @@ void Node::Save(QXmlStreamWriter *writer, const QString &custom_name) const
|
||||
|
||||
writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(this)));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("pos"),
|
||||
QStringLiteral("%1:%2").arg(QString::number(GetPosition().x()),
|
||||
QString::number(GetPosition().y())));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("label"),
|
||||
GetLabel());
|
||||
|
||||
foreach (NodeParam* param, parameters()) {
|
||||
param->Save(writer);
|
||||
}
|
||||
@@ -112,6 +122,11 @@ void Node::Save(QXmlStreamWriter *writer, const QString &custom_name) const
|
||||
writer->writeEndElement(); // node
|
||||
}
|
||||
|
||||
QString Node::ShortName() const
|
||||
{
|
||||
return Name();
|
||||
}
|
||||
|
||||
QString Node::Category() const
|
||||
{
|
||||
// Return an empty category for any nodes that don't use one
|
||||
@@ -220,6 +235,11 @@ void Node::SaveInternal(QXmlStreamWriter *) const
|
||||
{
|
||||
}
|
||||
|
||||
QList<NodeInput *> Node::GetInputsToHash() const
|
||||
{
|
||||
return GetInputsIncludingArrays();
|
||||
}
|
||||
|
||||
QString Node::ReadFileAsString(const QString &filename)
|
||||
{
|
||||
QFile f(filename);
|
||||
@@ -277,6 +297,83 @@ void Node::DrawGizmos(QPainter *, const QRect &) const
|
||||
{
|
||||
}
|
||||
|
||||
const QString &Node::GetLabel() const
|
||||
{
|
||||
return label_;
|
||||
}
|
||||
|
||||
void Node::SetLabel(const QString &s)
|
||||
{
|
||||
if (label_ != s) {
|
||||
label_ = s;
|
||||
|
||||
emit LabelChanged(label_);
|
||||
}
|
||||
}
|
||||
|
||||
void Node::Hash(QCryptographicHash &hash, const rational& time) const
|
||||
{
|
||||
// Add this Node's ID
|
||||
hash.addData(id().toUtf8());
|
||||
|
||||
QList<NodeInput*> inputs = GetInputsToHash();
|
||||
|
||||
foreach (NodeInput* input, inputs) {
|
||||
// For each input, try to hash its value
|
||||
|
||||
// Get time adjustment
|
||||
// For a single frame, we only care about one of the times
|
||||
rational input_time = InputTimeAdjustment(input, TimeRange(time, time)).in();
|
||||
|
||||
if (input->IsConnected()) {
|
||||
// Traverse down this edge
|
||||
input->get_connected_node()->Hash(hash, input_time);
|
||||
} else {
|
||||
// Grab the value at this time
|
||||
QVariant value = input->get_value_at_time(input_time);
|
||||
hash.addData(NodeParam::ValueToBytes(input->data_type(), value));
|
||||
}
|
||||
|
||||
// We have one exception for FOOTAGE types, since we resolve the footage into a frame in the renderer
|
||||
if (input->data_type() == NodeParam::kFootage) {
|
||||
StreamPtr stream = input->get_standard_value().value<StreamPtr>();
|
||||
|
||||
if (stream) {
|
||||
// Add footage details to hash
|
||||
|
||||
// Footage filename
|
||||
hash.addData(stream->footage()->filename().toUtf8());
|
||||
|
||||
// Footage last modified date
|
||||
hash.addData(stream->footage()->timestamp().toString().toUtf8());
|
||||
|
||||
// Footage stream
|
||||
hash.addData(QString::number(stream->index()).toUtf8());
|
||||
|
||||
if (stream->type() == Stream::kImage || stream->type() == Stream::kVideo) {
|
||||
ImageStreamPtr image_stream = std::static_pointer_cast<ImageStream>(stream);
|
||||
|
||||
// Current color config and space
|
||||
hash.addData(image_stream->footage()->project()->color_manager()->GetConfigFilename().toUtf8());
|
||||
hash.addData(image_stream->colorspace().toUtf8());
|
||||
|
||||
// Alpha associated setting
|
||||
hash.addData(QString::number(image_stream->premultiplied_alpha()).toUtf8());
|
||||
}
|
||||
|
||||
// Footage timestamp
|
||||
if (stream->type() == Stream::kVideo) {
|
||||
hash.addData(QStringLiteral("%1/%2").arg(QString::number(input_time.numerator()),
|
||||
QString::number(input_time.denominator())).toUtf8());
|
||||
|
||||
hash.addData(QString::number(static_cast<VideoStream*>(stream.get())->start_time()).toUtf8());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Node::CopyInputs(Node *source, Node *destination, bool include_connections)
|
||||
{
|
||||
Q_ASSERT(source->id() == destination->id());
|
||||
@@ -295,6 +392,9 @@ void Node::CopyInputs(Node *source, Node *destination, bool include_connections)
|
||||
NodeInput::CopyValues(src, dst, include_connections);
|
||||
}
|
||||
}
|
||||
|
||||
destination->SetPosition(source->GetPosition());
|
||||
destination->SetLabel(source->GetLabel());
|
||||
}
|
||||
|
||||
bool Node::CanBeDeleted() const
|
||||
@@ -559,7 +659,7 @@ NodeValue Node::InputValueFromTable(NodeInput *input, NodeValueDatabase &db, boo
|
||||
}
|
||||
}
|
||||
|
||||
const QPointF &Node::GetPosition()
|
||||
const QPointF &Node::GetPosition() const
|
||||
{
|
||||
return position_;
|
||||
}
|
||||
@@ -567,6 +667,8 @@ const QPointF &Node::GetPosition()
|
||||
void Node::SetPosition(const QPointF &pos)
|
||||
{
|
||||
position_ = pos;
|
||||
|
||||
emit PositionChanged(position_);
|
||||
}
|
||||
|
||||
void Node::AddInput(NodeInput *input)
|
||||
|
||||
+31
-2
@@ -92,6 +92,13 @@ public:
|
||||
*/
|
||||
virtual QString Name() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Returns a shortened name of this node if applicable
|
||||
*
|
||||
* Defaults to returning Name() but can be overridden.
|
||||
*/
|
||||
virtual QString ShortName() const;
|
||||
|
||||
/**
|
||||
* @brief Return the unique identifier of the node
|
||||
*
|
||||
@@ -343,7 +350,7 @@ public:
|
||||
|
||||
virtual NodeValue InputValueFromTable(NodeInput* input, NodeValueDatabase &db, bool take) const;
|
||||
|
||||
const QPointF& GetPosition();
|
||||
const QPointF& GetPosition() const;
|
||||
|
||||
void SetPosition(const QPointF& pos);
|
||||
|
||||
@@ -357,6 +364,11 @@ public:
|
||||
|
||||
virtual void DrawGizmos(QPainter* p, const QRect &viewport) const;
|
||||
|
||||
const QString& GetLabel() const;
|
||||
void SetLabel(const QString& s);
|
||||
|
||||
virtual void Hash(QCryptographicHash& hash, const rational &time) const;
|
||||
|
||||
protected:
|
||||
void AddInput(NodeInput* input);
|
||||
|
||||
@@ -368,6 +380,8 @@ protected:
|
||||
|
||||
virtual void SaveInternal(QXmlStreamWriter* writer) const;
|
||||
|
||||
virtual QList<NodeInput*> GetInputsToHash() const;
|
||||
|
||||
public slots:
|
||||
|
||||
signals:
|
||||
@@ -389,6 +403,16 @@ signals:
|
||||
*/
|
||||
void EdgeRemoved(NodeEdgePtr edge);
|
||||
|
||||
/**
|
||||
* @brief Signal emitted whenever the position is set through SetPosition()
|
||||
*/
|
||||
void PositionChanged(const QPointF& pos);
|
||||
|
||||
/**
|
||||
* @brief Signal emitted when SetLabel() is called
|
||||
*/
|
||||
void LabelChanged(const QString& s);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Add a parameter to this node
|
||||
@@ -424,8 +448,13 @@ private:
|
||||
*/
|
||||
QPointF position_;
|
||||
|
||||
/**
|
||||
* @brief Custom user label for node
|
||||
*/
|
||||
QString label_;
|
||||
|
||||
private slots:
|
||||
void InputChanged(const TimeRange &range);
|
||||
void InputChanged(const OLIVE_NAMESPACE::TimeRange &range);
|
||||
|
||||
void InputConnectionChanged(NodeEdgePtr edge);
|
||||
|
||||
|
||||
@@ -418,6 +418,16 @@ NodeInputArray *TrackOutput::block_input() const
|
||||
return block_input_;
|
||||
}
|
||||
|
||||
void TrackOutput::Hash(QCryptographicHash &hash, const rational &time) const
|
||||
{
|
||||
// Resolve block list
|
||||
Block* b = BlockAtTime(time);
|
||||
|
||||
if (b) {
|
||||
return b->Hash(hash, time);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackOutput::SetTrackName(const QString &name)
|
||||
{
|
||||
track_name_ = name;
|
||||
@@ -556,9 +566,7 @@ void TrackOutput::BlockDisconnected(NodeEdgePtr edge)
|
||||
block_cache_.removeAt(index_of_block);
|
||||
|
||||
// If there were blocks following this one, update their ins/outs
|
||||
if (index_of_block < block_cache_.size()) {
|
||||
UpdateInOutFrom(index_of_block);
|
||||
}
|
||||
UpdateInOutFrom(index_of_block);
|
||||
|
||||
// Join the previous and next blocks together
|
||||
if (connected_block->previous()) {
|
||||
|
||||
@@ -152,6 +152,8 @@ public:
|
||||
|
||||
NodeInputArray* block_input() const;
|
||||
|
||||
virtual void Hash(QCryptographicHash& hash, const rational &time) const override;
|
||||
|
||||
public slots:
|
||||
void SetTrackName(const QString& name);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user