implemented gizmo transforming through the node graph

This commit is contained in:
itsmattkc
2022-05-15 14:36:30 -07:00
parent a2ff3d607a
commit e9844ee135
15 changed files with 157 additions and 79 deletions
+4 -2
View File
@@ -79,10 +79,12 @@ void CropDistortNode::Value(const NodeValueRow &value, const NodeGlobals &global
{
ShaderJob job;
job.Insert(value);
job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this));
job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn);
job.SetWillChangeImageSize(false);
if (TexturePtr texture = job.Get(kTextureInput).toTexture()) {
job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, QVector2D(texture->params().width(), texture->params().height()), this));
if (job.Get(kTextureInput).toTexture()) {
if (!qIsNull(job.Get(kLeftInput).toDouble())
|| !qIsNull(job.Get(kRightInput).toDouble())
|| !qIsNull(job.Get(kTopInput).toDouble())
@@ -84,7 +84,7 @@ void TransformDistortNode::Retranslate()
void TransformDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
// Generate matrix
QMatrix4x4 generated_matrix = GenerateMatrix(value, true, false, false, false);
QMatrix4x4 generated_matrix = GenerateMatrix(value, false, false, false);
// Pop texture
NodeValue texture_meta = value[kTextureInput];
@@ -143,7 +143,7 @@ void TransformDistortNode::Hash(QCryptographicHash &hash, const NodeGlobals &glo
TexturePtr tex = db[kTextureInput].toTexture();
if (tex) {
VideoParams tex_params = tex->params();
QMatrix4x4 matrix = GenerateMatrix(db, true, false, false, false);
QMatrix4x4 matrix = GenerateMatrix(db, false, false, false);
matrix = GenerateAutoScaledMatrix(matrix, db, globals, tex_params);
if (!matrix.isIdentity()) {
@@ -162,7 +162,7 @@ void TransformDistortNode::GizmoDragStart(const NodeValueRow &row, double x, dou
if (gizmo == anchor_gizmo_) {
gizmo_inverted_transform_ = GenerateMatrix(row, false, true, true, false).toTransform().inverted();
gizmo_inverted_transform_ = GenerateMatrix(row, true, true, false).toTransform().inverted();
} else if (IsAScaleGizmo(gizmo)) {
@@ -204,7 +204,7 @@ void TransformDistortNode::GizmoDragStart(const NodeValueRow &row, double x, dou
}
// Store current matrix
gizmo_inverted_transform_ = GenerateMatrix(row, false, true, true, true).toTransform().inverted();
gizmo_inverted_transform_ = GenerateMatrix(row, true, true, true).toTransform().inverted();
} else if (gizmo == rotation_gizmo_) {
@@ -389,7 +389,7 @@ void TransformDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const N
// Fold values into a matrix for the rectangle
QMatrix4x4 rectangle_matrix;
rectangle_matrix.scale(sequence_half_res);
rectangle_matrix *= AdjustMatrixByResolutions(GenerateMatrix(row, false, false, false, false),
rectangle_matrix *= AdjustMatrixByResolutions(GenerateMatrix(row, false, false, false),
sequence_res,
tex_sz,
tex_offset,
@@ -409,7 +409,7 @@ void TransformDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const N
// Draw anchor point
QMatrix4x4 anchor_matrix;
anchor_matrix.scale(sequence_half_res);
anchor_matrix *= AdjustMatrixByResolutions(GenerateMatrix(row, false, true, false, false),
anchor_matrix *= AdjustMatrixByResolutions(GenerateMatrix(row, true, false, false),
sequence_res,
tex_sz,
tex_offset,
@@ -432,6 +432,15 @@ void TransformDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const N
SetInputProperty(kAnchorInput, QStringLiteral("offset"), tex_sz * 0.5);
}
QTransform TransformDistortNode::GizmoTransformation(const NodeValueRow &row, const NodeGlobals &globals) const
{
if (TexturePtr texture = row[kTextureInput].toTexture()) {
auto m = GenerateMatrix(row, false, false, false);
return GenerateAutoScaledMatrix(m, row, globals, texture->params()).toTransform();
}
return super::GizmoTransformation(row, globals);
}
QPointF TransformDistortNode::CreateScalePoint(double x, double y, const QPointF &half_res, const QMatrix4x4 &mat)
{
return mat.map(QPointF(x, y)) + half_res;
@@ -82,6 +82,7 @@ public:
AutoScaleType autoscale_type = kAutoScaleNone);
virtual void UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) override;
virtual QTransform GizmoTransformation(const NodeValueRow &row, const NodeGlobals &globals) const override;
static const QString kTextureInput;
static const QString kAutoscaleInput;
+10 -40
View File
@@ -90,63 +90,33 @@ void MatrixGenerator::Retranslate()
void MatrixGenerator::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
// Push matrix output
QMatrix4x4 mat = GenerateMatrix(value, true, false, false, false);
QMatrix4x4 mat = GenerateMatrix(value, false, false, false);
table->Push(NodeValue::kMatrix, mat, this);
}
QMatrix4x4 MatrixGenerator::GenerateMatrix(const NodeValueRow &value, bool take, bool ignore_anchor, bool ignore_position, bool ignore_scale) const
QMatrix4x4 MatrixGenerator::GenerateMatrix(const NodeValueRow &value, bool ignore_anchor, bool ignore_position, bool ignore_scale) const
{
QVector2D anchor;
QVector2D position;
QVector2D scale;
if (!ignore_anchor) {
if (take) {
// Take and store
anchor = value[kAnchorInput].toVec2();
} else {
// Get and store
anchor = value[kAnchorInput].toVec2();
}
} else if (take) {
// Just take
value[kAnchorInput].toVec2();
anchor = value[kAnchorInput].toVec2();
}
if (!ignore_scale) {
if (take) {
scale = value[kScaleInput].toVec2();
} else {
scale = value[kScaleInput].toVec2();
}
} else if (take) {
value[kScaleInput].toVec2();
scale = value[kScaleInput].toVec2();
}
if (!ignore_position) {
if (take) {
position = value[kPositionInput].toVec2();
} else {
position = value[kPositionInput].toVec2();
}
} else if (take) {
value[kPositionInput].toVec2();
position = value[kPositionInput].toVec2();
}
if (take) {
return GenerateMatrix(position,
value[kRotationInput].toDouble(),
scale,
value[kUniformScaleInput].toBool(),
anchor);
} else {
return GenerateMatrix(position,
value[kRotationInput].toDouble(),
scale,
value[kUniformScaleInput].toBool(),
anchor);
}
return GenerateMatrix(position,
value[kRotationInput].toDouble(),
scale,
value[kUniformScaleInput].toBool(),
anchor);
}
QMatrix4x4 MatrixGenerator::GenerateMatrix(const QVector2D& pos,
+1 -1
View File
@@ -53,7 +53,7 @@ public:
static const QString kAnchorInput;
protected:
QMatrix4x4 GenerateMatrix(const NodeValueRow &value, bool take, bool ignore_anchor, bool ignore_position, bool ignore_scale) const;
QMatrix4x4 GenerateMatrix(const NodeValueRow &value, bool ignore_anchor, bool ignore_position, bool ignore_scale) const;
static QMatrix4x4 GenerateMatrix(const QVector2D &pos,
const float &rot,
const QVector2D &scale,
+1 -1
View File
@@ -50,7 +50,7 @@ QByteArray HashTraverser::GetHash(const Node *node, const Node::ValueHint &hint,
//Hash(reference);
// Our overrides will generate a hash from this
NodeValueTable table = GenerateTable(node, hint, range);
NodeValueTable table = GenerateTable(node, range);
NodeValue final_value = GenerateRowValueElement(hint, NodeValue::kTexture, &table);
HashNodeValue(final_value);
+2
View File
@@ -889,6 +889,8 @@ public:
return gizmos_;
}
virtual QTransform GizmoTransformation(const NodeValueRow &row, const NodeGlobals &globals) const { return QTransform(); }
virtual void UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals){}
const QString& GetLabel() const;
+2 -2
View File
@@ -381,7 +381,7 @@ rational ViewerOutput::VerifyLengthInternal(Track::Type type) const
switch (type) {
case Track::kVideo:
if (IsInputConnected(kTextureInput)) {
NodeValueTable t = traverser.GenerateTable(GetConnectedOutput(kTextureInput), GetValueHintForInput(kTextureInput), TimeRange(0, 0));
NodeValueTable t = traverser.GenerateTable(GetConnectedOutput(kTextureInput), TimeRange(0, 0));
rational r = t.Get(NodeValue::kRational, QStringLiteral("length")).value<rational>();
if (!r.isNaN()) {
return r;
@@ -390,7 +390,7 @@ rational ViewerOutput::VerifyLengthInternal(Track::Type type) const
break;
case Track::kAudio:
if (IsInputConnected(kSamplesInput)) {
NodeValueTable t = traverser.GenerateTable(GetConnectedOutput(kSamplesInput), GetValueHintForInput(kSamplesInput), TimeRange(0, 0));
NodeValueTable t = traverser.GenerateTable(GetConnectedOutput(kSamplesInput), TimeRange(0, 0));
rational r = t.Get(NodeValue::kRational, QStringLiteral("length")).value<rational>();;
if (!r.isNaN()) {
return r;
+58 -7
View File
@@ -141,6 +141,16 @@ int NodeTraverser::GenerateRowValueElementIndex(const Node *node, const QString
return GenerateRowValueElementIndex(node->GetValueHintForInput(input, element), node->GetInputDataType(input), table);
}
void NodeTraverser::Transform(QTransform *transform, const Node *start, const Node *end, const TimeRange &range)
{
transform_ = transform;
transform_start_ = start;
GenerateTable(end, range);
transform_ = nullptr;
}
NodeGlobals NodeTraverser::GenerateGlobals(const VideoParams &params, const TimeRange &time)
{
return NodeGlobals(QVector2D(params.width(), params.height()), params.pixel_aspect_ratio(), time);
@@ -179,6 +189,20 @@ int NodeTraverser::GetChannelCountFromJob(const GenerateJob &job)
return VideoParams::kRGBAChannelCount;
}
TexturePtr NodeTraverser::GetMainTextureFromJob(const GenerateJob &job)
{
// FIXME: Should probably take Node::GetEffectInput into account here
for (auto it=job.GetValues().cbegin(); it!=job.GetValues().cend(); it++) {
if (it.value().type() == NodeValue::kTexture) {
if (TexturePtr t = it.value().toTexture()) {
return t;
}
}
}
return nullptr;
}
NodeValueTable NodeTraverser::ProcessInput(const Node* node, const QString& input, const TimeRange& range)
{
// If input is connected, retrieve value directly
@@ -187,7 +211,7 @@ NodeValueTable NodeTraverser::ProcessInput(const Node* node, const QString& inpu
TimeRange adjusted_range = node->InputTimeAdjustment(input, -1, range);
// Value will equal something from the connected node, follow it
return GenerateTable(node->GetConnectedOutput(input), node->GetValueHintForInput(input), adjusted_range);
return GenerateTable(node->GetConnectedOutput(input), adjusted_range);
} else {
@@ -205,7 +229,7 @@ NodeValueTable NodeTraverser::ProcessInput(const Node* node, const QString& inpu
TimeRange adjusted_range = node->InputTimeAdjustment(input, i, range);
if (node->IsInputConnected(input, i)) {
sub_tbl = GenerateTable(node->GetConnectedOutput(input, i), node->GetValueHintForInput(input, i), adjusted_range);
sub_tbl = GenerateTable(node->GetConnectedOutput(input, i), adjusted_range);
} else {
QVariant input_value = node->GetValueAtTime(input, adjusted_range.in(), i);
sub_tbl.Push(node->GetInputDataType(input), input_value, node);
@@ -231,11 +255,12 @@ NodeValueTable NodeTraverser::ProcessInput(const Node* node, const QString& inpu
}
NodeTraverser::NodeTraverser() :
cancel_(nullptr)
cancel_(nullptr),
transform_(nullptr)
{
}
NodeValueTable NodeTraverser::GenerateTable(const Node *n, const Node::ValueHint &hint, const TimeRange& range)
NodeValueTable NodeTraverser::GenerateTable(const Node *n, const TimeRange& range)
{
const Track* track = dynamic_cast<const Track*>(n);
if (track) {
@@ -264,7 +289,24 @@ NodeValueTable NodeTraverser::GenerateTable(const Node *n, const Node::ValueHint
NodeValueTable table = database.Merge();
// By this point, the node should have all the inputs it needs to render correctly
n->Value(row, GenerateGlobals(video_params_, range), &table);
NodeGlobals globals = GenerateGlobals(video_params_, range);
n->Value(row, globals, &table);
if (transform_) {
if (!transform_start_) {
if (!transform_ignore_.contains(n)) {
QTransform t = n->GizmoTransformation(row, globals);
if (!t.isIdentity()) {
qDebug() << "transforming" << n;
(*transform_) *= t;
}
transform_ignore_.append(n);
}
} else if (transform_start_ == n) {
transform_start_ = nullptr;
}
}
return table;
} else {
@@ -288,7 +330,7 @@ NodeValueTable NodeTraverser::GenerateBlockTable(const Track *track, const TimeR
NodeValueTable table;
if (active_block) {
table = GenerateTable(active_block, track->GetValueHintForInput(Track::kBlockInput, track->GetArrayIndexFromBlock(active_block)), Track::TransformRangeForBlock(active_block, range));
table = GenerateTable(active_block, Track::TransformRangeForBlock(active_block, range));
}
return table;
@@ -307,12 +349,21 @@ void NodeTraverser::ResolveJobs(NodeValue &val, const TimeRange &range)
ShaderJob job = val.value<ShaderJob>();
PreProcessRow(range, job.GetValues());
VideoParams tex_params = GetCacheVideoParams();
tex_params.set_channel_count(GetChannelCountFromJob(job));
if (!job.GetWillChangeImageSize()) {
if (TexturePtr texture = GetMainTextureFromJob(job)) {
tex_params.set_width(texture->params().width());
tex_params.set_height(texture->params().height());
tex_params.set_divider(texture->params().divider());
}
}
TexturePtr tex = CreateTexture(tex_params);
PreProcessRow(range, job.GetValues());
ProcessShader(tex, val.source(), range, job);
val.set_value(tex);
+9 -1
View File
@@ -37,7 +37,7 @@ class NodeTraverser
public:
NodeTraverser();
NodeValueTable GenerateTable(const Node *n, const Node::ValueHint &hint, const TimeRange &range);
NodeValueTable GenerateTable(const Node *n, const TimeRange &range);
NodeValueDatabase GenerateDatabase(const Node *node, const TimeRange &range);
@@ -50,6 +50,8 @@ public:
int GenerateRowValueElementIndex(const Node::ValueHint &hint, NodeValue::Type preferred_type, const NodeValueTable *table);
int GenerateRowValueElementIndex(const Node *node, const QString &input, int element, const NodeValueTable *table);
void Transform(QTransform *transform, const Node *start, const Node *end, const TimeRange &range);
static NodeGlobals GenerateGlobals(const VideoParams &params, const TimeRange &time);
static NodeGlobals GenerateGlobals(const VideoParams &params, const rational &time)
{
@@ -78,6 +80,8 @@ public:
static int GetChannelCountFromJob(const GenerateJob& job);
static TexturePtr GetMainTextureFromJob(const GenerateJob& job);
protected:
NodeValueTable ProcessInput(const Node *node, const QString &input, const TimeRange &range);
@@ -152,6 +156,10 @@ private:
const QAtomicInt *cancel_;
const Node *transform_start_;
QTransform *transform_;
QVector<const Node*> transform_ignore_;
};
}