Merge branch 'master' into nodeviewredux

This commit is contained in:
itsmattkc
2020-05-08 13:00:21 +10:00
39 changed files with 774 additions and 301 deletions
+2
View File
@@ -9,6 +9,8 @@ build/
.DS_Store
.vscode
.vs
CmakeSettings.json
#
# Qt ignores taken from https://github.com/github/gitignore
+1 -1
View File
@@ -111,7 +111,7 @@ else()
endif()
if(UNIX AND NOT APPLE)
target_compile_options(
target_link_options(
${OLIVE_TARGET}
PRIVATE
-rdynamic
+2
View File
@@ -47,7 +47,9 @@ OLIVE_NAMESPACE_EXIT
#define MACRO_NAME_AS_STR(s) #s
#define MACRO_VAL_AS_STR(s) MACRO_NAME_AS_STR(s)
#define OLIVE_NS_CONST_ARG(x, y) QArgument<const OLIVE_NAMESPACE::x>("const " MACRO_VAL_AS_STR(OLIVE_NAMESPACE) "::" #x, y)
#define OLIVE_NS_ARG(x, y) QArgument<OLIVE_NAMESPACE::x>(MACRO_VAL_AS_STR(OLIVE_NAMESPACE) "::" #x, y)
#define OLIVE_NS_RETURN_ARG(x, y) QReturnArgument<OLIVE_NAMESPACE::x>(MACRO_VAL_AS_STR(OLIVE_NAMESPACE) "::" #x, y)
/**
* Copy/move deleters. Similar to Q_DISABLE_COPY_MOVE, et al. but those functions are not present in Qt < 5.13 so we
+2 -2
View File
@@ -98,8 +98,8 @@ void Config::SetDefaults()
config_map_["DiskCachePath"] = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
config_map_["DiskCacheSize"] = 20.0;
config_map_["DiskCacheBehind"] = QVariant::fromValue(rational(2));
config_map_["DiskCacheAhead"] = QVariant::fromValue(rational(10));
config_map_["DiskCacheBehind"] = QVariant::fromValue(rational(1));
config_map_["DiskCacheAhead"] = QVariant::fromValue(rational(5));
config_map_["ClearDiskCacheOnClose"] = false;
config_map_["DefaultSequenceWidth"] = 1920;
@@ -85,12 +85,14 @@ PreferencesDiskTab::PreferencesDiskTab()
cache_ahead_slider_ = new FloatSlider();
cache_ahead_slider_->SetFormat(tr("%1 seconds"));
cache_ahead_slider_->SetMinimum(0);
cache_ahead_slider_->SetValue(Config::Current()["DiskCacheAhead"].value<rational>().toDouble());
cache_behavior_layout->addWidget(cache_ahead_slider_, row, 1);
cache_behavior_layout->addWidget(new QLabel(tr("Cache Behind:")), row, 2);
cache_behind_slider_ = new FloatSlider();
cache_behind_slider_->SetMinimum(0);
cache_behind_slider_->SetFormat(tr("%1 seconds"));
cache_behind_slider_->SetValue(Config::Current()["DiskCacheBehind"].value<rational>().toDouble());
cache_behavior_layout->addWidget(cache_behind_slider_, row, 3);
+2
View File
@@ -36,6 +36,8 @@ set(OLIVE_SOURCES
node/input.cpp
node/inputarray.h
node/inputarray.cpp
node/inputdragger.h
node/inputdragger.cpp
node/keyframe.h
node/keyframe.cpp
node/node.h
+168 -19
View File
@@ -20,9 +20,12 @@
#include "matrix.h"
#include <QGuiApplication>
#include <QMatrix4x4>
#include <QVector2D>
#include "common/range.h"
OLIVE_NAMESPACE_ENTER
MatrixGenerator::MatrixGenerator()
@@ -97,55 +100,201 @@ NodeValueTable MatrixGenerator::Value(NodeValueDatabase &value) const
return output;
}
bool MatrixGenerator::GizmoPress(const NodeValueDatabase &db, const QPointF &p, const QVector2D &scale, const QSize &viewport)
{
GizmoSharedData gizmo_data(viewport, scale);
QPointF anchor_pt = GetGizmoAnchorPoint(db, gizmo_data);
int anchor_radius = GetGizmoAnchorPointRadius();
if (InRange(p.x(), anchor_pt.x(), anchor_radius * 2.0)
&& InRange(p.y(), anchor_pt.y(), anchor_radius * 2.0)) {
gizmo_drag_ = anchor_input_;
gizmo_start2_ = db[position_input_].Get(NodeParam::kVec2).value<QVector2D>();
} else {
gizmo_drag_ = position_input_;
}
gizmo_start_ = db[gizmo_drag_].Get(NodeParam::kVec2).value<QVector2D>();
gizmo_mouse_start_ = p;
return true;
}
void MatrixGenerator::GizmoMove(const QPointF &p, const QVector2D &scale, const rational &time)
{
QVector2D movement = 2.0 * QVector2D(p - gizmo_mouse_start_) / scale;
QVector2D new_pos = gizmo_start_ + movement;
if (!gizmo_x_dragger_.IsStarted()) {
gizmo_x_dragger_.Start(gizmo_drag_, time, 0);
}
if (!gizmo_y_dragger_.IsStarted()) {
gizmo_y_dragger_.Start(gizmo_drag_, time, 1);
}
gizmo_x_dragger_.Drag(new_pos.x());
gizmo_y_dragger_.Drag(new_pos.y());
if (gizmo_drag_ == anchor_input_) {
// If we're dragging the anchor, counter the position at the same time
QVector2D new_pos2 = gizmo_start2_ + movement;
if (!gizmo_x2_dragger_.IsStarted()) {
gizmo_x2_dragger_.Start(position_input_, time, 0);
}
if (!gizmo_y2_dragger_.IsStarted()) {
gizmo_y2_dragger_.Start(position_input_, time, 1);
}
gizmo_x2_dragger_.Drag(new_pos2.x());
gizmo_y2_dragger_.Drag(new_pos2.y());
InvalidateVisible(position_input_, position_input_);
}
InvalidateVisible(gizmo_drag_, gizmo_drag_);
}
void MatrixGenerator::GizmoRelease()
{
gizmo_x_dragger_.End();
gizmo_y_dragger_.End();
gizmo_x2_dragger_.End();
gizmo_y2_dragger_.End();
}
bool MatrixGenerator::HasGizmos() const
{
return true;
}
void MatrixGenerator::DrawGizmos(NodeValueDatabase &db, QPainter *p, const QVector2D &scale) const
void MatrixGenerator::DrawGizmos(const NodeValueDatabase &db, QPainter *p, const QVector2D &scale, const QSize& viewport) const
{
// FIXME: Implement this properly
/*
p->setPen(Qt::white);
// Fold values into a matrix
QMatrix4x4 matrix = GenerateMatrix(db);
GizmoSharedData gizmo_data(viewport, scale);
// Set QPainter transform to our matrix
p->setTransform(matrix.toTransform());
{
// Fold values into a matrix
QMatrix4x4 matrix;
matrix.scale(gizmo_data.half_scale);
matrix *= GenerateMatrix(db, false);
matrix.scale(gizmo_data.inverted_half_scale);
// Draw ellipse
p->drawEllipse(QRect(0, 0, 100, 100));
*/
// Create rect and transform it
QVector<QPointF> points = {QPointF(-100, -100),
QPointF(100, -100),
QPointF(100, 100),
QPointF(-100, 100),
QPointF(-100, -100)};
QPolygonF poly(points);
poly = matrix.toTransform().map(poly);
poly.translate(gizmo_data.half_viewport);
// Draw square
p->drawPolyline(poly);
}
{
// Draw anchor point marker (with no anchor point translation)
QPointF pt = GetGizmoAnchorPoint(db, gizmo_data);
// Draw anchor point
int anchor_pt_radius = GetGizmoAnchorPointRadius();
p->drawEllipse(pt, anchor_pt_radius, anchor_pt_radius);
p->drawLines({QLineF(pt.x() - anchor_pt_radius, pt.y(),
pt.x() + anchor_pt_radius, pt.y()),
QLineF(pt.x(), pt.y() - anchor_pt_radius,
pt.x(), pt.y() + anchor_pt_radius)});
}
}
QMatrix4x4 MatrixGenerator::GenerateMatrix(NodeValueDatabase &value) const
{
return GenerateMatrix(value[position_input_].Take(NodeParam::kVec2).value<QVector2D>(),
value[rotation_input_].Take(NodeParam::kFloat).toFloat(),
value[scale_input_].Take(NodeParam::kVec2).value<QVector2D>(),
value[uniform_scale_input_].Take(NodeParam::kBoolean).toBool(),
value[anchor_input_].Take(NodeParam::kVec2).value<QVector2D>());
}
QMatrix4x4 MatrixGenerator::GenerateMatrix(const NodeValueDatabase &value, bool ignore_anchor) const
{
QVector2D anchor;
if (!ignore_anchor) {
anchor = value[anchor_input_].Get(NodeParam::kVec2).value<QVector2D>();
}
return GenerateMatrix(value[position_input_].Get(NodeParam::kVec2).value<QVector2D>(),
value[rotation_input_].Get(NodeParam::kFloat).toFloat(),
value[scale_input_].Get(NodeParam::kVec2).value<QVector2D>(),
value[uniform_scale_input_].Get(NodeParam::kBoolean).toBool(),
anchor);
}
QMatrix4x4 MatrixGenerator::GenerateMatrix(const QVector2D& pos,
const float& rot,
const QVector2D& scale,
bool uniform_scale,
const QVector2D& anchor)
{
QMatrix4x4 mat;
// Position translate
QVector2D pos = value[position_input_].Take(NodeParam::kVec2).value<QVector2D>();
// Position
mat.translate(pos);
// Rotation
mat.rotate(value[rotation_input_].Take(NodeParam::kFloat).toFloat(), 0, 0, 1);
mat.rotate(rot, 0, 0, 1);
// Scale and Uniform Scale
QVector2D scale = value[scale_input_].Take(NodeParam::kVec2).value<QVector2D>();
if (value[uniform_scale_input_].Take(NodeParam::kBoolean).toBool()) {
scale.setY(scale.x());
// Scale
if (uniform_scale) {
QVector2D uniformed(scale.x(), scale.x());
mat.scale(uniformed);
} else {
mat.scale(scale);
}
mat.scale(scale);
// Anchor Point
mat.translate(-value[anchor_input_].Take(NodeParam::kVec2).value<QVector2D>());
mat.translate(-anchor);
return mat;
}
QPointF MatrixGenerator::GetGizmoAnchorPoint(const NodeValueDatabase &db,
const GizmoSharedData& gizmo_data) const
{
QMatrix4x4 matrix;
matrix.scale(gizmo_data.half_scale);
matrix *= GenerateMatrix(db, true);
matrix.scale(gizmo_data.inverted_half_scale);
QPointF pt = matrix.toTransform().map(QPointF());
pt += gizmo_data.half_viewport;
return pt;
}
int MatrixGenerator::GetGizmoAnchorPointRadius()
{
return QFontMetrics(qApp->font()).height() / 2;
}
void MatrixGenerator::UniformScaleChanged()
{
scale_input_->set_property("disabley", uniform_scale_input_->get_standard_value().toBool());
}
MatrixGenerator::GizmoSharedData::GizmoSharedData(const QSize &viewport, const QVector2D &scale)
{
half_viewport = QPointF(viewport.width() / 2, viewport.height() / 2);
half_scale = scale * 0.5;
inverted_half_scale = QVector2D(1.0f / half_scale.x(), 1.0f / half_scale.y());
}
OLIVE_NAMESPACE_EXIT
+34 -1
View File
@@ -21,7 +21,10 @@
#ifndef MATRIXGENERATOR_H
#define MATRIXGENERATOR_H
#include <QVector2D>
#include "node/node.h"
#include "node/inputdragger.h"
OLIVE_NAMESPACE_ENTER
@@ -44,10 +47,32 @@ public:
virtual NodeValueTable Value(NodeValueDatabase& value) const override;
virtual bool HasGizmos() const override;
virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p, const QVector2D &scale) const override;
virtual void DrawGizmos(const NodeValueDatabase& db, QPainter *p, const QVector2D &scale, const QSize& viewport) const override;
virtual bool GizmoPress(const NodeValueDatabase& db, const QPointF &p, const QVector2D &scale, const QSize& viewport) override;
virtual void GizmoMove(const QPointF &p, const QVector2D &scale, const rational &time) override;
virtual void GizmoRelease() override;
private:
struct GizmoSharedData {
GizmoSharedData(const QSize& viewport, const QVector2D& scale);
QPointF half_viewport;
QVector2D half_scale;
QVector2D inverted_half_scale;
};
QMatrix4x4 GenerateMatrix(NodeValueDatabase& value) const;
QMatrix4x4 GenerateMatrix(const NodeValueDatabase& value, bool ignore_anchor) const;
static QMatrix4x4 GenerateMatrix(const QVector2D &pos,
const float &rot,
const QVector2D &scale,
bool uniform_scale,
const QVector2D &anchor);
QPointF GetGizmoAnchorPoint(const NodeValueDatabase &db, const GizmoSharedData &gizmo_data) const;
static int GetGizmoAnchorPointRadius();
NodeInput* gizmo_drag_;
NodeInput* position_input_;
@@ -59,6 +84,14 @@ private:
NodeInput* anchor_input_;
QVector2D gizmo_start_;
QVector2D gizmo_start2_;
QPointF gizmo_mouse_start_;
NodeInputDragger gizmo_x_dragger_;
NodeInputDragger gizmo_y_dragger_;
NodeInputDragger gizmo_x2_dragger_;
NodeInputDragger gizmo_y2_dragger_;
private slots:
void UniformScaleChanged();
+73 -11
View File
@@ -20,6 +20,7 @@
#include "polygon.h"
#include <QGuiApplication>
#include <QVector2D>
OLIVE_NAMESPACE_ENTER
@@ -99,35 +100,96 @@ bool PolygonGenerator::HasGizmos() const
return true;
}
void PolygonGenerator::DrawGizmos(NodeValueDatabase &db, QPainter *p, const QVector2D &scale) const
void PolygonGenerator::DrawGizmos(const NodeValueDatabase &db, QPainter *p, const QVector2D &scale, const QSize &viewport) const
{
if (!points_input_->GetSize()) {
return;
}
QVector<QPointF> points(points_input_->GetSize());
p->setPen(Qt::white);
p->setBrush(Qt::white);
int rect_sz = p->fontMetrics().height() / 8;
QVector<QPointF> points = GetGizmoCoordinates(db, scale);
QVector<QRectF> rects = GetGizmoRects(points);
points.append(points.first());
p->drawPolyline(points.constData(), points.size());
p->drawRects(rects);
}
bool PolygonGenerator::GizmoPress(const NodeValueDatabase &db, const QPointF &p, const QVector2D &scale, const QSize& viewport)
{
QVector<QPointF> points = GetGizmoCoordinates(db, scale);
QVector<QRectF> rects = GetGizmoRects(points);
for (int i=0;i<rects.size();i++) {
const QRectF& r = rects.at(i);
if (r.contains(p)) {
gizmo_drag_ = points_input_->At(i);
gizmo_drag_start_ = points.at(i);
return true;
}
}
return false;
}
void PolygonGenerator::GizmoMove(const QPointF &p, const QVector2D &scale, const rational& time)
{
QVector2D new_pos = QVector2D(p) / scale;
if (!gizmo_x_dragger_.IsStarted()) {
gizmo_x_dragger_.Start(gizmo_drag_, time, 0);
}
if (!gizmo_y_dragger_.IsStarted()) {
gizmo_y_dragger_.Start(gizmo_drag_, time, 1);
}
gizmo_x_dragger_.Drag(new_pos.x());
gizmo_y_dragger_.Drag(new_pos.y());
InvalidateVisible(gizmo_drag_, gizmo_drag_);
}
void PolygonGenerator::GizmoRelease()
{
gizmo_x_dragger_.End();
gizmo_y_dragger_.End();
}
QVector<QPointF> PolygonGenerator::GetGizmoCoordinates(const NodeValueDatabase &db, const QVector2D& scale) const
{
QVector<QPointF> points(points_input_->GetSize());
for (int i=0;i<points_input_->GetSize();i++) {
QVector2D v = db[points_input_->At(i)].Take(NodeParam::kVec2).value<QVector2D>();
QVector2D v = db[points_input_->At(i)].Get(NodeParam::kVec2).value<QVector2D>();
v *= scale;
QPointF pt = v.toPointF();
points[i] = pt;
QRectF rect(pt - QPointF(rect_sz, rect_sz),
pt + QPointF(rect_sz, rect_sz));
p->drawRect(rect);
}
points.append(points.first());
return points;
}
p->drawPolyline(points.constData(), points.size());
QVector<QRectF> PolygonGenerator::GetGizmoRects(const QVector<QPointF> &points) const
{
QVector<QRectF> rects(points.size());
int rect_sz = QFontMetrics(qApp->font()).height() / 8;
for (int i=0;i<points.size();i++) {
const QPointF& p = points.at(i);
rects[i] = QRectF(p - QPointF(rect_sz, rect_sz),
p + QPointF(rect_sz, rect_sz));
}
return rects;
}
OLIVE_NAMESPACE_EXIT
+15 -6
View File
@@ -22,6 +22,7 @@
#define POLYGONGENERATOR_H
#include "node/node.h"
#include "node/inputdragger.h"
OLIVE_NAMESPACE_ENTER
@@ -43,19 +44,27 @@ public:
virtual QString ShaderFragmentCode(const NodeValueDatabase&) const override;
virtual bool HasGizmos() const override;
virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p, const QVector2D &scale) const override;
virtual void DrawGizmos(const NodeValueDatabase& db, QPainter *p, const QVector2D &scale, const QSize& viewport) const override;
/*
virtual bool GizmoPress(const QPointF &p) override;
virtual void GizmoMove(const QPointF &p) override;
virtual void GizmoRelease(const QPointF &p) override;
*/
virtual bool GizmoPress(const NodeValueDatabase& db, const QPointF &p, const QVector2D &scale, const QSize& viewport) override;
virtual void GizmoMove(const QPointF &p, const QVector2D &scale, const rational &time) override;
virtual void GizmoRelease() override;
private:
QVector<QPointF> GetGizmoCoordinates(const NodeValueDatabase &db, const QVector2D &scale) const;
QVector<QRectF> GetGizmoRects(const QVector<QPointF>& points) const;
NodeInputArray* points_input_;
NodeInput* color_input_;
NodeInput* gizmo_drag_;
QPointF gizmo_drag_start_;
NodeInputDragger gizmo_x_dragger_;
NodeInputDragger gizmo_y_dragger_;
};
OLIVE_NAMESPACE_EXIT
+7
View File
@@ -316,6 +316,8 @@ void NodeInput::Init(DataType type)
void NodeInput::SetDefaultValue(const QVector<QVariant> &default_value)
{
default_value_ = default_value;
for (int i=0;i<standard_value_.size();i++) {
standard_value_.replace(i, default_value.at(i));
}
@@ -382,6 +384,11 @@ void NodeInput::GetDependencies(QList<Node *> &list, bool traverse, bool exclusi
}
}
QVariant NodeInput::GetDefaultValue() const
{
return combine_track_values_into_normal_value(default_value_);
}
QList<Node *> NodeInput::GetDependencies(bool traverse, bool exclusive_only) const
{
QList<Node *> list;
+7
View File
@@ -277,6 +277,8 @@ public:
void GetDependencies(QList<Node*>& list, bool traverse, bool exclusive_only) const;
QVariant GetDefaultValue() const;
QList<Node*> GetDependencies(bool traverse = true, bool exclusive_only = false) const;
QList<Node*> GetExclusiveDependencies() const;
@@ -368,6 +370,11 @@ private:
*/
QVector<QVariant> standard_value_;
/**
* @brief Default value that can be reset if the user requests
*/
QVector<QVariant> default_value_;
/**
* @brief Internal keyframe array
*
+118
View File
@@ -0,0 +1,118 @@
/***
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 "inputdragger.h"
#include "core.h"
#include "node.h"
#include "widget/nodeparamview/nodeparamviewundo.h"
OLIVE_NAMESPACE_ENTER
NodeInputDragger::NodeInputDragger() :
input_(nullptr)
{
}
bool NodeInputDragger::IsStarted() const
{
return input_;
}
void NodeInputDragger::Start(NodeInput *input, const rational &time, int track)
{
Q_ASSERT(!input_);
// Set up new drag
input_ = input;
time_ = time;
track_ = track;
// Cache current value
start_value_ = input_->get_value_at_time_for_track(time, track);
// Determine whether we are creating a keyframe or not
if (input_->is_keyframing()) {
dragging_key_ = input_->get_keyframe_at_time_on_track(time, track);
drag_created_key_ = !dragging_key_;
if (drag_created_key_) {
dragging_key_ = NodeKeyframe::Create(time,
start_value_,
input_->get_best_keyframe_type_for_time(time, track),
track);
// We disable default signal emitting during the drag
input_->blockSignals(true);
input_->insert_keyframe(dragging_key_);
input_->blockSignals(false);
emit input_->KeyframeAdded(dragging_key_);
}
}
}
void NodeInputDragger::Drag(const QVariant& value)
{
Q_ASSERT(input_);
end_value_ = value;
input_->blockSignals(true);
if (input_->is_keyframing()) {
dragging_key_->set_value(value);
} else {
input_->set_standard_value(value, track_);
}
input_->blockSignals(false);
}
void NodeInputDragger::End()
{
if (!IsStarted()) {
return;
}
QUndoCommand* command = new QUndoCommand();
if (input_->is_keyframing()) {
if (drag_created_key_) {
// We created a keyframe in this process
new NodeParamInsertKeyframeCommand(input_, dragging_key_, true, command);
}
// We just set a keyframe's value
// We do this even when inserting a keyframe because we don't actually perform an insert in this undo command
// so this will ensure the ValueChanged() signal is sent correctly
new NodeParamSetKeyframeValueCommand(dragging_key_, end_value_, start_value_, command);
} else {
// We just set the standard value
new NodeParamSetStandardValueCommand(input_, track_, end_value_, start_value_, command);
}
Core::instance()->undo_stack()->push(command);
input_ = nullptr;
}
OLIVE_NAMESPACE_EXIT
+60
View File
@@ -0,0 +1,60 @@
/***
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 NODEINPUTDRAGGER_H
#define NODEINPUTDRAGGER_H
#include "node/input.h"
OLIVE_NAMESPACE_ENTER
class NodeInputDragger
{
public:
NodeInputDragger();
bool IsStarted() const;
void Start(NodeInput* input, const rational& time, int track);
void Drag(const QVariant &value);
void End();
private:
NodeInput* input_;
int track_;
rational time_;
QVariant start_value_;
QVariant end_value_;
NodeKeyframePtr dragging_key_;
bool drag_created_key_;
};
OLIVE_NAMESPACE_EXIT
#endif // NODEINPUTDRAGGER_H
+4 -4
View File
@@ -287,20 +287,20 @@ bool Node::HasGizmos() const
return false;
}
void Node::DrawGizmos(NodeValueDatabase &, QPainter *, const QVector2D &) const
void Node::DrawGizmos(const NodeValueDatabase &, QPainter *, const QVector2D &, const QSize &) const
{
}
bool Node::GizmoPress(const QPointF &)
bool Node::GizmoPress(const NodeValueDatabase &, const QPointF &, const QVector2D &, const QSize &viewport)
{
return false;
}
void Node::GizmoMove(const QPointF &)
void Node::GizmoMove(const QPointF &, const QVector2D &, const rational &)
{
}
void Node::GizmoRelease(const QPointF &)
void Node::GizmoRelease()
{
}
+4 -4
View File
@@ -383,11 +383,11 @@ public:
virtual bool HasGizmos() const;
virtual void DrawGizmos(NodeValueDatabase& db, QPainter* p, const QVector2D &scale) const;
virtual void DrawGizmos(const NodeValueDatabase& db, QPainter* p, const QVector2D &scale, const QSize& viewport) const;
virtual bool GizmoPress(const QPointF& p);
virtual void GizmoMove(const QPointF& p);
virtual void GizmoRelease(const QPointF& p);
virtual bool GizmoPress(const NodeValueDatabase& db, const QPointF& p, const QVector2D &scale, const QSize& viewport);
virtual void GizmoMove(const QPointF& p, const QVector2D &scale, const rational &time);
virtual void GizmoRelease();
const QString& GetLabel() const;
void SetLabel(const QString& s);
+6
View File
@@ -120,6 +120,12 @@ void ImageStream::set_colorspace(const QString &color)
emit ParametersChanged();
}
QString ImageStream::get_colorspace_match_string() const
{
return QStringLiteral("%1:%2").arg(footage()->project()->color_manager()->GetConfigFilename(),
colorspace());
}
void ImageStream::ColorConfigChanged()
{
ColorManager* color_manager = footage()->project()->color_manager();
+2
View File
@@ -48,6 +48,8 @@ public:
const QString& colorspace(bool default_if_empty = true) const;
void set_colorspace(const QString& color);
QString get_colorspace_match_string() const;
protected:
virtual void FootageSetEvent(Footage*) override;
+4 -6
View File
@@ -27,21 +27,19 @@ AudioWorker::AudioWorker(QHash<Node *, Node *> *copy_map, QObject *parent) :
{
}
void AudioWorker::FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range, NodeValueTable* table)
NodeValue AudioWorker::FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range)
{
if (stream->type() != Stream::kAudio) {
return;
}
if (decoder->HasConformedVersion(audio_params())) {
SampleBufferPtr frame = decoder->RetrieveAudio(range.in(), range.out() - range.in(), audio_params());
if (frame) {
table->Push(NodeParam::kSamples, QVariant::fromValue(frame));
return NodeValue(NodeParam::kSamples, QVariant::fromValue(frame));
}
} else {
emit ConformUnavailable(decoder->stream(), CurrentPath().range(), range.out(), audio_params());
}
return NodeValue();
}
void AudioWorker::RunNodeAccelerated(const Node *node, const TimeRange &range, NodeValueDatabase &input_params_in, NodeValueTable &output_params)
+1 -1
View File
@@ -31,7 +31,7 @@ public:
AudioWorker(QHash<Node*, Node*>* copy_map, QObject* parent = nullptr);
protected:
virtual void FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range, NodeValueTable* table) override;
virtual NodeValue FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range) override;
virtual void RunNodeAccelerated(const Node *node, const TimeRange& range, NodeValueDatabase& input_params, NodeValueTable& output_params) override;
+11
View File
@@ -154,6 +154,17 @@ NodeValueTable AudioRenderWorker::RenderBlock(const TrackOutput *track, const Ti
return merged_table;
}
void AudioRenderWorker::FootageProcessingEvent(StreamPtr stream, const TimeRange &input_time, NodeValueTable *table)
{
if (stream->type() != Stream::kAudio) {
return;
}
NodeValue value = GetDataFromStream(stream, input_time);
table->Push(value);
}
const AudioRenderingParams &AudioRenderWorker::audio_params() const
{
return audio_params_;
+2
View File
@@ -43,6 +43,8 @@ protected:
virtual NodeValueTable RenderBlock(const TrackOutput *track, const TimeRange& range) override;
virtual void FootageProcessingEvent(StreamPtr stream, const TimeRange &input_time, NodeValueTable* table) override;
const AudioRenderingParams& audio_params() const;
private:
+1 -5
View File
@@ -63,13 +63,9 @@ bool OpenGLBackend::InitInternal()
// Initiate one thread per CPU core
for (int i=0;i<threads().size();i++) {
// Create one processor object for each thread
OpenGLWorker* processor = new OpenGLWorker(frame_cache());
OpenGLWorker* processor = new OpenGLWorker(frame_cache(), proxy_);
processor->SetParameters(params());
processors_.append(processor);
connect(processor, &OpenGLWorker::RequestFrameToValue, proxy_, &OpenGLProxy::FrameToValue, Qt::BlockingQueuedConnection);
connect(processor, &OpenGLWorker::RequestTextureToBuffer, proxy_, &OpenGLProxy::TextureToBuffer, Qt::BlockingQueuedConnection);
connect(processor, &OpenGLWorker::RequestRunNodeAccelerated, proxy_, &OpenGLProxy::RunNodeAccelerated, Qt::BlockingQueuedConnection);
}
return true;
+74 -100
View File
@@ -67,133 +67,107 @@ bool OpenGLProxy::Init()
return true;
}
void OpenGLProxy::FrameToValue(FramePtr frame, StreamPtr stream, NodeValueTable* table)
NodeValue OpenGLProxy::FrameToValue(FramePtr frame, StreamPtr stream)
{
// Ensure stream is video or image type
if (stream->type() != Stream::kVideo && stream->type() != Stream::kImage) {
return;
}
ImageStreamPtr video_stream = std::static_pointer_cast<ImageStream>(stream);
// Set up OCIO context
QString colorspace_match = QStringLiteral("%1:%2").arg(video_stream->footage()->project()->color_manager()->GetConfigFilename(), video_stream->colorspace());
QString colorspace_match = video_stream->get_colorspace_match_string();
OpenGLTextureCache::ReferencePtr footage_tex_ref = nullptr;
OpenGLColorProcessorPtr color_processor = std::static_pointer_cast<OpenGLColorProcessor>(color_cache_.Get(colorspace_match));
if (stream->type() == Stream::kImage && still_image_cache_.Has(stream.get())) {
CachedStill cs = still_image_cache_.Get(stream.get());
if (!color_processor) {
color_processor = OpenGLColorProcessor::Create(video_stream->footage()->project()->color_manager(),
video_stream->colorspace(),
video_stream->footage()->project()->color_manager()->GetReferenceColorSpace());
color_cache_.Add(colorspace_match, color_processor);
}
if (cs.colorspace == colorspace_match
&& cs.alpha_is_associated == video_stream->premultiplied_alpha()
&& cs.divider == video_params_.divider()) {
footage_tex_ref = cs.texture;
} else {
still_image_cache_.Remove(stream.get());
ColorManager::OCIOMethod ocio_method = ColorManager::GetOCIOMethodForMode(video_params_.mode());
// OCIO's CPU conversion is more accurate, so for online we render on CPU but offline we render GPU
if (ocio_method == ColorManager::kOCIOAccurate) {
bool has_alpha = PixelFormat::FormatHasAlphaChannel(frame->format());
// Convert frame to float for OCIO
frame = PixelFormat::ConvertPixelFormat(frame,
has_alpha
? PixelFormat::PIX_FMT_RGBA32F
: PixelFormat::PIX_FMT_RGB32F);
// If alpha is associated, disassociate for the color transform
if (has_alpha && video_stream->premultiplied_alpha()) {
ColorManager::DisassociateAlpha(frame);
}
// Perform color transform
color_processor->ConvertFrame(frame);
// Associate alpha
if (has_alpha) {
if (video_stream->premultiplied_alpha()) {
ColorManager::ReassociateAlpha(frame);
} else {
ColorManager::AssociateAlpha(frame);
}
}
}
if (!footage_tex_ref) {
OpenGLColorProcessorPtr color_processor = std::static_pointer_cast<OpenGLColorProcessor>(color_cache_.Get(colorspace_match));
OpenGLTextureCache::ReferencePtr footage_tex_ref = texture_cache_.Get(ctx_, frame);
if (!color_processor) {
color_processor = OpenGLColorProcessor::Create(video_stream->footage()->project()->color_manager(),
video_stream->colorspace(),
video_stream->footage()->project()->color_manager()->GetReferenceColorSpace());
color_cache_.Add(colorspace_match, color_processor);
if (ocio_method == ColorManager::kOCIOFast) {
if (!color_processor->IsEnabled()) {
color_processor->Enable(ctx_, video_stream->premultiplied_alpha());
}
ColorManager::OCIOMethod ocio_method = ColorManager::GetOCIOMethodForMode(video_params_.mode());
VideoRenderingParams frame_params = frame->video_params();
// OCIO's CPU conversion is more accurate, so for online we render on CPU but offline we render GPU
if (ocio_method == ColorManager::kOCIOAccurate) {
bool has_alpha = PixelFormat::FormatHasAlphaChannel(frame->format());
// Check frame aspect ratio
if (frame->sample_aspect_ratio() != 1 && frame->sample_aspect_ratio() != 0) {
int new_width = frame_params.width();
int new_height = frame_params.height();
// Convert frame to float for OCIO
frame = PixelFormat::ConvertPixelFormat(frame,
has_alpha
? PixelFormat::PIX_FMT_RGBA32F
: PixelFormat::PIX_FMT_RGB32F);
// If alpha is associated, disassociate for the color transform
if (has_alpha && video_stream->premultiplied_alpha()) {
ColorManager::DisassociateAlpha(frame);
// Scale the frame in a way that does not reduce the resolution
if (frame->sample_aspect_ratio() > 1) {
// Make wider
new_width = qRound(static_cast<double>(new_width) * frame->sample_aspect_ratio().toDouble());
} else {
// Make taller
new_height = qRound(static_cast<double>(new_height) / frame->sample_aspect_ratio().toDouble());
}
// Perform color transform
color_processor->ConvertFrame(frame);
// Associate alpha
if (has_alpha) {
if (video_stream->premultiplied_alpha()) {
ColorManager::ReassociateAlpha(frame);
} else {
ColorManager::AssociateAlpha(frame);
}
}
frame_params = VideoRenderingParams(new_width,
new_height,
frame_params.format(),
frame_params.divider());
}
footage_tex_ref = texture_cache_.Get(ctx_, frame);
VideoRenderingParams dest_params(frame_params.width(),
frame_params.height(),
video_params_.format(),
frame_params.divider());
if (ocio_method == ColorManager::kOCIOFast) {
if (!color_processor->IsEnabled()) {
color_processor->Enable(ctx_, video_stream->premultiplied_alpha());
}
// Create destination texture
OpenGLTextureCache::ReferencePtr associated_tex_ref = texture_cache_.Get(ctx_, dest_params);
VideoRenderingParams frame_params = frame->video_params();
buffer_.Attach(associated_tex_ref->texture(), true);
buffer_.Bind();
footage_tex_ref->texture()->Bind();
// Check frame aspect ratio
if (frame->sample_aspect_ratio() != 1 && frame->sample_aspect_ratio() != 0) {
int new_width = frame_params.width();
int new_height = frame_params.height();
// Set viewport for texture size
functions_->glViewport(0, 0, associated_tex_ref->texture()->width(), associated_tex_ref->texture()->height());
// Scale the frame in a way that does not reduce the resolution
if (frame->sample_aspect_ratio() > 1) {
// Make wider
new_width = qRound(static_cast<double>(new_width) * frame->sample_aspect_ratio().toDouble());
} else {
// Make taller
new_height = qRound(static_cast<double>(new_height) / frame->sample_aspect_ratio().toDouble());
}
// Blit old texture to new texture through OCIO shader
color_processor->ProcessOpenGL();
frame_params = VideoRenderingParams(new_width,
new_height,
frame_params.format(),
frame_params.divider());
}
footage_tex_ref->texture()->Release();
buffer_.Release();
buffer_.Detach();
VideoRenderingParams dest_params(frame_params.width(),
frame_params.height(),
video_params_.format(),
frame_params.divider());
// Create destination texture
OpenGLTextureCache::ReferencePtr associated_tex_ref = texture_cache_.Get(ctx_, dest_params);
buffer_.Attach(associated_tex_ref->texture(), true);
buffer_.Bind();
footage_tex_ref->texture()->Bind();
// Set viewport for texture size
functions_->glViewport(0, 0, associated_tex_ref->texture()->width(), associated_tex_ref->texture()->height());
// Blit old texture to new texture through OCIO shader
color_processor->ProcessOpenGL();
footage_tex_ref->texture()->Release();
buffer_.Release();
buffer_.Detach();
footage_tex_ref = associated_tex_ref;
}
if (stream->type() == Stream::kImage) {
// Since this is a still image, we could likely optimize this
still_image_cache_.Add(stream.get(), {footage_tex_ref, colorspace_match, video_stream->premultiplied_alpha(), video_params_.divider()});
}
footage_tex_ref = associated_tex_ref;
}
table->Push(NodeParam::kTexture, QVariant::fromValue(footage_tex_ref));
return NodeValue(NodeParam::kTexture, QVariant::fromValue(footage_tex_ref));
}
void OpenGLProxy::Close()
+6 -13
View File
@@ -31,7 +31,8 @@
OLIVE_NAMESPACE_ENTER
class OpenGLProxy : public QObject {
class OpenGLProxy : public QObject
{
Q_OBJECT
public:
OpenGLProxy(QObject* parent = nullptr);
@@ -63,13 +64,14 @@ public:
void Close();
void FrameToValue(FramePtr frame, StreamPtr stream, NodeValueTable* table);
void SetParameters(const VideoRenderingParams& params);
void RunNodeAccelerated(const Node *node, const TimeRange &range, NodeValueDatabase &input_params, NodeValueTable& output_params);
public slots:
void RunNodeAccelerated(const OLIVE_NAMESPACE::Node *node, const OLIVE_NAMESPACE::TimeRange &range, OLIVE_NAMESPACE::NodeValueDatabase &input_params, OLIVE_NAMESPACE::NodeValueTable& output_params);
void TextureToBuffer(const QVariant& texture, int width, int height, const QMatrix4x4& matrix, void *buffer, int linesize);
void SetParameters(const VideoRenderingParams& params);
OLIVE_NAMESPACE::NodeValue FrameToValue(OLIVE_NAMESPACE::FramePtr frame, OLIVE_NAMESPACE::StreamPtr stream);
private:
QOpenGLContext* ctx_;
@@ -89,15 +91,6 @@ private:
OpenGLTextureCache texture_cache_;
struct CachedStill {
OpenGLTextureCache::ReferencePtr texture;
QString colorspace;
bool alpha_is_associated;
int divider;
};
RenderCache<Stream*, CachedStill> still_image_cache_;
private slots:
void FinishInit();
+30 -6
View File
@@ -31,30 +31,54 @@
OLIVE_NAMESPACE_ENTER
OpenGLWorker::OpenGLWorker(VideoRenderFrameCache *frame_cache, QObject *parent) :
VideoRenderWorker(frame_cache, parent)
OpenGLWorker::OpenGLWorker(VideoRenderFrameCache *frame_cache, OpenGLProxy *proxy, QObject *parent) :
VideoRenderWorker(frame_cache, parent),
proxy_(proxy)
{
}
void OpenGLWorker::FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range, NodeValueTable *table)
NodeValue OpenGLWorker::FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range)
{
FramePtr frame = decoder->RetrieveVideo(range.in(),
video_params().divider(),
video_params().mode() == RenderMode::kOffline);
NodeValue value;
if (frame) {
emit RequestFrameToValue(frame, stream, table);
QMetaObject::invokeMethod(proxy_,
"FrameToValue",
Qt::BlockingQueuedConnection,
OLIVE_NS_RETURN_ARG(NodeValue, value),
OLIVE_NS_ARG(FramePtr, frame),
OLIVE_NS_ARG(StreamPtr, stream));
}
return value;
}
void OpenGLWorker::RunNodeAccelerated(const Node *node, const TimeRange &range, NodeValueDatabase &input_params, NodeValueTable &output_params)
{
emit RequestRunNodeAccelerated(node, range, input_params, output_params);
QMetaObject::invokeMethod(proxy_,
"RunNodeAccelerated",
Qt::BlockingQueuedConnection,
OLIVE_NS_CONST_ARG(Node*, node),
OLIVE_NS_CONST_ARG(TimeRange&, range),
OLIVE_NS_ARG(NodeValueDatabase&, input_params),
OLIVE_NS_ARG(NodeValueTable&, output_params));
}
void OpenGLWorker::TextureToBuffer(const QVariant &tex_in, int width, int height, const QMatrix4x4& matrix, void *buffer, int linesize)
{
emit RequestTextureToBuffer(tex_in, width, height, matrix, buffer, linesize);
QMetaObject::invokeMethod(proxy_,
"TextureToBuffer",
Qt::BlockingQueuedConnection,
Q_ARG(const QVariant&, tex_in),
Q_ARG(int, width),
Q_ARG(int, height),
Q_ARG(const QMatrix4x4&, matrix),
Q_ARG(void*, buffer),
Q_ARG(int, linesize));
}
OLIVE_NAMESPACE_EXIT
+6 -8
View File
@@ -26,6 +26,7 @@
#include "../videorenderworker.h"
#include "openglframebuffer.h"
#include "openglproxy.h"
#include "openglshadercache.h"
#include "opengltexturecache.h"
@@ -35,22 +36,19 @@ class OpenGLWorker : public VideoRenderWorker {
Q_OBJECT
public:
OpenGLWorker(VideoRenderFrameCache* frame_cache,
OpenGLProxy* proxy,
QObject* parent = nullptr);
signals:
void RequestFrameToValue(FramePtr frame, StreamPtr stream, NodeValueTable* table);
void RequestRunNodeAccelerated(const Node *node, const TimeRange &range, NodeValueDatabase &input_params, NodeValueTable& output_params);
void RequestTextureToBuffer(const QVariant& texture, int width, int height, const QMatrix4x4& matrix, void *buffer, int linesize);
protected:
virtual void FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range, NodeValueTable* table) override;
virtual NodeValue FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range) override;
virtual void RunNodeAccelerated(const Node *node, const TimeRange &range, NodeValueDatabase &input_params, NodeValueTable& output_params) override;
virtual void TextureToBuffer(const QVariant& texture, int width, int height, const QMatrix4x4& matrix, void *buffer, int linesize) override;
private:
OpenGLProxy* proxy_;
};
OLIVE_NAMESPACE_EXIT
+9 -7
View File
@@ -98,18 +98,20 @@ DecoderPtr RenderWorker::ResolveDecoderFromInput(StreamPtr stream)
return decoder;
}
bool RenderWorker::IsStarted()
{
return started_;
}
void RenderWorker::FootageProcessingEvent(StreamPtr stream, const TimeRange& input_time, NodeValueTable *table)
NodeValue RenderWorker::GetDataFromStream(StreamPtr stream, const TimeRange &input_time)
{
DecoderPtr decoder = ResolveDecoderFromInput(stream);
if (decoder) {
FrameToValue(decoder, stream, input_time, table);
return FrameToValue(decoder, stream, input_time);
}
return NodeValue();
}
bool RenderWorker::IsStarted()
{
return started_;
}
void RenderWorker::ProcessNodeEvent(const Node *node, const TimeRange &range, NodeValueDatabase &input_params, NodeValueTable &output_params)
+3 -3
View File
@@ -57,14 +57,14 @@ protected:
virtual void RunNodeAccelerated(const Node *node, const TimeRange& range, NodeValueDatabase &input_params, NodeValueTable &output_params);
virtual void FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range, NodeValueTable* table) = 0;
virtual void FootageProcessingEvent(StreamPtr stream, const TimeRange &input_time, NodeValueTable* table) override;
virtual NodeValue FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range) = 0;
virtual void ProcessNodeEvent(const Node *node, const TimeRange &range, NodeValueDatabase &input_params, NodeValueTable &output_params) override;
DecoderPtr ResolveDecoderFromInput(StreamPtr stream);
NodeValue GetDataFromStream(StreamPtr stream, const TimeRange& input_time);
const NodeDependency& CurrentPath() const;
private:
+42
View File
@@ -116,6 +116,48 @@ NodeValueTable VideoRenderWorker::RenderInternal(const NodeDependency& path, con
return value;
}
void VideoRenderWorker::FootageProcessingEvent(StreamPtr stream, const TimeRange &input_time, NodeValueTable *table)
{
if (stream->type() != Stream::kVideo && stream->type() != Stream::kImage) {
return;
}
ImageStreamPtr video_stream = std::static_pointer_cast<ImageStream>(stream);
rational time_match = (stream->type() == Stream::kImage) ? rational() : input_time.in();
QString colorspace_match = video_stream->get_colorspace_match_string();
NodeValue value;
bool found_cache = false;
if (still_image_cache_.Has(stream.get())) {
CachedStill cs = still_image_cache_.Get(stream.get());
if (cs.colorspace == colorspace_match
&& cs.alpha_is_associated == video_stream->premultiplied_alpha()
&& cs.divider == video_params_.divider()
&& cs.time == time_match) {
value = cs.texture;
found_cache = true;
} else {
still_image_cache_.Remove(stream.get());
}
}
if (!found_cache) {
value = GetDataFromStream(stream, input_time);
still_image_cache_.Add(stream.get(), {value,
colorspace_match,
video_stream->premultiplied_alpha(),
video_params_.divider(),
time_match});
}
table->Push(value);
}
void VideoRenderWorker::SetParameters(const VideoRenderingParams &video_params)
{
video_params_ = video_params;
+12
View File
@@ -98,6 +98,8 @@ protected:
virtual NodeValueTable RenderInternal(const NodeDependency& CurrentPath, const qint64& job_time) override;
virtual void FootageProcessingEvent(StreamPtr stream, const TimeRange &input_time, NodeValueTable* table) override;
ColorProcessorCache* color_cache();
private:
@@ -119,6 +121,16 @@ private:
OperatingMode operating_mode_;
struct CachedStill {
NodeValue texture;
QString colorspace;
bool alpha_is_associated;
int divider;
rational time;
};
RenderCache<Stream*, CachedStill> still_image_cache_;
private slots:
};
+13 -13
View File
@@ -69,7 +69,7 @@ colorspaces:
ITU BT.709 primaries based scene referred linear space.
isdata: false
allocation: lg2
allocationvars: [-12.473931188, 12.526068812]
allocationvars: [-10.0, 10.0, 0.00392156862]
# - !<ColorSpace>
# name: Debug
@@ -80,10 +80,10 @@ colorspaces:
# Debug purposes only. Do not use.
# isdata: false
# allocation: lg2
# allocationvars: [-12.473931188, 12.526068812]
# allocationvars: [-10.0, 10.0, 0.00392156862]
# from_reference: !<GroupTransform>
# children:
# - !<AllocationTransform> {allocation: lg2, vars: [-12.473931188, 12.526068812]} #[-12.473931188, 7.526068812]}
# - !<AllocationTransform> {allocation: lg2, vars: [-10.0, 10.0, 0.00392156862]} #[-12.473931188, 7.526068812]}
# - !<AllocationTransform> {allocation: uniform, vars: [0, 0.66]} #0.825
- !<ColorSpace>
@@ -95,13 +95,13 @@ colorspaces:
Log based filmic shaper with 16.5 stops of latitude, and 25 stops of dynamic range.
isdata: false
allocation: lg2
allocationvars: [-12.473931188, 12.526068812]
allocationvars: [-10.0, 10.0, 0.00392156862]
from_reference: !<GroupTransform>
children:
- !<AllocationTransform> {allocation: lg2, vars: [-12.473931188, 12.526068812]}
- !<AllocationTransform> {allocation: lg2, vars: [-10.0, 10.0, 0.00392156862]}
- !<FileTransform> {src: desat65cube.spi3d, interpolation: best}
- !<AllocationTransform> {allocation: uniform, vars: [0, 0.66]}
to_reference: !<AllocationTransform> {allocation: lg2, vars: [-12.473931188, 4.026068812], direction: inverse}
to_reference: !<AllocationTransform> {allocation: lg2, vars: [-10, 6.5, 0.00392156862], direction: inverse}
# - !<ColorSpace>
# name: Desat Log Encoding
@@ -112,8 +112,8 @@ colorspaces:
# Desaturation transform for proper crosstalk. Not intended for use.
# isdata: false
# allocation: lg2
# allocationvars: [-12.473931188, 12.526068812]
# to_reference: !<AllocationTransform> {allocation: lg2, vars: [-12.473931188, 12.526068812], direction: inverse}
# allocationvars: [-10.0, 10.0, 0.00392156862]
# to_reference: !<AllocationTransform> {allocation: lg2, vars: [-10.0, 10.0, 0.00392156862], direction: inverse}
- !<ColorSpace>
name: sRGB OETF
@@ -134,7 +134,7 @@ colorspaces:
bitdepth: 32f
isdata: false
allocation: lg2
allocationvars: [-12.4739, 12.5261]
allocationvars: [-10.0, 10.0, 0.00392156862]
to_reference: !<GroupTransform>
children:
- !<MatrixTransform> {matrix: [0.515121, 0.291977, 0.157104, 0, 0.241196, 0.692245, 0.0665741, 0, -0.00105286, 0.0418854, 0.784073, 0, 0, 0, 0, 1]}
@@ -177,7 +177,7 @@ colorspaces:
Log based filmic shaper with 16.5 stops of latitude, and 25 stops of dynamic range with Apple P3 primaries.
isdata: false
allocation: lg2
allocationvars: [-12.473931188, 12.526068812]
allocationvars: [-10.0, 10.0, 0.00392156862]
from_reference: !<GroupTransform>
children:
- !<ColorSpaceTransform> {src: Linear, dst: Filmic Log Encoding}
@@ -189,7 +189,7 @@ colorspaces:
- !<ExponentTransform> {value: [2.2, 2.2, 2.2, 1.0]}
- !<ColorSpaceTransform> {src: Apple DCI-P3 D65, dst: Linear}
- !<ExponentTransform> {value: [2.2, 2.2, 2.2, 1.0], direction: inverse}
- !<AllocationTransform> {allocation: lg2, vars: [-12.473931188, 4.026068812], direction: inverse}
- !<AllocationTransform> {allocation: lg2, vars: [-10.0, 6.5, 0.00392156862], direction: inverse}
- !<ColorSpace>
name: BT.1886 Filmic Log Encoding
@@ -200,7 +200,7 @@ colorspaces:
Log based filmic shaper with 16.5 stops of latitude, and 25 stops of dynamic range with REC.709 primaries.
isdata: false
allocation: lg2
allocationvars: [-12.473931188, 12.526068812]
allocationvars: [-10.0, 10.0, 0.00392156862]
from_reference: !<GroupTransform>
children:
- !<ColorSpaceTransform> {src: Linear, dst: Filmic Log Encoding}
@@ -210,7 +210,7 @@ colorspaces:
children:
- !<ExponentTransform> {value: [2.4, 2.4, 2.4, 1.0]}
- !<ExponentTransform> {value: [2.2, 2.2, 2.2, 1.0], direction: inverse}
- !<AllocationTransform> {allocation: lg2, vars: [-12.473931188, 4.026068812], direction: inverse}
- !<AllocationTransform> {allocation: lg2, vars: [-10.0, 10.0, 0.00392156862], direction: inverse}
- !<ColorSpace>
name: Fuji F-Log OETF
@@ -31,9 +31,12 @@ NodeParamViewArrayWidget::NodeParamViewArrayWidget(NodeInputArray* array, QWidge
QHBoxLayout* layout = new QHBoxLayout(this);
count_lbl_ = new QLabel();
layout->addWidget(count_lbl_, 1);
layout->addWidget(count_lbl_);
layout->addStretch();
plus_btn_ = new QPushButton(tr("+"));
plus_btn_->setFixedWidth(plus_btn_->sizeHint().height());
layout->addWidget(plus_btn_);
connect(plus_btn_, &QPushButton::clicked, this, &NodeParamViewArrayWidget::AddElement);
@@ -42,9 +42,7 @@ OLIVE_NAMESPACE_ENTER
NodeParamViewWidgetBridge::NodeParamViewWidgetBridge(NodeInput *input, QObject *parent) :
QObject(parent),
input_(input),
dragging_(false),
drag_created_keyframe_(false)
input_(input)
{
CreateWidgets();
@@ -227,74 +225,23 @@ void NodeParamViewWidgetBridge::ProcessSlider(SliderBase *slider, const QVariant
if (slider->IsDragging()) {
// While we're dragging, we block the input's normal signalling and create our own
input_->blockSignals(true);
if (!dragging_) {
// Set up new drag
dragging_ = true;
// Cache current value
drag_old_value_ = input_->get_value_at_time_for_track(node_time, slider_track);
// Determine whether we are creating a keyframe or not
if (input_->is_keyframing()) {
dragging_keyframe_ = input_->get_keyframe_at_time_on_track(node_time, slider_track);
drag_created_keyframe_ = !dragging_keyframe_;
if (drag_created_keyframe_) {
dragging_keyframe_ = NodeKeyframe::Create(node_time,
value,
input_->get_best_keyframe_type_for_time(node_time, slider_track),
slider_track);
input_->insert_keyframe(dragging_keyframe_);
// We re-enable signals temporarily to emit the keyframe added signal
input_->blockSignals(false);
emit input_->KeyframeAdded(dragging_keyframe_);
input_->blockSignals(true);
}
}
if (!dragger_.IsStarted()) {
dragger_.Start(input_, node_time, slider_track);
}
if (input_->is_keyframing()) {
dragging_keyframe_->set_value(value);
} else {
input_->set_standard_value(value, slider_track);
}
input_->blockSignals(false);
dragger_.Drag(value);
input_->parentNode()->InvalidateVisible(input_, input_);
} else if (dragger_.IsStarted()) {
// We were dragging and just stopped
dragger_.Drag(value);
dragger_.End();
} else {
if (dragging_) {
// We were dragging and just stopped
dragging_ = false;
QUndoCommand* command = new QUndoCommand();
if (input_->is_keyframing()) {
if (drag_created_keyframe_) {
// We created a keyframe in this process
new NodeParamInsertKeyframeCommand(input_, dragging_keyframe_, true, command);
}
// We just set a keyframe's value
// We do this even when inserting a keyframe because we don't actually perform an insert in this undo command
// so this will ensure the ValueChanged() signal is sent correctly
new NodeParamSetKeyframeValueCommand(dragging_keyframe_, value, drag_old_value_, command);
} else {
// We just set the standard value
new NodeParamSetStandardValueCommand(input_, slider_track, value, drag_old_value_, command);
}
Core::instance()->undo_stack()->push(command);
} else {
// No drag was involved, we can just push the value
SetInputValue(value, slider_track);
}
// No drag was involved, we can just push the value
SetInputValue(value, slider_track);
}
}
@@ -529,7 +476,7 @@ rational NodeParamViewWidgetBridge::GetCurrentTimeAsNodeTime() const
void NodeParamViewWidgetBridge::InputValueChanged(const TimeRange &range)
{
if (!dragging_ && range.in() <= time_ && range.out() >= time_) {
if (!dragger_.IsStarted() && range.in() <= time_ && range.out() >= time_) {
// We'll need to update the widgets because the values have changed on our current time
UpdateWidgetValues();
}
@@ -24,6 +24,7 @@
#include <QObject>
#include "node/input.h"
#include "node/inputdragger.h"
#include "widget/slider/sliderbase.h"
#include "widget/timetarget/timetarget.h"
@@ -60,10 +61,7 @@ private:
rational time_;
bool dragging_;
bool drag_created_keyframe_;
QVariant drag_old_value_;
NodeKeyframePtr dragging_keyframe_;
NodeInputDragger dragger_;
private slots:
void WidgetCallback();
+10 -7
View File
@@ -48,7 +48,8 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
color_menu_enabled_(true),
divider_(Config::Current()["DefaultViewerDivider"].toInt()),
override_color_manager_(nullptr),
time_changed_from_timer_(false)
time_changed_from_timer_(false),
playback_is_audio_only_(false)
{
// Set up main layout
QVBoxLayout* layout = new QVBoxLayout(this);
@@ -379,10 +380,12 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only)
controls_->ShowPauseButton();
if (stack_->currentWidget() == sizer_) {
connect(main_gl_widget(), &ViewerDisplayWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
} else {
playback_is_audio_only_ = (stack_->currentWidget() != sizer_ || !isVisible());
if (playback_is_audio_only_) {
connect(AudioManager::instance(), &AudioManager::OutputNotified, this, &ViewerWidget::PlaybackTimerUpdate);
} else {
connect(main_gl_widget(), &ViewerDisplayWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
}
}
@@ -702,10 +705,10 @@ void ViewerWidget::Pause()
playback_speed_ = 0;
controls_->ShowPlayButton();
if (stack_->currentWidget() == sizer_) {
disconnect(main_gl_widget(), &ViewerDisplayWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
} else {
if (playback_is_audio_only_) {
disconnect(AudioManager::instance(), &AudioManager::OutputNotified, this, &ViewerWidget::PlaybackTimerUpdate);
} else {
disconnect(main_gl_widget(), &ViewerDisplayWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
}
}
}
+2
View File
@@ -195,6 +195,8 @@ private:
bool play_in_to_out_only_;
bool playback_is_audio_only_;
AudioWaveformView* waveform_view_;
QList<ViewerWindow*> windows_;
+16 -11
View File
@@ -191,11 +191,11 @@ void ViewerDisplayWidget::SetTime(const rational &time)
void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event)
{
if (gizmos_) {
if (gizmos_->GizmoPress(GetTexturePosition(event->pos()))) {
gizmo_click_ = true;
return;
}
if (gizmos_
&& gizmos_->GizmoPress(gizmo_db_, event->pos(), QVector2D(GetTexturePosition(size())), size())) {
gizmo_click_ = true;
gizmo_drag_time_ = GetGizmoTime();
return;
}
QOpenGLWidget::mousePressEvent(event);
@@ -206,7 +206,7 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event)
void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event)
{
if (gizmo_click_) {
gizmos_->GizmoMove(GetTexturePosition(event->pos()));
gizmos_->GizmoMove(event->pos(), QVector2D(GetTexturePosition(size())), gizmo_drag_time_);
return;
}
@@ -236,7 +236,7 @@ void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event)
void ViewerDisplayWidget::mouseReleaseEvent(QMouseEvent *event)
{
if (gizmo_click_) {
gizmos_->GizmoRelease(GetTexturePosition(event->pos()));
gizmos_->GizmoRelease();
gizmo_click_ = false;
return;
@@ -294,12 +294,12 @@ void ViewerDisplayWidget::paintGL()
if (gizmos_) {
GizmoTraverser gt;
rational node_time = GetAdjustedTime(GetTimeTarget(), gizmos_, time_, NodeParam::kInput);
rational node_time = GetGizmoTime();
NodeValueDatabase db = gt.GenerateDatabase(gizmos_, TimeRange(node_time, node_time));
gizmo_db_ = gt.GenerateDatabase(gizmos_, TimeRange(node_time, node_time));
QPainter p(this);
gizmos_->DrawGizmos(db, &p, QVector2D(GetTexturePosition(size())));
gizmos_->DrawGizmos(gizmo_db_, &p, QVector2D(GetTexturePosition(size())), size());
}
// Draw action/title safe areas
@@ -328,7 +328,7 @@ void ViewerDisplayWidget::paintGL()
int cross = qMin(w, h) / 32;
QLine lines[] = {QLine(rect().center().x() - cross, rect().center().y(), rect().center().x() + cross, rect().center().y()),
QLine lines[] = {QLine(rect().center().x() - cross, rect().center().y(),rect().center().x() + cross, rect().center().y()),
QLine(rect().center().x(), rect().center().y() - cross, rect().center().x(), rect().center().y() + cross)};
p.drawLines(lines, 2);
@@ -351,6 +351,11 @@ QPointF ViewerDisplayWidget::GetTexturePosition(const double &x, const double &y
y / gizmo_params_.height());
}
rational ViewerDisplayWidget::GetGizmoTime()
{
return GetAdjustedTime(GetTimeTarget(), gizmos_, time_, NodeParam::kInput);
}
#ifdef Q_OS_LINUX
void ViewerDisplayWidget::ShowNouveauWarning()
{
+4 -2
View File
@@ -162,6 +162,8 @@ private:
QPointF GetTexturePosition(const QSize& size);
QPointF GetTexturePosition(const double& x, const double& y);
rational GetGizmoTime();
/**
* @brief Internal reference to the OpenGL texture to draw. Set in SetTexture() and used in paintGL().
*/
@@ -188,9 +190,9 @@ private:
ViewerSafeMarginInfo safe_margin_;
Node* gizmos_;
NodeValueDatabase gizmo_db_;
rational gizmo_drag_time_;
VideoRenderingParams gizmo_params_;
bool gizmo_click_;
rational time_;