nodes: added distort nodes
Adds nodes for cropping and transforming
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
add_subdirectory(audio)
|
||||
add_subdirectory(block)
|
||||
add_subdirectory(distort)
|
||||
add_subdirectory(filter)
|
||||
add_subdirectory(generator)
|
||||
add_subdirectory(input)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
@@ -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
|
||||
)
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -37,6 +37,7 @@ public:
|
||||
kGapBlock,
|
||||
kPolygonGenerator,
|
||||
kMatrixGenerator,
|
||||
kTransformDistort,
|
||||
kFootageInput,
|
||||
kTrackOutput,
|
||||
kAudioVolume,
|
||||
@@ -52,6 +53,7 @@ public:
|
||||
kCrossDissolveTransition,
|
||||
kDipToColorTransition,
|
||||
kMosaicFilter,
|
||||
kCropDistort,
|
||||
|
||||
// Count value
|
||||
kInternalNodeCount
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user