Merge branch 'master' into rational_slider
This commit is contained in:
+45
-30
@@ -32,6 +32,7 @@ const QString Block::kLengthInput = QStringLiteral("length_in");
|
||||
const QString Block::kMediaInInput = QStringLiteral("media_in_in");
|
||||
const QString Block::kEnabledInput = QStringLiteral("enabled_in");
|
||||
const QString Block::kSpeedInput = QStringLiteral("speed_in");
|
||||
const QString Block::kReverseInput = QStringLiteral("reverse_in");
|
||||
|
||||
Block::Block() :
|
||||
previous_(nullptr),
|
||||
@@ -51,10 +52,14 @@ Block::Block() :
|
||||
|
||||
AddInput(kEnabledInput, NodeValue::kBoolean, true, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
|
||||
|
||||
AddInput(kSpeedInput, NodeValue::kFloat, 1.0);
|
||||
AddInput(kSpeedInput, NodeValue::kFloat, 1.0, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
|
||||
SetInputProperty(kSpeedInput, QStringLiteral("view"), FloatSlider::kPercentage);
|
||||
SetInputProperty(kSpeedInput, QStringLiteral("min"), 0.0);
|
||||
IgnoreHashingFrom(kSpeedInput);
|
||||
|
||||
AddInput(kReverseInput, NodeValue::kBoolean, false, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
|
||||
IgnoreHashingFrom(kReverseInput);
|
||||
|
||||
// A block's length must be greater than 0
|
||||
set_length_and_media_out(1);
|
||||
}
|
||||
@@ -77,6 +82,11 @@ void Block::set_length_and_media_out(const rational &length)
|
||||
return;
|
||||
}
|
||||
|
||||
if (reverse()) {
|
||||
// Calculate media_in adjustment
|
||||
set_media_in(SequenceToMediaTime(length - this->length(), true));
|
||||
}
|
||||
|
||||
set_length_internal(length);
|
||||
}
|
||||
|
||||
@@ -88,8 +98,10 @@ void Block::set_length_and_media_in(const rational &length)
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate media_in adjustment
|
||||
set_media_in(SequenceToMediaTime(this->length() - length));
|
||||
if (!reverse()) {
|
||||
// Calculate media_in adjustment
|
||||
set_media_in(SequenceToMediaTime(this->length() - length));
|
||||
}
|
||||
|
||||
// Set the length without setting media out
|
||||
set_length_internal(length);
|
||||
@@ -117,7 +129,7 @@ void Block::set_enabled(bool e)
|
||||
emit EnabledChanged();
|
||||
}
|
||||
|
||||
rational Block::SequenceToMediaTime(const rational &sequence_time) const
|
||||
rational Block::SequenceToMediaTime(const rational &sequence_time, bool ignore_reverse) const
|
||||
{
|
||||
// These constants are not considered "values" per se, so we don't modify them
|
||||
if (sequence_time == RATIONAL_MIN || sequence_time == RATIONAL_MAX) {
|
||||
@@ -126,22 +138,23 @@ rational Block::SequenceToMediaTime(const rational &sequence_time) const
|
||||
|
||||
rational local_time = sequence_time;
|
||||
|
||||
// FIXME: Doesn't handle reversing
|
||||
if (IsInputStatic(kSpeedInput)) {
|
||||
double speed_value = GetStandardValue(kSpeedInput).toDouble();
|
||||
double speed_value = speed();
|
||||
|
||||
if (qIsNull(speed_value)) {
|
||||
// Effectively holds the frame at the in point
|
||||
local_time = 0;
|
||||
} else if (!qFuzzyCompare(speed_value, 1.0)) {
|
||||
// Multiply time
|
||||
local_time = rational::fromDouble(local_time.toDouble() * speed_value);
|
||||
}
|
||||
} else {
|
||||
// FIXME: We'll need to calculate the speed hoo boy
|
||||
if (qIsNull(speed_value)) {
|
||||
// Effectively holds the frame at the in point
|
||||
local_time = 0;
|
||||
} else if (!qFuzzyCompare(speed_value, 1.0)) {
|
||||
// Multiply time
|
||||
local_time = rational::fromDouble(local_time.toDouble() * speed_value);
|
||||
}
|
||||
|
||||
return local_time + media_in();
|
||||
rational media_time = local_time + media_in();
|
||||
|
||||
if (reverse() && !ignore_reverse) {
|
||||
media_time = length() - media_time;
|
||||
}
|
||||
|
||||
return media_time;
|
||||
}
|
||||
|
||||
rational Block::MediaToSequenceTime(const rational &media_time) const
|
||||
@@ -151,21 +164,22 @@ rational Block::MediaToSequenceTime(const rational &media_time) const
|
||||
return media_time;
|
||||
}
|
||||
|
||||
rational sequence_time = media_time - media_in();
|
||||
rational sequence_time = media_time;
|
||||
|
||||
// FIXME: Doesn't handle reversing
|
||||
if (IsInputKeyframing(kSpeedInput) || IsInputConnected(kSpeedInput)) {
|
||||
// FIXME: We'll need to calculate the speed hoo boy
|
||||
} else {
|
||||
double speed_value = GetStandardValue(kSpeedInput).toDouble();
|
||||
if (reverse()) {
|
||||
sequence_time = length() - sequence_time;
|
||||
}
|
||||
|
||||
if (qIsNull(speed_value)) {
|
||||
// Effectively holds the frame at the in point, also prevents divide by zero
|
||||
sequence_time = 0;
|
||||
} else if (!qFuzzyCompare(speed_value, 1.0)) {
|
||||
// Multiply time
|
||||
sequence_time = rational::fromDouble(sequence_time.toDouble() / speed_value);
|
||||
}
|
||||
sequence_time -= media_in();
|
||||
|
||||
double speed_value = speed();
|
||||
|
||||
if (qIsNull(speed_value)) {
|
||||
// Effectively holds the frame at the in point, also prevents divide by zero
|
||||
sequence_time = 0;
|
||||
} else if (!qFuzzyCompare(speed_value, 1.0)) {
|
||||
// Multiply time
|
||||
sequence_time = rational::fromDouble(sequence_time.toDouble() / speed_value);
|
||||
}
|
||||
|
||||
return sequence_time;
|
||||
@@ -208,6 +222,7 @@ void Block::Retranslate()
|
||||
SetInputName(kMediaInInput, tr("Media In"));
|
||||
SetInputName(kEnabledInput, tr("Enabled"));
|
||||
SetInputName(kSpeedInput, tr("Speed"));
|
||||
SetInputName(kReverseInput, tr("Reverse"));
|
||||
}
|
||||
|
||||
void Block::Hash(const QString &, QCryptographicHash &, const rational &) const
|
||||
|
||||
+12
-1
@@ -151,12 +151,23 @@ public:
|
||||
return block_links_;
|
||||
}
|
||||
|
||||
double speed() const
|
||||
{
|
||||
return GetStandardValue(kSpeedInput).toDouble();
|
||||
}
|
||||
|
||||
bool reverse() const
|
||||
{
|
||||
return GetStandardValue(kReverseInput).toBool();
|
||||
}
|
||||
|
||||
virtual void Hash(const QString& output, QCryptographicHash &hash, const rational &time) const override;
|
||||
|
||||
static const QString kLengthInput;
|
||||
static const QString kMediaInInput;
|
||||
static const QString kEnabledInput;
|
||||
static const QString kSpeedInput;
|
||||
static const QString kReverseInput;
|
||||
|
||||
public slots:
|
||||
|
||||
@@ -166,7 +177,7 @@ signals:
|
||||
void LengthChanged();
|
||||
|
||||
protected:
|
||||
rational SequenceToMediaTime(const rational& sequence_time) const;
|
||||
rational SequenceToMediaTime(const rational& sequence_time, bool ignore_reverse = false) const;
|
||||
|
||||
rational MediaToSequenceTime(const rational& media_time) const;
|
||||
|
||||
|
||||
@@ -114,12 +114,15 @@ void ClipBlock::Retranslate()
|
||||
SetInputName(kBufferIn, tr("Buffer"));
|
||||
}
|
||||
|
||||
void ClipBlock::Hash(const QString &output, QCryptographicHash &hash, const rational &time) const
|
||||
void ClipBlock::Hash(const QString &out, QCryptographicHash &hash, const rational &time) const
|
||||
{
|
||||
Q_UNUSED(out)
|
||||
|
||||
if (IsInputConnected(kBufferIn)) {
|
||||
rational t = InputTimeAdjustment(kBufferIn, -1, TimeRange(time, time)).in();
|
||||
|
||||
GetConnectedNode(kBufferIn)->Hash(output, hash, t);
|
||||
NodeOutput output = GetConnectedOutput(kBufferIn);
|
||||
output.node()->Hash(output.output(), hash, t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "project/folder/folder.h"
|
||||
#include "project/footage/footage.h"
|
||||
#include "project/sequence/sequence.h"
|
||||
#include "node/input/value/valuenode.h"
|
||||
|
||||
namespace olive {
|
||||
QList<Node*> NodeFactory::library_;
|
||||
@@ -234,6 +235,8 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id)
|
||||
return new Folder();
|
||||
case kProjectSequence:
|
||||
return new Sequence();
|
||||
case kValueNode:
|
||||
return new ValueNode();
|
||||
|
||||
case kInternalNodeCount:
|
||||
break;
|
||||
|
||||
@@ -56,6 +56,7 @@ public:
|
||||
kProjectFootage,
|
||||
kProjectFolder,
|
||||
kProjectSequence,
|
||||
kValueNode,
|
||||
|
||||
// Count value
|
||||
kInternalNodeCount
|
||||
|
||||
+8
-1
@@ -30,10 +30,17 @@ NodeGraph::NodeGraph()
|
||||
{
|
||||
}
|
||||
|
||||
NodeGraph::~NodeGraph()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void NodeGraph::Clear()
|
||||
{
|
||||
// By deleting the last nodes first, we assume that nodes that are most important are deleted last
|
||||
// (e.g. Project's ColorManager or ProjectSettingsNode.
|
||||
while (!node_children_.isEmpty()) {
|
||||
delete node_children_.first();
|
||||
delete node_children_.last();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,11 @@ public:
|
||||
*/
|
||||
NodeGraph();
|
||||
|
||||
/**
|
||||
* @brief NodeGraph Destructor
|
||||
*/
|
||||
virtual ~NodeGraph() override;
|
||||
|
||||
/**
|
||||
* @brief Destructively destroys all nodes in the graph
|
||||
*/
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
add_subdirectory(time)
|
||||
add_subdirectory(value)
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "multicamnode.h"
|
||||
|
||||
MultiCamNode::MultiCamNode()
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef MULTICAMNODE_H
|
||||
#define MULTICAMNODE_H
|
||||
|
||||
|
||||
class MultiCamNode
|
||||
{
|
||||
public:
|
||||
MultiCamNode();
|
||||
};
|
||||
|
||||
#endif // MULTICAMNODE_H
|
||||
@@ -0,0 +1,22 @@
|
||||
# Olive - Non-Linear Video Editor
|
||||
# Copyright (C) 2020 Olive Team
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
node/input/value/valuenode.h
|
||||
node/input/value/valuenode.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,81 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2020 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "valuenode.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
const QString ValueNode::kTypeInput = QStringLiteral("type_in");
|
||||
const QString ValueNode::kValueInput = QStringLiteral("value_in");
|
||||
const QVector<NodeValue::Type> ValueNode::kSupportedTypes = {
|
||||
NodeValue::kFloat,
|
||||
NodeValue::kInt,
|
||||
NodeValue::kRational,
|
||||
NodeValue::kVec2,
|
||||
NodeValue::kVec3,
|
||||
NodeValue::kVec4,
|
||||
NodeValue::kColor,
|
||||
NodeValue::kText,
|
||||
NodeValue::kMatrix,
|
||||
NodeValue::kFont,
|
||||
};
|
||||
|
||||
#define super Node
|
||||
|
||||
ValueNode::ValueNode()
|
||||
{
|
||||
AddInput(kTypeInput, NodeValue::kCombo, 0, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
|
||||
|
||||
AddInput(kValueInput, kSupportedTypes.first(), QVariant(), InputFlags(kInputFlagNotConnectable));
|
||||
}
|
||||
|
||||
void ValueNode::Retranslate()
|
||||
{
|
||||
SetInputName(kTypeInput, QStringLiteral("Type"));
|
||||
SetInputName(kValueInput, QStringLiteral("Value"));
|
||||
|
||||
QStringList type_names;
|
||||
type_names.reserve(kSupportedTypes.size());
|
||||
foreach (NodeValue::Type type, kSupportedTypes) {
|
||||
type_names.append(NodeValue::GetPrettyDataTypeName(type));
|
||||
}
|
||||
SetComboBoxStrings(kTypeInput, type_names);
|
||||
}
|
||||
|
||||
NodeValueTable ValueNode::Value(const QString &output, NodeValueDatabase &value) const
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
|
||||
// Pop combobox value off table because no other node will need it
|
||||
value[kTypeInput].Take(NodeValue::kCombo);
|
||||
|
||||
return value.Merge();
|
||||
}
|
||||
|
||||
void ValueNode::InputValueChangedEvent(const QString &input, int element)
|
||||
{
|
||||
if (input == kTypeInput) {
|
||||
SetInputDataType(kValueInput, kSupportedTypes.at(GetStandardValue(kTypeInput).toInt()));
|
||||
}
|
||||
|
||||
super::InputValueChangedEvent(input, element);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2020 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef VALUENODE_H
|
||||
#define VALUENODE_H
|
||||
|
||||
#include "node/node.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class ValueNode : public Node
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ValueNode();
|
||||
|
||||
NODE_DEFAULT_DESTRUCTOR(ValueNode)
|
||||
|
||||
virtual Node* copy() const override
|
||||
{
|
||||
return new ValueNode();
|
||||
}
|
||||
|
||||
virtual QString Name() const override
|
||||
{
|
||||
return tr("Value");
|
||||
}
|
||||
|
||||
virtual QString id() const override
|
||||
{
|
||||
return QStringLiteral("org.olivevideoeditor.Olive.value");
|
||||
}
|
||||
|
||||
virtual QVector<CategoryID> Category() const override
|
||||
{
|
||||
return {kCategoryInput};
|
||||
}
|
||||
|
||||
virtual QString Description() const override
|
||||
{
|
||||
return tr("Create a single value that can be connected to various other inputs.");
|
||||
}
|
||||
|
||||
static const QString kTypeInput;
|
||||
static const QString kValueInput;
|
||||
|
||||
virtual void Retranslate() override;
|
||||
|
||||
virtual NodeValueTable Value(const QString &output, NodeValueDatabase &value) const override;
|
||||
|
||||
protected:
|
||||
virtual void InputValueChangedEvent(const QString &input, int element) override;
|
||||
|
||||
private:
|
||||
static const QVector<NodeValue::Type> kSupportedTypes;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // VALUENODE_H
|
||||
@@ -36,7 +36,7 @@ bool NodeInputDragger::IsStarted() const
|
||||
return input_.IsValid();
|
||||
}
|
||||
|
||||
void NodeInputDragger::Start(const NodeKeyframeTrackReference &input, const rational &time)
|
||||
void NodeInputDragger::Start(const NodeKeyframeTrackReference &input, const rational &time, bool create_key_on_all_tracks)
|
||||
{
|
||||
Q_ASSERT(!IsStarted());
|
||||
|
||||
@@ -52,9 +52,8 @@ void NodeInputDragger::Start(const NodeKeyframeTrackReference &input, const rati
|
||||
// Determine whether we are creating a keyframe or not
|
||||
if (input_.input().IsKeyframing()) {
|
||||
dragging_key_ = node->GetKeyframeAtTimeOnTrack(input_, time);
|
||||
drag_created_key_ = !dragging_key_;
|
||||
|
||||
if (drag_created_key_) {
|
||||
if (!dragging_key_) {
|
||||
dragging_key_ = new NodeKeyframe(time,
|
||||
start_value_,
|
||||
node->GetBestKeyframeTypeForTimeOnTrack(input_, time),
|
||||
@@ -62,6 +61,19 @@ void NodeInputDragger::Start(const NodeKeyframeTrackReference &input, const rati
|
||||
input_.input().element(),
|
||||
input_.input().input(),
|
||||
node);
|
||||
created_keys_.append(dragging_key_);
|
||||
|
||||
if (create_key_on_all_tracks) {
|
||||
int nb_tracks = NodeValue::get_number_of_keyframe_tracks(input.input().node()->GetInputDataType(input.input().input()));
|
||||
for (int i=0; i<nb_tracks; i++) {
|
||||
if (i != input.track()) {
|
||||
NodeKeyframeTrackReference this_ref(input.input(), i);
|
||||
created_keys_.append(new NodeKeyframe(time, node->GetSplitValueAtTimeOnTrack(this_ref, time),
|
||||
node->GetBestKeyframeTypeForTimeOnTrack(this_ref, time),
|
||||
i, input.input().element(), input.input().input(), node));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,9 +124,9 @@ void NodeInputDragger::End()
|
||||
MultiUndoCommand* command = new MultiUndoCommand();
|
||||
|
||||
if (input_.input().node()->IsInputKeyframing(input_.input())) {
|
||||
if (drag_created_key_) {
|
||||
for (int i=0; i<created_keys_.size(); i++) {
|
||||
// We created a keyframe in this process
|
||||
command->add_child(new NodeParamInsertKeyframeCommand(input_.input().node(), dragging_key_));
|
||||
command->add_child(new NodeParamInsertKeyframeCommand(input_.input().node(), created_keys_.at(i)));
|
||||
}
|
||||
|
||||
// We just set a keyframe's value
|
||||
@@ -129,6 +141,7 @@ void NodeInputDragger::End()
|
||||
Core::instance()->undo_stack()->push(command);
|
||||
|
||||
input_.Reset();
|
||||
created_keys_.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
|
||||
bool IsStarted() const;
|
||||
|
||||
void Start(const NodeKeyframeTrackReference& input, const rational& time);
|
||||
void Start(const NodeKeyframeTrackReference& input, const rational& time, bool create_key_on_all_tracks = true);
|
||||
|
||||
void Drag(QVariant value);
|
||||
|
||||
@@ -50,8 +50,7 @@ private:
|
||||
QVariant end_value_;
|
||||
|
||||
NodeKeyframe* dragging_key_;
|
||||
|
||||
bool drag_created_key_;
|
||||
QVector<NodeKeyframe*> created_keys_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -27,14 +27,10 @@
|
||||
namespace olive {
|
||||
|
||||
NodeInputImmediate::NodeInputImmediate(NodeValue::Type type, const SplitValue &default_val) :
|
||||
default_value_(default_val),
|
||||
keyframing_(false)
|
||||
{
|
||||
int track_size = NodeValue::get_number_of_keyframe_tracks(type);
|
||||
|
||||
keyframe_tracks_.resize(track_size);
|
||||
standard_value_.resize(track_size);
|
||||
|
||||
set_split_standard_value(default_val);
|
||||
set_data_type(type);
|
||||
}
|
||||
|
||||
void NodeInputImmediate::set_standard_value_on_track(const QVariant &value, int track)
|
||||
@@ -179,6 +175,16 @@ bool NodeInputImmediate::has_keyframe_at_time(const rational &time) const
|
||||
return false;
|
||||
}
|
||||
|
||||
void NodeInputImmediate::set_data_type(NodeValue::Type type)
|
||||
{
|
||||
int track_size = NodeValue::get_number_of_keyframe_tracks(type);
|
||||
|
||||
keyframe_tracks_.resize(track_size);
|
||||
standard_value_.resize(track_size);
|
||||
|
||||
set_split_standard_value(default_value_);
|
||||
}
|
||||
|
||||
NodeKeyframe *NodeInputImmediate::get_earliest_keyframe() const
|
||||
{
|
||||
NodeKeyframe* earliest = nullptr;
|
||||
|
||||
@@ -151,12 +151,19 @@ public:
|
||||
return (!is_keyframing() || keyframe_tracks_.at(track).isEmpty());
|
||||
}
|
||||
|
||||
void set_data_type(NodeValue::Type type);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Non-keyframed value
|
||||
*/
|
||||
SplitValue standard_value_;
|
||||
|
||||
/**
|
||||
* @brief Default value
|
||||
*/
|
||||
SplitValue default_value_;
|
||||
|
||||
/**
|
||||
* @brief Internal keyframe array
|
||||
*
|
||||
|
||||
@@ -107,13 +107,16 @@ void MergeNode::Hash(const QString &output, QCryptographicHash &hash, const rati
|
||||
// connected node happens to return nothing (a gap for instance). Therefore we only add our
|
||||
// fingerprint if the base AND the blend change the hash. Otherwise, we assume it's a passthrough.
|
||||
|
||||
Q_UNUSED(output)
|
||||
|
||||
QByteArray current_result = hash.result();
|
||||
|
||||
bool base_changed_hash = false;
|
||||
bool blend_changed_hash = false;
|
||||
|
||||
if (IsInputConnected(kBaseIn)) {
|
||||
GetConnectedNode(kBaseIn)->Hash(output, hash, time);
|
||||
NodeOutput base_output = GetConnectedOutput(kBaseIn);
|
||||
base_output.node()->Hash(base_output.output(), hash, time);
|
||||
|
||||
QByteArray post_base_hash = hash.result();
|
||||
base_changed_hash = (post_base_hash != current_result);
|
||||
@@ -121,7 +124,8 @@ void MergeNode::Hash(const QString &output, QCryptographicHash &hash, const rati
|
||||
}
|
||||
|
||||
if(IsInputConnected(kBlendIn)) {
|
||||
GetConnectedNode(kBlendIn)->Hash(output, hash, time);
|
||||
NodeOutput blend_output = GetConnectedOutput(kBlendIn);
|
||||
blend_output.node()->Hash(blend_output.output(), hash, time);
|
||||
|
||||
blend_changed_hash = (hash.result() != current_result);
|
||||
}
|
||||
|
||||
+23
-9
@@ -48,7 +48,8 @@ Node::Node(bool create_default_output) :
|
||||
override_color_(-1),
|
||||
last_change_time_(0),
|
||||
folder_(nullptr),
|
||||
operation_stack_(0)
|
||||
operation_stack_(0),
|
||||
cache_result_(false)
|
||||
{
|
||||
if (create_default_output) {
|
||||
AddOutput();
|
||||
@@ -504,10 +505,15 @@ NodeValue::Type Node::GetInputDataType(const QString &id) const
|
||||
|
||||
void Node::SetInputDataType(const QString &id, const NodeValue::Type &type)
|
||||
{
|
||||
Input* i = GetInternalInputData(id);
|
||||
Input* input_meta = GetInternalInputData(id);
|
||||
|
||||
if (i) {
|
||||
i->type = type;
|
||||
if (input_meta) {
|
||||
input_meta->type = type;
|
||||
|
||||
int array_sz = InputArraySize(id);
|
||||
for (int i=-1; i<array_sz; i++) {
|
||||
GetImmediate(id, i)->set_data_type(type);
|
||||
}
|
||||
|
||||
emit InputDataTypeChanged(id, type);
|
||||
} else {
|
||||
@@ -692,7 +698,12 @@ SplitValue Node::GetSplitDefaultValue(const QString &input) const
|
||||
|
||||
QVariant Node::GetSplitDefaultValueOnTrack(const QString &input, int track) const
|
||||
{
|
||||
return GetSplitDefaultValue(input).at(track);
|
||||
SplitValue val = GetSplitDefaultValue(input);
|
||||
if (track < val.size()) {
|
||||
return val.at(track);
|
||||
} else {
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
const QVector<NodeKeyframeTrack> &Node::GetKeyframeTracks(const QString &input, int element) const
|
||||
@@ -2285,12 +2296,15 @@ void NodeSetPositionAndShiftSurroundingsCommand::redo()
|
||||
foreach (Node* surrounding, node_->parent()->nodes()) {
|
||||
if (bounding_rect.contains(surrounding->GetPosition()) && surrounding != node_) {
|
||||
QPointF new_pos = surrounding->GetPosition();
|
||||
if (surrounding->GetPosition().y() > position_.y()) {
|
||||
new_pos.setY(new_pos.y() + 0.5);
|
||||
} else {
|
||||
new_pos.setY(new_pos.y() - 0.5);
|
||||
|
||||
qreal move_rate = 0.50;
|
||||
|
||||
if (surrounding->GetPosition().y() < position_.y()) {
|
||||
move_rate = -move_rate;
|
||||
}
|
||||
|
||||
new_pos.setY(new_pos.y() + move_rate);
|
||||
|
||||
auto sur_command = new NodeSetPositionAndShiftSurroundingsCommand(surrounding, new_pos, true);
|
||||
sur_command->redo();
|
||||
commands_.append(sur_command);
|
||||
|
||||
@@ -756,6 +756,16 @@ public:
|
||||
folder_ = folder;
|
||||
}
|
||||
|
||||
bool GetCacheTextures() const
|
||||
{
|
||||
return cache_result_;
|
||||
}
|
||||
|
||||
void SetCacheTextures(bool e)
|
||||
{
|
||||
cache_result_ = e;
|
||||
}
|
||||
|
||||
static const QString kDefaultOutput;
|
||||
|
||||
protected:
|
||||
@@ -1191,6 +1201,8 @@ private:
|
||||
|
||||
int operation_stack_;
|
||||
|
||||
bool cache_result_;
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* @brief Slot when a keyframe's time changes to keep the keyframes correctly sorted by time
|
||||
|
||||
@@ -574,11 +574,13 @@ bool Track::IsLocked() const
|
||||
|
||||
void Track::Hash(const QString &output, QCryptographicHash &hash, const rational &time) const
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
|
||||
Block* b = BlockAtTime(time);
|
||||
|
||||
// Defer to block at this time, don't add any of our own information to the hash
|
||||
if (b) {
|
||||
b->Hash(output, hash, TransformTimeForBlock(b, time));
|
||||
b->Hash(kDefaultOutput, hash, TransformTimeForBlock(b, time));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,8 @@ const uint64_t ViewerOutput::kVideoParamEditMask = VideoParamEdit::kWidthHeight
|
||||
|
||||
ViewerOutput::ViewerOutput(bool create_default_streams) :
|
||||
video_frame_cache_(this),
|
||||
audio_playback_cache_(this)
|
||||
audio_playback_cache_(this),
|
||||
cache_enabled_(true)
|
||||
{
|
||||
AddInput(kVideoParamsInput, NodeValue::kVideoParams, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable | kInputFlagArray));
|
||||
SetInputProperty(kVideoParamsInput, QStringLiteral("mask"), QVariant::fromValue(kVideoParamEditMask));
|
||||
@@ -195,14 +196,18 @@ void ViewerOutput::set_default_parameters()
|
||||
|
||||
void ViewerOutput::ShiftVideoCache(const rational &from, const rational &to)
|
||||
{
|
||||
video_frame_cache_.Shift(from, to);
|
||||
if (cache_enabled_) {
|
||||
video_frame_cache_.Shift(from, to);
|
||||
}
|
||||
|
||||
ShiftVideoEvent(from, to);
|
||||
}
|
||||
|
||||
void ViewerOutput::ShiftAudioCache(const rational &from, const rational &to)
|
||||
{
|
||||
audio_playback_cache_.Shift(from, to);
|
||||
if (cache_enabled_) {
|
||||
audio_playback_cache_.Shift(from, to);
|
||||
}
|
||||
|
||||
ShiftAudioEvent(from, to);
|
||||
}
|
||||
@@ -217,16 +222,18 @@ void ViewerOutput::InvalidateCache(const TimeRange& range, const QString& from,
|
||||
{
|
||||
Q_UNUSED(element)
|
||||
|
||||
if (from == kTextureInput || from == kSamplesInput
|
||||
|| from == kVideoParamsInput || from == kAudioParamsInput) {
|
||||
TimeRange invalidated_range(qMax(rational(), range.in()),
|
||||
qMin(GetLength(), range.out()));
|
||||
if (cache_enabled_) {
|
||||
if (from == kTextureInput || from == kSamplesInput
|
||||
|| from == kVideoParamsInput || from == kAudioParamsInput) {
|
||||
TimeRange invalidated_range(qMax(rational(), range.in()),
|
||||
qMin(GetLength(), range.out()));
|
||||
|
||||
if (invalidated_range.in() != invalidated_range.out()) {
|
||||
if (from == kTextureInput || from == kVideoParamsInput) {
|
||||
video_frame_cache_.Invalidate(invalidated_range, job_time);
|
||||
} else {
|
||||
audio_playback_cache_.Invalidate(invalidated_range, job_time);
|
||||
if (invalidated_range.in() != invalidated_range.out()) {
|
||||
if (from == kTextureInput || from == kVideoParamsInput) {
|
||||
video_frame_cache_.Invalidate(invalidated_range, job_time);
|
||||
} else {
|
||||
audio_playback_cache_.Invalidate(invalidated_range, job_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -307,7 +314,9 @@ void ViewerOutput::VerifyLength()
|
||||
video_length = t.Get(NodeValue::kRational, QStringLiteral("length")).value<rational>();
|
||||
}
|
||||
|
||||
video_frame_cache_.SetLength(video_length);
|
||||
if (cache_enabled_) {
|
||||
video_frame_cache_.SetLength(video_length);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@@ -318,7 +327,9 @@ void ViewerOutput::VerifyLength()
|
||||
audio_length = t.Get(NodeValue::kRational, QStringLiteral("length")).value<rational>();
|
||||
}
|
||||
|
||||
audio_playback_cache_.SetLength(audio_length);
|
||||
if (cache_enabled_) {
|
||||
audio_playback_cache_.SetLength(audio_length);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@@ -392,7 +403,9 @@ void ViewerOutput::InputValueChangedEvent(const QString &input, int element)
|
||||
}
|
||||
|
||||
if (frame_rate_changed) {
|
||||
video_frame_cache_.SetTimebase(new_video_params.frame_rate_as_time_base());
|
||||
if (cache_enabled_) {
|
||||
video_frame_cache_.SetTimebase(new_video_params.frame_rate_as_time_base());
|
||||
}
|
||||
emit FrameRateChanged(new_video_params.frame_rate());
|
||||
}
|
||||
|
||||
@@ -412,7 +425,9 @@ void ViewerOutput::InputValueChangedEvent(const QString &input, int element)
|
||||
|
||||
emit AudioParamsChanged();
|
||||
|
||||
audio_playback_cache_.SetParameters(GetAudioParams());
|
||||
if (cache_enabled_) {
|
||||
audio_playback_cache_.SetParameters(GetAudioParams());
|
||||
}
|
||||
|
||||
cached_audio_params_ = new_audio_params;
|
||||
|
||||
@@ -514,6 +529,11 @@ int ViewerOutput::AddStream(Track::Type type, const QVariant& value)
|
||||
return index;
|
||||
}
|
||||
|
||||
void ViewerOutput::SetViewerCacheEnabled(bool e)
|
||||
{
|
||||
cache_enabled_ = e;
|
||||
}
|
||||
|
||||
void ViewerOutput::InputResized(const QString &input, int old_size, int new_size)
|
||||
{
|
||||
if (input == kVideoParamsInput || input == kAudioParamsInput) {
|
||||
|
||||
@@ -188,6 +188,8 @@ protected:
|
||||
|
||||
int AddStream(Track::Type type, const QVariant &value);
|
||||
|
||||
void SetViewerCacheEnabled(bool e);
|
||||
|
||||
private:
|
||||
rational last_length_;
|
||||
|
||||
@@ -203,6 +205,8 @@ private:
|
||||
|
||||
TimelinePoints timeline_points_;
|
||||
|
||||
bool cache_enabled_;
|
||||
|
||||
private slots:
|
||||
void InputResized(const QString& input, int old_size, int new_size);
|
||||
|
||||
|
||||
@@ -48,6 +48,9 @@ Footage::Footage(const QString &filename) :
|
||||
Clear();
|
||||
|
||||
set_filename(filename);
|
||||
|
||||
SetCacheTextures(true);
|
||||
SetViewerCacheEnabled(false);
|
||||
}
|
||||
|
||||
void Footage::Retranslate()
|
||||
@@ -298,66 +301,27 @@ QString Footage::DescribeAudioStream(const AudioParams ¶ms)
|
||||
QString::number(params.sample_rate()));
|
||||
}
|
||||
|
||||
bool Footage::CompareFootageToFile(Footage *footage, const QString &filename)
|
||||
{
|
||||
// Heuristic to determine if file has changed
|
||||
QFileInfo info(filename);
|
||||
|
||||
if (info.exists()) {
|
||||
/*if (info.lastModified().toMSecsSinceEpoch() == footage->timestamp()) {
|
||||
// Footage has not been modified and is where we expect
|
||||
return true;
|
||||
} else {
|
||||
// Footage may have changed and we'll have to re-probe it. It also may not have, in which
|
||||
// case nothing needs to change.
|
||||
DecoderPtr decoder = Decoder::CreateFromID(footage->decoder());
|
||||
|
||||
Streams probed_streams = decoder->Probe(filename, nullptr);
|
||||
|
||||
if (probed_streams == footage->streams_) {
|
||||
return true;
|
||||
}
|
||||
}*/
|
||||
Q_UNUSED(footage)
|
||||
|
||||
// Simplified, since our footage node is much more tolerant, we'll try this
|
||||
return true;
|
||||
}
|
||||
|
||||
// Footage file couldn't be found or resolved to something we didn't expect
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Footage::CompareFootageToItsFilename(Footage *footage)
|
||||
{
|
||||
return CompareFootageToFile(footage, footage->filename());
|
||||
}
|
||||
|
||||
void Footage::Hash(const QString& output, QCryptographicHash &hash, const rational &time) const
|
||||
{
|
||||
super::Hash(output, hash, time);
|
||||
|
||||
// Footage last modified date
|
||||
hash.addData(QString::number(timestamp()).toUtf8());
|
||||
|
||||
// Translate output ID to stream
|
||||
Track::Reference ref = Track::Reference::FromString(output);
|
||||
|
||||
QString fn = filename();
|
||||
|
||||
if (!fn.isEmpty()) {
|
||||
if (ref.type() == Track::kVideo) {
|
||||
VideoParams params = GetVideoParams(ref.index());
|
||||
|
||||
if (params.is_valid()) {
|
||||
// Add footage details to hash
|
||||
|
||||
// Footage filename
|
||||
hash.addData(filename().toUtf8());
|
||||
|
||||
// Footage last modified date
|
||||
hash.addData(QString::number(timestamp()).toUtf8());
|
||||
QString fn = filename();
|
||||
|
||||
// Footage stream
|
||||
hash.addData(QString::number(ref.index()).toUtf8());
|
||||
|
||||
if (ref.type() == Track::kVideo) {
|
||||
if (!fn.isEmpty()) {
|
||||
// Current color config and space
|
||||
hash.addData(project()->color_manager()->GetConfigFilename().toUtf8());
|
||||
hash.addData(GetColorspaceToUse(params).toUtf8());
|
||||
@@ -373,10 +337,11 @@ void Footage::Hash(const QString& output, QCryptographicHash &hash, const ration
|
||||
int64_t video_ts = Timecode::time_to_timestamp(time, params.time_base());
|
||||
|
||||
// Add timestamp in units of the video stream's timebase
|
||||
hash.addData(reinterpret_cast<const char*>(&video_ts), sizeof(int64_t));
|
||||
hash.addData(reinterpret_cast<const char*>(&video_ts), sizeof(video_ts));
|
||||
|
||||
// Add start time - used for both image sequences and video streams
|
||||
hash.addData(QString::number(params.start_time()).toUtf8());
|
||||
auto start_time = params.start_time();
|
||||
hash.addData(reinterpret_cast<const char*>(&start_time), sizeof(start_time));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -490,58 +455,6 @@ void Footage::UpdateTooltip()
|
||||
}
|
||||
}
|
||||
|
||||
/*void Footage::AddStreamAsInput(Track::Type type, int index, QVariant value)
|
||||
{
|
||||
QString input_id = GetInputIDOfIndex(type, index);
|
||||
|
||||
Track::Reference ref(type, index);
|
||||
|
||||
// Create input for parameters
|
||||
NodeValue::Type value_type;
|
||||
uint64_t param_mask = 0;
|
||||
|
||||
if (type == Track::kVideo) {
|
||||
VideoParams vp = value.value<VideoParams>();
|
||||
value_type = NodeValue::kVideoParams;
|
||||
|
||||
// Universal parameters for video/image footage
|
||||
param_mask |= VideoParamEdit::kEnabled;
|
||||
param_mask |= VideoParamEdit::kColorspace;
|
||||
param_mask |= VideoParamEdit::kPixelAspect;
|
||||
param_mask |= VideoParamEdit::kInterlacing;
|
||||
|
||||
if (vp.channel_count() == VideoParams::kRGBAChannelCount) {
|
||||
// If this has an alpha channel, add a premultiplied optino
|
||||
param_mask |= VideoParamEdit::kPremultipliedAlpha;
|
||||
}
|
||||
|
||||
if (vp.video_type() != VideoParams::kVideoTypeVideo) {
|
||||
// This is either a still image or an image sequence, add properties for those
|
||||
param_mask |= VideoParamEdit::kIsImageSequence;
|
||||
param_mask |= VideoParamEdit::kStartTime;
|
||||
param_mask |= VideoParamEdit::kEndTime;
|
||||
param_mask |= VideoParamEdit::kFrameRate;
|
||||
} else {
|
||||
// Ensure timebase isn't overwritten by the frame rate field
|
||||
param_mask |= VideoParamEdit::kFrameRateIsNotTimebase;
|
||||
}
|
||||
} else {
|
||||
value_type = NodeValue::kAudioParams;
|
||||
param_mask = 0;
|
||||
}
|
||||
|
||||
AddInput(input_id, value_type,
|
||||
InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
|
||||
SetStandardValue(input_id, value);
|
||||
SetInputProperty(input_id, QStringLiteral("mask"), QVariant::fromValue(param_mask));
|
||||
inputs_for_stream_properties_.insert(ref, input_id);
|
||||
|
||||
// Create output for stream
|
||||
QString output_id = Track::Reference(type, index).ToString();
|
||||
AddOutput(output_id);
|
||||
outputs_for_streams_.insert(ref, output_id);
|
||||
}*/
|
||||
|
||||
void Footage::CheckFootage()
|
||||
{
|
||||
QString fn = filename();
|
||||
@@ -559,21 +472,4 @@ void Footage::CheckFootage()
|
||||
}
|
||||
}
|
||||
|
||||
/*QString Track::Reference::video_colorspace(bool default_if_empty) const
|
||||
{
|
||||
if (IsValid()) {
|
||||
VideoParams params = footage_->GetVideoParams(index_);
|
||||
|
||||
if (params.is_valid()) {
|
||||
if (params.colorspace().isEmpty() && default_if_empty) {
|
||||
|
||||
} else {
|
||||
return params.colorspace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QString();
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
@@ -170,9 +170,6 @@ public:
|
||||
static QString DescribeVideoStream(const VideoParams& params);
|
||||
static QString DescribeAudioStream(const AudioParams& params);
|
||||
|
||||
static bool CompareFootageToFile(Footage* footage, const QString& filename);
|
||||
static bool CompareFootageToItsFilename(Footage* footage);
|
||||
|
||||
virtual void Hash(const QString& output, QCryptographicHash &hash, const rational &time) const override;
|
||||
|
||||
virtual NodeValueTable Value(const QString &output, NodeValueDatabase& value) const override;
|
||||
|
||||
@@ -220,16 +220,6 @@ void Project::set_filename(const QString &s)
|
||||
emit NameChanged();
|
||||
}
|
||||
|
||||
ColorManager *Project::color_manager()
|
||||
{
|
||||
return color_manager_;
|
||||
}
|
||||
|
||||
bool Project::is_modified() const
|
||||
{
|
||||
return is_modified_;
|
||||
}
|
||||
|
||||
void Project::set_modified(bool e)
|
||||
{
|
||||
is_modified_ = e;
|
||||
|
||||
@@ -62,9 +62,10 @@ public:
|
||||
QString pretty_filename() const;
|
||||
void set_filename(const QString& s);
|
||||
|
||||
ColorManager* color_manager();
|
||||
ColorManager* color_manager() { return color_manager_; }
|
||||
ProjectSettingsNode* settings() { return settings_; }
|
||||
|
||||
bool is_modified() const;
|
||||
bool is_modified() const { return is_modified_; }
|
||||
void set_modified(bool e);
|
||||
|
||||
bool has_autorecovery_been_saved() const;
|
||||
|
||||
@@ -454,7 +454,7 @@ void ProjectViewModel::DisconnectItem(Node *n)
|
||||
disconnect(f, &Folder::BeginRemoveItem, this, &ProjectViewModel::ItemRemoved);
|
||||
|
||||
foreach (Node* c, f->children()) {
|
||||
ConnectItem(c);
|
||||
DisconnectItem(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+27
-10
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "node.h"
|
||||
#include "render/job/footagejob.h"
|
||||
#include "render/rendermanager.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -110,7 +111,7 @@ NodeValueTable NodeTraverser::GenerateTable(const Node *n, const QString& output
|
||||
// By this point, the node should have all the inputs it needs to render correctly
|
||||
NodeValueTable table = n->Value(output, database);
|
||||
|
||||
PostProcessTable(n, range, table);
|
||||
PostProcessTable(n, output, range, table);
|
||||
|
||||
return table;
|
||||
}
|
||||
@@ -171,10 +172,15 @@ QVariant NodeTraverser::ProcessFrameGeneration(const Node *node, const GenerateJ
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant NodeTraverser::GetCachedFrame(const Node *node, const rational &time)
|
||||
void NodeTraverser::SaveCachedTexture(const QByteArray &hash, const QVariant &texture)
|
||||
{
|
||||
Q_UNUSED(node)
|
||||
Q_UNUSED(time)
|
||||
Q_UNUSED(hash)
|
||||
Q_UNUSED(texture)
|
||||
}
|
||||
|
||||
QVariant NodeTraverser::GetCachedTexture(const QByteArray& hash)
|
||||
{
|
||||
Q_UNUSED(hash)
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
@@ -190,17 +196,23 @@ void NodeTraverser::AddGlobalsToDatabase(NodeValueDatabase &db, const TimeRange&
|
||||
db.Insert(QStringLiteral("global"), global);
|
||||
}
|
||||
|
||||
void NodeTraverser::PostProcessTable(const Node *node, const TimeRange &range, NodeValueTable &output_params)
|
||||
void NodeTraverser::PostProcessTable(const Node *node, const QString& output, const TimeRange &range, NodeValueTable &output_params)
|
||||
{
|
||||
bool got_cached_frame = false;
|
||||
QByteArray cached_node_hash;
|
||||
|
||||
// Convert footage to image/sample buffers
|
||||
QVariant cached_frame = GetCachedFrame(node, range.in());
|
||||
if (!cached_frame.isNull()) {
|
||||
output_params.Push(NodeValue::kTexture, cached_frame, node);
|
||||
if (CanCacheFrames() && node->GetCacheTextures()) {
|
||||
// This node is set to cache the result, see if we can retrieved a previously cached version
|
||||
cached_node_hash = RenderManager::Hash(node, output, GetCacheVideoParams(), range.in());
|
||||
|
||||
// No more to do here
|
||||
got_cached_frame = true;
|
||||
QVariant cached_frame = GetCachedTexture(cached_node_hash);
|
||||
if (!cached_frame.isNull()) {
|
||||
output_params.Push(NodeValue::kTexture, cached_frame, node);
|
||||
|
||||
// No more to do here
|
||||
got_cached_frame = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Strip out any jobs or footage
|
||||
@@ -285,6 +297,11 @@ void NodeTraverser::PostProcessTable(const Node *node, const TimeRange &range, N
|
||||
output_params.Push(NodeValue::kSamples, value, node);
|
||||
}
|
||||
}
|
||||
|
||||
if (CanCacheFrames() && node->GetCacheTextures() && !got_cached_frame) {
|
||||
// Save cached texture
|
||||
SaveCachedTexture(cached_node_hash, output_params.Get(NodeValue::kTexture));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
-2
@@ -59,7 +59,19 @@ protected:
|
||||
|
||||
virtual QVariant ProcessFrameGeneration(const Node *node, const GenerateJob& job);
|
||||
|
||||
virtual QVariant GetCachedFrame(const Node *node, const rational &time);
|
||||
virtual QVariant GetCachedTexture(const QByteArray& hash);
|
||||
|
||||
virtual void SaveCachedTexture(const QByteArray& hash, const QVariant& texture);
|
||||
|
||||
virtual bool CanCacheFrames()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual VideoParams GetCacheVideoParams()
|
||||
{
|
||||
return VideoParams();
|
||||
}
|
||||
|
||||
void AddGlobalsToDatabase(NodeValueDatabase& db, const TimeRange &range) const;
|
||||
|
||||
@@ -69,7 +81,7 @@ protected:
|
||||
}
|
||||
|
||||
private:
|
||||
void PostProcessTable(const Node *node, const TimeRange &range, NodeValueTable &output_params);
|
||||
void PostProcessTable(const Node *node, const QString &output, const TimeRange &range, NodeValueTable &output_params);
|
||||
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user