Merge branch 'master' into nodeviewredux
This commit is contained in:
@@ -9,6 +9,8 @@ build/
|
||||
.DS_Store
|
||||
|
||||
.vscode
|
||||
.vs
|
||||
CmakeSettings.json
|
||||
|
||||
#
|
||||
# Qt ignores taken from https://github.com/github/gitignore
|
||||
|
||||
+1
-1
@@ -111,7 +111,7 @@ else()
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_compile_options(
|
||||
target_link_options(
|
||||
${OLIVE_TARGET}
|
||||
PRIVATE
|
||||
-rdynamic
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,6 +195,8 @@ private:
|
||||
|
||||
bool play_in_to_out_only_;
|
||||
|
||||
bool playback_is_audio_only_;
|
||||
|
||||
AudioWaveformView* waveform_view_;
|
||||
|
||||
QList<ViewerWindow*> windows_;
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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_;
|
||||
|
||||
Reference in New Issue
Block a user