feat: hide non-texture OFX params from node graph + host coordinate standardization

Hide non-texture OFX params from node graph
  --------------------------------------------
  OFX plugins like ColorCorrect expose dozens of scalar parameters as
  node inputs, making nodes extremely tall and pushing Source/Mask far
  down. Previously attempted via kInputFlagHidden, but that also hid
  them from the parameter panel.

  Fix: move the filter to NodeViewItem::IsInputValid() instead.
  For OFX plugin nodes (getPluginInstance() != nullptr), only
  kTexture inputs are rendered as ports. Scalar parameters remain
  fully visible in the parameter panel.

  Files: app/widget/nodeview/nodeviewitem.cpp
         app/node/plugins/Plugin.cpp

  Standardize OFX host coordinate system
  --------------------------------------
  Olive's OFX host had partial and inconsistent coordinate handling.

  1. Fix Project coordinate methods
     - getProjectSize() / getProjectExtent() / getProjectOffset()
       now multiply X by pixel_aspect_ratio(), returning canonical
       coordinates per the OFX spec.

  2. Fix Clip default RoD
     - OliveClipInstance::getRegionOfDefinition() default now returns
       {0, 0, width*PAR, height} instead of raw pixel coords.

  3. Add parameter coordinate system conversion
     - DoubleInstance / Double2DInstance / Double3DInstance now check
       _descriptor.getDefaultCoordinateSystem().
     - For kOfxParamCoordinatesNormalised:
         get: internal pixel value -> normalised (divide by extent)
         set: normalised plugin value -> pixel (multiply by extent)
     - DefaultValueForParam() also converts normalised defaults to
       canonical before storing in Node, keeping Olive internal/UI
       values consistently in pixel space.

  Files: app/pluginSupport/OlivePluginInstance.cpp
         app/pluginSupport/OliveClip.cpp
         app/pluginSupport/paraminstance.h
         app/node/plugins/Plugin.cpp
