nodes: added distort nodes

Adds nodes for cropping and transforming
This commit is contained in:
itsmattkc
2020-11-22 11:34:37 +11:00
parent 3e48aef88c
commit 54cd244801
19 changed files with 1152 additions and 236 deletions
+1
View File
@@ -16,6 +16,7 @@
add_subdirectory(audio)
add_subdirectory(block)
add_subdirectory(distort)
add_subdirectory(filter)
add_subdirectory(generator)
add_subdirectory(input)
+23
View File
@@ -0,0 +1,23 @@
# Olive - Non-Linear Video Editor
# Copyright (C) 2020 Olive Team
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
add_subdirectory(crop)
add_subdirectory(transform)
set(OLIVE_SOURCES
${OLIVE_SOURCES}
PARENT_SCOPE
)
+22
View File
@@ -0,0 +1,22 @@
# Olive - Non-Linear Video Editor
# Copyright (C) 2020 Olive Team
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/distort/crop/cropdistortnode.cpp
node/distort/crop/cropdistortnode.h
PARENT_SCOPE
)
+274
View File
@@ -0,0 +1,274 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "cropdistortnode.h"
#include "common/lerp.h"
namespace olive {
CropDistortNode::CropDistortNode()
{
texture_input_ = new NodeInput(QStringLiteral("tex_in"), NodeParam::kTexture);
AddInput(texture_input_);
left_input_ = new NodeInput(QStringLiteral("left_in"), NodeParam::kFloat, 0.0);
left_input_->set_property(QStringLiteral("min"), 0.0);
left_input_->set_property(QStringLiteral("max"), 1.0);
left_input_->set_property(QStringLiteral("view"), QStringLiteral("percent"));
AddInput(left_input_);
top_input_ = new NodeInput(QStringLiteral("top_in"), NodeParam::kFloat, 0.0);
top_input_->set_property(QStringLiteral("min"), 0.0);
top_input_->set_property(QStringLiteral("max"), 1.0);
top_input_->set_property(QStringLiteral("view"), QStringLiteral("percent"));
AddInput(top_input_);
right_input_ = new NodeInput(QStringLiteral("right_in"), NodeParam::kFloat, 0.0);
right_input_->set_property(QStringLiteral("min"), 0.0);
right_input_->set_property(QStringLiteral("max"), 1.0);
right_input_->set_property(QStringLiteral("view"), QStringLiteral("percent"));
AddInput(right_input_);
bottom_input_ = new NodeInput(QStringLiteral("bottom_in"), NodeParam::kFloat, 0.0);
bottom_input_->set_property(QStringLiteral("min"), 0.0);
bottom_input_->set_property(QStringLiteral("max"), 1.0);
bottom_input_->set_property(QStringLiteral("view"), QStringLiteral("percent"));
AddInput(bottom_input_);
feather_input_ = new NodeInput(QStringLiteral("feather_in"), NodeParam::kFloat, 0.0);
feather_input_->set_property(QStringLiteral("min"), 0.0);
AddInput(feather_input_);
}
void CropDistortNode::Retranslate()
{
texture_input_->set_name(tr("Texture"));
left_input_->set_name(tr("Left"));
top_input_->set_name(tr("Top"));
right_input_->set_name(tr("Right"));
bottom_input_->set_name(tr("Bottom"));
feather_input_->set_name(tr("Feather"));
}
NodeValueTable CropDistortNode::Value(NodeValueDatabase &value) const
{
ShaderJob job;
job.InsertValue(texture_input_, value);
job.InsertValue(left_input_, value);
job.InsertValue(top_input_, value);
job.InsertValue(right_input_, value);
job.InsertValue(bottom_input_, value);
job.InsertValue(feather_input_, value);
job.InsertValue(QStringLiteral("resolution_in"),
ShaderValue(value[QStringLiteral("global")].Get(NodeParam::kVec2, QStringLiteral("resolution")), NodeParam::kVec2));
job.SetAlphaChannelRequired(true);
NodeValueTable table = value.Merge();
if (!job.GetValue(texture_input_).data.isNull()) {
if (!qIsNull(job.GetValue(left_input_).data.toDouble())
|| !qIsNull(job.GetValue(right_input_).data.toDouble())
|| !qIsNull(job.GetValue(top_input_).data.toDouble())
|| !qIsNull(job.GetValue(bottom_input_).data.toDouble())) {
table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this);
} else {
table.Push(NodeParam::kTexture, job.GetValue(texture_input_).data, this);
}
}
return table;
}
ShaderCode CropDistortNode::GetShaderCode(const QString &shader_id) const
{
Q_UNUSED(shader_id)
return ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/crop.frag")));
}
void CropDistortNode::DrawGizmos(NodeValueDatabase &db, QPainter *p)
{
QVector2D resolution = db[QStringLiteral("global")].Get(NodeParam::kVec2, QStringLiteral("resolution")).value<QVector2D>();
const int handle_radius = GetGizmoHandleRadius();
p->setPen(QPen(Qt::white, 0));
double left_pt = resolution.x() * db[left_input_].Get(NodeParam::kFloat).toDouble();
double top_pt = resolution.y() * db[top_input_].Get(NodeParam::kFloat).toDouble();
double right_pt = resolution.x() * (1.0 - db[right_input_].Get(NodeParam::kFloat).toDouble());
double bottom_pt = resolution.y() * (1.0 - db[bottom_input_].Get(NodeParam::kFloat).toDouble());
double center_x_pt = lerp(left_pt, right_pt, 0.5);
double center_y_pt = lerp(top_pt, bottom_pt, 0.5);
gizmo_whole_rect_ = QRectF(left_pt, top_pt, right_pt - left_pt, bottom_pt - top_pt);
p->drawRect(gizmo_whole_rect_);
gizmo_resize_handle_[kGizmoScaleTopLeft] = CreateGizmoHandleRect(QPointF(left_pt, top_pt), handle_radius);
gizmo_resize_handle_[kGizmoScaleTopCenter] = CreateGizmoHandleRect(QPointF(center_x_pt, top_pt), handle_radius);
gizmo_resize_handle_[kGizmoScaleTopRight] = CreateGizmoHandleRect(QPointF(right_pt, top_pt), handle_radius);
gizmo_resize_handle_[kGizmoScaleBottomLeft] = CreateGizmoHandleRect(QPointF(left_pt, bottom_pt), handle_radius);
gizmo_resize_handle_[kGizmoScaleBottomCenter] = CreateGizmoHandleRect(QPointF(center_x_pt, bottom_pt), handle_radius);
gizmo_resize_handle_[kGizmoScaleBottomRight] = CreateGizmoHandleRect(QPointF(right_pt, bottom_pt), handle_radius);
gizmo_resize_handle_[kGizmoScaleCenterLeft] = CreateGizmoHandleRect(QPointF(left_pt, center_y_pt), handle_radius);
gizmo_resize_handle_[kGizmoScaleCenterRight] = CreateGizmoHandleRect(QPointF(right_pt, center_y_pt), handle_radius);
p->setPen(Qt::NoPen);
p->setBrush(Qt::white);
DrawAndExpandGizmoHandles(p, handle_radius, gizmo_resize_handle_, kGizmoScaleCount);
}
bool CropDistortNode::GizmoPress(NodeValueDatabase &db, const QPointF &p)
{
bool found_handle = false;
bool gizmo_active[kGizmoScaleCount] = {false};
for (int i=0; i<kGizmoScaleCount; i++) {
gizmo_active[i] = gizmo_resize_handle_[i].contains(p);
if (gizmo_active[i]) {
found_handle = true;
break;
}
}
bool in_rect = found_handle ? false : gizmo_whole_rect_.contains(p);
qDebug() << "Active handles:";
for (int i=0; i<kGizmoScaleCount; i++) {
qDebug() << " " << i << gizmo_active[i];
}
qDebug() << " Rect:" << in_rect;
gizmo_drag_ = kGizmoNone;
// Drag handle
if (gizmo_active[kGizmoScaleTopLeft]
|| gizmo_active[kGizmoScaleCenterLeft]
|| gizmo_active[kGizmoScaleBottomLeft]
|| in_rect) {
gizmo_drag_ |= kGizmoLeft;
gizmo_start_.append(db[left_input_].Get(NodeParam::kFloat));
}
if (gizmo_active[kGizmoScaleTopLeft]
|| gizmo_active[kGizmoScaleTopCenter]
|| gizmo_active[kGizmoScaleTopRight]
|| in_rect) {
gizmo_drag_ |= kGizmoTop;
gizmo_start_.append(db[top_input_].Get(NodeParam::kFloat));
}
if (gizmo_active[kGizmoScaleTopRight]
|| gizmo_active[kGizmoScaleCenterRight]
|| gizmo_active[kGizmoScaleBottomRight]
|| in_rect) {
gizmo_drag_ |= kGizmoRight;
gizmo_start_.append(db[right_input_].Get(NodeParam::kFloat));
}
if (gizmo_active[kGizmoScaleBottomLeft]
|| gizmo_active[kGizmoScaleBottomCenter]
|| gizmo_active[kGizmoScaleBottomRight]
|| in_rect) {
gizmo_drag_ |= kGizmoBottom;
gizmo_start_.append(db[bottom_input_].Get(NodeParam::kFloat));
}
if (gizmo_drag_ > kGizmoNone) {
gizmo_res_ = db[QStringLiteral("global")].Get(NodeParam::kVec2, QStringLiteral("resolution")).value<QVector2D>();
gizmo_drag_start_ = p;
return true;
}
return false;
}
void CropDistortNode::GizmoMove(const QPointF &p, const rational &time)
{
if (gizmo_dragger_.isEmpty()) {
gizmo_dragger_.resize(gizmo_start_.size());
int counter = 0;
if (gizmo_drag_ & kGizmoLeft) {
gizmo_dragger_[counter].Start(left_input_, time, 0);
counter++;
}
if (gizmo_drag_ & kGizmoTop) {
gizmo_dragger_[counter].Start(top_input_, time, 0);
counter++;
}
if (gizmo_drag_ & kGizmoRight) {
gizmo_dragger_[counter].Start(right_input_, time, 0);
counter++;
}
if (gizmo_drag_ & kGizmoBottom) {
gizmo_dragger_[counter].Start(bottom_input_, time, 0);
counter++;
}
}
int counter = 0;
double x_diff = (p.x() - gizmo_drag_start_.x()) / gizmo_res_.x();
double y_diff = (p.y() - gizmo_drag_start_.y()) / gizmo_res_.y();
if (gizmo_drag_ & kGizmoLeft) {
gizmo_dragger_[counter].Drag(gizmo_start_[counter].toDouble() + x_diff);
counter++;
}
if (gizmo_drag_ & kGizmoTop) {
gizmo_dragger_[counter].Drag(gizmo_start_[counter].toDouble() + y_diff);
counter++;
}
if (gizmo_drag_ & kGizmoRight) {
gizmo_dragger_[counter].Drag(gizmo_start_[counter].toDouble() - x_diff);
counter++;
}
if (gizmo_drag_ & kGizmoBottom) {
gizmo_dragger_[counter].Drag(gizmo_start_[counter].toDouble() - y_diff);
counter++;
}
}
void CropDistortNode::GizmoRelease()
{
for (NodeInputDragger& i : gizmo_dragger_) {
i.End();
}
gizmo_dragger_.clear();
gizmo_start_.clear();
}
}
+111
View File
@@ -0,0 +1,111 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef CROPDISTORTNODE_H
#define CROPDISTORTNODE_H
#include <QVector2D>
#include "node/inputdragger.h"
#include "node/node.h"
namespace olive {
class CropDistortNode : public Node
{
public:
CropDistortNode();
virtual Node* copy() const override
{
return new CropDistortNode();
}
virtual QString Name() const override
{
return tr("Crop");
}
virtual QString id() const override
{
return QStringLiteral("org.olivevideoeditor.Olive.crop");
}
virtual QVector<CategoryID> Category() const override
{
return {kCategoryDistort};
}
virtual QString Description() const override
{
return tr("Crop the edges of an image.");
}
virtual void Retranslate() override;
virtual NodeValueTable Value(NodeValueDatabase& value) const override;
virtual ShaderCode GetShaderCode(const QString &shader_id) const override;
virtual bool HasGizmos() const override
{
return true;
}
virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p) override;
virtual bool GizmoPress(NodeValueDatabase& db, const QPointF &p) override;
virtual void GizmoMove(const QPointF &p, const rational &time) override;
virtual void GizmoRelease() override;
private:
NodeInput* texture_input_;
NodeInput* left_input_;
NodeInput* top_input_;
NodeInput* right_input_;
NodeInput* bottom_input_;
NodeInput* feather_input_;
// Gizmo variables
QRectF gizmo_resize_handle_[kGizmoScaleCount];
QRectF gizmo_whole_rect_;
enum GizmoDragDirection {
kGizmoNone = 0x0,
kGizmoLeft = 0x1,
kGizmoTop = 0x2,
kGizmoRight = 0x4,
kGizmoBottom = 0x8,
kGizmoRectangle = 0xFF
};
int gizmo_drag_;
QVector<NodeInputDragger> gizmo_dragger_;
QVector<QVariant> gizmo_start_;
QPointF gizmo_drag_start_;
QVector2D gizmo_res_;
};
}
#endif // CROPDISTORTNODE_H
+22
View File
@@ -0,0 +1,22 @@
# Olive - Non-Linear Video Editor
# Copyright (C) 2020 Olive Team
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/distort/transform/transformdistortnode.cpp
node/distort/transform/transformdistortnode.h
PARENT_SCOPE
)
@@ -0,0 +1,414 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "transformdistortnode.h"
#include <QGuiApplication>
#include "common/range.h"
namespace olive {
TransformDistortNode::TransformDistortNode()
{
autoscale_input_ = new NodeInput(QStringLiteral("autoscale_in"), NodeParam::kBoolean, false);
AddInput(autoscale_input_);
texture_input_ = new NodeInput(QStringLiteral("tex_in"), NodeParam::kTexture);
AddInput(texture_input_);
}
void TransformDistortNode::Retranslate()
{
MatrixGenerator::Retranslate();
autoscale_input_->set_name(tr("Auto-Scale"));
texture_input_->set_name(tr("Texture"));
}
NodeValueTable TransformDistortNode::Value(NodeValueDatabase &value) const
{
// Generate matrix
QMatrix4x4 generated_matrix = GenerateMatrix(value, true, false, false);
// Pop texture
TexturePtr texture = value[texture_input_].Take(NodeParam::kTexture).value<TexturePtr>();
// Merge table
NodeValueTable table = value.Merge();
// If we have a texture, generate a matrix and make it happen
if (texture) {
// Adjust our matrix by the resolutions involved
QVector2D sequence_res = value[QStringLiteral("global")].Get(NodeParam::kVec2, QStringLiteral("resolution")).value<QVector2D>();
QVector2D texture_res(texture->params().width() * texture->pixel_aspect_ratio().toDouble(), texture->params().height());
bool autoscale = value[autoscale_input_].Get(NodeParam::kBoolean).toBool();
QMatrix4x4 real_matrix = AdjustMatrixByResolutions(generated_matrix,
sequence_res,
texture_res,
autoscale);
if (real_matrix.isIdentity()) {
// We don't expect any changes, just push as normal
table.Push(NodeParam::kTexture, QVariant::fromValue(texture), this);
} else {
// The matrix will transform things
ShaderJob job;
job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(texture), NodeParam::kTexture));
job.InsertValue(QStringLiteral("ove_mvpmat"), ShaderValue(real_matrix, NodeParam::kMatrix));
table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this);
}
}
return table;
}
ShaderCode TransformDistortNode::GetShaderCode(const QString &shader_id) const
{
Q_UNUSED(shader_id);
// Returns default frag and vert shader
return ShaderCode();
}
bool TransformDistortNode::GizmoPress(NodeValueDatabase &db, const QPointF &p)
{
// Store cursor position
gizmo_drag_pos_ = p;
// Check scaling
bool gizmo_scale_active[kGizmoScaleCount] = {false};
bool scaling = false;
for (int i=0; i<kGizmoScaleCount; i++) {
gizmo_scale_active[i] = gizmo_resize_handle_[i].contains(p);
if (gizmo_scale_active[i]) {
scaling = true;
break;
}
}
if (scaling) {
// Dragging scale handle
gizmo_start_ = {db[scale_input()].Get(NodeParam::kVec2)};
gizmo_drag_ = scale_input();
gizmo_scale_uniform_ = db[uniform_scale_input()].Get(NodeParam::kBoolean).toBool();
if (gizmo_scale_active[kGizmoScaleTopLeft] || gizmo_scale_active[kGizmoScaleTopRight]
|| gizmo_scale_active[kGizmoScaleBottomLeft] || gizmo_scale_active[kGizmoScaleBottomRight]) {
gizmo_scale_axes_ = kGizmoScaleBoth;
} else if (gizmo_scale_active[kGizmoScaleCenterLeft] || gizmo_scale_active[kGizmoScaleCenterRight]) {
gizmo_scale_axes_ = kGizmoScaleXOnly;
} else {
gizmo_scale_axes_ = kGizmoScaleYOnly;
}
// Store texture size
QVector2D texture_sz = db[texture_input()].Get(NodeParam::kTexture).value<QVector2D>();
gizmo_scale_anchor_ = db[anchor_input()].Get(NodeParam::kVec2).value<QVector2D>() + texture_sz/2;
if (gizmo_scale_active[kGizmoScaleTopRight]
|| gizmo_scale_active[kGizmoScaleBottomRight]
|| gizmo_scale_active[kGizmoScaleCenterRight]) {
// Right handles, flip X axis
gizmo_scale_anchor_.setX(texture_sz.x() - gizmo_scale_anchor_.x());
}
if (gizmo_scale_active[kGizmoScaleBottomLeft]
|| gizmo_scale_active[kGizmoScaleBottomRight]
|| gizmo_scale_active[kGizmoScaleBottomCenter]) {
// Bottom handles, flip Y axis
gizmo_scale_anchor_.setY(texture_sz.y() - gizmo_scale_anchor_.y());
}
return true;
} else if (gizmo_anchor_pt_.contains(p)) {
// Dragging the anchor point specifically
gizmo_start_ = {db[anchor_input()].Get(NodeParam::kVec2),
db[position_input()].Get(NodeParam::kVec2)};
gizmo_drag_ = anchor_input();
// Store current matrix
gizmo_matrix_ = GenerateMatrix(db, false, true, true);
return true;
} else if (gizmo_rect_.containsPoint(p, Qt::OddEvenFill)) {
// Dragging the main rectangle
gizmo_start_ = {db[position_input()].Get(NodeParam::kVec2)};
gizmo_drag_ = position_input();
return true;
} else {
// Dragging rotation
gizmo_start_ = {db[rotation_input()].Get(NodeParam::kFloat)};
gizmo_drag_ = rotation_input();
gizmo_start_angle_ = qAtan2(gizmo_drag_pos_.y() - gizmo_anchor_pt_.center().y(),
gizmo_drag_pos_.x() - gizmo_anchor_pt_.center().x());
return true;
}
return false;
}
void TransformDistortNode::GizmoMove(const QPointF &p, const rational &time)
{
QPointF movement = (p - gizmo_drag_pos_);
QVector2D vec_movement(movement);
if (gizmo_drag_ == anchor_input()) {
// Dragging the anchor point around
if (gizmo_dragger_.isEmpty()) {
gizmo_dragger_.resize(4);
gizmo_dragger_[0].Start(anchor_input(), time, 0);
gizmo_dragger_[1].Start(anchor_input(), time, 1);
gizmo_dragger_[2].Start(position_input(), time, 0);
gizmo_dragger_[3].Start(position_input(), time, 1);
}
QVector2D inverted_movement(gizmo_matrix_.toTransform().inverted().map(movement));
QVector2D anchor_cont = gizmo_start_[0].value<QVector2D>() + inverted_movement;
QVector2D position_cont = gizmo_start_[1].value<QVector2D>() + vec_movement;
gizmo_dragger_[0].Drag(anchor_cont.x());
gizmo_dragger_[1].Drag(anchor_cont.y());
gizmo_dragger_[2].Drag(position_cont.x());
gizmo_dragger_[3].Drag(position_cont.y());
} else if (gizmo_drag_ == position_input()) {
// Dragging the main rectangle around
if (gizmo_dragger_.isEmpty()) {
gizmo_dragger_.resize(2);
gizmo_dragger_[0].Start(position_input(), time, 0);
gizmo_dragger_[1].Start(position_input(), time, 1);
}
QVector2D position_cont = gizmo_start_[0].value<QVector2D>() + vec_movement;
gizmo_dragger_[0].Drag(position_cont.x());
gizmo_dragger_[1].Drag(position_cont.y());
} else if (gizmo_drag_ == scale_input()) {
// Dragging a resize handle
if (gizmo_dragger_.isEmpty()) {
if (gizmo_scale_uniform_ || gizmo_scale_axes_ == kGizmoScaleXOnly) {
gizmo_dragger_.resize(1);
gizmo_dragger_[0].Start(scale_input(), time, 0);
} else if (gizmo_scale_axes_ == kGizmoScaleYOnly) {
gizmo_dragger_.resize(1);
gizmo_dragger_[0].Start(scale_input(), time, 1);
} else {
gizmo_dragger_.resize(2);
gizmo_dragger_[0].Start(scale_input(), time, 0);
gizmo_dragger_[1].Start(scale_input(), time, 1);
}
}
switch (gizmo_scale_axes_) {
case kGizmoScaleXOnly:
gizmo_dragger_[0].Drag(qAbs((p.x() - gizmo_anchor_pt_.center().x()) / gizmo_scale_anchor_.x()));
break;
case kGizmoScaleYOnly:
gizmo_dragger_[0].Drag(qAbs((p.y() - gizmo_anchor_pt_.center().y()) / gizmo_scale_anchor_.y()));
break;
case kGizmoScaleBoth:
if (gizmo_scale_uniform_) {
double distance = std::hypot(p.x() - gizmo_anchor_pt_.center().x(), p.y() - gizmo_anchor_pt_.center().y());
double texture_diag = std::hypot(gizmo_scale_anchor_.x(), gizmo_scale_anchor_.y());
gizmo_dragger_[0].Drag(qAbs(distance / texture_diag));
} else {
gizmo_dragger_[0].Drag(qAbs((p.x() - gizmo_anchor_pt_.center().x()) / gizmo_scale_anchor_.x()));
gizmo_dragger_[1].Drag(qAbs((p.y() - gizmo_anchor_pt_.center().y()) / gizmo_scale_anchor_.y()));
}
break;
}
} else if (gizmo_drag_ == rotation_input()) {
// Dragging outside the rectangle to rotate
if (gizmo_dragger_.isEmpty()) {
gizmo_dragger_.resize(1);
gizmo_dragger_[0].Start(rotation_input(), time, 0);
}
double current_angle = qAtan2(p.y() - gizmo_anchor_pt_.center().y(),
p.x() - gizmo_anchor_pt_.center().x());
double rotation_difference = (current_angle - gizmo_start_angle_) * 57.2958;
double rotation_cont = gizmo_start_[0].toDouble() + rotation_difference;
gizmo_dragger_[0].Drag(rotation_cont);
}
}
void TransformDistortNode::GizmoRelease()
{
for (NodeInputDragger& i : gizmo_dragger_) {
i.End();
}
gizmo_dragger_.clear();
gizmo_start_.clear();
gizmo_drag_ = nullptr;
}
QMatrix4x4 TransformDistortNode::AdjustMatrixByResolutions(const QMatrix4x4 &mat, const QVector2D &sequence_res, const QVector2D &texture_res, bool auto_sz)
{
// First, create an identity matrix
QMatrix4x4 adjusted_matrix;
// Scale it to a square based on the sequence's resolution
adjusted_matrix.scale(2.0 / sequence_res.x(), 2.0 / sequence_res.y(), 1.0);
// Adjust by the matrix we generated earlier
adjusted_matrix *= mat;
// Scale back out to texture size (adjusted by pixel aspect)
adjusted_matrix.scale(texture_res.x() * 0.5, texture_res.y() * 0.5, 1.0);
// If auto-scale is enabled, fit the texture to the sequence (without cropping)
if (auto_sz) {
double footage_real_ar = texture_res.x() / texture_res.y();
double sequence_real_ar = sequence_res.x() / sequence_res.y();
double autoscale_val;
if (sequence_real_ar > footage_real_ar) {
// Sequence is wider than footage, scale by height
autoscale_val = sequence_res.y() / texture_res.y();
} else {
// Footage is wider than sequence, scale by width
autoscale_val = sequence_res.x() / texture_res.x();
}
adjusted_matrix.scale(autoscale_val, autoscale_val, 1.0);
}
return adjusted_matrix;
}
QPointF TransformDistortNode::CreateScalePoint(double x, double y, const QPointF &half_res, const QMatrix4x4 &mat)
{
return mat.map(QPointF(x, y)) + half_res;
}
void TransformDistortNode::DrawGizmos(NodeValueDatabase &db, QPainter *p)
{
// 0 pen width is always 1px wide despite any transform
p->setPen(QPen(Qt::white, 0));
// Get the sequence resolution
QVector2D sequence_res = db[QStringLiteral("global")].Get(NodeParam::kVec2, QStringLiteral("resolution")).value<QVector2D>();
QVector2D sequence_half_res = sequence_res/2;
QPointF sequence_half_res_pt = sequence_half_res.toPointF();
// GizmoTraverser just returns the sizes of the textures and no other data
QVector2D tex_sz = db[texture_input_].Get(NodeParam::kTexture).value<QVector2D>();
// Retrieve autoscale value
bool autoscale = db[autoscale_input_].Get(NodeParam::kBoolean).toBool();
// Fold values into a matrix for the rectangle
QMatrix4x4 rectangle_matrix;
rectangle_matrix.scale(sequence_half_res);
rectangle_matrix *= AdjustMatrixByResolutions(GenerateMatrix(db, false, false, false),
sequence_res,
tex_sz,
autoscale);
// Create rect and transform it
const QVector<QPointF> points = {QPointF(-1, -1),
QPointF(1, -1),
QPointF(1, 1),
QPointF(-1, 1),
QPointF(-1, -1)};
QTransform rectangle_transform = rectangle_matrix.toTransform();
gizmo_rect_ = rectangle_transform.map(points);
gizmo_rect_.translate(sequence_half_res_pt);
// Draw rectangle
p->drawPolyline(gizmo_rect_);
// Draw anchor point
QMatrix4x4 anchor_matrix;
anchor_matrix.scale(sequence_half_res);
anchor_matrix *= AdjustMatrixByResolutions(GenerateMatrix(db, false, true, false),
sequence_res,
tex_sz,
autoscale);
QPointF anchor_pt = anchor_matrix.toTransform().map(QPointF(0, 0)) + sequence_half_res_pt;
const int anchor_pt_radius = QFontMetrics(qApp->font()).height() / 2 * 3;
gizmo_anchor_pt_ = QRectF(anchor_pt.x() - anchor_pt_radius,
anchor_pt.y() - anchor_pt_radius,
anchor_pt_radius*2,
anchor_pt_radius*2);
p->drawEllipse(anchor_pt, anchor_pt_radius, anchor_pt_radius);
p->drawLines({QLineF(anchor_pt.x() - anchor_pt_radius, anchor_pt.y(),
anchor_pt.x() + anchor_pt_radius, anchor_pt.y()),
QLineF(anchor_pt.x(), anchor_pt.y() - anchor_pt_radius,
anchor_pt.x(), anchor_pt.y() + anchor_pt_radius)});
// Draw scale handles
p->setPen(Qt::NoPen);
p->setBrush(Qt::white);
const int resize_handle_rad = GetGizmoHandleRadius();
gizmo_resize_handle_[kGizmoScaleTopLeft] = CreateGizmoHandleRect(CreateScalePoint(-1, -1, sequence_half_res_pt, rectangle_matrix), resize_handle_rad);
gizmo_resize_handle_[kGizmoScaleTopCenter] = CreateGizmoHandleRect(CreateScalePoint( 0, -1, sequence_half_res_pt, rectangle_matrix), resize_handle_rad);
gizmo_resize_handle_[kGizmoScaleTopRight] = CreateGizmoHandleRect(CreateScalePoint( 1, -1, sequence_half_res_pt, rectangle_matrix), resize_handle_rad);
gizmo_resize_handle_[kGizmoScaleBottomLeft] = CreateGizmoHandleRect(CreateScalePoint(-1, 1, sequence_half_res_pt, rectangle_matrix), resize_handle_rad);
gizmo_resize_handle_[kGizmoScaleBottomCenter] = CreateGizmoHandleRect(CreateScalePoint( 0, 1, sequence_half_res_pt, rectangle_matrix), resize_handle_rad);
gizmo_resize_handle_[kGizmoScaleBottomRight] = CreateGizmoHandleRect(CreateScalePoint( 1, 1, sequence_half_res_pt, rectangle_matrix), resize_handle_rad);
gizmo_resize_handle_[kGizmoScaleCenterLeft] = CreateGizmoHandleRect(CreateScalePoint(-1, 0, sequence_half_res_pt, rectangle_matrix), resize_handle_rad);
gizmo_resize_handle_[kGizmoScaleCenterRight] = CreateGizmoHandleRect(CreateScalePoint( 1, 0, sequence_half_res_pt, rectangle_matrix), resize_handle_rad);
DrawAndExpandGizmoHandles(p, resize_handle_rad, gizmo_resize_handle_, kGizmoScaleCount);
// Use offsets to make the appearance of values that start in the top left, even though we
// really anchor around the center
position_input()->set_property(QStringLiteral("offset"), sequence_res * 0.5);
anchor_input()->set_property(QStringLiteral("offset"), tex_sz * 0.5);
}
}
@@ -0,0 +1,124 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef TRANSFORMDISTORTNODE_H
#define TRANSFORMDISTORTNODE_H
#include "node/generator/matrix/matrix.h"
namespace olive {
class TransformDistortNode : public MatrixGenerator
{
Q_OBJECT
public:
TransformDistortNode();
virtual Node* copy() const override
{
return new TransformDistortNode();
}
virtual QString Name() const override
{
return tr("Transform");
}
virtual QString ShortName() const override
{
return Node::ShortName();
}
virtual QString id() const override
{
return QStringLiteral("org.olivevideoeditor.Olive.transform");
}
virtual QVector<CategoryID> Category() const override
{
return {kCategoryDistort};
}
virtual QString Description() const override
{
return tr("Transform an image in 2D space. Equivalent to multiplying by an orthographic matrix.");
}
virtual void Retranslate() override;
virtual NodeValueTable Value(NodeValueDatabase& value) const override;
virtual ShaderCode GetShaderCode(const QString& shader_id) const override;
virtual bool HasGizmos() const override
{
return true;
}
virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p) override;
virtual bool GizmoPress(NodeValueDatabase& db, const QPointF &p) override;
virtual void GizmoMove(const QPointF &p, const rational &time) override;
virtual void GizmoRelease() override;
NodeInput* texture_input() const
{
return texture_input_;
}
static QMatrix4x4 AdjustMatrixByResolutions(const QMatrix4x4& mat,
const QVector2D& sequence_res,
const QVector2D& texture_res,
bool auto_sz);
private:
static QPointF CreateScalePoint(double x, double y, const QPointF& half_res, const QMatrix4x4& mat);
NodeInput* texture_input_;
NodeInput* autoscale_input_;
// Gizmo variables
NodeInput* gizmo_drag_;
QVector<QVariant> gizmo_start_;
QVector<NodeInputDragger> gizmo_dragger_;
QPointF gizmo_drag_pos_;
double gizmo_start_angle_;
bool gizmo_scale_uniform_;
enum GizmoScaleType {
kGizmoScaleXOnly,
kGizmoScaleYOnly,
kGizmoScaleBoth
};
GizmoScaleType gizmo_scale_axes_;
QMatrix4x4 gizmo_matrix_;
QVector2D gizmo_scale_anchor_;
// Gizmo on screen object storage
QPolygonF gizmo_rect_;
QRectF gizmo_anchor_pt_;
QRectF gizmo_resize_handle_[kGizmoScaleCount];
};
}
#endif // TRANSFORMDISTORTNODE_H
+6
View File
@@ -26,6 +26,8 @@
#include "block/gap/gap.h"
#include "block/transition/crossdissolve/crossdissolvetransition.h"
#include "block/transition/diptocolor/diptocolortransition.h"
#include "distort/crop/cropdistortnode.h"
#include "distort/transform/transformdistortnode.h"
#include "generator/matrix/matrix.h"
#include "generator/polygon/polygon.h"
#include "generator/solid/solid.h"
@@ -183,6 +185,8 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id)
return new PolygonGenerator();
case kMatrixGenerator:
return new MatrixGenerator();
case kTransformDistort:
return new TransformDistortNode();
case kFootageInput:
return new MediaInput();
case kTrackOutput:
@@ -215,6 +219,8 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id)
return new DipToColorTransition();
case kMosaicFilter:
return new MosaicFilterNode();
case kCropDistort:
return new CropDistortNode();
case kInternalNodeCount:
break;
+2
View File
@@ -37,6 +37,7 @@ public:
kGapBlock,
kPolygonGenerator,
kMatrixGenerator,
kTransformDistort,
kFootageInput,
kTrackOutput,
kAudioVolume,
@@ -52,6 +53,7 @@ public:
kCrossDissolveTransition,
kDipToColorTransition,
kMosaicFilter,
kCropDistort,
// Count value
kInternalNodeCount
+37 -156
View File
@@ -20,12 +20,9 @@
#include "matrix.h"
#include <QGuiApplication>
#include <QMatrix4x4>
#include <QVector2D>
#include "common/range.h"
namespace olive {
MatrixGenerator::MatrixGenerator()
@@ -94,144 +91,54 @@ void MatrixGenerator::Retranslate()
NodeValueTable MatrixGenerator::Value(NodeValueDatabase &value) const
{
// Push matrix output
QMatrix4x4 mat = GenerateMatrix(value);
QMatrix4x4 mat = GenerateMatrix(value, true, false, false);
NodeValueTable output = value.Merge();
output.Push(NodeParam::kMatrix, mat, this);
return output;
}
bool MatrixGenerator::GizmoPress(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());
}
}
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 QSize& viewport) const
{
p->setPen(Qt::white);
GizmoSharedData gizmo_data(viewport, scale);
{
// Fold values into a matrix
QMatrix4x4 matrix;
matrix.scale(gizmo_data.half_scale);
matrix *= GenerateMatrix(db, false);
matrix.scale(gizmo_data.inverted_half_scale);
// 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(NodeValueDatabase &value, bool ignore_anchor) const
QMatrix4x4 MatrixGenerator::GenerateMatrix(NodeValueDatabase &value, bool take, bool ignore_anchor, bool ignore_position) const
{
QVector2D anchor;
QVector2D position;
if (!ignore_anchor) {
anchor = value[anchor_input_].Get(NodeParam::kVec2).value<QVector2D>();
if (take) {
// Take and store
anchor = value[anchor_input_].Take(NodeParam::kVec2).value<QVector2D>();
} else {
// Get and store
anchor = value[anchor_input_].Get(NodeParam::kVec2).value<QVector2D>();
}
} else if (take) {
// Just take
value[anchor_input_].Take(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);
if (!ignore_position) {
if (take) {
position = value[position_input_].Take(NodeParam::kVec2).value<QVector2D>();
} else {
position = value[position_input_].Get(NodeParam::kVec2).value<QVector2D>();
}
} else if (take) {
value[position_input_].Take(NodeParam::kVec2).value<QVector2D>();
}
if (take) {
return GenerateMatrix(position,
value[rotation_input_].Take(NodeParam::kFloat).toFloat(),
value[scale_input_].Take(NodeParam::kVec2).value<QVector2D>(),
value[uniform_scale_input_].Take(NodeParam::kBoolean).toBool(),
anchor);
} else {
return GenerateMatrix(position,
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,
@@ -263,35 +170,9 @@ QMatrix4x4 MatrixGenerator::GenerateMatrix(const QVector2D& pos,
return mat;
}
QPointF MatrixGenerator::GetGizmoAnchorPoint(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());
}
}
+27 -29
View File
@@ -46,34 +46,40 @@ public:
virtual NodeValueTable Value(NodeValueDatabase& value) const override;
virtual bool HasGizmos() const override;
virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p, const QVector2D &scale, const QSize& viewport) const override;
virtual bool GizmoPress(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(NodeValueDatabase &value, bool ignore_anchor) const;
protected:
QMatrix4x4 GenerateMatrix(NodeValueDatabase &value, bool take, bool ignore_anchor, bool ignore_position) const;
static QMatrix4x4 GenerateMatrix(const QVector2D &pos,
const float &rot,
const QVector2D &scale,
bool uniform_scale,
const QVector2D &anchor);
QPointF GetGizmoAnchorPoint(NodeValueDatabase &db, const GizmoSharedData &gizmo_data) const;
static int GetGizmoAnchorPointRadius();
NodeInput* gizmo_drag_;
NodeInput* position_input() const
{
return position_input_;
}
NodeInput* rotation_input() const
{
return rotation_input_;
}
NodeInput* scale_input() const
{
return scale_input_;
}
NodeInput* uniform_scale_input() const
{
return uniform_scale_input_;
}
NodeInput* anchor_input() const
{
return anchor_input_;
}
private:
NodeInput* position_input_;
NodeInput* rotation_input_;
@@ -84,14 +90,6 @@ 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();
+4 -3
View File
@@ -89,7 +89,7 @@ ShaderCode PolygonGenerator::GetShaderCode(const QString &shader_id) const
{
Q_UNUSED(shader_id)
return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/polygon.frag"), QString());
return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/polygon.frag"));
}
NodeValueTable PolygonGenerator::Value(NodeValueDatabase &value) const
@@ -98,6 +98,7 @@ NodeValueTable PolygonGenerator::Value(NodeValueDatabase &value) const
job.InsertValue(points_input_, value);
job.InsertValue(color_input_, value);
job.InsertValue(QStringLiteral("resolution_in"), ShaderValue(value[QStringLiteral("global")].Get(NodeParam::kVec2, QStringLiteral("resolution")), NodeParam::kVec2));
job.SetAlphaChannelRequired(true);
NodeValueTable table = value.Merge();
@@ -110,7 +111,7 @@ bool PolygonGenerator::HasGizmos() const
return true;
}
void PolygonGenerator::DrawGizmos(NodeValueDatabase &db, QPainter *p, const QVector2D &scale, const QSize &viewport) const
/*void PolygonGenerator::DrawGizmos(NodeValueDatabase &db, QPainter *p) const
{
Q_UNUSED(viewport)
@@ -170,7 +171,7 @@ void PolygonGenerator::GizmoRelease()
{
gizmo_x_dragger_.End();
gizmo_y_dragger_.End();
}
}*/
QVector<QPointF> PolygonGenerator::GetGizmoCoordinates(NodeValueDatabase &db, const QVector2D& scale) const
{
+4 -4
View File
@@ -45,11 +45,11 @@ public:
virtual NodeValueTable Value(NodeValueDatabase &value) const override;
virtual bool HasGizmos() const override;
virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p, const QVector2D &scale, const QSize& viewport) const override;
//virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p) const override;
virtual bool GizmoPress(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;
//virtual bool GizmoPress(NodeValueDatabase &db, const QPointF &p) override;
//virtual void GizmoMove(const QPointF &p, const QVector2D &scale, const rational &time) override;
//virtual void GizmoRelease() override;
private:
QVector<QPointF> GetGizmoCoordinates(NodeValueDatabase &db, const QVector2D &scale) const;
+29 -8
View File
@@ -24,6 +24,7 @@
#include <QVector2D>
#include "common/tohex.h"
#include "node/distort/transform/transformdistortnode.h"
#include "render/color.h"
namespace olive {
@@ -48,7 +49,17 @@ ShaderCode MathNodeBase::GetShaderCodeInternal(const QString &shader_id, NodeInp
// No-op frag shader (can we return QString() instead?)
operation = QStringLiteral("texture(%1, ove_texcoord)").arg(tex_in->id());
vert = FileFunctions::ReadFileAsString(":/shaders/matrix.vert").arg(mat_in->id(), tex_in->id());
vert = QStringLiteral("uniform mat4 %1;\n"
"\n"
"in vec4 a_position;\n"
"in vec2 a_texcoord;\n"
"\n"
"out vec2 ove_texcoord;\n"
"\n"
"void main() {\n"
" gl_Position = %1 * a_position;\n"
" ove_texcoord = a_texcoord;\n"
"}\n").arg(mat_in->id());
} else {
switch (op) {
@@ -287,22 +298,32 @@ NodeValueTable MathNodeBase::ValueInternal(NodeValueDatabase &value, Operation o
bool operation_is_noop = false;
const NodeValue& number_val = val_a.type() == NodeParam::kTexture ? val_b : val_a;
const NodeValue& texture_val = val_a.type() == NodeParam::kTexture ? val_a : val_b;
TexturePtr texture = texture_val.data().value<TexturePtr>();
if (pairing == kPairTextureNumber) {
if (!texture) {
operation_is_noop = true;
} else if (pairing == kPairTextureNumber) {
if (NumberIsNoOp(operation, RetrieveNumber(number_val))) {
operation_is_noop = true;
}
} else if (pairing == kPairTextureMatrix) {
// Only allow matrix multiplication
bool matrix_is_identity = false;
QVector2D sequence_res = value[QStringLiteral("global")].Get(NodeParam::kVec2, QStringLiteral("resolution")).value<QVector2D>();
QVector2D texture_res(texture->params().width() * texture->pixel_aspect_ratio().toDouble(), texture->params().height());
// FIXME: The matrix in the shader is transformed around footage+sequence resolution so we
// need to do that here to determine if the matrix is truly identity. But to do that,
// we need access to the texture parameters which is currently not possible.
QMatrix4x4 adjusted_matrix = TransformDistortNode::AdjustMatrixByResolutions(number_val.data().value<QMatrix4x4>(),
sequence_res,
texture_res,
false);
if (operation != kOpMultiply || matrix_is_identity) {
if (operation != kOpMultiply || adjusted_matrix.isIdentity()) {
operation_is_noop = true;
} else {
// Replace with adjusted matrix
job.InsertValue(val_a.type() == NodeParam::kTexture ? param_b_in : param_a_in,
ShaderValue(adjusted_matrix, NodeParam::kMatrix));
// It's likely an alpha channel will result from this operation
job.SetAlphaChannelRequired(true);
}
@@ -310,7 +331,7 @@ NodeValueTable MathNodeBase::ValueInternal(NodeValueDatabase &value, Operation o
if (operation_is_noop) {
// Just push texture as-is
output.Push(val_a.type() == NodeParam::kTexture ? val_a : val_b);
output.Push(texture_val);
} else {
// Push shader job
output.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this);
+27
View File
@@ -21,6 +21,7 @@
#include "node.h"
#include <QApplication>
#include <QGuiApplication>
#include <QDebug>
#include <QFile>
@@ -935,4 +936,30 @@ void Node::InputConnectionChanged(NodeEdgePtr edge)
InvalidateCache(TimeRange(RATIONAL_MIN, RATIONAL_MAX), edge->input(), edge->input());
}
QRectF Node::CreateGizmoHandleRect(const QPointF &pt, int radius)
{
return QRectF(pt.x() - radius,
pt.y() - radius,
2*radius,
2*radius);;
}
int Node::GetGizmoHandleRadius()
{
return QFontMetrics(qApp->font()).height() / 2;
}
void Node::DrawAndExpandGizmoHandles(QPainter *p, int handle_radius, QRectF *rects, int count)
{
for (int i=0; i<count; i++) {
QRectF& r = rects[i];
// Draw rect on screen
p->drawRect(r);
// Extend rect so it's easier to drag with handle
r.adjust(-handle_radius, -handle_radius, handle_radius, handle_radius);
}
}
}
+18
View File
@@ -444,6 +444,24 @@ protected:
virtual QVector<NodeInput*> GetInputsToHash() const;
enum GizmoScaleHandles {
kGizmoScaleTopLeft,
kGizmoScaleTopCenter,
kGizmoScaleTopRight,
kGizmoScaleBottomLeft,
kGizmoScaleBottomCenter,
kGizmoScaleBottomRight,
kGizmoScaleCenterLeft,
kGizmoScaleCenterRight,
kGizmoScaleCount,
};
static QRectF CreateGizmoHandleRect(const QPointF& pt, int radius);
static int GetGizmoHandleRadius();
static void DrawAndExpandGizmoHandles(QPainter* p, int handle_radius, QRectF* rects, int count);
protected slots:
void InputChanged(const olive::TimeRange &range);
-35
View File
@@ -1,35 +0,0 @@
uniform mat4 %1;
uniform vec2 %2_resolution;
uniform vec2 ove_resolution;
in vec4 a_position;
in vec2 a_texcoord;
out vec2 ove_texcoord;
mat4 scale_mat4(vec3 scale) {
return mat4(
scale.x, 0.0, 0.0, 0.0,
0.0, scale.y, 0.0, 0.0,
0.0, 0.0, scale.z, 0.0,
0.0, 0.0, 0.0, 1.0
);
}
void main() {
// Create identity matrix
mat4 transform = mat4(1.0);
// Scale to square
transform *= scale_mat4(vec3(1.0 / ove_resolution, 1.0));
// Multiply by received matrix
transform *= %1;
// Scale back out to footage size
transform *= scale_mat4(vec3(%2_resolution, 1.0));
gl_Position = transform * a_position;
ove_texcoord = a_texcoord;
}
+7 -1
View File
@@ -30,6 +30,7 @@
#include "core.h"
#include "dialog/sequence/sequence.h"
#include "node/audio/volume/volume.h"
#include "node/distort/transform/transformdistortnode.h"
#include "node/generator/matrix/matrix.h"
#include "node/input/media/media.h"
#include "node/math/math/math.h"
@@ -419,7 +420,12 @@ void ImportTool::DropGhosts(bool insert)
video_input->SetStream(footage_stream);
new NodeAddCommand(dst_graph, video_input, command);
new NodeEdgeAddCommand(video_input->output(), clip->texture_input(), command);
TransformDistortNode* transform = new TransformDistortNode();
new NodeAddCommand(dst_graph, transform, command);
new NodeEdgeAddCommand(video_input->output(), transform->texture_input(), command);
new NodeEdgeAddCommand(transform->output(), clip->texture_input(), command);
/*
MatrixGenerator* matrix = new MatrixGenerator();