/* * Oak Video Editor - Non-Linear Video Editor * Copyright (C) 2025 Olive CE 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 . * */ // Copyright OpenFX and contributors to the OpenFX project. #ifndef PARAM_INSTANCE_H #define PARAM_INSTANCE_H #include "olive/core/util/rational.h" #include "pluginSupport/OlivePluginInstance.h" #include #include #include #include #include "ofxhParam.h" #include "node/nodeundo.h" #include "node/plugins/Plugin.h" #include "core.h" #include "undo/undocommand.h" #include "common/Current.h" #include #include #include 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") .arg(QString::fromStdString(descriptor.getName())); } void SubmitUndoCommand(const std::shared_ptr &node, UndoCommand *command, const QString &label); class NodeBoundParam { public: virtual ~NodeBoundParam() = default; virtual void SetNode(const std::shared_ptr &node) = 0; }; class PushbuttonInstance : public OFX::Host::Param::PushbuttonInstance, public NodeBoundParam { protected: std::shared_ptr node; OFX::Host::Param::Descriptor *_descriptor; public: PushbuttonInstance(std::shared_ptr effect, const std::string &name, OFX::Host::Param::Descriptor &descriptor, OFX::Host::Param::SetInstance *paramSet = nullptr) : OFX::Host::Param::PushbuttonInstance(descriptor, paramSet) , node(effect) { _descriptor = &descriptor; }; void SetNode(const std::shared_ptr &new_node) override { node = new_node; } }; class IntegerInstance : public OFX::Host::Param::IntegerInstance, public NodeBoundParam { protected: std::shared_ptr _node; OFX::Host::Param::Descriptor &_descriptor; QString id; mutable std::mutex no_node_mutex_; bool has_value_ = false; int value_ = 0; public: IntegerInstance(std::shared_ptr node, OFX::Host::Param::Descriptor &descriptor, OFX::Host::Param::SetInstance *paramSet = nullptr) : OFX::Host::Param::IntegerInstance(descriptor, paramSet) , _node(node) , _descriptor(descriptor) , id(_descriptor.getName().c_str()) { try { value_ = _descriptor.getProperties().getIntProperty( kOfxParamPropDefault); has_value_ = true; } catch (...) { value_ = 0; has_value_ = false; } } void SetNode(const std::shared_ptr &new_node) override { _node = new_node; } OfxStatus get(int &a) { if (!_node) { std::lock_guard lock(no_node_mutex_); a = has_value_ ? value_ : 0; return kOfxStatOK; } if (id.isEmpty()) { return kOfxStatErrBadHandle; } QVariant variant = _node->GetStandardValue(id); if (variant.canConvert()) { a = variant.toInt(); return kOfxStatOK; } a = 0; return kOfxStatErrValue; } OfxStatus get(OfxTime time, int &data) { if (!_node) { std::lock_guard lock(no_node_mutex_); data = has_value_ ? value_ : 0; return kOfxStatOK; } if (id.isEmpty()) { return kOfxStatErrBadHandle; } QVariant variant = _node->GetValueAtTime(id, rational::fromDouble(time)); if (variant.canConvert()) { data = variant.toInt(); return kOfxStatOK; } data = 0; return kOfxStatErrValue; } OfxStatus set(int data) { if (!_node) { std::lock_guard lock(no_node_mutex_); value_ = data; has_value_ = true; return kOfxStatOK; } SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kInt, data); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(_node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(_node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, int data) { if (!_node) { std::lock_guard lock(no_node_mutex_); value_ = data; has_value_ = true; return kOfxStatOK; } auto command = new MultiUndoCommand(); Node::SetValueAtTime( NodeInput(_node.get(), _descriptor.getName().c_str()), rational::fromDouble(time), data, 0, command, true); SubmitUndoCommand(_node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class DoubleInstance : public OFX::Host::Param::DoubleInstance, public NodeBoundParam { protected: std::shared_ptr node; OFX::Host::Param::Descriptor &_descriptor; bool has_value_ = false; double value_ = 0.0; public: DoubleInstance(std::shared_ptr effect, const std::string &name, OFX::Host::Param::Descriptor &descriptor, OFX::Host::Param::SetInstance *paramSet = nullptr) : OFX::Host::Param::DoubleInstance(descriptor, paramSet) , node(effect) , _descriptor(descriptor) { (void)name; try { value_ = _descriptor.getProperties().getDoubleProperty( kOfxParamPropDefault); has_value_ = true; } catch (...) { value_ = 0.0; has_value_ = false; } } void SetNode(const std::shared_ptr &new_node) override { node = new_node; } OfxStatus get(double &data) { if (!node) { data = has_value_ ? value_ : 0.0; return kOfxStatOK; } QVariant variant = node->GetStandardValue(_descriptor.getName().c_str()); if (variant.canConvert()) { data = variant.toDouble(); if (IsNormalisedCoordinateSystem(_descriptor)) { double xSize, ySize; GetProjectExtent(xSize, ySize); data = ToNormalised(data, xSize); } return kOfxStatOK; } data = 0.0; return kOfxStatErrValue; } OfxStatus get(OfxTime time, double &data) { if (!node) { data = has_value_ ? value_ : 0.0; return kOfxStatOK; } QVariant variant = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)); if (variant.canConvert()) { data = variant.toDouble(); if (IsNormalisedCoordinateSystem(_descriptor)) { double xSize, ySize; GetProjectExtent(xSize, ySize); data = ToNormalised(data, xSize); } return kOfxStatOK; } data = 0.0; return kOfxStatErrValue; } OfxStatus set(double data) { if (!node) { value_ = data; 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, val); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, double data) { if (!node) { value_ = data; 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), val, 0, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus derive(OfxTime, double &) { return kOfxStatErrUnsupported; } OfxStatus integrate(OfxTime, OfxTime, double &) { return kOfxStatErrUnsupported; } }; class BooleanInstance : public OFX::Host::Param::BooleanInstance, public NodeBoundParam { protected: std::shared_ptr node; OFX::Host::Param::Descriptor &_descriptor; bool has_value_ = false; bool value_ = false; bool DefaultValue() const { return _descriptor.getProperties().getIntProperty( kOfxParamPropDefault) != 0; } public: BooleanInstance(std::shared_ptr effect, const std::string &name, OFX::Host::Param::Descriptor &descriptor, OFX::Host::Param::SetInstance *paramSet = nullptr) : OFX::Host::Param::BooleanInstance(descriptor, paramSet) , node(effect) , _descriptor(descriptor) { (void)name; value_ = DefaultValue(); has_value_ = true; } void SetNode(const std::shared_ptr &new_node) override { node = new_node; } OfxStatus get(bool &data) { if (!node) { data = has_value_ ? value_ : false; return kOfxStatOK; } QVariant variant = node->GetStandardValue(_descriptor.getName().c_str()); if (variant.canConvert()) { data = variant.toBool(); return kOfxStatOK; } data = DefaultValue(); return kOfxStatOK; } OfxStatus get(OfxTime time, bool &data) { if (!node) { data = has_value_ ? value_ : false; return kOfxStatOK; } QVariant variant = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)); if (variant.isNull()) { qWarning().noquote() << "Boolean get failed: Varient is null" << time << rational::fromDouble(time).toDouble(); } if (!variant.isValid()) { qWarning().noquote() << "Boolean get failed: Varient is invalid" << time << rational::fromDouble(time).toDouble(); } if (variant.canConvert()) { data = variant.toBool(); return kOfxStatOK; } data = DefaultValue(); return kOfxStatOK; } OfxStatus set(bool data) { if (!node) { value_ = data; has_value_ = true; return kOfxStatOK; } SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kBoolean, data); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, bool data) { if (!node) { value_ = data; has_value_ = true; return kOfxStatOK; } auto command = new MultiUndoCommand(); Node::SetValueAtTime( NodeInput(node.get(), _descriptor.getName().c_str()), rational::fromDouble(time), data, 0, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class ChoiceInstance : public OFX::Host::Param::ChoiceInstance, public NodeBoundParam { protected: std::shared_ptr node; OFX::Host::Param::Descriptor &_descriptor; bool has_value_ = false; int value_ = 0; public: ChoiceInstance(std::shared_ptr effect, const std::string &name, OFX::Host::Param::Descriptor &descriptor, OFX::Host::Param::SetInstance *paramSet = nullptr) : OFX::Host::Param::ChoiceInstance(descriptor, paramSet) , node(effect) , _descriptor(descriptor) { (void)name; try { value_ = _descriptor.getProperties().getIntProperty( kOfxParamPropDefault); has_value_ = true; } catch (...) { value_ = 0; has_value_ = false; } } void SetNode(const std::shared_ptr &new_node) override { node = new_node; } OfxStatus get(int &data) { if (!node) { data = has_value_ ? value_ : 0; return kOfxStatOK; } QVariant variant = node->GetStandardValue(_descriptor.getName().c_str()); if (variant.canConvert()) { data = variant.toInt(); return kOfxStatOK; } data = 0; return kOfxStatErrValue; } OfxStatus get(OfxTime time, int &data) { if (!node) { data = has_value_ ? value_ : 0; return kOfxStatOK; } QVariant variant = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)); if (variant.canConvert()) { data = variant.toInt(); return kOfxStatOK; } data = 0; return kOfxStatErrValue; } OfxStatus set(int data) { if (!node) { value_ = data; has_value_ = true; return kOfxStatOK; } SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kCombo, data); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, int data) { if (!node) { value_ = data; has_value_ = true; return kOfxStatOK; } auto command = new MultiUndoCommand(); Node::SetValueAtTime( NodeInput(node.get(), _descriptor.getName().c_str()), rational::fromDouble(time), data, 0, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class RGBAInstance : public OFX::Host::Param::RGBAInstance, public NodeBoundParam { protected: std::shared_ptr node; OFX::Host::Param::Descriptor &_descriptor; bool has_value_ = false; double value_[4] = { 0.0, 0.0, 0.0, 0.0 }; public: RGBAInstance(std::shared_ptr effect, const std::string &name, OFX::Host::Param::Descriptor &descriptor, OFX::Host::Param::SetInstance *paramSet = nullptr) : OFX::Host::Param::RGBAInstance(descriptor, paramSet) , node(effect) , _descriptor(descriptor) { (void)name; } void SetNode(const std::shared_ptr &new_node) override { node = new_node; } OfxStatus get(double &r, double &g, double &b, double &a) { if (!node) { if (has_value_) { r = value_[0]; g = value_[1]; b = value_[2]; a = value_[3]; } else { r = g = b = a = 0.0; } return kOfxStatOK; } olive::core::Color c = node->GetStandardValue(_descriptor.getName().c_str()) .value(); r = static_cast(c.red()); g = static_cast(c.green()); b = static_cast(c.blue()); a = static_cast(c.alpha()); return kOfxStatOK; } OfxStatus get(OfxTime time, double &r, double &g, double &b, double &a) { if (!node) { if (has_value_) { r = value_[0]; g = value_[1]; b = value_[2]; a = value_[3]; } else { r = g = b = a = 0.0; } return kOfxStatOK; } olive::core::Color c = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)) .value(); r = static_cast(c.red()); g = static_cast(c.green()); b = static_cast(c.blue()); a = static_cast(c.alpha()); return kOfxStatOK; } OfxStatus set(double r, double g, double b, double a) { if (!node) { value_[0] = r; value_[1] = g; value_[2] = b; value_[3] = a; has_value_ = true; return kOfxStatOK; } SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kColor, QVariant::fromValue(olive::core::Color(r, g, b, a))); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, double r, double g, double b, double a) { if (!node) { value_[0] = r; value_[1] = g; value_[2] = b; value_[3] = a; has_value_ = true; return kOfxStatOK; } auto command = new MultiUndoCommand(); const QString name = _descriptor.getName().c_str(); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), r, 0, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), g, 1, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), b, 2, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), a, 3, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class RGBInstance : public OFX::Host::Param::RGBInstance, public NodeBoundParam { protected: std::shared_ptr node; OFX::Host::Param::Descriptor &_descriptor; bool has_value_ = false; double value_[3] = { 0.0, 0.0, 0.0 }; public: RGBInstance(std::shared_ptr effect, const std::string &name, OFX::Host::Param::Descriptor &descriptor, OFX::Host::Param::SetInstance *paramSet = nullptr) : OFX::Host::Param::RGBInstance(descriptor, paramSet) , node(effect) , _descriptor(descriptor) { (void)name; } void SetNode(const std::shared_ptr &new_node) override { node = new_node; } OfxStatus get(double &r, double &g, double &b) { if (!node) { if (has_value_) { r = value_[0]; g = value_[1]; b = value_[2]; } else { r = g = b = 0.0; } return kOfxStatOK; } olive::core::Color c = node->GetStandardValue(_descriptor.getName().c_str()) .value(); r = static_cast(c.red()); g = static_cast(c.green()); b = static_cast(c.blue()); return kOfxStatOK; } OfxStatus get(OfxTime time, double &r, double &g, double &b) { if (!node) { if (has_value_) { r = value_[0]; g = value_[1]; b = value_[2]; } else { r = g = b = 0.0; } return kOfxStatOK; } olive::core::Color c = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)) .value(); r = static_cast(c.red()); g = static_cast(c.green()); b = static_cast(c.blue()); return kOfxStatOK; } OfxStatus set(double r, double g, double b) { if (!node) { value_[0] = r; value_[1] = g; value_[2] = b; has_value_ = true; return kOfxStatOK; } SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kColor, QVariant::fromValue(olive::core::Color(r, g, b))); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, double r, double g, double b) { if (!node) { value_[0] = r; value_[1] = g; value_[2] = b; has_value_ = true; return kOfxStatOK; } auto command = new MultiUndoCommand(); const QString name = _descriptor.getName().c_str(); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), r, 0, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), g, 1, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), b, 2, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class Double2DInstance : public OFX::Host::Param::Double2DInstance, public NodeBoundParam { protected: std::shared_ptr node; OFX::Host::Param::Descriptor &_descriptor; bool has_value_ = false; double value_[2] = { 0.0, 0.0 }; public: Double2DInstance(std::shared_ptr effect, const std::string &name, OFX::Host::Param::Descriptor &descriptor, OFX::Host::Param::SetInstance *paramSet = nullptr) : OFX::Host::Param::Double2DInstance(descriptor, paramSet) , node(effect) , _descriptor(descriptor) { (void)name; } void SetNode(const std::shared_ptr &new_node) override { node = new_node; } OfxStatus get(double &x, double &y) { if (!node) { if (has_value_) { x = value_[0]; y = value_[1]; } else { x = y = 0.0; } return kOfxStatOK; } QVector2D vec = node->GetStandardValue(_descriptor.getName().c_str()) .value(); x = static_cast(vec.x()); y = static_cast(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) { if (!node) { if (has_value_) { x = value_[0]; y = value_[1]; } else { x = y = 0.0; } return kOfxStatOK; } QVector2D vec = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)) .value(); x = static_cast(vec.x()); y = static_cast(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) { if (!node) { value_[0] = x; value_[1] = y; 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(xv, yv)); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, double x, double y) { if (!node) { value_[0] = x; value_[1] = y; 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), xv, 0, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), yv, 1, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class Integer2DInstance : public OFX::Host::Param::Integer2DInstance, public NodeBoundParam { protected: std::shared_ptr node; OFX::Host::Param::Descriptor &_descriptor; bool has_value_ = false; int value_[2] = { 0, 0 }; public: Integer2DInstance(std::shared_ptr effect, const std::string &name, OFX::Host::Param::Descriptor &descriptor, OFX::Host::Param::SetInstance *paramSet = nullptr) : OFX::Host::Param::Integer2DInstance(descriptor, paramSet) , node(effect) , _descriptor(descriptor) { (void)name; } void SetNode(const std::shared_ptr &new_node) override { node = new_node; } OfxStatus get(int &x, int &y) { if (!node) { if (has_value_) { x = value_[0]; y = value_[1]; } else { x = y = 0; } return kOfxStatOK; } QVector2D vec = node->GetStandardValue(_descriptor.getName().c_str()) .value(); x = static_cast(vec.x()); y = static_cast(vec.y()); return kOfxStatOK; } OfxStatus get(OfxTime time, int &x, int &y) { if (!node) { if (has_value_) { x = value_[0]; y = value_[1]; } else { x = y = 0; } return kOfxStatOK; } QVector2D vec = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)) .value(); x = static_cast(vec.x()); y = static_cast(vec.y()); return kOfxStatOK; } OfxStatus set(int x, int y) { if (!node) { value_[0] = x; value_[1] = y; has_value_ = true; return kOfxStatOK; } SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kVec2, QVector2D(x, y)); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, int x, int y) { if (!node) { value_[0] = x; value_[1] = y; has_value_ = true; return kOfxStatOK; } auto command = new MultiUndoCommand(); const QString name = _descriptor.getName().c_str(); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), x, 0, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), y, 1, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class Double3DInstance : public OFX::Host::Param::Double3DInstance, public NodeBoundParam { protected: std::shared_ptr node; OFX::Host::Param::Descriptor &_descriptor; bool has_value_ = false; double value_[3] = { 0.0, 0.0, 0.0 }; public: Double3DInstance(std::shared_ptr effect, const std::string &name, OFX::Host::Param::Descriptor &descriptor, OFX::Host::Param::SetInstance *paramSet = nullptr) : OFX::Host::Param::Double3DInstance(descriptor, paramSet) , node(effect) , _descriptor(descriptor) { (void)name; } void SetNode(const std::shared_ptr &new_node) override { node = new_node; } OfxStatus get(double &x, double &y, double &z) { if (!node) { if (has_value_) { x = value_[0]; y = value_[1]; z = value_[2]; } else { x = y = z = 0.0; } return kOfxStatOK; } QVector3D vec = node->GetStandardValue(_descriptor.getName().c_str()) .value(); x = static_cast(vec.x()); y = static_cast(vec.y()); z = static_cast(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) { if (!node) { if (has_value_) { x = value_[0]; y = value_[1]; z = value_[2]; } else { x = y = z = 0.0; } return kOfxStatOK; } QVector3D vec = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)) .value(); x = static_cast(vec.x()); y = static_cast(vec.y()); z = static_cast(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) { if (!node) { value_[0] = x; value_[1] = y; value_[2] = z; 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(xv, yv, zv)); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, double x, double y, double z) { if (!node) { value_[0] = x; value_[1] = y; value_[2] = z; 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), xv, 0, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), yv, 1, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), zv, 2, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class Integer3DInstance : public OFX::Host::Param::Integer3DInstance, public NodeBoundParam { protected: std::shared_ptr node; OFX::Host::Param::Descriptor &_descriptor; bool has_value_ = false; int value_[3] = { 0, 0, 0 }; public: Integer3DInstance(std::shared_ptr effect, const std::string &name, OFX::Host::Param::Descriptor &descriptor, OFX::Host::Param::SetInstance *paramSet = nullptr) : OFX::Host::Param::Integer3DInstance(descriptor, paramSet) , node(effect) , _descriptor(descriptor) { (void)name; } void SetNode(const std::shared_ptr &new_node) override { node = new_node; } OfxStatus get(int &x, int &y, int &z) { if (!node) { if (has_value_) { x = value_[0]; y = value_[1]; z = value_[2]; } else { x = y = z = 0; } return kOfxStatOK; } QVector3D vec = node->GetStandardValue(_descriptor.getName().c_str()) .value(); x = static_cast(vec.x()); y = static_cast(vec.y()); z = static_cast(vec.z()); return kOfxStatOK; } OfxStatus get(OfxTime time, int &x, int &y, int &z) { if (!node) { if (has_value_) { x = value_[0]; y = value_[1]; z = value_[2]; } else { x = y = z = 0; } return kOfxStatOK; } QVector3D vec = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)) .value(); x = static_cast(vec.x()); y = static_cast(vec.y()); z = static_cast(vec.z()); return kOfxStatOK; } OfxStatus set(int x, int y, int z) { if (!node) { value_[0] = x; value_[1] = y; value_[2] = z; has_value_ = true; return kOfxStatOK; } SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kVec3, QVector3D(x, y, z)); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, int x, int y, int z) { if (!node) { value_[0] = x; value_[1] = y; value_[2] = z; has_value_ = true; return kOfxStatOK; } auto command = new MultiUndoCommand(); const QString name = _descriptor.getName().c_str(); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), x, 0, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), y, 1, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), z, 2, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class StringInstance : public OFX::Host::Param::StringInstance, public NodeBoundParam { protected: std::shared_ptr node; OFX::Host::Param::Descriptor &_descriptor; bool has_value_ = false; std::string value_; public: StringInstance(std::shared_ptr effect, const std::string &name, OFX::Host::Param::Descriptor &descriptor, OFX::Host::Param::SetInstance *paramSet = nullptr) : OFX::Host::Param::StringInstance(descriptor, paramSet) , node(effect) , _descriptor(descriptor) { (void)name; try { value_ = _descriptor.getProperties().getStringProperty( kOfxParamPropDefault); has_value_ = true; } catch (...) { value_.clear(); has_value_ = false; } } void SetNode(const std::shared_ptr &new_node) override { node = new_node; } OfxStatus get(std::string &data) { if (!node) { data = has_value_ ? value_ : std::string(); return kOfxStatOK; } QVariant variant = node->GetStandardValue(_descriptor.getName().c_str()); if (variant.canConvert()) { data = variant.toString().toStdString(); return kOfxStatOK; } data.clear(); return kOfxStatErrValue; } OfxStatus get(OfxTime time, std::string &data) { if (!node) { data = has_value_ ? value_ : std::string(); return kOfxStatOK; } QVariant variant = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)); if (variant.canConvert()) { data = variant.toString().toStdString(); return kOfxStatOK; } data.clear(); return kOfxStatErrValue; } OfxStatus set(const char *data) { if (!node) { value_ = data ? data : ""; has_value_ = true; return kOfxStatOK; } QString v = QString::fromUtf8(data); SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kText, v); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, const char *data) { if (!node) { value_ = data ? data : ""; has_value_ = true; return kOfxStatOK; } auto command = new MultiUndoCommand(); Node::SetValueAtTime(NodeInput(node.get(), _descriptor.getName().c_str()), rational::fromDouble(time), QString::fromUtf8(data), 0, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class CustomInstance : public OFX::Host::Param::CustomInstance, public NodeBoundParam { protected: std::shared_ptr node; OFX::Host::Param::Descriptor &_descriptor; bool has_value_ = false; std::string value_; public: CustomInstance(std::shared_ptr effect, const std::string &name, OFX::Host::Param::Descriptor &descriptor, OFX::Host::Param::SetInstance *paramSet = nullptr) : OFX::Host::Param::CustomInstance(descriptor, paramSet) , node(effect) , _descriptor(descriptor) { (void)name; } void SetNode(const std::shared_ptr &new_node) override { node = new_node; } OfxStatus get(std::string &data) { if (!node) { data = has_value_ ? value_ : std::string(); return kOfxStatOK; } QVariant variant = node->GetStandardValue(_descriptor.getName().c_str()); if (variant.canConvert()) { data = variant.toByteArray().toStdString(); return kOfxStatOK; } if (variant.canConvert()) { data = variant.toString().toStdString(); return kOfxStatOK; } data.clear(); return kOfxStatErrValue; } OfxStatus get(OfxTime time, std::string &data) { if (!node) { data = has_value_ ? value_ : std::string(); return kOfxStatOK; } QVariant variant = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)); if (variant.canConvert()) { data = variant.toByteArray().toStdString(); return kOfxStatOK; } if (variant.canConvert()) { data = variant.toString().toStdString(); return kOfxStatOK; } data.clear(); return kOfxStatErrValue; } OfxStatus set(const char *data) { if (!node) { value_ = data ? data : ""; has_value_ = true; return kOfxStatOK; } QByteArray v = QByteArray(data); SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kBinary, v); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, const char *data) { if (!node) { value_ = data ? data : ""; has_value_ = true; return kOfxStatOK; } auto command = new MultiUndoCommand(); Node::SetValueAtTime( NodeInput(node.get(), _descriptor.getName().c_str()), rational::fromDouble(time), QByteArray(data), 0, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class GroupInstance : public OFX::Host::Param::GroupInstance { public: GroupInstance(OFX::Host::Param::Descriptor &descriptor, OFX::Host::Param::SetInstance *paramSet = nullptr) : OFX::Host::Param::GroupInstance(descriptor, paramSet) { } }; class PageInstance : public OFX::Host::Param::PageInstance { public: PageInstance(OFX::Host::Param::Descriptor &descriptor, OFX::Host::Param::SetInstance *paramSet = nullptr) : OFX::Host::Param::PageInstance(descriptor, paramSet) { } }; } } #endif // HOST_DEMO_PARAM_INSTANCE_H