This commit is contained in:
itsmattkc
2020-04-28 17:14:17 +10:00
102 changed files with 1179 additions and 1339 deletions
+1 -1
View File
@@ -229,7 +229,7 @@ ExportDialog::ExportDialog(ViewerOutput *viewer_node, QWidget *parent) :
// Update renderer
// FIXME: This is going to be VERY slow since it will need to hash every single frame. It would be better to have a
// the renderer save the map as some sort of file that this can load.
preview_viewer_->video_renderer()->InvalidateCache(TimeRange(0, viewer_node_->Length()));
preview_viewer_->video_renderer()->InvalidateCache(TimeRange(0, viewer_node_->Length()), nullptr);
progress_timer_.setInterval(1000);
connect(&progress_timer_, &QTimer::timeout, this, &ExportDialog::UpdateTimeLabels);
-3
View File
@@ -50,9 +50,6 @@ int main(int argc, char *argv[]) {
format.setProfile(QSurfaceFormat::CoreProfile);
QSurfaceFormat::setDefaultFormat(format);
// Try to share OpenGL contexts
QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
// Create application instance
QApplication a(argc, argv);
+1 -1
View File
@@ -16,7 +16,7 @@
add_subdirectory(audio)
add_subdirectory(block)
add_subdirectory(distort)
add_subdirectory(generator)
add_subdirectory(input)
add_subdirectory(math)
add_subdirectory(output)
+3 -3
View File
@@ -40,7 +40,7 @@ Block::Block() :
length_input_->SetConnectable(false);
length_input_->set_is_keyframable(false);
AddInput(length_input_);
connect(length_input_, SIGNAL(ValueChanged(const rational&, const rational&)), this, SLOT(LengthInputChanged()));
connect(length_input_, &NodeInput::ValueChanged, this, &Block::LengthInputChanged);
media_in_input_ = new NodeInput("media_in_in", NodeParam::kRational);
media_in_input_->SetConnectable(false);
@@ -343,14 +343,14 @@ NodeInput *Block::speed_input() const
return speed_input_;
}
void Block::InvalidateCache(const rational &start_range, const rational &end_range, NodeInput *from)
void Block::InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput *source)
{
// We ignore length changes since they don't have an effect on our frames
if (from == length_input_) {
return;
}
Node::InvalidateCache(start_range, end_range, from);
Node::InvalidateCache(range, from, source);
}
OLIVE_NAMESPACE_EXIT
+1 -1
View File
@@ -97,7 +97,7 @@ public:
NodeInput* media_in_input() const;
NodeInput* speed_input() const;
virtual void InvalidateCache(const rational& start_range, const rational& end_range, NodeInput* from = nullptr) override;
virtual void InvalidateCache(const TimeRange& range, NodeInput* from, NodeInput* source) override;
public slots:
+5 -5
View File
@@ -59,12 +59,12 @@ NodeInput *ClipBlock::texture_input() const
return texture_input_;
}
void ClipBlock::InvalidateCache(const rational &start_range, const rational &end_range, NodeInput *from)
void ClipBlock::InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput *source)
{
// If signal is from texture input, transform all times from media time to sequence time
if (from == texture_input_) {
rational start = MediaToSequenceTime(start_range);
rational end = MediaToSequenceTime(end_range);
rational start = MediaToSequenceTime(range.in());
rational end = MediaToSequenceTime(range.out());
// Ensure range actually covers this clip's area
if (!(end < in() || start > out())) {
@@ -73,12 +73,12 @@ void ClipBlock::InvalidateCache(const rational &start_range, const rational &end
start = qMax(start, in());
end = qMin(end, out());
Node::InvalidateCache(start, end, from);
Node::InvalidateCache(TimeRange(start, end), from, source);
}
} else {
// Otherwise, pass signal along normally
Node::InvalidateCache(start_range, end_range, from);
Node::InvalidateCache(range, from, source);
}
}
+1 -1
View File
@@ -44,7 +44,7 @@ public:
NodeInput* texture_input() const;
virtual void InvalidateCache(const rational &start_range, const rational &end_range, NodeInput *from = nullptr) override;
virtual void InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput* source) override;
virtual TimeRange InputTimeAdjustment(NodeInput* input, const TimeRange& input_time) const override;
+3 -3
View File
@@ -25,7 +25,7 @@
#include "block/clip/clip.h"
#include "block/gap/gap.h"
#include "block/transition/externaltransition.h"
#include "distort/transform/transform.h"
#include "generator/matrix/matrix.h"
#include "input/media/video/video.h"
#include "input/media/audio/audio.h"
#include "input/time/timeinput.h"
@@ -141,8 +141,8 @@ Node *NodeFactory::CreateInternal(const NodeFactory::InternalID &id)
return new ClipBlock();
case kGapBlock:
return new GapBlock();
case kTransformDistort:
return new TransformDistort();
case kMatrixGenerator:
return new MatrixGenerator();
case kVideoInput:
return new VideoInput();
case kAudioInput:
+1 -1
View File
@@ -36,7 +36,7 @@ public:
kClipBlock,
kGapBlock,
kAudioInput,
kTransformDistort,
kMatrixGenerator,
kVideoInput,
kTrackOutput,
kAudioVolume,
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
add_subdirectory(transform)
add_subdirectory(matrix)
set(OLIVE_SOURCES
${OLIVE_SOURCES}
@@ -16,7 +16,7 @@
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/distort/transform/transform.h
node/distort/transform/transform.cpp
node/generator/matrix/matrix.h
node/generator/matrix/matrix.cpp
PARENT_SCOPE
)
@@ -18,14 +18,14 @@
***/
#include "transform.h"
#include "matrix.h"
#include <QMatrix4x4>
#include <QVector2D>
OLIVE_NAMESPACE_ENTER
TransformDistort::TransformDistort()
MatrixGenerator::MatrixGenerator()
{
position_input_ = new NodeInput("pos_in", NodeParam::kVec2);
AddInput(position_input_);
@@ -42,39 +42,39 @@ TransformDistort::TransformDistort()
uniform_scale_input_ = new NodeInput("uniform_scale_in", NodeParam::kBoolean, true);
uniform_scale_input_->set_is_keyframable(false);
uniform_scale_input_->SetConnectable(false);
connect(uniform_scale_input_, &NodeInput::ValueChanged, this, &TransformDistort::UniformScaleChanged);
connect(uniform_scale_input_, &NodeInput::ValueChanged, this, &MatrixGenerator::UniformScaleChanged);
AddInput(uniform_scale_input_);
anchor_input_ = new NodeInput("anchor_in", NodeParam::kVec2);
AddInput(anchor_input_);
}
Node *TransformDistort::copy() const
Node *MatrixGenerator::copy() const
{
return new TransformDistort();
return new MatrixGenerator();
}
QString TransformDistort::Name() const
QString MatrixGenerator::Name() const
{
return tr("Transform");
return tr("Orthographic Matrix");
}
QString TransformDistort::id() const
QString MatrixGenerator::id() const
{
return QStringLiteral("org.olivevideoeditor.Olive.transform");
}
QString TransformDistort::Category() const
QString MatrixGenerator::Category() const
{
return tr("Distort");
return tr("Generator");
}
QString TransformDistort::Description() const
QString MatrixGenerator::Description() const
{
return tr("Apply transformations to position, rotation, and scale.");
return tr("Generate an orthographic matrix using position, rotation, and scale.");
}
void TransformDistort::Retranslate()
void MatrixGenerator::Retranslate()
{
position_input_->set_name(tr("Position"));
rotation_input_->set_name(tr("Rotation"));
@@ -83,7 +83,7 @@ void TransformDistort::Retranslate()
anchor_input_->set_name(tr("Anchor Point"));
}
NodeValueTable TransformDistort::Value(NodeValueDatabase &value) const
NodeValueTable MatrixGenerator::Value(NodeValueDatabase &value) const
{
QMatrix4x4 mat;
@@ -110,7 +110,7 @@ NodeValueTable TransformDistort::Value(NodeValueDatabase &value) const
return output;
}
void TransformDistort::UniformScaleChanged()
void MatrixGenerator::UniformScaleChanged()
{
scale_input_->set_property("disabley", uniform_scale_input_->get_standard_value().toBool());
}
@@ -18,18 +18,18 @@
***/
#ifndef TRANSFORMDISTORT_H
#define TRANSFORMDISTORT_H
#ifndef MATRIXGENERATOR_H
#define MATRIXGENERATOR_H
#include "node/node.h"
OLIVE_NAMESPACE_ENTER
class TransformDistort : public Node
class MatrixGenerator : public Node
{
Q_OBJECT
public:
TransformDistort();
MatrixGenerator();
virtual Node* copy() const override;
+45 -7
View File
@@ -60,7 +60,7 @@ NodeInput::NodeInput(const QString &id, const NodeParam::DataType &type) :
Init(type);
}
bool NodeInput::IsArray()
bool NodeInput::IsArray() const
{
return false;
}
@@ -273,7 +273,6 @@ void NodeInput::SaveConnections(QXmlStreamWriter *writer) const
writer->writeEndElement(); // connections
}
const NodeParam::DataType &NodeInput::data_type() const
{
return data_type_;
@@ -363,6 +362,45 @@ QVariant NodeInput::StringToValue(const DataType& data_type, const QString &stri
}
}
void NodeInput::GetDependencies(QList<Node *> &list, bool traverse, bool exclusive_only) const
{
if (IsConnected()
&& (get_connected_output()->edges().size() == 1 || !exclusive_only)) {
Node* connected = get_connected_node();
if (!list.contains(connected)) {
list.append(connected);
if (traverse) {
QList<NodeInput*> connected_inputs = connected->GetInputsIncludingArrays();
foreach (NodeInput* i, connected_inputs) {
i->GetDependencies(list, traverse, exclusive_only);
}
}
}
}
}
QList<Node *> NodeInput::GetDependencies(bool traverse, bool exclusive_only) const
{
QList<Node *> list;
GetDependencies(list, traverse, exclusive_only);
return list;
}
QList<Node *> NodeInput::GetExclusiveDependencies() const
{
return GetDependencies(true, true);
}
QList<Node *> NodeInput::GetImmediateDependencies() const
{
return GetDependencies(false, false);
}
QVariant NodeInput::StringToValue(const QString &string, QList<XMLNodeData::FootageConnection>& footage_connections)
{
if (data_type_ == NodeParam::kFootage) {
@@ -757,7 +795,7 @@ void NodeInput::KeyframeBezierInChanged()
start = keyframe_tracks_.at(key->track()).at(keyframe_index - 1)->time();
}
emit ValueChanged(start, end);
emit ValueChanged(TimeRange(start, end));
}
void NodeInput::KeyframeBezierOutChanged()
@@ -772,7 +810,7 @@ void NodeInput::KeyframeBezierOutChanged()
end = keyframe_tracks_.at(key->track()).at(keyframe_index + 1)->time();
}
emit ValueChanged(start, end);
emit ValueChanged(TimeRange(start, end));
}
int NodeInput::FindIndexOfKeyframeFromRawPtr(NodeKeyframe *raw_ptr) const
@@ -855,7 +893,7 @@ TimeRange NodeInput::get_range_around_index(int index, int track) const
void NodeInput::emit_time_range(const TimeRange &range)
{
emit ValueChanged(range.in(), range.out());
emit ValueChanged(range);
}
void NodeInput::emit_range_affected_by_keyframe(NodeKeyframe *key)
@@ -915,7 +953,7 @@ void NodeInput::set_standard_value(const QVariant &value, int track)
if (is_using_standard_value(track)) {
// If this standard value is being used, we need to send a value changed signal
emit ValueChanged(RATIONAL_MIN, RATIONAL_MAX);
emit ValueChanged(TimeRange(RATIONAL_MIN, RATIONAL_MAX));
}
}
@@ -964,7 +1002,7 @@ void NodeInput::CopyValues(NodeInput *source, NodeInput *dest, bool include_conn
}
}
emit dest->ValueChanged(RATIONAL_MIN, RATIONAL_MAX);
emit dest->ValueChanged(TimeRange(RATIONAL_MIN, RATIONAL_MAX));
}
void NodeInput::set_property(const QString &key, const QVariant &value)
+10 -2
View File
@@ -49,7 +49,7 @@ public:
NodeInput(const QString &id, const DataType& type, const QVariant& default_value);
NodeInput(const QString &id, const DataType& type);
virtual bool IsArray();
virtual bool IsArray() const;
/**
* @brief Returns kInput
@@ -270,8 +270,16 @@ public:
static QVariant StringToValue(const DataType &data_type, const QString &string);
void GetDependencies(QList<Node*>& list, bool traverse, bool exclusive_only) const;
QList<Node*> GetDependencies(bool traverse = true, bool exclusive_only = false) const;
QList<Node*> GetExclusiveDependencies() const;
QList<Node*> GetImmediateDependencies() const;
signals:
void ValueChanged(const rational& start, const rational& end);
void ValueChanged(const TimeRange& range);
void KeyframeEnableChanged(bool);
-4
View File
@@ -22,10 +22,6 @@
OLIVE_NAMESPACE_ENTER
AudioInput::AudioInput()
{
}
Node *AudioInput::copy() const
{
return new AudioInput();
+1 -2
View File
@@ -28,7 +28,7 @@ OLIVE_NAMESPACE_ENTER
class AudioInput : public MediaInput
{
public:
AudioInput();
AudioInput() = default;
virtual Node* copy() const override;
@@ -36,7 +36,6 @@ public:
virtual QString id() const override;
virtual QString Description() const override;
private:
};
OLIVE_NAMESPACE_EXIT
+3 -3
View File
@@ -31,7 +31,7 @@ MediaInput::MediaInput() :
footage_input_ = new NodeInput("footage_in", NodeInput::kFootage);
footage_input_->SetConnectable(false);
footage_input_->set_is_keyframable(false);
connect(footage_input_, SIGNAL(ValueChanged(const rational&, const rational&)), this, SLOT(FootageChanged()));
connect(footage_input_, &NodeInput::ValueChanged, this, &MediaInput::FootageChanged);
AddInput(footage_input_);
}
@@ -67,7 +67,7 @@ NodeValueTable MediaInput::Value(NodeValueDatabase &value) const
}
// Push buffer to the top of the stack
NodeValue buffer = value[footage_input_].GetWithMeta(NodeParam::kSamples);
NodeValue buffer = value[footage_input_].GetWithMeta(NodeParam::kBuffer);
if (buffer.type() != NodeParam::kNone) {
table.Push(buffer);
}
@@ -96,7 +96,7 @@ void MediaInput::FootageChanged()
void MediaInput::FootageParametersChanged()
{
InvalidateCache(0, RATIONAL_MAX, footage_input_);
InvalidateCache(TimeRange(0, RATIONAL_MAX), footage_input_, footage_input_);
}
OLIVE_NAMESPACE_EXIT
-33
View File
@@ -31,12 +31,6 @@
OLIVE_NAMESPACE_ENTER
VideoInput::VideoInput()
{
matrix_input_ = new NodeInput("matrix_in", NodeInput::kMatrix);
AddInput(matrix_input_);
}
Node *VideoInput::copy() const
{
return new VideoInput();
@@ -57,31 +51,4 @@ QString VideoInput::Description() const
return tr("Import a video footage stream.");
}
NodeInput *VideoInput::matrix_input() const
{
return matrix_input_;
}
Node::Capabilities VideoInput::GetCapabilities(const NodeValueDatabase &) const
{
return kShader;
}
QString VideoInput::ShaderVertexCode(const NodeValueDatabase&) const
{
return ReadFileAsString(":/shaders/videoinput.vert");
}
QString VideoInput::ShaderFragmentCode(const NodeValueDatabase&) const
{
return ReadFileAsString(":/shaders/videoinput.frag");
}
void VideoInput::Retranslate()
{
MediaInput::Retranslate();
matrix_input_->set_name(tr("Transform"));
}
OLIVE_NAMESPACE_EXIT
+1 -14
View File
@@ -31,7 +31,7 @@ OLIVE_NAMESPACE_ENTER
class VideoInput : public MediaInput
{
public:
VideoInput();
VideoInput() = default;
virtual Node* copy() const override;
@@ -39,19 +39,6 @@ public:
virtual QString id() const override;
virtual QString Description() const override;
NodeInput* matrix_input() const;
virtual Capabilities GetCapabilities(const NodeValueDatabase&) const override;
virtual QString ShaderVertexCode(const NodeValueDatabase&) const override;
virtual QString ShaderFragmentCode(const NodeValueDatabase&) const override;
virtual void Retranslate() override;
protected:
private:
NodeInput* matrix_input_;
};
OLIVE_NAMESPACE_EXIT
+3 -3
View File
@@ -33,7 +33,7 @@ NodeInputArray::NodeInputArray(const QString &id, const DataType &type, const QV
{
}
bool NodeInputArray::IsArray()
bool NodeInputArray::IsArray() const
{
return true;
}
@@ -79,8 +79,8 @@ void NodeInputArray::SetSize(int size)
sub_params_.replace(i, new_param);
connect(new_param, &NodeInput::ValueChanged, this, &NodeInput::ValueChanged);
connect(new_param, &NodeInput::EdgeAdded, this, &NodeInput::EdgeAdded);
connect(new_param, &NodeInput::EdgeRemoved, this, &NodeInput::EdgeRemoved);
connect(new_param, &NodeInput::EdgeAdded, this, &NodeInputArray::SubParamEdgeAdded);
connect(new_param, &NodeInput::EdgeRemoved, this, &NodeInputArray::SubParamEdgeRemoved);
}
}
+5 -1
View File
@@ -31,7 +31,7 @@ class NodeInputArray : public NodeInput
public:
NodeInputArray(const QString &id, const DataType& type, const QVariant& default_value = 0);
virtual bool IsArray() override;
virtual bool IsArray() const override;
int GetSize() const;
@@ -54,6 +54,10 @@ public:
signals:
void SizeChanged(int size);
void SubParamEdgeAdded(NodeEdgePtr edge);
void SubParamEdgeRemoved(NodeEdgePtr edge);
protected:
virtual void LoadInternal(QXmlStreamReader* reader, XMLNodeData& xml_node_data, const QAtomicInt *cancelled) override;
+103 -91
View File
@@ -131,9 +131,9 @@ QString MathNode::ShaderFragmentCode(const NodeValueDatabase &input) const
// Override the operation for this operation since we multiply texture COORDS by the matrix rather than
NodeParam* tex_in = (type_a == NodeParam::kTexture) ? param_a_in_ : param_b_in_;
NodeParam* mat_in = (type_a == NodeParam::kTexture) ? param_b_in_ : param_a_in_;
operation = QStringLiteral("texture(%1, (vec4(ove_texcoord, 0.0, 1.0) * %2).xy)").arg(tex_in->id(), mat_in->id());
// No-op frag shader (can we return QString() instead?)
operation = QStringLiteral("texture(%1, ove_texcoord)").arg(tex_in->id());
} else {
switch (GetOperation()) {
@@ -176,6 +176,25 @@ QString MathNode::ShaderFragmentCode(const NodeValueDatabase &input) const
operation);
}
QString MathNode::ShaderVertexCode(const NodeValueDatabase &input) const
{
PairingCalculator calc(input[param_a_in_], input[param_b_in_]);
if (calc.GetMostLikelyPairing() == kPairTextureMatrix && GetOperation() == kOpMultiply) {
NodeParam::DataType type_a = calc.GetMostLikelyValueA().type();
// Override the operation for this operation since we multiply texture COORDS by the matrix rather than
NodeParam* tex_in = (type_a == NodeParam::kTexture) ? param_a_in_ : param_b_in_;
NodeParam* mat_in = (type_a == NodeParam::kTexture) ? param_b_in_ : param_a_in_;
return ReadFileAsString(":/shaders/matrix.vert").arg(mat_in->id(), tex_in->id());
}
return QString();
}
NodeValue MathNode::InputValueFromTable(NodeInput *input, NodeValueDatabase &db, bool take) const
{
if (input == param_a_in_ || input == param_b_in_) {
@@ -382,6 +401,11 @@ MathNode::Operation MathNode::GetOperation() const
return static_cast<Operation>(method_in_->get_standard_value().toInt());
}
void MathNode::SetOperation(MathNode::Operation o)
{
method_in_->set_standard_value(o);
}
QString MathNode::GetShaderUniformType(const NodeParam::DataType &type)
{
switch (type) {
@@ -405,6 +429,81 @@ QString MathNode::GetShaderVariableCall(const QString &input_id, const NodeParam
return input_id;
}
QVector4D MathNode::RetrieveVector(const NodeValue &val)
{
// QVariant doesn't know that QVector*D can convert themselves so we do it here
switch (val.type()) {
case NodeParam::kVec2:
return val.data().value<QVector2D>();
case NodeParam::kVec3:
return val.data().value<QVector3D>();
case NodeParam::kVec4:
default:
return val.data().value<QVector4D>();
}
}
void MathNode::PushVector(NodeValueTable *output, NodeParam::DataType type, const QVector4D &vec)
{
switch (type) {
case NodeParam::kVec2:
output->Push(type, QVector2D(vec));
break;
case NodeParam::kVec3:
output->Push(type, QVector3D(vec));
break;
case NodeParam::kVec4:
output->Push(type, vec);
break;
default:
break;
}
}
float MathNode::RetrieveNumber(const NodeValue &val)
{
if (val.type() == NodeParam::kRational) {
return val.data().value<rational>().toDouble();
} else {
return val.data().toFloat();
}
}
MathNode::PairingCalculator::PairingCalculator(const NodeValueTable &table_a, const NodeValueTable &table_b)
{
QVector<int> pair_likelihood_a = GetPairLikelihood(table_a);
QVector<int> pair_likelihood_b = GetPairLikelihood(table_b);
int weight_a = qMax(0, table_b.Count() - table_a.Count());
int weight_b = qMax(0, table_a.Count() - table_b.Count());
QVector<int> likelihoods(kPairCount);
for (int i=0;i<kPairCount;i++) {
if (pair_likelihood_a.at(i) == -1 || pair_likelihood_b.at(i) == -1) {
likelihoods.replace(i, -1);
} else {
likelihoods.replace(i, pair_likelihood_a.at(i) + weight_a + pair_likelihood_b.at(i) + weight_b);
}
}
most_likely_pairing_ = kPairNone;
for (int i=0;i<likelihoods.size();i++) {
if (likelihoods.at(i) > -1) {
if (most_likely_pairing_ == kPairNone
|| likelihoods.at(i) > likelihoods.at(most_likely_pairing_)) {
most_likely_pairing_ = static_cast<Pairing>(i);
}
}
}
if (most_likely_pairing_ != kPairNone) {
most_likely_value_a_ = table_a.At(pair_likelihood_a.at(most_likely_pairing_));
most_likely_value_b_ = table_b.At(pair_likelihood_b.at(most_likely_pairing_));
}
}
QVector<int> MathNode::PairingCalculator::GetPairLikelihood(const NodeValueTable &table)
{
// FIXME: When we introduce a manual override, placing it here would be the least problematic
@@ -448,88 +547,6 @@ QVector<int> MathNode::PairingCalculator::GetPairLikelihood(const NodeValueTable
return likelihood;
}
MathNode::Pairing MathNode::PairingCalculator::GetMostLikelyPairingInternal(const QVector<int> &a,
const QVector<int> &b,
const int& weight_a,
const int& weight_b)
{
QVector<int> likelihoods(kPairCount);
for (int i=0;i<likelihoods.size();i++) {
if (a.at(i) == -1 || b.at(i) == -1) {
likelihoods.replace(i, -1);
} else {
likelihoods.replace(i, a.at(i) + weight_a + b.at(i) + weight_b);
}
}
Pairing pairing = kPairNone;
for (int i=0;i<likelihoods.size();i++) {
if (likelihoods.at(i) > -1) {
if (pairing == kPairNone
|| likelihoods.at(i) > likelihoods.at(pairing)) {
pairing = static_cast<Pairing>(i);
}
}
}
return pairing;
}
QVector4D MathNode::RetrieveVector(const NodeValue &val)
{
// QVariant doesn't know that QVector*D can convert themselves so we do it here
switch (val.type()) {
case NodeParam::kVec2:
return val.data().value<QVector2D>();
case NodeParam::kVec3:
return val.data().value<QVector3D>();
case NodeParam::kVec4:
default:
return val.data().value<QVector4D>();
}
}
void MathNode::PushVector(NodeValueTable *output, NodeParam::DataType type, const QVector4D &vec)
{
switch (type) {
case NodeParam::kVec2:
output->Push(type, QVector2D(vec));
break;
case NodeParam::kVec3:
output->Push(type, QVector3D(vec));
break;
case NodeParam::kVec4:
output->Push(type, vec);
break;
default:
break;
}
}
float MathNode::RetrieveNumber(const NodeValue &val)
{
if (val.type() == NodeParam::kRational) {
return val.data().value<rational>().toDouble();
} else {
return val.data().toFloat();
}
}
MathNode::PairingCalculator::PairingCalculator(const NodeValueTable &table_a, const NodeValueTable &table_b) :
table_a_(table_a),
table_b_(table_b)
{
pair_likelihood_a_ = GetPairLikelihood(table_a_);
pair_likelihood_b_ = GetPairLikelihood(table_b_);
most_likely_pairing_ = GetMostLikelyPairingInternal(pair_likelihood_a_,
pair_likelihood_b_,
qMax(0, table_b_.Count() - table_a_.Count()),
qMax(0, table_a_.Count() - table_b_.Count()));
}
bool MathNode::PairingCalculator::FoundMostLikelyPairing() const
{
return (most_likely_pairing_ > kPairNone && most_likely_pairing_ < kPairCount);
@@ -542,17 +559,12 @@ MathNode::Pairing MathNode::PairingCalculator::GetMostLikelyPairing() const
const NodeValue &MathNode::PairingCalculator::GetMostLikelyValueA() const
{
return GetMostLikelyValue(table_a_, pair_likelihood_a_);
return most_likely_value_a_;
}
const NodeValue &MathNode::PairingCalculator::GetMostLikelyValueB() const
{
return GetMostLikelyValue(table_b_, pair_likelihood_b_);
}
const NodeValue& MathNode::PairingCalculator::GetMostLikelyValue(const NodeValueTable &table, const QVector<int> &likelihood) const
{
return table.At(likelihood.at(most_likely_pairing_));
return most_likely_value_b_;
}
template<typename T, typename U>
+5 -11
View File
@@ -42,6 +42,7 @@ public:
virtual Capabilities GetCapabilities(const NodeValueDatabase&) const override;
virtual QString ShaderID(const NodeValueDatabase&) const override;
virtual QString ShaderFragmentCode(const NodeValueDatabase&) const override;
virtual QString ShaderVertexCode(const NodeValueDatabase&input) const override;
virtual NodeValue InputValueFromTable(NodeInput* input, NodeValueDatabase &db, bool take) const override;
@@ -53,7 +54,6 @@ public:
NodeInput* param_a_in() const;
NodeInput* param_b_in() const;
private:
enum Operation {
kOpAdd,
kOpSubtract,
@@ -63,7 +63,9 @@ private:
};
Operation GetOperation() const;
void SetOperation(Operation o);
private:
enum Pairing {
kPairNone = -1,
@@ -96,21 +98,13 @@ private:
const NodeValue& GetMostLikelyValueB() const;
private:
static Pairing GetMostLikelyPairingInternal(const QVector<int> &a, const QVector<int> &b, const int &weight_a, const int &weight_b);
static QVector<int> GetPairLikelihood(const NodeValueTable& table);
const NodeValue &GetMostLikelyValue(const NodeValueTable& table, const QVector<int>& likelihood) const;
Pairing most_likely_pairing_;
const NodeValueTable& table_a_;
NodeValue most_likely_value_a_;
const NodeValueTable& table_b_;
QVector<int> pair_likelihood_a_;
QVector<int> pair_likelihood_b_;
NodeValue most_likely_value_b_;
};
+63 -130
View File
@@ -75,7 +75,13 @@ void Node::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const QAto
continue;
}
NodeParam* param = GetParameterWithID(param_id);
NodeParam* param;
if (reader->name() == QStringLiteral("input")) {
param = GetInputWithID(param_id);
} else {
param = GetOutputWithID(param_id);
}
if (!param) {
qDebug() << "No parameter in" << id() << "with parameter" << param_id;
@@ -153,21 +159,21 @@ NodeValueTable Node::Value(NodeValueDatabase &value) const
return value.Merge();
}
void Node::InvalidateCache(const rational &start_range, const rational &end_range, NodeInput *from)
void Node::InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput *source)
{
Q_UNUSED(from)
SendInvalidateCache(start_range, end_range);
SendInvalidateCache(range, source);
}
void Node::InvalidateVisible(NodeInput *from)
void Node::InvalidateVisible(NodeInput *from, NodeInput* source)
{
Q_UNUSED(from)
foreach (NodeParam* param, params_) {
if (param->type() == NodeParam::kOutput) {
foreach (NodeEdgePtr edge, param->edges()) {
edge->input()->parentNode()->InvalidateVisible(edge->input());
edge->input()->parentNode()->InvalidateVisible(edge->input(), source);
}
}
}
@@ -185,7 +191,7 @@ TimeRange Node::OutputTimeAdjustment(NodeInput *, const TimeRange &input_time) c
return input_time;
}
void Node::SendInvalidateCache(const rational &start_range, const rational &end_range)
void Node::SendInvalidateCache(const TimeRange &range, NodeInput *source)
{
// Loop through all parameters (there should be no children that are not NodeParams)
foreach (NodeParam* param, params_) {
@@ -199,25 +205,7 @@ void Node::SendInvalidateCache(const rational &start_range, const rational &end_
Node* connected_node = connected_input->parentNode();
// Send clear cache signal to the Node
connected_node->InvalidateCache(start_range, end_range, connected_input);
}
}
}
}
void Node::DependentEdgeChanged(NodeInput *from)
{
Q_UNUSED(from)
foreach (NodeParam* p, params_) {
if (p->type() == NodeParam::kOutput && p->IsConnected()) {
NodeOutput* out = static_cast<NodeOutput*>(p);
foreach (NodeEdgePtr edge, out->edges()) {
NodeInput* connected_input = edge->input();
Node* connected_node = connected_input->parentNode();
connected_node->DependentEdgeChanged(connected_input);
connected_node->InvalidateCache(range, connected_input, source);
}
}
}
@@ -300,57 +288,6 @@ void Node::CopyInputs(Node *source, Node *destination, bool include_connections)
}
}
void DuplicateConnectionsBetweenListsInternal(const QList<Node *> &source, const QList<Node *> &destination, NodeInput* source_input, NodeInput* dest_input)
{
if (source_input->IsConnected()) {
// Get this input's connected outputs
NodeOutput* source_output = source_input->get_connected_output();
Node* source_output_node = source_output->parentNode();
// Find equivalent in destination list
Node* dest_output_node = destination.at(source.indexOf(source_output_node));
Q_ASSERT(dest_output_node->id() == source_output_node->id());
NodeOutput* dest_output = static_cast<NodeOutput*>(dest_output_node->GetParameterWithID(source_output->id()));
NodeParam::ConnectEdge(dest_output, dest_input);
}
// If inputs are arrays, duplicate their connections too
if (source_input->IsArray()) {
NodeInputArray* source_array = static_cast<NodeInputArray*>(source_input);
NodeInputArray* dest_array = static_cast<NodeInputArray*>(dest_input);
for (int i=0;i<source_array->GetSize();i++) {
DuplicateConnectionsBetweenListsInternal(source, destination, source_array->At(i), dest_array->At(i));
}
}
}
void Node::DuplicateConnectionsBetweenLists(const QList<Node *> &source, const QList<Node *> &destination)
{
Q_ASSERT(source.size() == destination.size());
for (int i=0;i<source.size();i++) {
Node* source_input_node = source.at(i);
Node* dest_input_node = destination.at(i);
Q_ASSERT(source_input_node->id() == dest_input_node->id());
for (int j=0;j<source_input_node->params_.size();j++) {
NodeParam* source_param = source_input_node->params_.at(j);
if (source_param->type() == NodeInput::kInput) {
NodeInput* source_input = static_cast<NodeInput*>(source_param);
NodeInput* dest_input = static_cast<NodeInput*>(dest_input_node->params_.at(j));
DuplicateConnectionsBetweenListsInternal(source, destination, source_input, dest_input);
}
}
}
}
bool Node::CanBeDeleted() const
{
return can_be_deleted_;
@@ -381,29 +318,6 @@ int Node::IndexOfParameter(NodeParam *param) const
return params_.indexOf(param);
}
void Node::TraverseInputInternal(QList<Node*>& list, NodeInput* input, bool traverse, bool exclusive_only) {
if (input->IsConnected()
&& (input->get_connected_output()->edges().size() == 1 || !exclusive_only)) {
Node* connected = input->get_connected_node();
if (!list.contains(connected)) {
list.append(connected);
if (traverse) {
GetDependenciesInternal(connected, list, traverse, exclusive_only);
}
}
}
if (input->IsArray()) {
NodeInputArray* input_array = static_cast<NodeInputArray*>(input);
for (int i=0;i<input_array->GetSize();i++) {
TraverseInputInternal(list, input_array->At(i), traverse, exclusive_only);
}
}
}
/**
* @brief Recursively collects dependencies of Node `n` and appends them to QList `list`
*
@@ -412,41 +326,30 @@ void Node::TraverseInputInternal(QList<Node*>& list, NodeInput* input, bool trav
* TRUE to recursively traverse each node for a complete dependency graph. FALSE to return only the immediate
* dependencies.
*/
void Node::GetDependenciesInternal(const Node* n, QList<Node*>& list, bool traverse, bool exclusive_only) {
foreach (NodeParam* p, n->parameters()) {
if (p->type() == NodeParam::kInput) {
NodeInput* input = static_cast<NodeInput*>(p);
QList<Node*> Node::GetDependenciesInternal(bool traverse, bool exclusive_only) const {
QList<NodeInput*> inputs = GetInputsIncludingArrays();
QList<Node*> list;
TraverseInputInternal(list, input, traverse, exclusive_only);
}
foreach (NodeInput* i, inputs) {
i->GetDependencies(list, traverse, exclusive_only);
}
return list;
}
QList<Node *> Node::GetDependencies() const
{
QList<Node *> node_list;
GetDependenciesInternal(this, node_list, true, false);
return node_list;
return GetDependenciesInternal(true, false);
}
QList<Node *> Node::GetExclusiveDependencies() const
{
QList<Node *> node_list;
GetDependenciesInternal(this, node_list, true, true);
return node_list;
return GetDependenciesInternal(true, true);
}
QList<Node *> Node::GetImmediateDependencies() const
{
QList<Node *> node_list;
GetDependenciesInternal(this, node_list, false, false);
return node_list;
return GetDependenciesInternal(false, false);
}
Node::Capabilities Node::GetCapabilities(const NodeValueDatabase &) const
@@ -479,7 +382,7 @@ NodeInput *Node::ShaderIterativeInput() const
return nullptr;
}
NodeInput* Node::ProcessesSamplesFrom(const NodeValueDatabase &value) const
NodeInput* Node::ProcessesSamplesFrom(const NodeValueDatabase &) const
{
return nullptr;
}
@@ -488,11 +391,25 @@ void Node::ProcessSamples(const NodeValueDatabase &, const AudioRenderingParams&
{
}
NodeParam *Node::GetParameterWithID(const QString &id) const
NodeInput *Node::GetInputWithID(const QString &id) const
{
foreach (NodeParam* param, params_) {
if (param->id() == id) {
return param;
QList<NodeInput*> inputs = GetInputsIncludingArrays();
foreach (NodeInput* i, inputs) {
if (i->id() == id) {
return i;
}
}
return nullptr;
}
NodeOutput *Node::GetOutputWithID(const QString &id) const
{
foreach (NodeParam* p, params_) {
if (p->type() == NodeParam::kOutput
&& p->id() == id) {
return static_cast<NodeOutput*>(p);
}
}
@@ -665,25 +582,41 @@ void Node::ConnectInput(NodeInput *input)
connect(input, &NodeInput::ValueChanged, this, &Node::InputChanged);
connect(input, &NodeInput::EdgeAdded, this, &Node::InputConnectionChanged);
connect(input, &NodeInput::EdgeRemoved, this, &Node::InputConnectionChanged);
if (input->IsArray()) {
NodeInputArray* array = static_cast<NodeInputArray*>(input);
connect(array, &NodeInputArray::SubParamEdgeAdded, this, &Node::InputConnectionChanged);
connect(array, &NodeInputArray::SubParamEdgeRemoved, this, &Node::InputConnectionChanged);
connect(array, &NodeInputArray::SubParamEdgeAdded, this, &Node::EdgeAdded);
connect(array, &NodeInputArray::SubParamEdgeRemoved, this, &Node::EdgeRemoved);
}
}
void Node::DisconnectInput(NodeInput *input)
{
if (input->IsArray()) {
NodeInputArray* array = static_cast<NodeInputArray*>(input);
disconnect(array, &NodeInputArray::SubParamEdgeAdded, this, &Node::InputConnectionChanged);
disconnect(array, &NodeInputArray::SubParamEdgeRemoved, this, &Node::InputConnectionChanged);
disconnect(array, &NodeInputArray::SubParamEdgeAdded, this, &Node::EdgeAdded);
disconnect(array, &NodeInputArray::SubParamEdgeRemoved, this, &Node::EdgeRemoved);
}
disconnect(input, &NodeInput::ValueChanged, this, &Node::InputChanged);
disconnect(input, &NodeInput::EdgeAdded, this, &Node::InputConnectionChanged);
disconnect(input, &NodeInput::EdgeRemoved, this, &Node::InputConnectionChanged);
}
void Node::InputChanged(rational start, rational end)
void Node::InputChanged(const TimeRange& range)
{
InvalidateCache(start, end, static_cast<NodeInput*>(sender()));
InvalidateCache(range, static_cast<NodeInput*>(sender()), static_cast<NodeInput*>(sender()));
}
void Node::InputConnectionChanged(NodeEdgePtr edge)
{
DependentEdgeChanged(edge->input());
InvalidateCache(RATIONAL_MIN, RATIONAL_MAX, static_cast<NodeInput*>(sender()));
InvalidateCache(TimeRange(RATIONAL_MIN, RATIONAL_MAX), edge->input(), edge->input());
}
OLIVE_NAMESPACE_EXIT
+12 -17
View File
@@ -29,7 +29,6 @@
#include "codec/samplebuffer.h"
#include "common/rational.h"
#include "common/xmlutils.h"
#include "node/dependency.h"
#include "node/input.h"
#include "node/inputarray.h"
#include "node/output.h"
@@ -196,9 +195,14 @@ public:
virtual void ProcessSamples(const NodeValueDatabase &values, const AudioRenderingParams& params, const SampleBufferPtr input, SampleBufferPtr output, int index) const;
/**
* @brief Returns the parameter with the specified ID (or nullptr if it doesn't exist)
* @brief Returns the input with the specified ID (or nullptr if it doesn't exist)
*/
NodeParam* GetParameterWithID(const QString& id) const;
NodeInput* GetInputWithID(const QString& id) const;
/**
* @brief Returns the output with the specified ID (or nullptr if it doesn't exist)
*/
NodeOutput* GetOutputWithID(const QString& id) const;
/**
* @brief Returns whether this Node outputs data to the Node `n` in any way
@@ -261,12 +265,12 @@ public:
* the DAG. Even if the time needs to be transformed somehow (e.g. converting media time to sequence time), you can
* call this function with transformed time and relay the signal that way.
*/
virtual void InvalidateCache(const rational& start_range, const rational& end_range, NodeInput* from = nullptr);
virtual void InvalidateCache(const TimeRange& range, NodeInput* from, NodeInput* source);
/**
* @brief Signal through node graph to only invalidate frames that are currently visible on a ViewerWidget
*/
virtual void InvalidateVisible(NodeInput *from);
virtual void InvalidateVisible(NodeInput *from, NodeInput* source);
/**
* @brief Adjusts time that should be sent to nodes connected to certain inputs.
@@ -288,11 +292,6 @@ public:
*/
static void CopyInputs(Node* source, Node* destination, bool include_connections = true);
/**
* @brief For a list of copies nodes, this function will duplicate all the connections in the source list to the destination list
*/
static void DuplicateConnectionsBetweenLists(const QList<Node*>& source, const QList<Node *> &destination);
/**
* @brief Return whether this Node can be deleted or not
*/
@@ -358,9 +357,7 @@ protected:
void ClearCachedValuesInParameters(const rational& start_range, const rational& end_range);
void SendInvalidateCache(const rational& start_range, const rational& end_range);
virtual void DependentEdgeChanged(NodeInput* from);
void SendInvalidateCache(const TimeRange &range, NodeInput *source);
virtual void LoadInternal(QXmlStreamReader* reader, XMLNodeData& xml_node_data);
@@ -403,9 +400,7 @@ private:
void DisconnectInput(NodeInput* input);
static void TraverseInputInternal(QList<Node*>& list, NodeInput* input, bool traverse, bool exclusive_only);
static void GetDependenciesInternal(const Node* n, QList<Node*>& list, bool traverse, bool exclusive_only);
QList<Node *> GetDependenciesInternal(bool traverse, bool exclusive_only) const;
QList<NodeParam *> params_;
@@ -425,7 +420,7 @@ private:
QPointF position_;
private slots:
void InputChanged(rational start, rational end);
void InputChanged(const TimeRange &range);
void InputConnectionChanged(NodeEdgePtr edge);
+131 -125
View File
@@ -38,9 +38,8 @@ TrackOutput::TrackOutput() :
block_input_ = new NodeInputArray("block_in", NodeParam::kAny);
block_input_->set_is_keyframable(false);
AddInput(block_input_);
connect(block_input_, &NodeInputArray::EdgeAdded, this, &TrackOutput::BlockConnected);
connect(block_input_, &NodeInputArray::EdgeRemoved, this, &TrackOutput::BlockDisconnected);
connect(block_input_, &NodeInputArray::SizeChanged, this, &TrackOutput::BlockListSizeChanged);
connect(block_input_, &NodeInputArray::SubParamEdgeAdded, this, &TrackOutput::BlockConnected);
connect(block_input_, &NodeInputArray::SubParamEdgeRemoved, this, &TrackOutput::BlockDisconnected);
muted_input_ = new NodeInput("muted_in", NodeParam::kBoolean);
muted_input_->set_is_keyframable(false);
@@ -128,6 +127,8 @@ const int &TrackOutput::Index()
void TrackOutput::SetIndex(const int &index)
{
index_ = index;
emit IndexChanged(index);
}
Block *TrackOutput::BlockContainingTime(const rational &time) const
@@ -231,15 +232,15 @@ QList<Block *> TrackOutput::BlocksAtTimeRange(const TimeRange &range) const
return list;
}
const QVector<Block *> &TrackOutput::Blocks() const
const QList<Block *> &TrackOutput::Blocks() const
{
return block_cache_;
}
void TrackOutput::InvalidateCache(const rational &start_range, const rational &end_range, NodeInput *from)
void TrackOutput::InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput *source)
{
if (block_invalidate_cache_stack_ == 0) {
Node::InvalidateCache(qMax(start_range, rational(0)), qMin(end_range, track_length()), from);
Node::InvalidateCache(TimeRange(qMax(range.in(), rational(0)), qMin(range.out(), track_length())), from, source);
}
}
@@ -263,35 +264,42 @@ void TrackOutput::InsertBlockAfter(Block *block, Block *before)
void TrackOutput::PrependBlock(Block *block)
{
InsertBlockAtIndex(block, 0);
BlockInvalidateCache();
block_input_->Prepend();
NodeParam::ConnectEdge(block->output(), block_input_->First());
UnblockInvalidateCache();
// Everything has shifted at this point
InvalidateCache(TimeRange(0, track_length()), block_input_, block_input_);
}
void TrackOutput::InsertBlockAtIndex(Block *block, int index)
{
BlockInvalidateCache();
block_input_->InsertAt(index);
int insert_index = GetInputIndexFromCacheIndex(index);
block_input_->InsertAt(insert_index);
NodeParam::ConnectEdge(block->output(),
block_input_->At(index));
block_input_->At(insert_index));
UnblockInvalidateCache();
InvalidateCache(block->in(), track_length());
InvalidateCache(TimeRange(block->in(), track_length()), block_input_, block_input_);
}
void TrackOutput::AppendBlock(Block *block)
{
BlockInvalidateCache();
int last_index = block_input_->GetSize();
block_input_->Append();
NodeParam::ConnectEdge(block->output(),
block_input_->At(last_index));
NodeParam::ConnectEdge(block->output(), block_input_->Last());
UnblockInvalidateCache();
// Invalidate area that block was added to
InvalidateCache(block->in(), track_length());
InvalidateCache(TimeRange(block->in(), track_length()), block_input_, block_input_);
}
void TrackOutput::BlockInvalidateCache()
@@ -310,20 +318,18 @@ void TrackOutput::RippleRemoveBlock(Block *block)
rational remove_in = block->in();
int index_of_block_to_remove = block_cache_.indexOf(block);
block_input_->RemoveAt(index_of_block_to_remove);
block_input_->RemoveAt(GetInputIndexFromCacheIndex(block));
UnblockInvalidateCache();
InvalidateCache(remove_in, track_length());
InvalidateCache(TimeRange(remove_in, track_length()), block_input_, block_input_);
}
void TrackOutput::ReplaceBlock(Block *old, Block *replace)
{
BlockInvalidateCache();
int index_of_old_block = block_cache_.indexOf(old);
int index_of_old_block = GetInputIndexFromCacheIndex(old);
NodeParam::DisconnectEdge(old->output(),
block_input_->At(index_of_old_block));
@@ -334,9 +340,9 @@ void TrackOutput::ReplaceBlock(Block *old, Block *replace)
UnblockInvalidateCache();
if (old->length() == replace->length()) {
InvalidateCache(replace->in(), replace->out());
InvalidateCache(TimeRange(replace->in(), replace->out()), block_input_, block_input_);
} else {
InvalidateCache(replace->in(), RATIONAL_MAX);
InvalidateCache(TimeRange(replace->in(), RATIONAL_MAX), block_input_, block_input_);
}
}
@@ -407,6 +413,11 @@ bool TrackOutput::IsLocked() const
return locked_;
}
NodeInputArray *TrackOutput::block_input() const
{
return block_input_;
}
void TrackOutput::SetTrackName(const QString &name)
{
track_name_ = name;
@@ -415,7 +426,7 @@ void TrackOutput::SetTrackName(const QString &name)
void TrackOutput::SetMuted(bool e)
{
muted_input_->set_standard_value(e);
InvalidateCache(0, track_length());
InvalidateCache(TimeRange(0, track_length()), block_input_, block_input_);
}
void TrackOutput::SetLocked(bool e)
@@ -425,107 +436,107 @@ void TrackOutput::SetLocked(bool e)
void TrackOutput::UpdateInOutFrom(int index)
{
Q_ASSERT(index >= 0);
Q_ASSERT(index < block_cache_.size());
rational new_track_length;
// Find block just before this one to find the last out point
for (int i=index-1;i>=0;i--) {
rational last_out = (index == 0) ? 0 : block_cache_.at(index - 1)->out();
// Iterate through all blocks updating their in/outs
for (int i=index; i<block_cache_.size(); i++) {
Block* b = block_cache_.at(i);
if (b) {
new_track_length = b->out();
break;
}
}
b->set_in(last_out);
for (int i=index;i<block_cache_.size();i++) {
Block* b = block_cache_.at(i);
last_out += b->length();
if (b) {
// Set in
b->set_in(new_track_length);
b->set_out(last_out);
// Set out
new_track_length += b->length();
b->set_out(new_track_length);
emit b->Refreshed();
}
emit b->Refreshed();
}
// Update track length
if (new_track_length != track_length_) {
if (last_out != track_length_) {
rational old_track_length = track_length_;
track_length_ = new_track_length;
track_length_ = last_out;
emit TrackLengthChanged();
InvalidateCache(qMin(old_track_length, new_track_length),
qMax(old_track_length, new_track_length));
InvalidateCache(TimeRange(qMin(old_track_length, last_out), qMax(old_track_length, last_out)),
block_input_,
block_input_);
}
}
void TrackOutput::UpdatePreviousAndNextOfIndex(int index)
int TrackOutput::GetInputIndexFromCacheIndex(int cache_index)
{
Block* ref = block_cache_.at(index);
return GetInputIndexFromCacheIndex(block_cache_.at(cache_index));
}
Block* previous = nullptr;
Block* next = nullptr;
// Find previous
for (int i=index-1;i>=0;i--) {
previous = block_cache_.at(i);
if (previous) {
break;
int TrackOutput::GetInputIndexFromCacheIndex(Block *block)
{
for (int i=0; i<block_input_->GetSize(); i++) {
if (block_input_->At(i)->get_connected_node() == block) {
return i;
}
}
// Find next
for (int i=index+1;i<block_cache_.size();i++) {
next = block_cache_.at(i);
if (next) {
break;
}
}
if (ref) {
// Link blocks together
ref->set_previous(previous);
ref->set_next(next);
if (previous)
previous->set_next(ref);
if (next)
next->set_previous(ref);
} else {
// Link previous and next together
if (previous)
previous->set_next(next);
if (next)
next->set_previous(previous);
}
return -1;
}
void TrackOutput::BlockConnected(NodeEdgePtr edge)
{
int block_index = block_input_->IndexOfSubParameter(edge->input());
Q_ASSERT(block_index >= 0);
// Determine what node was just connected
Node* connected_node = edge->output()->parentNode();
Block* connected_block = connected_node->IsBlock() ? static_cast<Block*>(connected_node) : nullptr;
block_cache_.replace(block_index, connected_block);
UpdatePreviousAndNextOfIndex(block_index);
UpdateInOutFrom(block_index);
if (connected_block) {
connect(connected_block, SIGNAL(LengthChanged(const rational&)), this, SLOT(BlockLengthChanged()));
// If this node is a block, we can do something with it
if (connected_node->IsBlock()) {
Block* connected_block = static_cast<Block*>(connected_node);
// See where this input falls in our internal "block cache"
Block* next = nullptr;
for (int i=block_input_->IndexOfSubParameter(edge->input())+1; i<block_input_->GetSize(); i++) {
Node* that_node = block_input_->At(i)->get_connected_node();
// If we find a block, this is the block that will follow the one just connected
if (that_node && that_node->IsBlock()) {
next = static_cast<Block*>(that_node);
break;
}
}
int real_block_index;
// Either insert or append depending on if we found a "next" block
if (next) {
// Insert block before this next block
real_block_index = block_cache_.indexOf(next);
block_cache_.insert(real_block_index, connected_block);
// Update values with next
next->set_previous(connected_block);
connected_block->set_next(next);
} else {
// No "next", this block must come at the end
real_block_index = block_cache_.size();
block_cache_.append(connected_block);
// Update next value
connected_block->set_next(nullptr);
}
// For all blocks after the block we inserted (including it), update the "previous" and "next"
// fields as well as the in/out values
if (real_block_index == 0) {
connected_block->set_previous(nullptr);
} else {
Block* prev = block_cache_.at(real_block_index - 1);
connected_block->set_previous(prev);
prev->set_next(connected_block);
}
UpdateInOutFrom(real_block_index);
// Make connections to this block
connect(connected_block, &Block::LengthChanged, this, &TrackOutput::BlockLengthChanged);
emit BlockAdded(connected_block);
}
@@ -533,46 +544,41 @@ void TrackOutput::BlockConnected(NodeEdgePtr edge)
void TrackOutput::BlockDisconnected(NodeEdgePtr edge)
{
int block_index = block_input_->IndexOfSubParameter(edge->input());
Q_ASSERT(block_index >= 0);
block_cache_.replace(block_index, nullptr);
UpdatePreviousAndNextOfIndex(block_index);
UpdateInOutFrom(block_index);
// See what kind of node was just connected
Node* connected_node = edge->output()->parentNode();
Block* connected_block = connected_node->IsBlock() ? static_cast<Block*>(connected_node) : nullptr;
if (connected_block) {
disconnect(connected_block, SIGNAL(LengthChanged(const rational&)), this, SLOT(BlockLengthChanged()));
// Update previous and next references
// If this was a block, we would have put it in our block cache in BlockConnected()
if (connected_node->IsBlock()) {
Block* connected_block = static_cast<Block*>(connected_node);
// Determine what index this block was in our cache and remove it
int index_of_block = block_cache_.indexOf(connected_block);
block_cache_.removeAt(index_of_block);
// If there were blocks following this one, update their ins/outs
UpdateInOutFrom(index_of_block);
// Join the previous and next blocks together
if (connected_block->previous()) {
connected_block->previous()->set_next(connected_block->next());
}
if (connected_block->next()) {
connected_block->next()->set_previous(connected_block->previous());
}
disconnect(connected_block, &Block::LengthChanged, this, &TrackOutput::BlockLengthChanged);
emit BlockRemoved(connected_block);
}
}
void TrackOutput::BlockListSizeChanged(int size)
{
int old_size = block_cache_.size();
block_cache_.resize(size);
// Fill new slots with nullptr
for (int i=old_size;i<size;i++) {
block_cache_.replace(i, nullptr);
}
}
void TrackOutput::BlockLengthChanged()
{
// Assumes sender is a Block
Block* b = static_cast<Block*>(sender());
int index = block_cache_.indexOf(b);
Q_ASSERT(index >= 0);
UpdateInOutFrom(index);
UpdateInOutFrom(block_cache_.indexOf(b));
}
void TrackOutput::MutedInputValueChanged()
+12 -6
View File
@@ -82,9 +82,9 @@ public:
Block* BlockAtTime(const rational& time) const;
QList<Block*> BlocksAtTimeRange(const TimeRange& range) const;
const QVector<Block*>& Blocks() const;
const QList<Block *> &Blocks() const;
virtual void InvalidateCache(const rational& start_range, const rational& end_range, NodeInput* from = nullptr) override;
virtual void InvalidateCache(const TimeRange& range, NodeInput* from, NodeInput *source) override;
/**
* @brief Adds Block `block` at the very beginning of the Sequence before all other clips
@@ -150,6 +150,8 @@ public:
bool IsLocked() const;
NodeInputArray* block_input() const;
public slots:
void SetTrackName(const QString& name);
@@ -183,14 +185,20 @@ signals:
*/
void MutedChanged(bool e);
/**
* @brief Signal emitted when the index has changed
*/
void IndexChanged(int i);
protected:
private:
void UpdateInOutFrom(int index);
void UpdatePreviousAndNextOfIndex(int index);
int GetInputIndexFromCacheIndex(int cache_index);
int GetInputIndexFromCacheIndex(Block* block);
QVector<Block*> block_cache_;
QList<Block*> block_cache_;
NodeInputArray* block_input_;
@@ -215,8 +223,6 @@ private slots:
void BlockDisconnected(NodeEdgePtr edge);
void BlockListSizeChanged(int size);
void BlockLengthChanged();
void MutedInputValueChanged();
+45 -32
View File
@@ -31,9 +31,8 @@ TrackList::TrackList(ViewerOutput *parent, const Timeline::TrackType &type, Node
track_input_(track_input),
type_(type)
{
connect(track_input, &NodeInputArray::EdgeAdded, this, &TrackList::TrackConnected);
connect(track_input, &NodeInputArray::EdgeRemoved, this, &TrackList::TrackDisconnected);
connect(track_input, &NodeInputArray::SizeChanged, this, &TrackList::TrackListSizeChanged);
connect(track_input, &NodeInputArray::SubParamEdgeAdded, this, &TrackList::TrackConnected);
connect(track_input, &NodeInputArray::SubParamEdgeRemoved, this, &TrackList::TrackDisconnected);
}
const Timeline::TrackType &TrackList::type() const
@@ -51,38 +50,22 @@ void TrackList::TrackRemovedBlock(Block *block)
emit BlockRemoved(block);
}
void TrackList::TrackListSizeChanged(int size)
{
int old_size = track_cache_.size();
track_cache_.resize(size);
// Fill new slots with nullptr
for (int i=old_size;i<size;i++) {
track_cache_.replace(i, nullptr);
}
}
const QVector<TrackOutput *> &TrackList::Tracks() const
const QVector<TrackOutput *> &TrackList::GetTracks() const
{
return track_cache_;
}
TrackOutput *TrackList::TrackAt(int index) const
TrackOutput *TrackList::GetTrackAt(int index) const
{
if (index < 0 || index >= track_cache_.size()) {
return nullptr;
}
return track_cache_.at(index);
}
const rational &TrackList::TrackLength() const
const rational &TrackList::GetTotalLength() const
{
return total_length_;
}
int TrackList::TrackCount() const
int TrackList::GetTrackCount() const
{
return track_cache_.size();
}
@@ -98,7 +81,7 @@ TrackOutput* TrackList::AddTrack()
NodeParam::ConnectEdge(track->output(),
track_input_->At(track_input_->GetSize() - 1));
// FIXME: Test code only
// Auto-merge with previous track
if (track_input_->GetSize() > 1) {
TrackOutput* last_track = nullptr;
@@ -120,8 +103,8 @@ TrackOutput* TrackList::AddTrack()
Node* blend = NodeFactory::CreateFromID(QStringLiteral("org.olivevideoeditor.Olive.alphaoverblend"));
GetParentGraph()->AddNode(blend);
NodeParam::ConnectEdge(track->output(), static_cast<NodeInput*>(blend->GetParameterWithID("blend_in")));
NodeParam::ConnectEdge(last_track->output(), static_cast<NodeInput*>(blend->GetParameterWithID("base_in")));
NodeParam::ConnectEdge(track->output(), static_cast<NodeInput*>(blend->GetInputWithID("blend_in")));
NodeParam::ConnectEdge(last_track->output(), static_cast<NodeInput*>(blend->GetInputWithID("base_in")));
NodeParam::ConnectEdge(blend->output(), edge->input());
break;
}
@@ -142,7 +125,6 @@ TrackOutput* TrackList::AddTrack()
}
}
}
// End test code
return track;
}
@@ -173,14 +155,38 @@ void TrackList::TrackConnected(NodeEdgePtr edge)
if (connected_node->IsTrack()) {
TrackOutput* connected_track = static_cast<TrackOutput*>(connected_node);
track_cache_.replace(track_index, connected_track);
{
// Find "real" index
TrackOutput* next = nullptr;
for (int i=track_index+1; i<track_input_->GetSize(); i++) {
Node* that_track = track_input_->At(i)->get_connected_node();
if (that_track && that_track->IsTrack()) {
next = static_cast<TrackOutput*>(that_track);
break;
}
}
int track_index;
if (next) {
// Insert track before "next"
track_index = track_cache_.indexOf(next);
track_cache_.insert(track_index, connected_track);
} else {
// No "next", this track must come at the end
track_index = track_cache_.size();
track_cache_.append(connected_track);
}
connected_track->SetIndex(track_index);
}
connect(connected_track, &TrackOutput::BlockAdded, this, &TrackList::TrackAddedBlock);
connect(connected_track, &TrackOutput::BlockRemoved, this, &TrackList::TrackRemovedBlock);
connect(connected_track, &TrackOutput::TrackLengthChanged, this, &TrackList::UpdateTotalLength);
connect(connected_track, &TrackOutput::TrackHeightChanged, this, &TrackList::TrackHeightChangedSlot);
connected_track->SetIndex(track_index);
connected_track->set_track_type(type_);
emit TrackListChanged();
@@ -201,10 +207,17 @@ void TrackList::TrackDisconnected(NodeEdgePtr edge)
Q_ASSERT(track_index >= 0);
Node* connected_node = edge->output()->parentNode();
TrackOutput* track = connected_node->IsTrack() ? static_cast<TrackOutput*>(connected_node) : nullptr;
if (track) {
track_cache_.replace(track_index, nullptr);
if (connected_node->IsTrack()) {
TrackOutput* track = static_cast<TrackOutput*>(connected_node);
int index_of_track = track_cache_.indexOf(track);
track_cache_.removeAt(index_of_track);
// Update indices for all subsequent tracks
for (int i=index_of_track; i<track_cache_.size(); i++) {
track_cache_.at(i)->SetIndex(i);
}
// Traverse through Tracks uncaching and disconnecting them
emit TrackRemoved(track);
+4 -9
View File
@@ -38,17 +38,17 @@ public:
const Timeline::TrackType& type() const;
const QVector<TrackOutput*>& Tracks() const;
const QVector<TrackOutput*>& GetTracks() const;
TrackOutput* TrackAt(int index) const;
TrackOutput* GetTrackAt(int index) const;
TrackOutput *AddTrack();
void RemoveTrack();
const rational& TrackLength() const;
const rational& GetTotalLength() const;
int TrackCount() const;
int GetTrackCount() const;
NodeGraph* GetParentGraph() const;
@@ -100,11 +100,6 @@ private slots:
*/
void TrackRemovedBlock(Block* block);
/**
* @brief Slot for when the count of tracks in the track input changes
*/
void TrackListSizeChanged(int size);
/**
* @brief Slot for when any of the track's length changes so we can update the length of the tracklist
*/
+10 -25
View File
@@ -92,26 +92,24 @@ NodeInput *ViewerOutput::samples_input() const
return samples_input_;
}
void ViewerOutput::InvalidateCache(const rational &start_range, const rational &end_range, NodeInput *from)
void ViewerOutput::InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput *source)
{
Node::InvalidateCache(start_range, end_range, from);
if (from == texture_input()) {
emit VideoChangedBetween(TimeRange(start_range, end_range));
emit VideoChangedBetween(range, source);
} else if (from == samples_input()) {
emit AudioChangedBetween(TimeRange(start_range, end_range));
emit AudioChangedBetween(range, source);
}
SendInvalidateCache(start_range, end_range);
Node::InvalidateCache(range, from, source);
}
void ViewerOutput::InvalidateVisible(NodeInput* from)
void ViewerOutput::InvalidateVisible(NodeInput* from, NodeInput *source)
{
if (from == texture_input()) {
emit VisibleInvalidated();
emit VisibleInvalidated(source);
}
Node::InvalidateVisible(from);
Node::InvalidateVisible(from, source);
}
const VideoParams &ViewerOutput::video_params() const
@@ -164,26 +162,13 @@ const QUuid &ViewerOutput::uuid() const
return uuid_;
}
void ViewerOutput::DependentEdgeChanged(NodeInput *from)
{
if (from == texture_input_) {
emit VideoGraphChanged();
} else if (from == samples_input_) {
emit AudioGraphChanged();
}
Node::DependentEdgeChanged(from);
}
void ViewerOutput::UpdateTrackCache()
{
track_cache_.clear();
foreach (TrackList* list, track_lists_) {
foreach (TrackOutput* track, list->Tracks()) {
if (track) {
track_cache_.append(track);
}
foreach (TrackOutput* track, list->GetTracks()) {
track_cache_.append(track);
}
}
}
@@ -206,7 +191,7 @@ void ViewerOutput::UpdateLength(const rational &length)
rational new_length = 0;
foreach (TrackList* list, track_lists_) {
new_length = qMax(new_length, list->TrackLength());
new_length = qMax(new_length, list->GetTotalLength());
}
if (new_length != timeline_length_) {
+5 -12
View File
@@ -55,8 +55,8 @@ public:
NodeInput* texture_input() const;
NodeInput* samples_input() const;
virtual void InvalidateCache(const rational &start_range, const rational &end_range, NodeInput *from = nullptr) override;
virtual void InvalidateVisible(NodeInput *from) override;
virtual void InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput* source) override;
virtual void InvalidateVisible(NodeInput *from, NodeInput* source) override;
const VideoParams& video_params() const;
const AudioParams& audio_params() const;
@@ -79,21 +79,14 @@ public:
const QString& media_name() const;
void set_media_name(const QString& name);
protected:
virtual void DependentEdgeChanged(NodeInput* from) override;
signals:
void TimebaseChanged(const rational&);
void VideoChangedBetween(const TimeRange& range);
void VideoChangedBetween(const TimeRange& range, NodeInput* source);
void AudioChangedBetween(const TimeRange& range);
void AudioChangedBetween(const TimeRange& range, NodeInput* source);
void VisibleInvalidated();
void VideoGraphChanged();
void AudioGraphChanged();
void VisibleInvalidated(NodeInput* source);
void LengthChanged(const rational& length);
+14
View File
@@ -32,9 +32,16 @@ CurvePanel::CurvePanel(QWidget *parent) :
Retranslate();
}
NodeInput *CurvePanel::GetInput() const
{
return static_cast<CurveWidget*>(GetTimeBasedWidget())->GetInput();
}
void CurvePanel::SetInput(NodeInput *input)
{
static_cast<CurveWidget*>(GetTimeBasedWidget())->SetInput(input);
Retranslate();
}
void CurvePanel::SetTimeTarget(Node *target)
@@ -59,6 +66,13 @@ void CurvePanel::Retranslate()
TimeBasedPanel::Retranslate();
SetTitle(tr("Curve Editor"));
NodeInput* connected_input = static_cast<CurveWidget*>(GetTimeBasedWidget())->GetInput();
if (connected_input) {
SetSubtitle(connected_input->name());
} else {
SetSubtitle(QString());
}
}
OLIVE_NAMESPACE_EXIT
+2
View File
@@ -32,6 +32,8 @@ class CurvePanel : public TimeBasedPanel
public:
CurvePanel(QWidget* parent);
NodeInput* GetInput() const;
public slots:
void SetInput(NodeInput* input);
+4 -1
View File
@@ -144,7 +144,10 @@ void PanelManager::FocusChanged(QWidget *old, QWidget *now)
void PanelManager::SetPanelsLocked(bool locked)
{
foreach (PanelWidget* panel, focus_history_) {
panel->SetMovementLocked(locked);
// Only affect panels actually in our layout
if (!panel->isFloating()) {
panel->SetMovementLocked(locked);
}
}
locked_ = locked;
+4
View File
@@ -177,6 +177,10 @@ T *PanelManager::CreatePanel(QWidget *parent)
panel->SetMovementLocked(locked_);
// Sane default for panel geometry
panel->resize(parent->size() / 3);
panel->move(panel->mapFromGlobal(parent->mapToGlobal(parent->pos())));
// Connect destroy signal so we can remove it from focus history
connect(panel, &PanelWidget::destroyed, this, &PanelManager::PanelDestroyed);
+82 -1
View File
@@ -20,15 +20,19 @@
#include "param.h"
#include "window/mainwindow/mainwindow.h"
OLIVE_NAMESPACE_ENTER
ParamPanel::ParamPanel(QWidget* parent) :
TimeBasedPanel(QStringLiteral("ParamPanel"), parent)
{
NodeParamView* view = new NodeParamView();
connect(view, &NodeParamView::SelectedInputChanged, this, &ParamPanel::SelectedInputChanged);
connect(view, &NodeParamView::InputDoubleClicked, this, &ParamPanel::CreateCurvePanel);
connect(view, &NodeParamView::TimeTargetChanged, this, &ParamPanel::TimeTargetChanged);
connect(view, &NodeParamView::RequestSelectNode, this, &ParamPanel::RequestSelectNode);
connect(view, &NodeParamView::OpenedNode, this, &ParamPanel::OpeningNode);
connect(view, &NodeParamView::ClosedNode, this, &ParamPanel::ClosingNode);
SetTimeBasedWidget(view);
Retranslate();
@@ -41,6 +45,20 @@ void ParamPanel::SetNodes(QList<Node *> nodes)
Retranslate();
}
void ParamPanel::SetTimestamp(const int64_t &timestamp)
{
TimeBasedPanel::SetTimestamp(timestamp);
// Ensure all CurvePanels are updated with this time too
QHash<NodeInput*, CurvePanel*>::const_iterator i;
for (i=open_curve_panels_.begin(); i!=open_curve_panels_.end(); i++) {
if (i.value() && i.value() != sender()) {
i.value()->SetTimestamp(timestamp);
}
}
}
void ParamPanel::Retranslate()
{
SetTitle(tr("Parameter Editor"));
@@ -56,4 +74,67 @@ void ParamPanel::Retranslate()
}
}
void ParamPanel::CreateCurvePanel(NodeInput *input)
{
if (!input->is_keyframable()) {
return;
}
CurvePanel* panel = open_curve_panels_.value(input);
if (panel) {
panel->raise();
return;
}
NodeParamView* view = static_cast<NodeParamView*>(GetTimeBasedWidget());
panel = Core::instance()->main_window()->AppendCurvePanel();
panel->SetInput(input);
panel->SetTimebase(view->timebase());
panel->SetTimestamp(view->GetTimestamp());
connect(view, &NodeParamView::TimebaseChanged, panel, &CurvePanel::SetTimebase);
connect(view, &NodeParamView::TimeChanged, panel, &CurvePanel::SetTimestamp);
connect(panel, &CurvePanel::TimeChanged, view, &NodeParamView::SetTimestamp);
connect(panel, &CurvePanel::TimeChanged, view, &NodeParamView::TimeChanged);
connect(panel, &CurvePanel::CloseRequested, this, &ParamPanel::ClosingCurvePanel);
open_curve_panels_.insert(input, panel);
}
void ParamPanel::OpeningNode(Node *n)
{
QList<NodeInput*> inputs = n->GetInputsIncludingArrays();
foreach (NodeInput* i, inputs) {
if (open_curve_panels_.contains(i)) {
// We had a CurvePanel open for this input that was closed in ClosingNode(), re-open it
CreateCurvePanel(i);
}
}
}
void ParamPanel::ClosingNode(Node *n)
{
QList<NodeInput*> inputs = n->GetInputsIncludingArrays();
foreach (NodeInput* i, inputs) {
CurvePanel* panel = open_curve_panels_.value(i);
// Close the panel (this also destroys it), but keep a reference in the hash
if (panel) {
panel->close();
open_curve_panels_.insert(i, nullptr);
}
}
}
void ParamPanel::ClosingCurvePanel()
{
CurvePanel* panel = static_cast<CurvePanel*>(sender());
open_curve_panels_.remove(panel->GetInput());
}
OLIVE_NAMESPACE_EXIT
+15 -2
View File
@@ -21,6 +21,7 @@
#ifndef PARAM_H
#define PARAM_H
#include "panel/curve/curve.h"
#include "panel/timebased/timebased.h"
#include "widget/nodeparamview/nodeparamview.h"
@@ -35,9 +36,9 @@ public:
public slots:
void SetNodes(QList<Node*> nodes);
signals:
void SelectedInputChanged(NodeInput* input);
virtual void SetTimestamp(const int64_t& timestamp) override;
signals:
void TimeTargetChanged(Node* node);
void RequestSelectNode(const QList<Node*>& target);
@@ -45,6 +46,18 @@ signals:
protected:
virtual void Retranslate() override;
private slots:
void CreateCurvePanel(NodeInput* input);
void OpeningNode(Node* n);
void ClosingNode(Node* n);
void ClosingCurvePanel();
private:
QHash<NodeInput*, CurvePanel*> open_curve_panels_;
};
OLIVE_NAMESPACE_EXIT
+1 -10
View File
@@ -84,19 +84,10 @@ QString ScopePanel::TypeToName(ScopePanel::Type t)
return QString();
}
void ScopePanel::SetDisplayReferredTexture(OpenGLTexture *texture)
{
Q_UNUSED(texture)
}
void ScopePanel::SetReferenceBuffer(Frame *frame)
{
histogram_->SetBuffer(frame);
}
void ScopePanel::SetReferenceTexture(OpenGLTexture *texture)
{
waveform_view_->SetTexture(texture);
waveform_view_->SetBuffer(frame);
}
void ScopePanel::SetColorManager(ColorManager *manager)
-4
View File
@@ -50,12 +50,8 @@ public:
static QString TypeToName(Type t);
public slots:
void SetDisplayReferredTexture(OpenGLTexture* texture);
void SetReferenceBuffer(Frame* frame);
void SetReferenceTexture(OpenGLTexture* texture);
void SetColorManager(ColorManager* manager);
protected:
+1 -1
View File
@@ -68,7 +68,7 @@ void TimeBasedPanel::SetTimebase(const rational &timebase)
widget_->SetTimebase(timebase);
}
void TimeBasedPanel::SetTime(const int64_t &timestamp)
void TimeBasedPanel::SetTimestamp(const int64_t &timestamp)
{
widget_->SetTimestamp(timestamp);
}
+1 -1
View File
@@ -89,7 +89,7 @@ public:
public slots:
void SetTimebase(const rational& timebase);
void SetTime(const int64_t& timestamp);
virtual void SetTimestamp(const int64_t& timestamp);
signals:
void TimeChanged(const int64_t& time);
+1 -25
View File
@@ -25,8 +25,7 @@
OLIVE_NAMESPACE_ENTER
ViewerPanelBase::ViewerPanelBase(const QString& object_name, QWidget *parent) :
TimeBasedPanel(object_name, parent),
scope_panel_count_(0)
TimeBasedPanel(object_name, parent)
{
}
@@ -98,36 +97,13 @@ void ViewerPanelBase::CreateScopePanel(ScopePanel::Type type)
p->SetType(type);
// We treat our scope panels as kind of children, and destroy them if we're ever destroyed
connect(this, &ViewerPanelBase::destroyed, p, &ScopePanel::deleteLater);
// If the scope closes, reduce the count (we do this because if no scopes are open, we can optimize the viewer slightly)
connect(p, &ScopePanel::CloseRequested, this, &ViewerPanelBase::ScopePanelClosed);
// Connect viewer widget texture drawing to scope panel
connect(vw, &ViewerWidget::DrewManagedTexture, p, &ScopePanel::SetDisplayReferredTexture);
connect(vw, &ViewerWidget::LoadedBuffer, p, &ScopePanel::SetReferenceBuffer);
connect(vw, &ViewerWidget::LoadedTexture, p, &ScopePanel::SetReferenceTexture);
connect(vw, &ViewerWidget::ColorManagerChanged, p, &ScopePanel::SetColorManager);
p->SetColorManager(vw->color_manager());
if (!scope_panel_count_) {
vw->SetEmitDrewManagedTextureEnabled(true);
}
scope_panel_count_++;
vw->ForceUpdate();
}
void ViewerPanelBase::ScopePanelClosed()
{
scope_panel_count_--;
if (!scope_panel_count_) {
static_cast<ViewerWidget*>(GetTimeBasedWidget())->SetEmitDrewManagedTextureEnabled(false);
}
}
OLIVE_NAMESPACE_EXIT
-6
View File
@@ -59,12 +59,6 @@ public:
protected:
void CreateScopePanel(ScopePanel::Type type);
private:
int scope_panel_count_;
private slots:
void ScopePanelClosed();
};
OLIVE_NAMESPACE_EXIT
+1 -13
View File
@@ -39,7 +39,7 @@ bool AudioBackend::InitInternal()
// Initiate one thread per CPU core
for (int i=0;i<threads().size();i++) {
// Create one processor object for each thread
AudioWorker* processor = new AudioWorker(&copy_map_);
AudioWorker* processor = new AudioWorker(&node_copy_map_);
processor->SetParameters(params());
processors_.append(processor);
}
@@ -51,18 +51,6 @@ void AudioBackend::CloseInternal()
{
}
bool AudioBackend::CompileInternal()
{
// This backend doesn't compile anything yet
return AudioRenderBackend::CompileInternal();
}
void AudioBackend::DecompileInternal()
{
// This backend doesn't compile anything yet
AudioRenderBackend::DecompileInternal();
}
void AudioBackend::ConnectWorkerToThis(RenderWorker *worker)
{
AudioRenderBackend::ConnectWorkerToThis(worker);
-4
View File
@@ -40,10 +40,6 @@ protected:
virtual void CloseInternal() override;
virtual bool CompileInternal() override;
virtual void DecompileInternal() override;
virtual void ConnectWorkerToThis(RenderWorker* worker) override;
private slots:
+2 -18
View File
@@ -58,31 +58,15 @@ void AudioRenderBackend::SetParameters(const AudioRenderingParams &params)
void AudioRenderBackend::ConnectViewer(ViewerOutput *node)
{
connect(node, &ViewerOutput::AudioChangedBetween, this, &AudioRenderBackend::InvalidateCache);
connect(node, &ViewerOutput::AudioGraphChanged, this, &AudioRenderBackend::QueueRecompile);
connect(node, &ViewerOutput::LengthChanged, this, &AudioRenderBackend::TruncateCache);
}
void AudioRenderBackend::DisconnectViewer(ViewerOutput *node)
{
disconnect(node, &ViewerOutput::AudioChangedBetween, this, &AudioRenderBackend::InvalidateCache);
disconnect(node, &ViewerOutput::AudioGraphChanged, this, &AudioRenderBackend::QueueRecompile);
disconnect(node, &ViewerOutput::LengthChanged, this, &AudioRenderBackend::TruncateCache);
}
bool AudioRenderBackend::CompileInternal()
{
for (int i=0;i<copied_graph_.nodes().size();i++) {
copy_map_.insert(copied_graph_.nodes().at(i), source_node_list_.at(i));
}
return true;
}
void AudioRenderBackend::DecompileInternal()
{
copy_map_.clear();
}
bool AudioRenderBackend::GenerateCacheIDInternal(QCryptographicHash &hash)
{
if (!params_.is_valid()) {
@@ -187,7 +171,7 @@ void AudioRenderBackend::ConformUnavailable(StreamPtr stream, TimeRange range, r
} else if (audio_stream->has_conformed_version(params)) {
// Index JUST finished, requeue this time
InvalidateCache(range);
InvalidateCache(range, nullptr);
} else {
@@ -215,7 +199,7 @@ void AudioRenderBackend::ConformUpdated(Stream *stream, AudioRenderingParams par
// Send invalidate cache signal
ic_from_conform_ = true;
InvalidateCache(copy.affected_range);
InvalidateCache(copy.affected_range, nullptr);
ic_from_conform_ = false;
}
-6
View File
@@ -54,10 +54,6 @@ protected:
virtual void DisconnectViewer(ViewerOutput* node) override;
virtual bool CompileInternal() override;
virtual void DecompileInternal() override;
/**
* @brief Internal function for generating the cache ID
*/
@@ -73,8 +69,6 @@ protected:
virtual void InvalidateCacheInternal(const rational &start_range, const rational &end_range) override;
QHash<Node*, Node*> copy_map_;
private:
struct ConformWaitInfo {
StreamPtr stream;
+1 -1
View File
@@ -100,7 +100,7 @@ NodeValueTable AudioRenderWorker::RenderBlock(const TrackOutput *track, const Ti
{
// Save waveform to file
Block* src_block = static_cast<Block*>(copy_map_->value(b));
Block* src_block = static_cast<Block*>(copy_map_->key(b));
QDir local_appdata_dir(Config::Current()["DiskCachePath"].toString());
QDir waveform_loc = local_appdata_dir.filePath(QStringLiteral("waveform"));
waveform_loc.mkpath(".");
+3 -3
View File
@@ -291,14 +291,14 @@ void Exporter::EncoderOpenedSuccessfully()
video_backend_->SetOperatingMode(VideoRenderWorker::kHashOnly);
connect(video_backend_, &VideoRenderBackend::QueueComplete, this, &Exporter::VideoHashesComplete);
video_backend_->InvalidateCache(export_range_);
video_backend_->InvalidateCache(export_range_, nullptr);
}
if (!audio_done_) {
// We set the audio backend to render the full sequence to the disk
connect(audio_backend_, &AudioRenderBackend::AudioComplete, this, &Exporter::AudioRendered);
audio_backend_->InvalidateCache(export_range_);
audio_backend_->InvalidateCache(export_range_, nullptr);
}
}
@@ -344,7 +344,7 @@ void Exporter::VideoHashesComplete()
}
foreach (const TimeRange& range, ranges) {
video_backend_->InvalidateCache(range);
video_backend_->InvalidateCache(range, nullptr);
}
}
@@ -89,15 +89,6 @@ void OpenGLBackend::CloseInternal()
VideoRenderBackend::CloseInternal();
}
bool OpenGLBackend::CompileInternal()
{
return true;
}
void OpenGLBackend::DecompileInternal()
{
}
void OpenGLBackend::ParamsChangedEvent()
{
// If we're initiated, we need to recreate the texture. Otherwise this backend isn't active so it doesn't matter.
@@ -43,10 +43,6 @@ protected:
virtual void CloseInternal() override;
virtual bool CompileInternal() override;
virtual void DecompileInternal() override;
virtual void ParamsChangedEvent() override;
private:
+3 -3
View File
@@ -132,7 +132,7 @@ void OpenGLProxy::FrameToValue(FramePtr frame, StreamPtr stream, NodeValueTable*
VideoRenderingParams footage_params(frame->width(), frame->height(), frame->format());
footage_tex_ref = texture_cache_.Get(ctx_, footage_params, frame->data(), frame->linesize_pixels());
footage_tex_ref = texture_cache_.Get(ctx_, footage_params, frame);
if (ocio_method == ColorManager::kOCIOFast) {
if (!color_processor->IsEnabled()) {
@@ -212,8 +212,8 @@ void OpenGLProxy::RunNodeAccelerated(const Node *node, const TimeRange &range, N
if (!shader) {
// Since we have shader code, compile it now
QString frag_code = node->ShaderFragmentCode(input_params);
QString vert_code = node->ShaderVertexCode(input_params);
QString frag_code = node->ShaderFragmentCode(input_params);
if (frag_code.isEmpty()) {
frag_code = OpenGLShader::CodeDefaultFragment();
@@ -258,7 +258,7 @@ void OpenGLProxy::RunNodeAccelerated(const Node *node, const TimeRange &range, N
NodeInput* input = static_cast<NodeInput*>(param);
// Get value from database at this input
NodeValue meta_value = node->InputValueFromTable(input, input_params, true);
NodeValue meta_value = node->InputValueFromTable(input, input_params, false);
const QVariant& value = meta_value.data();
NodeParam::DataType data_type;
@@ -37,23 +37,23 @@ const GLfloat blit_vertices[] = {
};
const GLfloat blit_texcoords[] = {
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0, 0.0,
0.0, 1.0,
1.0, 1.0
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f
};
const GLfloat flipped_blit_texcoords[] = {
0.0, 1.0,
1.0, 1.0,
1.0, 0.0,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
0.0, 1.0,
0.0, 0.0,
1.0, 0.0
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
};
/**
@@ -65,7 +65,8 @@ const GLfloat flipped_blit_texcoords[] = {
*
* Currently active QOpenGLFunctions object (use context()->functions() if unsure).
*/
void OpenGLRenderFunctions::PrepareToDraw(QOpenGLFunctions* f) {
void OpenGLRenderFunctions::PrepareToDraw(QOpenGLFunctions* f)
{
f->glGenerateMipmap(GL_TEXTURE_2D);
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -141,7 +142,6 @@ void OpenGLRenderFunctions::Blit(OpenGLShaderPtr pipeline, bool flipped, QMatrix
void OpenGLRenderFunctions::Blit(OpenGLShader *pipeline, bool flipped, QMatrix4x4 matrix)
{
// FIXME: is currentContext() reliable here?
QOpenGLFunctions* func = QOpenGLContext::currentContext()->functions();
PrepareToDraw(func);
@@ -153,13 +153,13 @@ void OpenGLRenderFunctions::Blit(OpenGLShader *pipeline, bool flipped, QMatrix4x
QOpenGLBuffer m_vbo;
m_vbo.create();
m_vbo.bind();
m_vbo.allocate(blit_vertices, 18 * static_cast<int>(sizeof(GLfloat)));
m_vbo.allocate(blit_vertices, 18 * sizeof(GLfloat));
m_vbo.release();
QOpenGLBuffer m_vbo2;
m_vbo2.create();
m_vbo2.bind();
m_vbo2.allocate(flipped ? flipped_blit_texcoords : blit_texcoords, 12 * static_cast<int>(sizeof(GLfloat)));
m_vbo2.allocate(flipped ? flipped_blit_texcoords : blit_texcoords, 12 * sizeof(GLfloat));
m_vbo2.release();
pipeline->bind();
@@ -167,13 +167,13 @@ void OpenGLRenderFunctions::Blit(OpenGLShader *pipeline, bool flipped, QMatrix4x
pipeline->setUniformValue("ove_mvpmat", matrix);
pipeline->setUniformValue("ove_maintex", 0);
GLuint vertex_location = static_cast<GLuint>(pipeline->attributeLocation("a_position"));
int vertex_location = pipeline->attributeLocation("a_position");
m_vbo.bind();
func->glEnableVertexAttribArray(vertex_location);
func->glVertexAttribPointer(vertex_location, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
m_vbo.release();
GLuint tex_location = static_cast<GLuint>(pipeline->attributeLocation("a_texcoord"));
int tex_location = pipeline->attributeLocation("a_texcoord");
m_vbo2.bind();
func->glEnableVertexAttribArray(tex_location);
func->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
+3 -6
View File
@@ -61,8 +61,8 @@ OpenGLShaderPtr OpenGLShader::CreateOCIO(QOpenGLContext* ctx,
shaderDesc.setLut3DEdgeLen(OCIO_LUT3D_EDGE_SIZE);
// Compute LUT
GLfloat* ocio_lut_data = new GLfloat[OCIO_NUM_3D_ENTRIES];
processor->getGpuLut3D(ocio_lut_data, shaderDesc);
std::vector<float> ocio_lut_data(OCIO_NUM_3D_ENTRIES);
processor->getGpuLut3D(&ocio_lut_data[0], shaderDesc);
// Create LUT texture
xf->glGenTextures(1, &lut_texture);
@@ -81,10 +81,7 @@ OpenGLShaderPtr OpenGLShader::CreateOCIO(QOpenGLContext* ctx,
// Allocate storage for texture
xf->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F,
OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE,
0, GL_RGB, GL_FLOAT, ocio_lut_data);
// Delete local copy
delete [] ocio_lut_data;
0, GL_RGB, GL_FLOAT, &ocio_lut_data[0]);
// Create OCIO shader code
QString shader_text;
@@ -74,6 +74,11 @@ void OpenGLTexture::Create(QOpenGLContext *ctx, int width, int height, const Pix
}
void OpenGLTexture::Create(QOpenGLContext *ctx, FramePtr frame)
{
Create(ctx, frame.get());
}
void OpenGLTexture::Create(QOpenGLContext *ctx, Frame *frame)
{
Create(ctx, frame->width(), frame->height(), frame->format(), frame->data(), frame->linesize_pixels());
}
@@ -120,6 +125,16 @@ const GLuint &OpenGLTexture::texture() const
return texture_;
}
void OpenGLTexture::Upload(FramePtr frame)
{
Upload(frame.get());
}
void OpenGLTexture::Upload(Frame *frame)
{
Upload(frame->data(), frame->linesize_pixels());
}
void OpenGLTexture::Upload(const void *data, int linesize)
{
if (!IsCreated()) {
@@ -44,6 +44,7 @@ public:
void Create(QOpenGLContext* ctx, int width, int height, const PixelFormat::Format &format, const void *data, int linesize);
void Create(QOpenGLContext* ctx, int width, int height, const PixelFormat::Format &format);
void Create(QOpenGLContext* ctx, FramePtr frame);
void Create(QOpenGLContext* ctx, Frame* frame);
bool IsCreated() const;
@@ -59,6 +60,8 @@ public:
const GLuint& texture() const;
void Upload(FramePtr frame);
void Upload(Frame* frame);
void Upload(const void *data, int linesize);
public slots:
@@ -29,6 +29,16 @@ OpenGLTextureCache::~OpenGLTextureCache()
}
}
OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(QOpenGLContext *ctx, const VideoRenderingParams &params, FramePtr frame)
{
return Get(ctx, params, frame.get());
}
OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(QOpenGLContext *ctx, const VideoRenderingParams &params, Frame *frame)
{
return Get(ctx, params, frame->data(), frame->linesize_pixels());
}
OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(QOpenGLContext* ctx, const VideoRenderingParams &params, const void *data, int linesize)
{
OpenGLTexturePtr texture = nullptr;
@@ -57,6 +57,8 @@ public:
DISABLE_COPY_MOVE(OpenGLTextureCache)
ReferencePtr Get(QOpenGLContext *ctx, const VideoRenderingParams& params, FramePtr frame);
ReferencePtr Get(QOpenGLContext *ctx, const VideoRenderingParams& params, Frame* frame);
ReferencePtr Get(QOpenGLContext *ctx, const VideoRenderingParams& params, const void *data, int linesize);
ReferencePtr Get(QOpenGLContext *ctx, const VideoRenderingParams& params);
+128 -102
View File
@@ -31,12 +31,9 @@ OLIVE_NAMESPACE_ENTER
RenderBackend::RenderBackend(QObject *parent) :
QObject(parent),
compiled_(false),
started_(false),
viewer_node_(nullptr),
copied_viewer_node_(nullptr),
recompile_queued_(false),
input_update_queued_(false)
copied_viewer_node_(nullptr)
{
// FIXME: Don't create in CLI mode
cancel_dialog_ = new RenderCancelDialog(Core::instance()->main_window());
@@ -84,7 +81,7 @@ void RenderBackend::Close()
CancelQueue();
Decompile();
SetViewerNode(nullptr);
CloseInternal();
@@ -114,23 +111,30 @@ const QString &RenderBackend::GetError() const
void RenderBackend::SetViewerNode(ViewerOutput *viewer_node)
{
if (viewer_node_ != nullptr) {
if (viewer_node_) {
CancelQueue();
DisconnectViewer(viewer_node_);
Decompile();
copied_graph_.Clear();
copied_viewer_node_ = nullptr;
node_copy_map_.clear();
}
viewer_node_ = viewer_node;
if (viewer_node_ != nullptr) {
if (viewer_node_) {
ConnectViewer(viewer_node_);
RegenerateCacheID();
}
InvalidateCache(TimeRange(0, RATIONAL_MAX));
copied_viewer_node_ = static_cast<ViewerOutput*>(viewer_node_->copy());
copied_graph_.AddNode(copied_viewer_node_);
node_copy_map_.insert(viewer_node_, copied_viewer_node_);
InvalidateCache(TimeRange(0, RATIONAL_MAX),
static_cast<NodeInput*>(viewer_node_->GetInputWithID(GetDependentInput()->id())));
}
}
bool RenderBackend::IsInitiated()
@@ -138,58 +142,6 @@ bool RenderBackend::IsInitiated()
return started_;
}
bool RenderBackend::Compile()
{
if (compiled_) {
return true;
}
// Get dependencies of viewer node
source_node_list_.append(viewer_node_);
source_node_list_.append(viewer_node_->GetDependencies());
// Copy all dependencies into graph
foreach (Node* n, source_node_list_) {
Node* copy = n->copy();
Node::CopyInputs(n, copy, false);
copied_graph_.AddNode(copy);
}
// We just copied the inputs, so if an input update is queued, it's unnecessary
input_update_queued_ = false;
// We know that the first node will be the viewer node since we appended that first in the copy
copied_viewer_node_ = static_cast<ViewerOutput*>(copied_graph_.nodes().first());
// Copy connections
Node::DuplicateConnectionsBetweenLists(source_node_list_, copied_graph_.nodes());
compiled_ = CompileInternal();
if (!compiled_) {
Decompile();
}
return compiled_;
}
void RenderBackend::Decompile()
{
if (!compiled_) {
return;
}
DecompileInternal();
copied_graph_.Clear();
copied_viewer_node_ = nullptr;
source_node_list_.clear();
compiled_ = false;
}
void RenderBackend::RegenerateCacheID()
{
QCryptographicHash hash(QCryptographicHash::Sha1);
@@ -261,34 +213,19 @@ void RenderBackend::CacheNext()
return;
}
if (!Init()
|| !ViewerIsConnected()
|| !CanRender()) {
if (!ViewerIsConnected()
|| !CanRender()
|| !Init()) {
return;
}
if ((input_update_queued_ || recompile_queued_) && !AllProcessorsAreAvailable()) {
return;
}
if (recompile_queued_) {
Decompile();
recompile_queued_ = false;
}
if (!compiled_ && !Compile()) {
return;
}
if (input_update_queued_) {
for (int i=0;i<source_node_list_.size();i++) {
Node* src = source_node_list_.at(i);
Node* dst = copied_graph_.nodes().at(i);
Node::CopyInputs(src, dst, false);
while (!input_update_queued_.isEmpty()) {
if (!AllProcessorsAreAvailable()) {
// To update the inputs, we need all workers to stop
return;
}
input_update_queued_ = false;
CopyNodeInputValue(input_update_queued_.takeFirst());
}
Node* node_connected_to_viewer = GetDependentInput()->get_connected_node();
@@ -356,12 +293,8 @@ void RenderBackend::CancelQueue()
cancel_dialog_->RunIfWorkersAreBusy();
}
void RenderBackend::InvalidateCache(const TimeRange &range)
void RenderBackend::InvalidateCache(const TimeRange &range, NodeInput *from)
{
if (!CanRender()) {
return;
}
// Adjust range to min/max values
rational start_range_adj = qMax(rational(0), range.in());
rational end_range_adj = qMin(GetSequenceLength(), range.out());
@@ -371,15 +304,18 @@ void RenderBackend::InvalidateCache(const TimeRange &range)
<< "and"
<< end_range_adj.toDouble();
// Queue value update
QueueValueUpdate();
if (from) {
// Queue value update
qDebug() << " from" << from->parentNode()->id() << "::" << from->id();
QueueValueUpdate(from);
}
InvalidateCacheInternal(start_range_adj, end_range_adj);
}
bool RenderBackend::ViewerIsConnected() const
{
return viewer_node_ != nullptr;
return viewer_node_;
}
const QString &RenderBackend::cache_id() const
@@ -387,9 +323,23 @@ const QString &RenderBackend::cache_id() const
return cache_id_;
}
void RenderBackend::QueueValueUpdate()
void RenderBackend::QueueValueUpdate(NodeInput* from)
{
input_update_queued_ = true;
if (!input_update_queued_.isEmpty()) {
// Remove any inputs that are dependents of this input since they may have been removed since
// it was queued
QList<Node*> deps = from->GetDependencies();
for (int i=0;i<input_update_queued_.size();i++) {
if (deps.contains(input_update_queued_.at(i)->parentNode())) {
// We don't need to queue this value since this input supersedes it
input_update_queued_.removeAt(i);
i--;
}
}
}
input_update_queued_.append(from);
}
bool RenderBackend::WorkerIsBusy(RenderWorker *worker) const
@@ -402,6 +352,87 @@ void RenderBackend::SetWorkerBusyState(RenderWorker *worker, bool busy)
processor_busy_state_.replace(processors_.indexOf(worker), busy);
}
void RenderBackend::CopyNodeInputValue(NodeInput *input)
{
// Find our copy of this parameter
Node* our_copy_node = node_copy_map_.value(input->parentNode());
NodeInput* our_copy = our_copy_node->GetInputWithID(input->id());
// Copy the standard/keyframe values between these two inputs
NodeInput::CopyValues(input,
our_copy,
false);
// Handle connections
if (input->IsConnected() || our_copy->IsConnected()) {
// If one of the inputs is connected, it's likely this change came from connecting or
// disconnecting whatever was connected to it
{
// We start by removing all old dependencies from the map
QList<Node*> old_deps = our_copy->GetExclusiveDependencies();
foreach (Node* i, old_deps) {
Node* n = node_copy_map_.take(node_copy_map_.key(i));
copied_graph_.TakeNode(n);
delete n;
}
}
// Then we copy all node dependencies and connections (if there are any)
CopyNodeMakeConnection(input, our_copy);
}
// Call on sub-elements too
if (input->IsArray()) {
foreach (NodeInput* i, static_cast<NodeInputArray*>(input)->sub_params()) {
CopyNodeInputValue(i);
}
}
}
Node* RenderBackend::CopyNodeConnections(Node* src_node)
{
// Check if this node is already in the map
Node* dst_node = node_copy_map_.value(src_node);
// If not, create it now
if (!dst_node) {
dst_node = src_node->copy();
copied_graph_.AddNode(dst_node);
node_copy_map_.insert(src_node, dst_node);
}
// Make sure its values are copied
Node::CopyInputs(src_node, dst_node, false);
// Copy all connections
QList<NodeInput*> src_node_inputs = src_node->GetInputsIncludingArrays();
QList<NodeInput*> dst_node_inputs = dst_node->GetInputsIncludingArrays();
for (int i=0;i<src_node_inputs.size();i++) {
NodeInput* src_input = src_node_inputs.at(i);
CopyNodeMakeConnection(src_input, dst_node_inputs.at(i));
}
return dst_node;
}
void RenderBackend::CopyNodeMakeConnection(NodeInput* src_input, NodeInput* dst_input)
{
//qDebug() << "Copying input" << src_input->id() << "from" << src_input->parentNode()->id();
if (src_input->IsConnected()) {
Node* dst_node = CopyNodeConnections(src_input->get_connected_node());
NodeOutput* corresponding_output = dst_node->GetOutputWithID(src_input->get_connected_output()->id());
NodeParam::ConnectEdge(corresponding_output,
dst_input);
}
}
bool RenderBackend::AllProcessorsAreAvailable() const
{
foreach (bool busy, processor_busy_state_) {
@@ -455,11 +486,6 @@ void RenderBackend::InitWorkers()
processor_busy_state_.fill(false);
}
void RenderBackend::QueueRecompile()
{
recompile_queued_ = true;
}
void RenderBackend::FootageUnavailable(StreamPtr stream, Decoder::RetrieveState state, const TimeRange &range, const rational &stream_time)
{
if (state == Decoder::kFailedToOpen){
@@ -484,7 +510,7 @@ void RenderBackend::FootageUnavailable(StreamPtr stream, Decoder::RetrieveState
|| (stream->type() == Stream::kAudio && std::static_pointer_cast<AudioStream>(stream)->index_done())) {
// Index JUST finished, requeue this time
InvalidateCache(range);
InvalidateCache(range, nullptr);
} else {
@@ -529,7 +555,7 @@ void RenderBackend::IndexUpdated(Stream* stream)
}
if (footage_ready) {
InvalidateCache(info.affected_range);
InvalidateCache(info.affected_range, nullptr);
footage_wait_info_.removeAt(i);
i--;
}
+8 -18
View File
@@ -52,11 +52,7 @@ public:
void CancelQueue();
public slots:
void InvalidateCache(const TimeRange &range);
bool Compile();
void Decompile();
void InvalidateCache(const TimeRange &range, NodeInput *from);
signals:
void QueueComplete();
@@ -68,10 +64,6 @@ protected:
virtual void CloseInternal();
virtual bool CompileInternal() = 0;
virtual void DecompileInternal() = 0;
virtual bool CanRender();
virtual TimeRange PopNextFrameFromQueue();
@@ -111,7 +103,7 @@ protected:
const QString& cache_id() const;
void QueueValueUpdate();
void QueueValueUpdate(NodeInput *from);
bool AllProcessorsAreAvailable() const;
bool WorkerIsBusy(RenderWorker* worker) const;
@@ -121,18 +113,17 @@ protected:
QVector<RenderWorker*> processors_;
bool compiled_;
QHash<TimeRange, qint64> render_job_info_;
QList<Node*> source_node_list_;
QHash<Node*, Node*> node_copy_map_;
NodeGraph copied_graph_;
protected slots:
void QueueRecompile();
private:
void CopyNodeInputValue(NodeInput* input);
Node *CopyNodeConnections(Node *src_node);
void CopyNodeMakeConnection(NodeInput *src_input, NodeInput *dst_input);
/**
* @brief Internal list of RenderProcessThreads
*/
@@ -160,8 +151,7 @@ private:
QString cache_id_;
bool recompile_queued_;
bool input_update_queued_;
QList<NodeInput*> input_update_queued_;
QVector<bool> processor_busy_state_;
@@ -49,14 +49,12 @@ VideoRenderBackend::VideoRenderBackend(QObject *parent) :
void VideoRenderBackend::ConnectViewer(ViewerOutput *node)
{
connect(node, &ViewerOutput::VideoChangedBetween, this, &VideoRenderBackend::InvalidateCache);
connect(node, &ViewerOutput::VideoGraphChanged, this, &VideoRenderBackend::QueueRecompile);
connect(node, &ViewerOutput::LengthChanged, this, &VideoRenderBackend::TruncateFrameCacheLength);
}
void VideoRenderBackend::DisconnectViewer(ViewerOutput *node)
{
disconnect(node, &ViewerOutput::VideoChangedBetween, this, &VideoRenderBackend::InvalidateCache);
disconnect(node, &ViewerOutput::VideoGraphChanged, this, &VideoRenderBackend::QueueRecompile);
disconnect(node, &ViewerOutput::LengthChanged, this, &VideoRenderBackend::TruncateFrameCacheLength);
frame_cache_.Clear();
+4 -1
View File
@@ -261,7 +261,10 @@ void VideoRenderWorker::SetFrameGenerationParams(int width, int height, const QM
bool VideoRenderWorker::InitInternal()
{
ResizeDownloadBuffer();
if (video_params_.is_valid()) {
ResizeDownloadBuffer();
}
return true;
}
@@ -1,8 +1,8 @@
#version 150
uniform mat4 matrix_in;
uniform mat4 %1;
uniform vec2 footage_in_resolution;
uniform vec2 %2_resolution;
uniform vec2 ove_resolution;
in vec4 a_position;
@@ -27,10 +27,10 @@ void main() {
transform *= scale_mat4(vec3(1.0 / ove_resolution, 1.0));
// Multiply by received matrix
transform *= matrix_in;
transform *= %1;
// Scale back out to footage size
transform *= scale_mat4(vec3(footage_in_resolution, 1.0));
transform *= scale_mat4(vec3(%2_resolution, 1.0));
gl_Position = transform * a_position;
ove_texcoord = a_texcoord;
+1 -2
View File
@@ -17,7 +17,6 @@
<file>solid.xml</file>
<file>stroke.frag</file>
<file>stroke.xml</file>
<file>videoinput.frag</file>
<file>videoinput.vert</file>
<file>matrix.vert</file>
</qresource>
</RCC>
-11
View File
@@ -1,11 +0,0 @@
#version 150
uniform sampler2D footage_in;
in vec2 ove_texcoord;
out vec4 fragColor;
void main(void) {
fragColor = texture(footage_in, ove_texcoord);
}
+5
View File
@@ -108,6 +108,11 @@ CurveWidget::~CurveWidget()
view_->Clear();
}
NodeInput *CurveWidget::GetInput() const
{
return input_;
}
void CurveWidget::SetInput(NodeInput *input)
{
if (bridge_) {
+1
View File
@@ -41,6 +41,7 @@ public:
virtual ~CurveWidget() override;
NodeInput* GetInput() const;
void SetInput(NodeInput* input);
const double& GetVerticalScale();
+2 -2
View File
@@ -174,7 +174,7 @@ void KeyframeViewBase::mouseMoveEvent(QMouseEvent *event)
// frame gets rendered in this time
input_parent->blockSignals(false);
input_parent->parentNode()->InvalidateVisible(input_parent);
input_parent->parentNode()->InvalidateVisible(input_parent, input_parent);
}
}
}
@@ -377,7 +377,7 @@ void KeyframeViewBase::ProcessBezierDrag(QPointF mouse_diff_scaled, bool include
input_parent->blockSignals(false);
input_parent->parentNode()->InvalidateVisible(input_parent);
input_parent->parentNode()->InvalidateVisible(input_parent, input_parent);
}
}
+5 -1
View File
@@ -126,6 +126,8 @@ void NodeParamView::SetNodes(QList<Node *> nodes)
// If we already have item widgets, delete them all now
foreach (NodeParamViewItem* item, items_) {
emit ClosedNode(item->GetNode());
delete item;
}
items_.clear();
@@ -149,12 +151,14 @@ void NodeParamView::SetNodes(QList<Node *> nodes)
connect(item, &NodeParamViewItem::KeyframeAdded, keyframe_view_, &KeyframeView::AddKeyframe);
connect(item, &NodeParamViewItem::KeyframeRemoved, keyframe_view_, &KeyframeView::RemoveKeyframe);
connect(item, &NodeParamViewItem::RequestSetTime, this, &NodeParamView::ItemRequestedTimeChanged);
connect(item, &NodeParamViewItem::InputClicked, this, &NodeParamView::SelectedInputChanged);
connect(item, &NodeParamViewItem::InputDoubleClicked, this, &NodeParamView::InputDoubleClicked);
connect(item, &NodeParamViewItem::RequestSelectNode, this, &NodeParamView::RequestSelectNode);
items_.append(item);
QTimer::singleShot(1, item, &NodeParamViewItem::SignalAllKeyframes);
emit OpenedNode(node);
}
ViewerOutput* viewer = nodes_.first()->FindOutputNode<ViewerOutput>();
+5 -1
View File
@@ -41,12 +41,16 @@ public:
const QList<Node*>& nodes();
signals:
void SelectedInputChanged(NodeInput* input);
void InputDoubleClicked(NodeInput* input);
void TimeTargetChanged(Node* target);
void RequestSelectNode(const QList<Node*>& target);
void OpenedNode(Node* n);
void ClosedNode(Node* n);
protected:
virtual void resizeEvent(QResizeEvent *event) override;
@@ -42,6 +42,8 @@ NodeParamViewConnectedLabel::NodeParamViewConnectedLabel(NodeInput *input, QWidg
connect(connected_to_lbl_, &ClickableLabel::MouseClicked, this, &NodeParamViewConnectedLabel::ConnectionClicked);
layout->addWidget(connected_to_lbl_);
layout->addStretch();
// Set up "link" font
QFont link_font = connected_to_lbl_->font();
link_font.setUnderline(true);
+13 -7
View File
@@ -46,7 +46,6 @@ NodeParamViewItem::NodeParamViewItem(Node *node, QWidget *parent) :
QHBoxLayout* title_bar_layout = new QHBoxLayout(title_bar_);
title_bar_collapse_btn_ = new CollapseButton();
connect(title_bar_collapse_btn_, &QPushButton::toggled, this, &NodeParamViewItemBody::setVisible);
title_bar_layout->addWidget(title_bar_collapse_btn_);
title_bar_lbl_ = new QLabel(title_bar_);
@@ -66,11 +65,12 @@ NodeParamViewItem::NodeParamViewItem(Node *node, QWidget *parent) :
}
body_ = new NodeParamViewItemBody(inputs);
connect(body_, &NodeParamViewItemBody::InputClicked, this, &NodeParamViewItem::InputClicked);
connect(body_, &NodeParamViewItemBody::InputDoubleClicked, this, &NodeParamViewItem::InputDoubleClicked);
connect(body_, &NodeParamViewItemBody::RequestSelectNode, this, &NodeParamViewItem::RequestSelectNode);
connect(body_, &NodeParamViewItemBody::RequestSetTime, this, &NodeParamViewItem::RequestSetTime);
connect(body_, &NodeParamViewItemBody::KeyframeAdded, this, &NodeParamViewItem::KeyframeAdded);
connect(body_, &NodeParamViewItemBody::KeyframeRemoved, this, &NodeParamViewItem::KeyframeRemoved);
connect(title_bar_collapse_btn_, &QPushButton::toggled, body_, &NodeParamViewItemBody::setVisible);
main_layout->addWidget(body_);
Retranslate();
@@ -88,6 +88,11 @@ void NodeParamViewItem::SetTime(const rational &time)
body_->SetTime(time_);
}
Node *NodeParamViewItem::GetNode() const
{
return node_;
}
void NodeParamViewItem::SignalAllKeyframes()
{
body_->SignalAllKeyframes();
@@ -142,7 +147,7 @@ NodeParamViewItemBody::NodeParamViewItemBody(const QVector<NodeInput *> &inputs,
// Add descriptor label
ui_objects.main_label = new ClickableLabel();
connect(ui_objects.main_label, &ClickableLabel::MouseClicked, this, &NodeParamViewItemBody::LabelClicked);
connect(ui_objects.main_label, &ClickableLabel::MouseDoubleClicked, this, &NodeParamViewItemBody::LabelDoubleClicked);
if (input->IsArray()) {
QHBoxLayout* array_label_layout = new QHBoxLayout();
@@ -164,7 +169,7 @@ NodeParamViewItemBody::NodeParamViewItemBody(const QVector<NodeInput *> &inputs,
connect(sub_body, &NodeParamViewItemBody::KeyframeAdded, this, &NodeParamViewItemBody::KeyframeAdded);
connect(sub_body, &NodeParamViewItemBody::KeyframeRemoved, this, &NodeParamViewItemBody::KeyframeRemoved);
connect(sub_body, &NodeParamViewItemBody::RequestSetTime, this, &NodeParamViewItemBody::RequestSetTime);
connect(sub_body, &NodeParamViewItemBody::InputClicked, this, &NodeParamViewItemBody::InputClicked);
connect(sub_body, &NodeParamViewItemBody::InputDoubleClicked, this, &NodeParamViewItemBody::InputDoubleClicked);
connect(sub_body, &NodeParamViewItemBody::RequestSelectNode, this, &NodeParamViewItemBody::RequestSelectNode);
} else {
content_layout->addWidget(ui_objects.main_label, row_count, 0);
@@ -330,12 +335,13 @@ void NodeParamViewItemBody::InputAddedKeyframe(NodeKeyframePtr key)
InputAddedKeyframeInternal(input, key);
}
void NodeParamViewItemBody::LabelClicked()
void NodeParamViewItemBody::LabelDoubleClicked()
{
QMap<NodeInput*, InputUI>::const_iterator iterator;
for (iterator=input_ui_map_.begin(); iterator!=input_ui_map_.end(); iterator++) {
if (iterator.value().connected_label == sender()) {
emit InputClicked(iterator.key());
if (iterator.value().main_label == sender()) {
emit InputDoubleClicked(iterator.key());
return;
}
}
+5 -3
View File
@@ -64,7 +64,7 @@ signals:
void RequestSetTime(const rational& time);
void InputClicked(NodeInput* input);
void InputDoubleClicked(NodeInput* input);
void RequestSelectNode(const QList<Node*>& node);
@@ -93,7 +93,7 @@ private slots:
void InputAddedKeyframe(NodeKeyframePtr key);
void LabelClicked();
void LabelDoubleClicked();
void ConnectionClicked();
@@ -109,6 +109,8 @@ public:
void SetTime(const rational& time);
Node* GetNode() const;
public slots:
void SignalAllKeyframes();
@@ -119,7 +121,7 @@ signals:
void RequestSetTime(const rational& time);
void InputClicked(NodeInput* input);
void InputDoubleClicked(NodeInput* input);
void RequestSelectNode(const QList<Node*>& node);
@@ -255,7 +255,7 @@ void NodeParamViewWidgetBridge::ProcessSlider(SliderBase *slider, const QVariant
input_->blockSignals(false);
input_->parentNode()->InvalidateVisible(input_);
input_->parentNode()->InvalidateVisible(input_, input_);
} else {
if (dragging_) {
@@ -513,9 +513,9 @@ rational NodeParamViewWidgetBridge::GetCurrentTimeAsNodeTime() const
return GetAdjustedTime(GetTimeTarget(), input_->parentNode(), time_, NodeParam::kInput);
}
void NodeParamViewWidgetBridge::InputValueChanged(const rational &start, const rational &end)
void NodeParamViewWidgetBridge::InputValueChanged(const TimeRange &range)
{
if (!dragging_ && start <= time_ && end >= time_) {
if (!dragging_ && range.in() <= time_ && range.out() >= time_) {
// We'll need to update the widgets because the values have changed on our current time
UpdateWidgetValues();
}
@@ -68,7 +68,7 @@ private:
private slots:
void WidgetCallback();
void InputValueChanged(const rational& start, const rational& end);
void InputValueChanged(const TimeRange& range);
void PropertyChanged(const QString& key, const QVariant& value);
+42 -9
View File
@@ -28,27 +28,35 @@ OLIVE_NAMESPACE_ENTER
WaveformScope::WaveformScope(QWidget* parent) :
ManagedDisplayWidget(parent),
texture_(nullptr)
buffer_(nullptr)
{
EnableDefaultContextMenu();
}
void WaveformScope::SetTexture(OpenGLTexture *texture)
void WaveformScope::SetBuffer(Frame *frame)
{
texture_ = texture;
buffer_ = frame;
update();
UploadTextureFromBuffer();
}
void WaveformScope::initializeGL()
{
ManagedDisplayWidget::initializeGL();
makeCurrent();
pipeline_ = OpenGLShader::Create();
pipeline_->create();
pipeline_->addShaderFromSourceCode(QOpenGLShader::Vertex, OpenGLShader::CodeDefaultVertex());
pipeline_->addShaderFromSourceCode(QOpenGLShader::Fragment, Node::ReadFileAsString(":/shaders/rgbwaveform.frag"));
pipeline_->link();
doneCurrent();
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &WaveformScope::CleanUp, Qt::DirectConnection);
if (buffer_) {
UploadTextureFromBuffer();
}
}
void WaveformScope::paintGL()
@@ -56,12 +64,12 @@ void WaveformScope::paintGL()
context()->functions()->glClearColor(0, 0, 0, 0);
context()->functions()->glClear(GL_COLOR_BUFFER_BIT);
if (!pipeline_ || !texture_) {
if (!pipeline_ || !texture_.IsCreated()) {
return;
}
pipeline_->bind();
pipeline_->setUniformValue("ove_resolution", texture_->width(), texture_->height());
pipeline_->setUniformValue("ove_resolution", texture_.width(), texture_.height());
pipeline_->setUniformValue("ove_viewport", width(), height());
// The general size of a pixel
@@ -69,17 +77,42 @@ void WaveformScope::paintGL()
pipeline_->release();
texture_->Bind();
texture_.Bind();
OpenGLRenderFunctions::Blit(pipeline_);
texture_->Release();
texture_.Release();
}
void WaveformScope::UploadTextureFromBuffer()
{
makeCurrent();
if (!texture_.IsCreated()
|| texture_.width() != buffer_->width()
|| texture_.height() != buffer_->height()
|| texture_.format() != buffer_->format()) {
texture_.Destroy();
texture_.Create(context(), buffer_);
} else {
texture_.Upload(buffer_);
}
doneCurrent();
update();
}
void WaveformScope::CleanUp()
{
qDebug() << "Cleaned up...";
makeCurrent();
pipeline_ = nullptr;
texture_ = nullptr;
texture_.Destroy();
doneCurrent();
}
OLIVE_NAMESPACE_EXIT
+6 -2
View File
@@ -36,7 +36,7 @@ public:
WaveformScope(QWidget* parent = nullptr);
public slots:
void SetTexture(OpenGLTexture* texture);
void SetBuffer(Frame* frame);
protected:
virtual void initializeGL() override;
@@ -44,9 +44,13 @@ protected:
virtual void paintGL() override;
private:
void UploadTextureFromBuffer();
OpenGLShaderPtr pipeline_;
OpenGLTexture* texture_;
OpenGLTexture texture_;
Frame* buffer_;
private slots:
void CleanUp();
+20 -5
View File
@@ -241,7 +241,7 @@ void TimelineWidget::ConnectNodeInternal(ViewerOutput *n)
view->ConnectTrackList(track_list);
// Defer to the track to make all the block UI items necessary
foreach (TrackOutput* track, n->track_list(track_type)->Tracks()) {
foreach (TrackOutput* track, n->track_list(track_type)->GetTracks()) {
AddTrack(track, track_type);
}
}
@@ -881,7 +881,7 @@ void TimelineWidget::InsertGapsAt(const rational &earliest_point, const rational
TrackOutput *TimelineWidget::GetTrackFromReference(const TrackReference &ref)
{
return GetConnectedNode()->track_list(ref.type())->TrackAt(ref.index());
return GetConnectedNode()->track_list(ref.type())->GetTrackAt(ref.index());
}
int TimelineWidget::GetTrackY(const TrackReference &ref)
@@ -1017,9 +1017,7 @@ void TimelineWidget::AddBlock(Block *block, TrackReference track)
void TimelineWidget::RemoveBlock(Block *block)
{
delete block_items_[block];
block_items_.remove(block);
delete block_items_.take(block);
}
void TimelineWidget::AddTrack(TrackOutput *track, Timeline::TrackType type)
@@ -1027,15 +1025,32 @@ void TimelineWidget::AddTrack(TrackOutput *track, Timeline::TrackType type)
foreach (Block* b, track->Blocks()) {
AddBlock(b, TrackReference(type, track->Index()));
}
connect(track, &TrackOutput::IndexChanged, this, &TimelineWidget::TrackIndexChanged);
}
void TimelineWidget::RemoveTrack(TrackOutput *track)
{
disconnect(track, &TrackOutput::IndexChanged, this, &TimelineWidget::TrackIndexChanged);
foreach (Block* b, track->Blocks()) {
RemoveBlock(b);
}
}
void TimelineWidget::TrackIndexChanged()
{
TrackOutput* track = static_cast<TrackOutput*>(sender());
TrackReference ref(track->track_type(), track->Index());
foreach (Block* b, track->Blocks()) {
TimelineViewBlockItem* item = block_items_.value(b);
item->SetYCoords(GetTrackY(ref), GetTrackHeight(ref));
item->SetTrack(ref);
}
}
void TimelineWidget::ViewSelectionChanged()
{
if (rubberband_.isVisible()) {
@@ -486,6 +486,7 @@ private slots:
void AddTrack(TrackOutput* track, Timeline::TrackType type);
void RemoveTrack(TrackOutput* track);
void TrackIndexChanged();
void ViewSelectionChanged();
+11 -8
View File
@@ -30,9 +30,10 @@
#include "core.h"
#include "dialog/sequence/sequence.h"
#include "node/audio/volume/volume.h"
#include "node/distort/transform/transform.h"
#include "node/generator/matrix/matrix.h"
#include "node/input/media/audio/audio.h"
#include "node/input/media/video/video.h"
#include "node/math/math/math.h"
#include "project/item/sequence/sequence.h"
#include "widget/nodeview/nodeviewundo.h"
#include "window/mainwindow/mainwindow.h"
@@ -397,15 +398,17 @@ void TimelineWidget::ImportTool::DropGhosts(bool insert)
VideoInput* video_input = new VideoInput();
video_input->SetFootage(footage_stream);
new NodeAddCommand(dst_graph, video_input, command);
new NodeEdgeAddCommand(video_input->output(), clip->texture_input(), command);
TransformDistort* transform = new TransformDistort();
new NodeAddCommand(dst_graph, transform, command);
new NodeEdgeAddCommand(transform->output(), video_input->matrix_input(), command);
MatrixGenerator* matrix = new MatrixGenerator();
new NodeAddCommand(dst_graph, matrix, command);
//OpacityNode* opacity = new OpacityNode();
//NodeParam::ConnectEdge(opacity->texture_output(), clip->texture_input());
//NodeParam::ConnectEdge(media->texture_output(), opacity->texture_input());
MathNode* multiply = new MathNode();
multiply->SetOperation(MathNode::kOpMultiply);
new NodeAddCommand(dst_graph, multiply, command);
new NodeEdgeAddCommand(video_input->output(), multiply->param_a_in(), command);
new NodeEdgeAddCommand(matrix->output(), multiply->param_b_in(), command);
new NodeEdgeAddCommand(multiply->output(), clip->texture_input(), command);
break;
}
case Stream::kAudio:
@@ -81,7 +81,7 @@ void TrackView::ConnectTrackList(TrackList *list)
list_ = list;
if (list_ != nullptr) {
foreach (TrackOutput* track, list_->Tracks()) {
foreach (TrackOutput* track, list_->GetTracks()) {
TrackViewItem* item = new TrackViewItem(track);
items_.append(item);
splitter_->Insert(track->Index(), track->GetTrackHeight(), item);
@@ -120,7 +120,7 @@ void TrackView::ScrollbarRangeChanged(int, int max)
void TrackView::TrackHeightChanged(int index, int height)
{
list_->TrackAt(index)->SetTrackHeight(height);
list_->GetTrackAt(index)->SetTrackHeight(height);
}
void TrackView::InsertTrack(TrackOutput *track)
@@ -141,7 +141,7 @@ void TrackViewSplitter::Remove(int index)
QList<int> sz = sizes();
if (alignment_ == Qt::AlignBottom) {
index = count() - index;
index = count() - 1 - index;
}
sz.removeAt(index);
+32 -32
View File
@@ -274,7 +274,9 @@ void TrackRippleRemoveAreaCommand::redo_internal()
track_->UnblockInvalidateCache();
track_->InvalidateCache(in_, insert_ ? out_ : RATIONAL_MAX);
track_->InvalidateCache(TimeRange(in_, insert_ ? out_ : RATIONAL_MAX),
track_->block_input(),
track_->block_input());
}
void TrackRippleRemoveAreaCommand::undo_internal()
@@ -328,7 +330,7 @@ void TrackRippleRemoveAreaCommand::undo_internal()
track_->UnblockInvalidateCache();
track_->InvalidateCache(in_, insert_ ? out_ : RATIONAL_MAX);
track_->InvalidateCache(TimeRange(in_, insert_ ? out_ : RATIONAL_MAX), track_->block_input(), track_->block_input());
}
TrackPlaceBlockCommand::TrackPlaceBlockCommand(TrackList *timeline, int track, Block *block, rational in, QUndoCommand *parent) :
@@ -345,13 +347,13 @@ void TrackPlaceBlockCommand::redo_internal()
added_track_count_ = 0;
// Get track (or make it if necessary)
while (track_index_ >= timeline_->Tracks().size()) {
while (track_index_ >= timeline_->GetTracks().size()) {
timeline_->AddTrack();
added_track_count_++;
}
track_ = timeline_->TrackAt(track_index_);
track_ = timeline_->GetTrackAt(track_index_);
append_ = (in_ >= track_->track_length());
@@ -608,36 +610,34 @@ void TrackCleanGapsCommand::redo_internal()
GapBlock* on_gap = nullptr;
QList<GapBlock*> consecutive_gaps;
TrackOutput* track = track_list_->TrackAt(track_index_);
TrackOutput* track = track_list_->GetTrackAt(track_index_);
foreach (Block* b, track->Blocks()) {
if (b) {
if (b->type() == Block::kGap) {
if (on_gap) {
consecutive_gaps.append(static_cast<GapBlock*>(b));
} else {
on_gap = static_cast<GapBlock*>(b);
}
} else if (on_gap) {
merged_gaps_.append({on_gap, on_gap->length(), consecutive_gaps});
// Remove each gap and add to the length of the merged
// We can block the IC signal because merging gaps won't actually change anything
track->BlockInvalidateCache();
rational new_gap_length = on_gap->length();
foreach (GapBlock* gap, consecutive_gaps) {
track->RippleRemoveBlock(gap);
static_cast<NodeGraph*>(track->parent())->TakeNode(gap, &memory_manager_);
new_gap_length += gap->length();
}
on_gap->set_length_and_media_out(new_gap_length);
track->UnblockInvalidateCache();
// Reset state
on_gap = nullptr;
consecutive_gaps.clear();
if (b->type() == Block::kGap) {
if (on_gap) {
consecutive_gaps.append(static_cast<GapBlock*>(b));
} else {
on_gap = static_cast<GapBlock*>(b);
}
} else if (on_gap) {
merged_gaps_.append({on_gap, on_gap->length(), consecutive_gaps});
// Remove each gap and add to the length of the merged
// We can block the IC signal because merging gaps won't actually change anything
track->BlockInvalidateCache();
rational new_gap_length = on_gap->length();
foreach (GapBlock* gap, consecutive_gaps) {
track->RippleRemoveBlock(gap);
static_cast<NodeGraph*>(track->parent())->TakeNode(gap, &memory_manager_);
new_gap_length += gap->length();
}
on_gap->set_length_and_media_out(new_gap_length);
track->UnblockInvalidateCache();
// Reset state
on_gap = nullptr;
consecutive_gaps.clear();
}
}
@@ -655,7 +655,7 @@ void TrackCleanGapsCommand::redo_internal()
void TrackCleanGapsCommand::undo_internal()
{
TrackOutput* track = track_list_->TrackAt(track_index_);
TrackOutput* track = track_list_->GetTrackAt(track_index_);
// Restored removed end gaps
foreach (GapBlock* gap, removed_end_gaps_) {
@@ -28,8 +28,6 @@ set(OLIVE_SOURCES
widget/timelinewidget/view/timelineviewbase.cpp
widget/timelinewidget/view/timelineviewblockitem.h
widget/timelinewidget/view/timelineviewblockitem.cpp
widget/timelinewidget/view/timelineviewenditem.h
widget/timelinewidget/view/timelineviewenditem.cpp
widget/timelinewidget/view/timelineviewghostitem.h
widget/timelinewidget/view/timelineviewghostitem.cpp
PARENT_SCOPE
+34 -10
View File
@@ -189,11 +189,7 @@ void TimelineView::drawBackground(QPainter *painter, const QRectF &rect)
int line_y = 0;
foreach (TrackOutput* track, connected_track_list_->Tracks()) {
if (!track) {
continue;
}
foreach (TrackOutput* track, connected_track_list_->GetTracks()) {
line_y += track->GetTrackHeight();
// One px gap between tracks
@@ -230,6 +226,17 @@ void TimelineView::ToolChangedEvent(Tool::Item tool)
}
}
void TimelineView::SceneRectUpdateEvent(QRectF &rect)
{
if (alignment() & Qt::AlignTop) {
rect.setTop(0);
rect.setBottom(GetHeightOfAllTracks() + height() / 2);
} else if (alignment() & Qt::AlignBottom) {
rect.setBottom(0);
rect.setTop(GetHeightOfAllTracks() - height() / 2);
}
}
Timeline::TrackType TimelineView::ConnectedTrackType()
{
if (connected_track_list_) {
@@ -279,8 +286,25 @@ TimelineViewMouseEvent TimelineView::CreateMouseEvent(const QPoint& pos, Qt::Key
return timeline_event;
}
int TimelineView::GetTrackY(int track_index)
int TimelineView::GetHeightOfAllTracks() const
{
if (connected_track_list_) {
if (alignment() & Qt::AlignTop) {
return GetTrackY(connected_track_list_->GetTrackCount());
} else {
return GetTrackY(connected_track_list_->GetTrackCount() - 1);
}
} else {
return 0;
}
}
int TimelineView::GetTrackY(int track_index) const
{
if (!connected_track_list_ || !connected_track_list_->GetTrackCount()) {
return 0;
}
int y = 0;
if (alignment() & Qt::AlignBottom) {
@@ -301,16 +325,16 @@ int TimelineView::GetTrackY(int track_index)
return y;
}
int TimelineView::GetTrackHeight(int track_index)
int TimelineView::GetTrackHeight(int track_index) const
{
if (!connected_track_list_ || track_index >= connected_track_list_->TrackCount()) {
if (!connected_track_list_ || track_index >= connected_track_list_->GetTrackCount()) {
return TrackOutput::GetDefaultTrackHeight();
}
return connected_track_list_->TrackAt(track_index)->GetTrackHeight();
return connected_track_list_->GetTrackAt(track_index)->GetTrackHeight();
}
QPoint TimelineView::GetScrollCoordinates()
QPoint TimelineView::GetScrollCoordinates() const
{
return QPoint(horizontalScrollBar()->value(), verticalScrollBar()->value());
}
@@ -53,10 +53,10 @@ public:
void DeselectAll();
int GetTrackY(int track_index);
int GetTrackHeight(int track_index);
int GetTrackY(int track_index) const;
int GetTrackHeight(int track_index) const;
QPoint GetScrollCoordinates();
QPoint GetScrollCoordinates() const;
void SetScrollCoordinates(const QPoint& pt);
void ConnectTrackList(TrackList* list);
@@ -91,6 +91,8 @@ protected:
virtual void ToolChangedEvent(Tool::Item tool) override;
virtual void SceneRectUpdateEvent(QRectF& rect) override;
private:
Timeline::TrackType ConnectedTrackType();
Stream::Type TrackTypeToStreamType(Timeline::TrackType track_type);
@@ -100,6 +102,8 @@ private:
TimelineViewMouseEvent CreateMouseEvent(const QPoint &pos, Qt::KeyboardModifiers modifiers);
int GetHeightOfAllTracks() const;
int SceneToTrack(double y);
void UserSetTime(const int64_t& time);
@@ -44,10 +44,6 @@ TimelineViewBase::TimelineViewBase(QWidget *parent) :
{
setScene(&scene_);
// Create end item
end_item_ = new TimelineViewEndItem();
scene_.addItem(end_item_);
// Set default scale
SetScale(1.0);
@@ -223,54 +219,28 @@ qreal TimelineViewBase::GetPlayheadX()
void TimelineViewBase::SetEndTime(const rational &length)
{
end_item_->SetEndTime(length);
end_time_ = length;
UpdateSceneRect();
}
void TimelineViewBase::UpdateSceneRect()
{
QRectF bounding_rect = scene_.itemsBoundingRect();
if (limit_y_axis_) {
// Make a gap of half the viewport height
if (alignment() & Qt::AlignBottom) {
bounding_rect.setTop(bounding_rect.top() - height()/2);
} else {
bounding_rect.setBottom(bounding_rect.bottom() + height()/2);
}
// Ensure the scene height is always AT LEAST the height of the view
// The scrollbar appears to have a 1px margin on the top and bottom, hence the -2
int minimum_height = height() - horizontalScrollBar()->height() - 2;
if (alignment() & Qt::AlignBottom) {
// Ensure the scene left and bottom are always 0
bounding_rect.setBottomLeft(QPointF(0, 0));
if (bounding_rect.top() > minimum_height) {
bounding_rect.setTop(-minimum_height);
}
} else {
// Ensure the scene left and top are always 0
bounding_rect.setTopLeft(QPointF(0, 0));
if (bounding_rect.height() < minimum_height) {
bounding_rect.setHeight(minimum_height);
}
}
} else {
// We'll still limit the X to 0 since that behavior is desired by all TimelineViewBase derivatives
bounding_rect.setLeft(0);
}
// There's no need for a timeline to ever go below 0 on the X scale
bounding_rect.setLeft(0);
// Ensure the scene is always the full length of the timeline with a gap at the end to work with
end_item_->SetEndPadding(width()/2);
bounding_rect.setRight(TimeToScene(end_time_) + width() / 2);
// Any further rect processing from derivatives can be done here
SceneRectUpdateEvent(bounding_rect);
// If the scene is already this rect, do nothing
if (scene_.sceneRect() == bounding_rect) {
return;
if (scene_.sceneRect() != bounding_rect) {
scene_.setSceneRect(bounding_rect);
}
scene_.setSceneRect(bounding_rect);
}
void TimelineViewBase::PageScrollToPlayhead()
@@ -299,9 +269,10 @@ void TimelineViewBase::ScaleChangedEvent(const double &scale)
{
TimelineScaledObject::ScaleChangedEvent(scale);
end_item_->SetScale(scale);
// Update scene rect
UpdateSceneRect();
// Force redraw for playhead
// Force redraw for playhead if the above function didn't do it
viewport()->update();
}
@@ -25,7 +25,6 @@
#include "core.h"
#include "timelineplayhead.h"
#include "timelineviewenditem.h"
#include "widget/timelinewidget/timelinescaledobject.h"
OLIVE_NAMESPACE_ENTER
@@ -57,6 +56,8 @@ protected:
virtual void ScaleChangedEvent(const double& scale) override;
virtual void SceneRectUpdateEvent(QRectF&){}
bool HandleZoomFromScroll(QWheelEvent* event);
bool WheelEventIsAZoomEvent(QWheelEvent* event);
@@ -95,14 +96,14 @@ private:
bool dragging_hand_;
DragMode pre_hand_drag_mode_;
TimelineViewEndItem* end_item_;
QGraphicsScene scene_;
bool limit_y_axis_;
DragMode default_drag_mode_;
rational end_time_;
private slots:
/**
* @brief Slot called whenever the view resizes or the scene contents change to enforce minimum scene sizes
@@ -134,7 +134,11 @@ void TimelineViewBlockItem::paint(QPainter *painter, const QStyleOptionGraphicsI
} else {
painter->setPen(Qt::lightGray);
}
painter->drawText(rect(), static_cast<int>(Qt::AlignLeft | Qt::AlignTop), block_->block_name());
int text_top = TrackOutput::GetTrackHeightMinimum() / 2 - painter->fontMetrics().height() / 2;
QRectF text_rect = rect();
text_rect.adjust(0, text_top, 0, 0);
painter->drawText(text_rect, Qt::AlignLeft | Qt::AlignTop, block_->block_name());
// Linked clips are underlined
if (block_->HasLinks()) {
@@ -1,61 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 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 "timelineviewenditem.h"
OLIVE_NAMESPACE_ENTER
TimelineViewEndItem::TimelineViewEndItem(QGraphicsItem *parent) :
TimelineViewRect(parent),
end_padding_(0)
{
}
void TimelineViewEndItem::SetEndTime(const rational &time)
{
end_time_ = time;
UpdateRect();
}
void TimelineViewEndItem::SetEndPadding(int padding)
{
end_padding_ = padding;
UpdateRect();
}
void TimelineViewEndItem::UpdateRect()
{
// Doesn't need to be more than one pixel
setRect(0, 0, 1, 1);
setPos(TimeToScene(end_time_) + end_padding_, 0);
}
void TimelineViewEndItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
// Item is invisible, this is a no-op
Q_UNUSED(painter)
Q_UNUSED(option)
Q_UNUSED(widget)
}
OLIVE_NAMESPACE_EXIT
@@ -1,53 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 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 TIMELINEVIEWENDITEM_H
#define TIMELINEVIEWENDITEM_H
#include "timelineviewrect.h"
OLIVE_NAMESPACE_ENTER
/**
* @brief An item placed at the end point of the Timeline to ensure the correct scene size
*/
class TimelineViewEndItem : public TimelineViewRect
{
public:
TimelineViewEndItem(QGraphicsItem* parent = nullptr);
void SetEndTime(const rational& time);
void SetEndPadding(int padding);
virtual void UpdateRect() override;
protected:
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
private:
rational end_time_;
int end_padding_;
};
OLIVE_NAMESPACE_EXIT
#endif // TIMELINEVIEWENDITEM_H
+2 -2
View File
@@ -24,8 +24,8 @@ set(OLIVE_SOURCES
widget/viewer/pixelsamplerwidget.cpp
widget/viewer/viewer.h
widget/viewer/viewer.cpp
widget/viewer/viewerglwidget.h
widget/viewer/viewerglwidget.cpp
widget/viewer/viewerdisplay.h
widget/viewer/viewerdisplay.cpp
widget/viewer/viewersafemargininfo.h
widget/viewer/viewersizer.h
widget/viewer/viewersizer.cpp
+1 -1
View File
@@ -35,7 +35,7 @@ FootageViewerWidget::FootageViewerWidget(QWidget *parent) :
audio_node_ = new AudioInput();
viewer_node_ = new ViewerOutput();
connect(main_gl_widget(), &ViewerGLWidget::DragStarted, this, &FootageViewerWidget::StartFootageDrag);
connect(main_gl_widget(), &ViewerDisplayWidget::DragStarted, this, &FootageViewerWidget::StartFootageDrag);
controls_->SetAudioVideoDragButtonsVisible(true);
connect(controls_, &PlaybackControls::VideoPressed, this, &FootageViewerWidget::StartVideoDrag);
+33 -36
View File
@@ -62,15 +62,13 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
sizer_ = new ViewerSizer();
stack_->addWidget(sizer_);
ViewerGLWidget* main_widget = new ViewerGLWidget();
connect(main_widget, &ViewerGLWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu);
connect(main_widget, &ViewerGLWidget::CursorColor, this, &ViewerWidget::CursorColor);
connect(main_widget, &ViewerGLWidget::LoadedBuffer, this, &ViewerWidget::LoadedBuffer);
connect(main_widget, &ViewerGLWidget::LoadedTexture, this, &ViewerWidget::LoadedTexture);
connect(main_widget, &ViewerGLWidget::DrewManagedTexture, this, &ViewerWidget::DrewManagedTexture);
connect(main_widget, &ViewerGLWidget::ColorProcessorChanged, this, &ViewerWidget::ColorProcessorChanged);
connect(main_widget, &ViewerGLWidget::ColorManagerChanged, this, &ViewerWidget::ColorManagerChanged);
connect(sizer_, &ViewerSizer::RequestMatrix, main_widget, &ViewerGLWidget::SetMatrix);
ViewerDisplayWidget* main_widget = new ViewerDisplayWidget();
connect(main_widget, &ViewerDisplayWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu);
connect(main_widget, &ViewerDisplayWidget::CursorColor, this, &ViewerWidget::CursorColor);
connect(main_widget, &ViewerDisplayWidget::LoadedBuffer, this, &ViewerWidget::LoadedBuffer);
connect(main_widget, &ViewerDisplayWidget::ColorProcessorChanged, this, &ViewerWidget::ColorProcessorChanged);
connect(main_widget, &ViewerDisplayWidget::ColorManagerChanged, this, &ViewerWidget::ColorManagerChanged);
connect(sizer_, &ViewerSizer::RequestMatrix, main_widget, &ViewerDisplayWidget::SetMatrix);
sizer_->SetWidget(main_widget);
gl_widgets_.append(main_widget);
@@ -152,8 +150,8 @@ void ViewerWidget::ConnectNodeInternal(ViewerOutput *n)
connect(n, &ViewerOutput::LengthChanged, this, &ViewerWidget::LengthChangedSlot);
connect(n, &ViewerOutput::VideoParamsChanged, this, &ViewerWidget::UpdateRendererParameters);
connect(n, &ViewerOutput::VisibleInvalidated, this, &ViewerWidget::InvalidateVisible);
connect(n, &ViewerOutput::VideoGraphChanged, this, &ViewerWidget::UpdateStack);
connect(n, &ViewerOutput::AudioGraphChanged, this, &ViewerWidget::UpdateStack);
connect(n, &ViewerOutput::VideoChangedBetween, this, &ViewerWidget::UpdateStack);
connect(n, &ViewerOutput::AudioChangedBetween, this, &ViewerWidget::UpdateStack);
SizeChangedSlot(n->video_params().width(), n->video_params().height());
LengthChangedSlot(n->Length());
@@ -168,7 +166,7 @@ void ViewerWidget::ConnectNodeInternal(ViewerOutput *n)
using_manager = nullptr;
}
foreach (ViewerGLWidget* glw, gl_widgets_) {
foreach (ViewerDisplayWidget* glw, gl_widgets_) {
glw->ConnectColorManager(using_manager);
}
@@ -194,13 +192,13 @@ void ViewerWidget::DisconnectNodeInternal(ViewerOutput *n)
disconnect(n, &ViewerOutput::LengthChanged, this, &ViewerWidget::LengthChangedSlot);
disconnect(n, &ViewerOutput::VideoParamsChanged, this, &ViewerWidget::UpdateRendererParameters);
disconnect(n, &ViewerOutput::VisibleInvalidated, this, &ViewerWidget::InvalidateVisible);
disconnect(n, &ViewerOutput::VideoGraphChanged, this, &ViewerWidget::UpdateStack);
disconnect(n, &ViewerOutput::AudioGraphChanged, this, &ViewerWidget::UpdateStack);
disconnect(n, &ViewerOutput::VideoChangedBetween, this, &ViewerWidget::UpdateStack);
disconnect(n, &ViewerOutput::AudioChangedBetween, this, &ViewerWidget::UpdateStack);
// Effectively disables the viewer and clears the state
SizeChangedSlot(0, 0);
foreach (ViewerGLWidget* glw, gl_widgets_) {
foreach (ViewerDisplayWidget* glw, gl_widgets_) {
glw->DisconnectColorManager();
}
@@ -234,12 +232,12 @@ void ViewerWidget::resizeEvent(QResizeEvent *event)
UpdateMinimumScale();
}
const QList<ViewerGLWidget*> &ViewerWidget::gl_widgets() const
const QList<ViewerDisplayWidget*> &ViewerWidget::gl_widgets() const
{
return gl_widgets_;
}
ViewerGLWidget *ViewerWidget::main_gl_widget() const
ViewerDisplayWidget *ViewerWidget::main_gl_widget() const
{
return gl_widgets_.first();
}
@@ -280,7 +278,7 @@ void ViewerWidget::SetOverrideSize(int width, int height)
void ViewerWidget::SetMatrix(const QMatrix4x4 &mat)
{
foreach (ViewerGLWidget* glw, gl_widgets_) {
foreach (ViewerDisplayWidget* glw, gl_widgets_) {
glw->SetMatrix(mat);
}
}
@@ -309,7 +307,7 @@ void ViewerWidget::SetFullScreen(QScreen *screen)
vw->gl_widget()->ConnectColorManager(main_gl_widget()->color_manager());
main_gl_widget()->ConnectSibling(vw->gl_widget());
connect(vw, &ViewerWindow::destroyed, this, &ViewerWidget::WindowAboutToClose);
connect(vw->gl_widget(), &ViewerGLWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu);
connect(vw->gl_widget(), &ViewerDisplayWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu);
if (GetConnectedNode()) {
vw->SetResolution(GetConnectedNode()->video_params().width(), GetConnectedNode()->video_params().height());
@@ -373,7 +371,7 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only)
controls_->ShowPauseButton();
if (stack_->currentWidget() == sizer_) {
connect(main_gl_widget(), &ViewerGLWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
connect(main_gl_widget(), &ViewerDisplayWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
} else {
connect(AudioManager::instance(), &AudioManager::OutputNotified, this, &ViewerWidget::PlaybackTimerUpdate);
}
@@ -427,17 +425,21 @@ void ViewerWidget::UpdateMinimumScale()
}
}
void ViewerWidget::SetColorTransform(const ColorTransform &transform, ViewerGLWidget *sender)
void ViewerWidget::SetColorTransform(const ColorTransform &transform, ViewerDisplayWidget *sender)
{
sender->SetColorTransform(transform);
}
void ViewerWidget::UpdateStack()
{
if (!GetConnectedNode() || GetConnectedNode()->texture_input()->IsConnected()) {
stack_->setCurrentWidget(sizer_);
} else {
if (GetConnectedNode()
&& !GetConnectedNode()->texture_input()->IsConnected()
&& GetConnectedNode()->samples_input()->IsConnected()) {
// If we have a node AND video is disconnected AND audio is connected, show waveform view
stack_->setCurrentWidget(waveform_view_);
} else {
// Otherwise show regular display
stack_->setCurrentWidget(sizer_);
}
}
@@ -527,7 +529,7 @@ void ViewerWidget::UpdateRendererParameters()
if (video_renderer_->params() != vparam) {
video_renderer_->SetParameters(vparam);
video_renderer_->InvalidateCache(TimeRange(0, GetConnectedNode()->Length()));
video_renderer_->InvalidateCache(TimeRange(0, GetConnectedNode()->Length()), nullptr);
}
AudioRenderingParams aparam(GetConnectedNode()->audio_params(),
@@ -535,7 +537,7 @@ void ViewerWidget::UpdateRendererParameters()
if (audio_renderer_->params() != aparam) {
audio_renderer_->SetParameters(aparam);
audio_renderer_->InvalidateCache(TimeRange(0, GetConnectedNode()->Length()));
audio_renderer_->InvalidateCache(TimeRange(0, GetConnectedNode()->Length()), nullptr);
}
}
@@ -543,7 +545,7 @@ void ViewerWidget::ShowContextMenu(const QPoint &pos)
{
Menu menu(static_cast<QWidget*>(sender()));
context_menu_widget_ = static_cast<ViewerGLWidget*>(sender());
context_menu_widget_ = static_cast<ViewerDisplayWidget*>(sender());
// Color options
if (context_menu_widget_->color_manager() && color_menu_enabled_) {
@@ -683,7 +685,7 @@ void ViewerWidget::Pause()
controls_->ShowPlayButton();
if (stack_->currentWidget() == sizer_) {
disconnect(main_gl_widget(), &ViewerGLWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
disconnect(main_gl_widget(), &ViewerDisplayWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
} else {
disconnect(AudioManager::instance(), &AudioManager::OutputNotified, this, &ViewerWidget::PlaybackTimerUpdate);
}
@@ -736,16 +738,11 @@ void ViewerWidget::SetColorTransform(const ColorTransform &transform)
void ViewerWidget::SetSignalCursorColorEnabled(bool e)
{
foreach (ViewerGLWidget* glw, gl_widgets_) {
foreach (ViewerDisplayWidget* glw, gl_widgets_) {
glw->SetSignalCursorColorEnabled(e);
}
}
void ViewerWidget::SetEmitDrewManagedTextureEnabled(bool e)
{
main_gl_widget()->SetEmitDrewManagedTextureEnabled(e);
}
void ViewerWidget::TimebaseChangedEvent(const rational &timebase)
{
TimeBasedWidget::TimebaseChangedEvent(timebase);
@@ -869,9 +866,9 @@ void ViewerWidget::SetZoomFromMenu(QAction *action)
sizer_->SetZoom(action->data().toInt());
}
void ViewerWidget::InvalidateVisible()
void ViewerWidget::InvalidateVisible(NodeInput* source)
{
video_renderer_->InvalidateCache(TimeRange(GetTime(), GetTime()));
video_renderer_->InvalidateCache(TimeRange(GetTime(), GetTime()), source);
}
OLIVE_NAMESPACE_EXIT
+7 -22
View File
@@ -35,7 +35,7 @@
#include "render/backend/opengl/openglbackend.h"
#include "render/backend/opengl/opengltexture.h"
#include "render/backend/audio/audiobackend.h"
#include "viewerglwidget.h"
#include "viewerdisplay.h"
#include "viewersizer.h"
#include "viewerwindow.h"
#include "widget/playbackcontrols/playbackcontrols.h"
@@ -107,11 +107,6 @@ public slots:
*/
void SetSignalCursorColorEnabled(bool e);
/**
* @brief Wrapper for ViewerGLWidget::SetEmitDrewManagedTextureEnabled()
*/
void SetEmitDrewManagedTextureEnabled(bool e);
signals:
/**
* @brief Wrapper for ViewerGLWidget::CursorColor()
@@ -123,16 +118,6 @@ signals:
*/
void LoadedBuffer(Frame* load_buffer);
/**
* @brief Wrapper for ViewerGLWidget::LoadedTexture()
*/
void LoadedTexture(OpenGLTexture* texture);
/**
* @brief Wrapper for ViewerGLWidget::DrewManagedTexture()
*/
void DrewManagedTexture(OpenGLTexture* texture);
/**
* @brief Request a scope panel
*
@@ -167,8 +152,8 @@ protected:
PlaybackControls* controls_;
const QList<ViewerGLWidget *> &gl_widgets() const;
ViewerGLWidget* main_gl_widget() const;
const QList<ViewerDisplayWidget *> &gl_widgets() const;
ViewerDisplayWidget* main_gl_widget() const;
private:
void UpdateTimeInternal(int64_t i);
@@ -183,7 +168,7 @@ private:
void UpdateMinimumScale();
void SetColorTransform(const ColorTransform& transform, ViewerGLWidget* sender);
void SetColorTransform(const ColorTransform& transform, ViewerDisplayWidget* sender);
QStackedWidget* stack_;
@@ -212,9 +197,9 @@ private:
QList<ViewerWindow*> windows_;
QList<ViewerGLWidget*> gl_widgets_;
QList<ViewerDisplayWidget*> gl_widgets_;
ViewerGLWidget* context_menu_widget_;
ViewerDisplayWidget* context_menu_widget_;
private slots:
void PlaybackTimerUpdate();
@@ -233,7 +218,7 @@ private slots:
void SetZoomFromMenu(QAction* action);
void InvalidateVisible();
void InvalidateVisible(NodeInput *source);
void UpdateStack();
@@ -18,7 +18,7 @@
***/
#include "viewerglwidget.h"
#include "viewerdisplay.h"
#include <OpenImageIO/imagebuf.h>
#include <QFileInfo>
@@ -37,30 +37,28 @@
OLIVE_NAMESPACE_ENTER
#ifdef Q_OS_LINUX
bool ViewerGLWidget::nouveau_check_done_ = false;
bool ViewerDisplayWidget::nouveau_check_done_ = false;
#endif
ViewerGLWidget::ViewerGLWidget(QWidget *parent) :
ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) :
ManagedDisplayWidget(parent),
managed_copy_pipeline_(nullptr),
has_image_(false),
signal_cursor_color_(false),
enable_display_referred_signal_(false)
signal_cursor_color_(false)
{
}
ViewerGLWidget::~ViewerGLWidget()
ViewerDisplayWidget::~ViewerDisplayWidget()
{
ContextCleanup();
}
void ViewerGLWidget::SetMatrix(const QMatrix4x4 &mat)
void ViewerDisplayWidget::SetMatrix(const QMatrix4x4 &mat)
{
matrix_ = mat;
update();
}
void ViewerGLWidget::SetImage(const QString &fn)
void ViewerDisplayWidget::SetImage(const QString &fn)
{
has_image_ = false;
@@ -91,14 +89,12 @@ void ViewerGLWidget::SetImage(const QString &fn)
input->read_image(input->spec().format, load_buffer_.data(), OIIO::AutoStride, load_buffer_.linesize_bytes());
input->close();
emit LoadedBuffer(&load_buffer_);
texture_.Upload(load_buffer_.data(), load_buffer_.linesize_pixels());
emit LoadedTexture(&texture_);
texture_.Upload(&load_buffer_);
doneCurrent();
emit LoadedBuffer(&load_buffer_);
has_image_ = true;
#if OIIO_VERSION < 10903
@@ -119,13 +115,13 @@ void ViewerGLWidget::SetImage(const QString &fn)
}
}
void ViewerGLWidget::SetSignalCursorColorEnabled(bool e)
void ViewerDisplayWidget::SetSignalCursorColorEnabled(bool e)
{
signal_cursor_color_ = e;
setMouseTracking(e);
}
void ViewerGLWidget::SetImageFromLoadBuffer(Frame *in_buffer)
void ViewerDisplayWidget::SetImageFromLoadBuffer(Frame *in_buffer)
{
has_image_ = in_buffer;
@@ -138,7 +134,7 @@ void ViewerGLWidget::SetImageFromLoadBuffer(Frame *in_buffer)
|| texture_.format() != in_buffer->format()) {
texture_.Create(context(), in_buffer->width(), in_buffer->height(), in_buffer->format(), in_buffer->data(), load_buffer_.linesize_pixels());
} else {
texture_.Upload(in_buffer->data(), load_buffer_.linesize_pixels());
texture_.Upload(in_buffer);
}
doneCurrent();
@@ -147,44 +143,32 @@ void ViewerGLWidget::SetImageFromLoadBuffer(Frame *in_buffer)
update();
}
void ViewerGLWidget::SetEmitDrewManagedTextureEnabled(bool e)
void ViewerDisplayWidget::ConnectSibling(ViewerDisplayWidget *sibling)
{
enable_display_referred_signal_ = e;
if (!enable_display_referred_signal_) {
// Destroy the texture now
managed_texture_.Destroy();
managed_copy_pipeline_ = nullptr;
framebuffer_.Destroy();
}
}
void ViewerGLWidget::ConnectSibling(ViewerGLWidget *sibling)
{
connect(this, &ViewerGLWidget::LoadedBuffer, sibling, &ViewerGLWidget::SetImageFromLoadBuffer, Qt::QueuedConnection);
connect(this, &ViewerDisplayWidget::LoadedBuffer, sibling, &ViewerDisplayWidget::SetImageFromLoadBuffer, Qt::QueuedConnection);
sibling->SetImageFromLoadBuffer(&load_buffer_);
}
const ViewerSafeMarginInfo &ViewerGLWidget::GetSafeMargin() const
const ViewerSafeMarginInfo &ViewerDisplayWidget::GetSafeMargin() const
{
return safe_margin_;
}
void ViewerGLWidget::SetSafeMargins(const ViewerSafeMarginInfo &safe_margin)
void ViewerDisplayWidget::SetSafeMargins(const ViewerSafeMarginInfo &safe_margin)
{
safe_margin_ = safe_margin;
update();
}
void ViewerGLWidget::mousePressEvent(QMouseEvent *event)
void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event)
{
QOpenGLWidget::mousePressEvent(event);
emit DragStarted();
}
void ViewerGLWidget::mouseMoveEvent(QMouseEvent *event)
void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event)
{
QOpenGLWidget::mouseMoveEvent(event);
@@ -209,11 +193,11 @@ void ViewerGLWidget::mouseMoveEvent(QMouseEvent *event)
}
}
void ViewerGLWidget::initializeGL()
void ViewerDisplayWidget::initializeGL()
{
ManagedDisplayWidget::initializeGL();
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ViewerGLWidget::ContextCleanup, Qt::DirectConnection);
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ViewerDisplayWidget::ContextCleanup, Qt::DirectConnection);
#ifdef Q_OS_LINUX
if (!nouveau_check_done_) {
@@ -231,7 +215,7 @@ void ViewerGLWidget::initializeGL()
#endif
}
void ViewerGLWidget::paintGL()
void ViewerDisplayWidget::paintGL()
{
// Get functions attached to this context (they will already be initialized)
QOpenGLFunctions* f = context()->functions();
@@ -243,33 +227,6 @@ void ViewerGLWidget::paintGL()
// We only draw if we have a pipeline
if (has_image_ && color_service() && texture_.IsCreated()) {
// If we're distributing our display-referred final buffer, we'll have to make a copy of it
if (enable_display_referred_signal_) {
if (!managed_texture_.IsCreated()
|| managed_texture_.width() != texture_.width()
|| managed_texture_.height() != texture_.height()
|| managed_texture_.format() != texture_.format()) {
managed_texture_.Destroy();
managed_texture_.Create(context(), texture_.width(), texture_.height(), texture_.format());
}
if (!managed_copy_pipeline_) {
managed_copy_pipeline_ = OpenGLShader::CreateDefault();
}
if (!framebuffer_.IsCreated()) {
framebuffer_.Create(context());
}
framebuffer_.Attach(&managed_texture_);
framebuffer_.Bind();
context()->functions()->glViewport(0, 0, managed_texture_.width(), managed_texture_.height());
}
// Bind retrieved texture
f->glBindTexture(GL_TEXTURE_2D, texture_.texture());
@@ -279,24 +236,6 @@ void ViewerGLWidget::paintGL()
// Release retrieved texture
f->glBindTexture(GL_TEXTURE_2D, 0);
if (enable_display_referred_signal_) {
framebuffer_.Release();
framebuffer_.Detach();
emit DrewManagedTexture(&managed_texture_);
// Bind retrieved texture
managed_texture_.Bind();
context()->functions()->glViewport(0, 0, width(), height());
OpenGLRenderFunctions::Blit(managed_copy_pipeline_);
// Bind retrieved texture
managed_texture_.Release();
}
}
// Draw action/title safe areas
@@ -333,7 +272,7 @@ void ViewerGLWidget::paintGL()
}
#ifdef Q_OS_LINUX
void ViewerGLWidget::ShowNouveauWarning()
void ViewerDisplayWidget::ShowNouveauWarning()
{
QMessageBox::warning(this,
tr("Driver Warning"),
@@ -344,14 +283,11 @@ void ViewerGLWidget::ShowNouveauWarning()
}
#endif
void ViewerGLWidget::ContextCleanup()
void ViewerDisplayWidget::ContextCleanup()
{
makeCurrent();
managed_copy_pipeline_ = nullptr;
texture_.Destroy();
managed_texture_.Destroy();
framebuffer_.Destroy();
doneCurrent();
}
@@ -49,7 +49,7 @@ OLIVE_NAMESPACE_ENTER
* the same texture object, use SetTexture() since it will nearly always be faster to just set it than to check *and*
* set it.
*/
class ViewerGLWidget : public ManagedDisplayWidget
class ViewerDisplayWidget : public ManagedDisplayWidget
{
Q_OBJECT
public:
@@ -60,9 +60,9 @@ public:
*
* QWidget parent.
*/
ViewerGLWidget(QWidget* parent = nullptr);
ViewerDisplayWidget(QWidget* parent = nullptr);
virtual ~ViewerGLWidget() override;
virtual ~ViewerDisplayWidget() override;
/**
* @brief Set an image to load and display on screen
@@ -71,7 +71,7 @@ public:
const QMatrix4x4& GetMatrix();
void ConnectSibling(ViewerGLWidget* sibling);
void ConnectSibling(ViewerDisplayWidget* sibling);
const ViewerSafeMarginInfo& GetSafeMargin() const;
void SetSafeMargins(const ViewerSafeMarginInfo& safe_margin);
@@ -101,15 +101,6 @@ public slots:
*/
void SetImageFromLoadBuffer(Frame* in_buffer);
/**
* @brief Enables or disables DrewManagedTexture()
*
* To emit a display referred texture, it needs to be copied after the color transform is complete. This naturally
* adds extra GPU cycles that are wasted if there's nothing receiving the signal. Therefore, the signal is disabled
* by default.
*/
void SetEmitDrewManagedTextureEnabled(bool e);
signals:
/**
* @brief Signal emitted when the user starts dragging from the viewer
@@ -130,18 +121,6 @@ signals:
*/
void LoadedBuffer(Frame* load_buffer);
/**
* @brief Signal emitted when a buffer is loaded into a texture
*
* This texture will be the direct output of the renderer in reference space in GPU VRAM.
*/
void LoadedTexture(OpenGLTexture* texture);
/**
* @brief Emitted when the a texture has been transformed to display
*/
void DrewManagedTexture(OpenGLTexture* texture);
protected:
/**
* @brief Override the mouse press event simply to emit the DragStarted() signal
@@ -173,23 +152,6 @@ private:
*/
OpenGLTexture texture_;
/**
* @brief Internal framebuffer used to draw to managed_texture_
*/
OpenGLFramebuffer framebuffer_;
/**
* @brief Internal referenceto the OpenGL texture that's been managed
*
* Kept so that scopes can use the display-referred buffer without having to transform again.
*/
OpenGLTexture managed_texture_;
/**
* @brief Pipeline used to draw to managed_texture_
*/
OpenGLShaderPtr managed_copy_pipeline_;
/**
* @brief Drawing matrix (defaults to identity)
*/
@@ -210,8 +172,6 @@ private:
ViewerSafeMarginInfo safe_margin_;
bool enable_display_referred_signal_;
private slots:
/**
* @brief Slot to connect just before the OpenGL context is destroyed to clean up resources
+2 -2
View File
@@ -32,11 +32,11 @@ ViewerWindow::ViewerWindow(QWidget *parent) :
layout->setMargin(0);
layout->setSpacing(0);
gl_widget_ = new ViewerGLWidget();
gl_widget_ = new ViewerDisplayWidget();
layout->addWidget(gl_widget_);
}
ViewerGLWidget *ViewerWindow::gl_widget() const
ViewerDisplayWidget *ViewerWindow::gl_widget() const
{
return gl_widget_;
}
+3 -3
View File
@@ -23,7 +23,7 @@
#include <QWidget>
#include "viewerglwidget.h"
#include "viewerdisplay.h"
OLIVE_NAMESPACE_ENTER
@@ -32,7 +32,7 @@ class ViewerWindow : public QWidget
public:
ViewerWindow(QWidget* parent = nullptr);
ViewerGLWidget* gl_widget() const;
ViewerDisplayWidget* gl_widget() const;
/**
* @brief Used to adjust resulting picture to be the right aspect ratio
@@ -45,7 +45,7 @@ protected:
virtual void closeEvent(QCloseEvent* e) override;
private:
ViewerGLWidget* gl_widget_;
ViewerDisplayWidget* gl_widget_;
};

Some files were not shown because too many files have changed in this diff Show More