This commit is contained in:
2026-05-14 21:54:18 +08:00
parent e012f16083
commit 4aa4d59770
5 changed files with 171 additions and 18 deletions
+2 -1
View File
@@ -538,7 +538,8 @@ olive::plugin::OliveClipInstance::getRegionOfDefinition(OfxTime time) const
}
OfxRectD regionOfDefinition;
regionOfDefinition.x1 = regionOfDefinition.y1 = 0;
regionOfDefinition.x2 = params_.width();
double par = params_.pixel_aspect_ratio().toDouble();
regionOfDefinition.x2 = params_.width() * par;
regionOfDefinition.y2 = params_.height();
return regionOfDefinition;
}
+9 -6
View File
@@ -276,18 +276,21 @@ OfxStatus OlivePluginInstance::clearPersistentMessage()
}
void OlivePluginInstance::getProjectSize(double &xSize, double &ySize) const
{
xSize =params_.width();
ySize =params_.height();
double par = params_.pixel_aspect_ratio().toDouble();
xSize = params_.width() * par;
ySize = params_.height();
}
void OlivePluginInstance::getProjectOffset(double &xOffset, double &yOffset) const
{
xOffset =params_.x();
yOffset =params_.y();
double par = params_.pixel_aspect_ratio().toDouble();
xOffset = params_.x() * par;
yOffset = params_.y();
}
void OlivePluginInstance::getProjectExtent(double &xSize, double &ySize) const
{
xSize =params_.width();
ySize =params_.height();
double par = params_.pixel_aspect_ratio().toDouble();
xSize = params_.width() * par;
ySize = params_.height();
}
double OlivePluginInstance::getProjectPixelAspectRatio() const
{
+113 -9
View File
@@ -32,12 +32,38 @@
#include "node/plugins/Plugin.h"
#include "core.h"
#include "undo/undocommand.h"
#include "common/Current.h"
#include <iostream>
#include <qlogging.h>
namespace olive
{
namespace plugin
{
inline bool IsNormalisedCoordinateSystem(
const OFX::Host::Param::Descriptor &descriptor)
{
return descriptor.getDefaultCoordinateSystem() ==
kOfxParamCoordinatesNormalised;
}
inline void GetProjectExtent(double &xSize, double &ySize)
{
auto &vp = Current::getInstance().currentVideoParams();
xSize = vp.width() * vp.pixel_aspect_ratio().toDouble();
ySize = vp.height();
}
inline double ToNormalised(double canonical, double extent)
{
return extent > 0 ? canonical / extent : canonical;
}
inline double ToCanonical(double normalised, double extent)
{
return extent > 0 ? normalised * extent : normalised;
}
inline QString ParamChangeLabel(const OFX::Host::Param::Descriptor &descriptor)
{
return QStringLiteral("Change %1")
@@ -185,6 +211,11 @@ public:
QVariant variant = node->GetStandardValue(_descriptor.getName().c_str());
if (variant.canConvert<double>()) {
data = variant.toDouble();
if (IsNormalisedCoordinateSystem(_descriptor)) {
double xSize, ySize;
GetProjectExtent(xSize, ySize);
data = ToNormalised(data, xSize);
}
return kOfxStatOK;
}
data = 0.0;
@@ -201,6 +232,11 @@ public:
rational::fromDouble(time));
if (variant.canConvert<double>()) {
data = variant.toDouble();
if (IsNormalisedCoordinateSystem(_descriptor)) {
double xSize, ySize;
GetProjectExtent(xSize, ySize);
data = ToNormalised(data, xSize);
}
return kOfxStatOK;
}
data = 0.0;
@@ -213,8 +249,14 @@ public:
has_value_ = true;
return kOfxStatOK;
}
double val = data;
if (IsNormalisedCoordinateSystem(_descriptor)) {
double xSize, ySize;
GetProjectExtent(xSize, ySize);
val = ToCanonical(val, xSize);
}
SplitValue split = NodeValue::split_normal_value_into_track_values(
NodeValue::kFloat, data);
NodeValue::kFloat, val);
auto command = new NodeParamSetSplitStandardValueCommand(
NodeInput(node.get(), _descriptor.getName().c_str()), split);
SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor));
@@ -227,10 +269,16 @@ public:
has_value_ = true;
return kOfxStatOK;
}
double val = data;
if (IsNormalisedCoordinateSystem(_descriptor)) {
double xSize, ySize;
GetProjectExtent(xSize, ySize);
val = ToCanonical(val, xSize);
}
auto command = new MultiUndoCommand();
Node::SetValueAtTime(
NodeInput(node.get(), _descriptor.getName().c_str()),
rational::fromDouble(time), data, 0, command, true);
rational::fromDouble(time), val, 0, command, true);
SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor));
return kOfxStatOK;
}
@@ -661,6 +709,12 @@ public:
.value<QVector2D>();
x = static_cast<double>(vec.x());
y = static_cast<double>(vec.y());
if (IsNormalisedCoordinateSystem(_descriptor)) {
double xSize, ySize;
GetProjectExtent(xSize, ySize);
x = ToNormalised(x, xSize);
y = ToNormalised(y, ySize);
}
return kOfxStatOK;
}
OfxStatus get(OfxTime time,double& x,double& y)
@@ -680,6 +734,12 @@ public:
.value<QVector2D>();
x = static_cast<double>(vec.x());
y = static_cast<double>(vec.y());
if (IsNormalisedCoordinateSystem(_descriptor)) {
double xSize, ySize;
GetProjectExtent(xSize, ySize);
x = ToNormalised(x, xSize);
y = ToNormalised(y, ySize);
}
return kOfxStatOK;
}
OfxStatus set(double x,double y)
@@ -690,8 +750,15 @@ public:
has_value_ = true;
return kOfxStatOK;
}
double xv = x, yv = y;
if (IsNormalisedCoordinateSystem(_descriptor)) {
double xSize, ySize;
GetProjectExtent(xSize, ySize);
xv = ToCanonical(xv, xSize);
yv = ToCanonical(yv, ySize);
}
SplitValue split = NodeValue::split_normal_value_into_track_values(
NodeValue::kVec2, QVector2D(x, y));
NodeValue::kVec2, QVector2D(xv, yv));
auto command = new NodeParamSetSplitStandardValueCommand(
NodeInput(node.get(), _descriptor.getName().c_str()), split);
SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor));
@@ -705,12 +772,19 @@ public:
has_value_ = true;
return kOfxStatOK;
}
double xv = x, yv = y;
if (IsNormalisedCoordinateSystem(_descriptor)) {
double xSize, ySize;
GetProjectExtent(xSize, ySize);
xv = ToCanonical(xv, xSize);
yv = ToCanonical(yv, ySize);
}
auto command = new MultiUndoCommand();
const QString name = _descriptor.getName().c_str();
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
x, 0, command, true);
xv, 0, command, true);
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
y, 1, command, true);
yv, 1, command, true);
SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor));
return kOfxStatOK;
}
@@ -844,6 +918,13 @@ public:
x = static_cast<double>(vec.x());
y = static_cast<double>(vec.y());
z = static_cast<double>(vec.z());
if (IsNormalisedCoordinateSystem(_descriptor)) {
double xSize, ySize;
GetProjectExtent(xSize, ySize);
x = ToNormalised(x, xSize);
y = ToNormalised(y, ySize);
z = ToNormalised(z, xSize);
}
return kOfxStatOK;
}
OfxStatus get(OfxTime time,double& x,double& y,double& z)
@@ -865,6 +946,13 @@ public:
x = static_cast<double>(vec.x());
y = static_cast<double>(vec.y());
z = static_cast<double>(vec.z());
if (IsNormalisedCoordinateSystem(_descriptor)) {
double xSize, ySize;
GetProjectExtent(xSize, ySize);
x = ToNormalised(x, xSize);
y = ToNormalised(y, ySize);
z = ToNormalised(z, xSize);
}
return kOfxStatOK;
}
OfxStatus set(double x,double y,double z)
@@ -876,8 +964,16 @@ public:
has_value_ = true;
return kOfxStatOK;
}
double xv = x, yv = y, zv = z;
if (IsNormalisedCoordinateSystem(_descriptor)) {
double xSize, ySize;
GetProjectExtent(xSize, ySize);
xv = ToCanonical(xv, xSize);
yv = ToCanonical(yv, ySize);
zv = ToCanonical(zv, xSize);
}
SplitValue split = NodeValue::split_normal_value_into_track_values(
NodeValue::kVec3, QVector3D(x, y, z));
NodeValue::kVec3, QVector3D(xv, yv, zv));
auto command = new NodeParamSetSplitStandardValueCommand(
NodeInput(node.get(), _descriptor.getName().c_str()), split);
SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor));
@@ -892,14 +988,22 @@ public:
has_value_ = true;
return kOfxStatOK;
}
double xv = x, yv = y, zv = z;
if (IsNormalisedCoordinateSystem(_descriptor)) {
double xSize, ySize;
GetProjectExtent(xSize, ySize);
xv = ToCanonical(xv, xSize);
yv = ToCanonical(yv, ySize);
zv = ToCanonical(zv, xSize);
}
auto command = new MultiUndoCommand();
const QString name = _descriptor.getName().c_str();
Node::SetValueAtTime(NodeInput(node.get(), name),
rational::fromDouble(time), x, 0, command, true);
rational::fromDouble(time), xv, 0, command, true);
Node::SetValueAtTime(NodeInput(node.get(), name),
rational::fromDouble(time), y, 1, command, true);
rational::fromDouble(time), yv, 1, command, true);
Node::SetValueAtTime(NodeInput(node.get(), name),
rational::fromDouble(time), z, 2, command, true);
rational::fromDouble(time), zv, 2, command, true);
SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor));
return kOfxStatOK;
}