diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 37ccd41ed..cb36f0ee5 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -55,6 +55,10 @@ configure_file(ts/translations.qrc.in ts/translations.qrc @ONLY) set(OLIVE_RESOURCES ${OLIVE_RESOURCES} ${CMAKE_CURRENT_BINARY_DIR}/ts/translations.qrc + render/job/pluginjob.cpp + render/job/pluginjob.h + widget/nodeparamview/nodeparambutton.cpp + widget/nodeparamview/nodeparambutton.h ) # Add version object diff --git a/app/common/Current.h b/app/common/Current.h index b2076e351..44487a2c0 100644 --- a/app/common/Current.h +++ b/app/common/Current.h @@ -19,7 +19,9 @@ #ifndef CURRENT_H #define CURRENT_H +#include "pluginSupport/OliveHost.h" #include "render/videoparams.h" +#include "render/job/pluginjob.h" class Current { public: @@ -51,10 +53,36 @@ public: { currentAudioParams_ = params; } + bool interactive() + { + return true; + } + + std::shared_ptr pluginHost() + { + return myHost; + } + + void setPluginHost(std::shared_ptr host) + { + myHost = host; + } + + std::shared_ptr pluginCache() + { + return plugin_cache_; + } + + void setPluginCache(std::shared_ptr cache) + { + plugin_cache_ = cache; + } private: static Current current; olive::VideoParams currentVideoParams_; olive::AudioParams currentAudioParams_; + std::shared_ptr myHost; + std::shared_ptr plugin_cache_; }; diff --git a/app/main.cpp b/app/main.cpp index e6cb7bfb5..efdbbf908 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -24,6 +24,7 @@ * Use the navigation above to find documentation on classes or source files. */ +#include "OliveHost.h" extern "C" { #include #include @@ -52,7 +53,6 @@ extern "C" { #ifdef USE_CRASHPAD #include "common/crashpadinterface.h" #endif // USE_CRASHPAD -#include "OlivePlugin.cpp" int decompress_project(const QString &project) { if (project.isEmpty()) { diff --git a/app/node/factory.cpp b/app/node/factory.cpp index 9529137ab..5d0400bba 100644 --- a/app/node/factory.cpp +++ b/app/node/factory.cpp @@ -29,6 +29,7 @@ #include "block/transition/diptocolor/diptocolortransition.h" #include "color/displaytransform/displaytransform.h" #include "color/ociogradingtransformlinear/ociogradingtransformlinear.h" +#include "common/Current.h" #include "distort/cornerpin/cornerpindistortnode.h" #include "distort/crop/cropdistortnode.h" #include "distort/flip/flipdistortnode.h" @@ -62,6 +63,8 @@ #include "math/trigonometry/trigonometry.h" #include "output/track/track.h" #include "output/viewer/viewer.h" +#include "pluginSupport/OliveHost.h" +#include "plugins/Plugin.h" #include "project/folder/folder.h" #include "project/footage/footage.h" #include "project/sequence/sequence.h" @@ -84,6 +87,19 @@ void NodeFactory::Initialize() library_.append(created_node); } + + std::shared_ptr host=std::make_shared(); + Current::getInstance().setPluginHost(host); + std::shared_ptr plugin_cache=std::make_shared(*host); + plugin_cache->registerInCache(*OFX::Host::PluginCache::getPluginCache()); + OFX::Host::PluginCache::getPluginCache()->scanPluginFiles(); + + + for (auto plugin : OFX::Host::PluginCache::getPluginCache()->getPlugins()) { + plugin::PluginNode *plugin_node=new plugin::PluginNode(dynamic_cast(plugin)); + library_.append(plugin_node); + } + } void NodeFactory::Destroy() diff --git a/app/node/node.h b/app/node/node.h index c4b356ac2..f73de0ee2 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -19,6 +19,8 @@ #ifndef NODE_H #define NODE_H +#include "ofxhImageEffectAPI.h" + #include #include #include @@ -1124,7 +1126,12 @@ public: static const QString kEnabledInput; + OFX::Host::ImageEffect::ImageEffectPlugin* getPlugin(); protected: + + // If is set, this is a plugin node. + OFX::Host::ImageEffect::ImageEffectPlugin* plugin= nullptr; + void InsertInput(const QString &id, NodeValue::Type type, const QVariant &default_value, InputFlags flags, int index); diff --git a/app/node/plugins/Plugin.cpp b/app/node/plugins/Plugin.cpp index f1b9b68b8..e74a86aab 100644 --- a/app/node/plugins/Plugin.cpp +++ b/app/node/plugins/Plugin.cpp @@ -17,44 +17,89 @@ */ #include "Plugin.h" + +#include "render/rendermanager.h" +#include "render/job/pluginjob.h" +olive::plugin::PluginNode::PluginNode( + OFX::Host::ImageEffect::ImageEffectPlugin *plugin) +{ + this->plugin = plugin; + auto params = plugin->getDescriptor().getParams(); + + for (auto param: params) { + + NodeValue::Type type; + + const std::string &ofxType = param.second->getType(); + if (ofxType == kOfxParamTypeInteger) { + type = NodeValue::kInt; + } else if (ofxType == kOfxParamTypeDouble) { + type = NodeValue::kFloat; + } else if (ofxType == kOfxParamTypeBoolean) { + type = NodeValue::kBoolean; + } else if (ofxType == kOfxParamTypeString) { + type = NodeValue::kText; + } else if (ofxType == kOfxParamTypeRGB || + ofxType == kOfxParamTypeRGBA) { + type = NodeValue::kColor; + } else if (ofxType == kOfxParamTypeChoice) { + type = NodeValue::kCombo; + } else if (ofxType == kOfxParamTypeDouble2D || + ofxType == kOfxParamTypeInteger2D){ + type = NodeValue::kVec2;} + else if (ofxType == kOfxParamTypeDouble3D || + ofxType == kOfxParamTypeInteger3D){ + type = NodeValue::kVec3; + } else if (ofxType == kOfxParamTypeStrChoice){ + type = NodeValue::kStrCombo; + }else if (ofxType == kOfxParamTypeBytes + || ofxType == kOfxParamTypeCustom) { + type = NodeValue::kBinary; + } else if (ofxType == kOfxParamTypePushButton) { + type = NodeValue::kPushButton; + } else if (ofxType == kOfxParamTypeGroup) { + // TODO + } else if (ofxType == kOfxParamTypePage) { + // TODO + }else { + type = NodeValue::kNone; + } + + + + AddInput(param.second->getName().data(), type); + } + +} QString olive::plugin::PluginNode::Name() const { - if (methods.name) { - char buffer[64]={0}; - bool ok=methods.name(buffer, 64); - if (ok) { - return QString(buffer); - } - } - return ""; + return plugin->getDescriptor() + .getProps() + .getStringProperty(kOfxPropLabel) + .data(); + } QString olive::plugin::PluginNode::Description() const { - if (methods.description) { - char buffer[1024] = { 0 }; - bool ok = methods.description(buffer, 1024); - if (ok) { - return QString(buffer); - } - } - return ""; + return plugin->getDescriptor().getProps().getStringProperty(kOfxPropPluginDescription).data(); + } void olive::plugin::PluginNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - methods.value(&node_ctx_functions); + TexturePtr tex = value[kTextureInput].toTexture(); + if (tex) { + PluginJob job(plugin, value); + table->Push(NodeValue::kTexture, tex->toJob(job), this); + } +} +void olive::plugin::PluginNode::pushButtonClicked(QString name) +{ } QString olive::plugin::PluginNode::id() const { - if (methods.id) { - char buffer[64]={0}; - bool ok=methods.id(buffer, 64); - if (ok) { - return QString(buffer); - } - } - return ""; + return plugin->getIdentifier().data(); } \ No newline at end of file diff --git a/app/node/plugins/Plugin.h b/app/node/plugins/Plugin.h index 5e69358dc..490a9d97f 100644 --- a/app/node/plugins/Plugin.h +++ b/app/node/plugins/Plugin.h @@ -18,36 +18,64 @@ #ifndef PLUGIN_NODES_H #define PLUGIN_NODES_H +#include "ofxhImageEffectAPI.h" +#include "ofxhPluginCache.h" #include "node/node.h" -#include "pluginSupport/Plugin.h" -#include "pluginSupport/OlivePlugin.cpp" + namespace olive { namespace plugin { +const QString kTextureInput = QStringLiteral("tex_in"); class PluginNode : public olive::Node{ public: - PluginNode():Node() - { - memset(&methods, 0, sizeof(olive_node_methods)); - }; - explicit PluginNode(struct olive_node_methods methods):Node() - { - this->methods=methods; - } - void setMethods(struct olive_node_methods methods) - { - this->methods=methods; - } + PluginNode(OFX::Host::ImageEffect::ImageEffectPlugin* plugin) ; + + QString Name() const override; QString id() const override; QVector Category() const override; QString Description() const override; + + void AddPushButton(); + void AddPage(); + + Node *copy() const override; + /** + * @brief The main processing function + * + * The node's main purpose is to take values from inputs to set values in outputs. For whatever subclass node you + * create, this is where the code for that goes. + * + * Note that as a video editor, the node graph has to work across time. Depending on the purpose of your node, it may + * output different values depending on the time, and even if not, it will likely be receiving different input + * depending on the time. Most of the difficult work here is handled by NodeInput::get_value() which you should pass + * the `time` parameter to. It will return its value (at that time, if it's keyframed), or pass the time to a + * corresponding output if it's connected to one. If your node doesn't directly deal with time, the default behavior + * of the NodeParam objects will handle everything related to it automatically. + */ void Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const override; -private: - struct olive_node_methods methods; + + /** + * @brief If Value() pushes a ShaderJob, this is the function that will process them. + */ + virtual void ProcessSamples(const NodeValueRow &values, + const SampleBuffer &input, SampleBuffer &output, + int index) const; + + /** + * @brief If Value() pushes a GenerateJob, override this function for the image to create + * + * @param frame + * + * The destination buffer. It will already be allocated and ready for writing to. + */ + virtual void GenerateFrame(FramePtr frame, const GenerateJob &job) const; + +public slots: + void pushButtonClicked(QString name); }; diff --git a/app/node/traverser.cpp b/app/node/traverser.cpp index 401446c85..f31aba4c8 100644 --- a/app/node/traverser.cpp +++ b/app/node/traverser.cpp @@ -387,6 +387,10 @@ QVector2D NodeTraverser::GenerateResolution() const video_params_.height()); } +/** + * Resolve Jobs. I need to add a PluginJob here and move the plugin code here. + * @param val + */ void NodeTraverser::ResolveJobs(NodeValue &val) { if (val.type() == NodeValue::kTexture) { diff --git a/app/node/value.h b/app/node/value.h index 590d5638d..5f1ff9d7b 100644 --- a/app/node/value.h +++ b/app/node/value.h @@ -163,7 +163,13 @@ public: * Resolves to `int` - the index currently selected */ kCombo, - + /** + * ComboBox type + * + * Resolves to `QString` - the text of choice currently selected + * This is to support the OpenFX type kOfxParamTypeStrChoice + */ + kStrCombo, /** * Video Parameters type * @@ -191,6 +197,10 @@ public: kBinary, /** + *Push Button + */ + kPushButton, + /** * End of list */ kDataTypeCount diff --git a/app/pluginSupport/CMakeLists.txt b/app/pluginSupport/CMakeLists.txt index 19b62b0f8..23adfb8ad 100644 --- a/app/pluginSupport/CMakeLists.txt +++ b/app/pluginSupport/CMakeLists.txt @@ -1,6 +1,10 @@ target_sources(libolive-editor PRIVATE OliveHost.h OliveHost.cpp - OliveInstance.h - OliveInstance.cpp + OlivePluginInstance.h + OlivePluginInstance.cpp + OliveClip.cpp + OliveClip.h + paraminstance.cpp + paraminstance.h ) \ No newline at end of file diff --git a/app/pluginSupport/OliveClip.cpp b/app/pluginSupport/OliveClip.cpp new file mode 100644 index 000000000..b41ec7cc7 --- /dev/null +++ b/app/pluginSupport/OliveClip.cpp @@ -0,0 +1,145 @@ +/* + * Olive Community Edition - 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 . + * + */ + +// +// Created by mikesolar on 25-10-1. +// + +#include "OliveClip.h" + +#include "common/Current.h" +const std::string &olive::plugin::OliveClipInstance::getUnmappedBitDepth() const +{ + switch (params_.format()) { + case PixelFormat::INVALID: + return kOfxBitDepthNone; + case PixelFormat::U8: + return kOfxBitDepthByte; + case PixelFormat::U16: + return kOfxBitDepthShort; + case PixelFormat::F16: + return kOfxBitDepthHalf; + case PixelFormat::F32: + return kOfxBitDepthFloat; + default: + return kOfxBitDepthNone; + } +} +const std::string & +olive::plugin::OliveClipInstance::getUnmappedComponents() const +{ + switch (params_.channel_count()) { + case 1: + return kOfxImageComponentAlpha; + case 3: + return kOfxImageComponentRGB; + case 4: + return kOfxImageComponentRGBA; + default: + return kOfxImageComponentNone; + } +} +const std::string &olive::plugin::OliveClipInstance::getPremult() const +{ + if (params_.premultiplied_alpha()) { + return kOfxImagePreMultiplied; + } else { + return kOfxImageUnPreMultiplied; + } +} +double olive::plugin::OliveClipInstance::getAspectRatio() const +{ + return params_ + .pixel_aspect_ratio() + .toDouble(); +} +double olive::plugin::OliveClipInstance::getFrameRate() const +{ + return params_.frame_rate().toDouble(); +} +void olive::plugin::OliveClipInstance::getFrameRange(double &startFrame, + double &endFrame) const +{ + startFrame = + params_.frame_rate().toDouble() * + params_.start_time(); + endFrame = + startFrame + + params_.frame_rate().toDouble() * + params_.duration(); +} +const std::string &olive::plugin::OliveClipInstance::getFieldOrder() const +{ + switch (params_.interlacing()) { + case VideoParams::kInterlaceNone: + return kOfxImageFieldNone; + case VideoParams::kInterlacedTopFirst: + return kOfxImageFieldUpper; + case VideoParams::kInterlacedBottomFirst: + return kOfxImageFieldLower; + } + return kOfxImageFieldNone; +} +bool olive::plugin::OliveClipInstance::getConnected() const +{ + return params_.format() == + PixelFormat::INVALID; +} +double olive::plugin::OliveClipInstance::getUnmappedFrameRate() const +{ + return getFrameRate(); +} +void olive::plugin::OliveClipInstance::getUnmappedFrameRange( + double &startFrame, double &endFrame) const +{ + getFrameRange(startFrame, endFrame); +} +bool olive::plugin::OliveClipInstance::getContinuousSamples() const +{ + return false; +} +OFX::Host::ImageEffect::Image * +olive::plugin::OliveClipInstance::getImage(OfxTime time, + const OfxRectD *optionalBounds) +{ + return &image_; +} +OfxRectD +olive::plugin::OliveClipInstance::getRegionOfDefinition(OfxTime time) const +{ + if (regionOfDefinitions_.contains(time)) { + return regionOfDefinitions_[time]; + } + OfxRectD regionOfDefinition; + regionOfDefinition.x1=regionOfDefinition.y1=0; + regionOfDefinition.x2=params_.width(); + regionOfDefinition.y2=params_.height(); + return regionOfDefinition; +} +void olive::plugin::OliveClipInstance::setRegionOfDefinition( + OfxRectD regionOfDefinition, OfxTime time) +{ + regionOfDefinitions_[time] = regionOfDefinition; +} + +void olive::plugin::OliveClipInstance::setDefaultRegionOfDefinition( + OfxRectD regionOfDefinition) +{ + defaultRegionOfDefinitions_ = regionOfDefinition; +} \ No newline at end of file diff --git a/app/pluginSupport/OliveClip.h b/app/pluginSupport/OliveClip.h new file mode 100644 index 000000000..833402257 --- /dev/null +++ b/app/pluginSupport/OliveClip.h @@ -0,0 +1,81 @@ +/* + * Olive Community Edition - 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 . + * + */ + +// +// Created by mikesolar on 25-10-1. +// + +#ifndef OLIVECLIP_H +#define OLIVECLIP_H +#include "ofxhClip.h" +#include "render/videoparams.h" + +#include +namespace olive +{ +namespace plugin +{ +class OliveClipInstance: public OFX::Host::ImageEffect::ClipInstance { +public: + OliveClipInstance(OFX::Host::ImageEffect::Instance* effectInstance, + OFX::Host::ImageEffect::ClipDescriptor& desc,VideoParams params) + : ClipInstance(effectInstance, desc) + { + params_ = params; + } + OFX::Host::ImageEffect::Image& getOutputImage() + { + return image_; + } + + const std::string &getUnmappedBitDepth() const override; + const std::string &getUnmappedComponents() const override; + const std::string &getPremult() const override; + double getAspectRatio() const override; + double getFrameRate() const override; + void getFrameRange(double &startFrame, double &endFrame) const override; + const std::string &getFieldOrder() const override; + bool getConnected() const override; + double getUnmappedFrameRate() const override; + void getUnmappedFrameRange(double &startFrame, double &endFrame) const override; + bool getContinuousSamples() const override; + OFX::Host::ImageEffect::Image* getImage(OfxTime time, const OfxRectD *optionalBounds) override; + OfxRectD getRegionOfDefinition(OfxTime time) const override; + + void setRegionOfDefinition(OfxRectD regionOfDefinition, OfxTime time); + void olive::plugin::OliveClipInstance::setDefaultRegionOfDefinition( + OfxRectD regionOfDefinition); +# ifdef OFX_SUPPORTS_OPENGLRENDER + OFX::Host::ImageEffect::Texture* loadTexture(OfxTime time, const char *format, const OfxRectD *optionalBounds) { return NULL; }; +# endif +private: + VideoParams params_; + + QMap regionOfDefinitions_; + + OfxRectD defaultRegionOfDefinitions_; + + OFX::Host::ImageEffect::Image image_; +}; +} +} + + + +#endif //OLIVECLIP_H diff --git a/app/pluginSupport/OliveHost.cpp b/app/pluginSupport/OliveHost.cpp index 8477cb4fd..c0a3c95c9 100644 --- a/app/pluginSupport/OliveHost.cpp +++ b/app/pluginSupport/OliveHost.cpp @@ -25,20 +25,16 @@ #include #include #include "OliveHost.h" + +#include "OlivePluginInstance.h" +#include "common/Current.h" using namespace OFX::Host; using namespace olive::plugin; -void loadPlugins(QString path) + +void olive::plugin::loadPlugins(QString path) { - QDir dir=(QCoreApplication::applicationDirPath()+path); - QFileInfoList files=dir.entryInfoList(); - for (auto& file:files) { - if (file.isDir()) { - OFX::Binary binary(file.absoluteFilePath().toStdString()); - - } - } + OFX::Host::ImageEffect::PluginCache imageEffectPluginCache(myHost); } - OliveHost::~OliveHost() { for(auto& descriptor:descriptors_){ @@ -79,7 +75,7 @@ OFX::Host::ImageEffect::Instance* OliveHost::newInstance(void* clientData, OFX::Host::ImageEffect::ImageEffectPlugin* plugin, OFX::Host::ImageEffect::Descriptor& desc, const std::string& context){ - //ImageEffect::Instance* instance=new ImageEffect::Instance(clientData,plugin,desc,context); + ImageEffect::Instance* instance=new OlivePluginInstance(plugin,desc,context,Current::getInstance().interactive()); instances_.append(instance); return instance; }; diff --git a/app/pluginSupport/OliveHost.h b/app/pluginSupport/OliveHost.h index f0d39d633..4fb5f020a 100644 --- a/app/pluginSupport/OliveHost.h +++ b/app/pluginSupport/OliveHost.h @@ -15,6 +15,8 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#ifndef OLIVE_HOST_H +#define OLIVE_HOST_H #include "ofxhHost.h" #include "ofxhImageEffectAPI.h" #include "ofxCore.h" @@ -66,4 +68,5 @@ private: QList instances_; }; } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/app/pluginSupport/OliveInstance.cpp b/app/pluginSupport/OlivePluginInstance.cpp similarity index 62% rename from app/pluginSupport/OliveInstance.cpp rename to app/pluginSupport/OlivePluginInstance.cpp index 8a8fba951..f39110443 100644 --- a/app/pluginSupport/OliveInstance.cpp +++ b/app/pluginSupport/OlivePluginInstance.cpp @@ -15,7 +15,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include "OliveInstance.h" +#include "OlivePluginInstance.h" + +#include "OliveClip.h" #include "ofxCore.h" #include "ofxMessage.h" #include "common/Current.h" @@ -26,11 +28,12 @@ #include #include #include +#include "paraminstance.h" namespace olive { namespace plugin { -OfxStatus OliveInstance::vmessage(const char *type, const char *id, +OfxStatus OlivePluginInstance::vmessage(const char *type, const char *id, const char *format, va_list args) { char *buffer = new char[1024]; @@ -57,7 +60,7 @@ OfxStatus OliveInstance::vmessage(const char *type, const char *id, return kOfxStatOK; } } -OfxStatus OliveInstance::setPersistentMessage(const char *type, const char *id, +OfxStatus OlivePluginInstance::setPersistentMessage(const char *type, const char *id, const char *format, va_list args) { char *buffer = new char[1024]; @@ -93,38 +96,73 @@ OfxStatus OliveInstance::setPersistentMessage(const char *type, const char *id, } return kOfxStatOK; } -OfxStatus OliveInstance::clearPersistentMessage() +OfxStatus OlivePluginInstance::clearPersistentMessage() { persistentErrors_.clear(); // TODO: tell the shell to remove message. return kOfxStatOK; } -void OliveInstance::getProjectSize(double &xSize, double &ySize) const +void OlivePluginInstance::getProjectSize(double &xSize, double &ySize) const { - xSize = Current::getInstance().currentVideoParams().width(); - ySize = Current::getInstance().currentVideoParams().height(); + xSize =params_.width(); + ySize =params_.height(); } -void OliveInstance::getProjectOffset(double &xOffset, double &yOffset) const +void OlivePluginInstance::getProjectOffset(double &xOffset, double &yOffset) const { - xOffset = Current::getInstance().currentVideoParams().x(); - yOffset = Current::getInstance().currentVideoParams().y(); + xOffset =params_.x(); + yOffset =params_.y(); } -void OliveInstance::getProjectExtent(double &xSize, double &ySize) const +void OlivePluginInstance::getProjectExtent(double &xSize, double &ySize) const { - xSize = Current::getInstance().currentVideoParams().width(); - ySize = Current::getInstance().currentVideoParams().height(); + xSize =params_.width(); + ySize =params_.height(); // TODO: Ensure this project does not support this. } -double OliveInstance::getProjectPixelAspectRatio() const +double OlivePluginInstance::getProjectPixelAspectRatio() const { return Current::getInstance() .currentVideoParams() .pixel_aspect_ratio() .toDouble(); } -double OliveInstance::getFrameRate() const +double OlivePluginInstance::getFrameRate() const { - return Current::getInstance().currentVideoParams().frame_rate().toDouble(); + return params_.frame_rate().toDouble(); +} + +double OlivePluginInstance::getEffectDuration() const +{ + // Return a default duration value + return 100.0; +} + +double OlivePluginInstance::getFrameRecursive() const +{ + // Return current frame (this would typically be set by the host during rendering) + return 0.0; +} + +void OlivePluginInstance::getRenderScaleRecursive(double &x, double &y) const +{ + // Return default render scale (1.0, 1.0) + x = 1.0; + y = 1.0; +} +OFX::Host::Param::Instance * +OlivePluginInstance::newParam(const std::string &name, + OFX::Host::Param::Descriptor &Descriptor) +{ + +} + +OFX::Host::ImageEffect::ClipInstance *OlivePluginInstance::newClipInstance( + OFX::Host::ImageEffect::Instance *plugin, + OFX::Host::ImageEffect::ClipDescriptor *descriptor, + int index) +{ + // Create a new clip instance + OFX::Host::ImageEffect::ClipInstance* clipInstance = new OliveClipInstance(plugin, *descriptor, params_); + return clipInstance; } } diff --git a/app/pluginSupport/OliveInstance.h b/app/pluginSupport/OlivePluginInstance.h similarity index 52% rename from app/pluginSupport/OliveInstance.h rename to app/pluginSupport/OlivePluginInstance.h index 30265f56c..db59e04c6 100644 --- a/app/pluginSupport/OliveInstance.h +++ b/app/pluginSupport/OlivePluginInstance.h @@ -15,11 +15,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - +#ifndef OLIVE_INSTANCE_H +#define OLIVE_INSTANCE_H #include "ofxCore.h" #include "ofxImageEffect.h" #include #include "ofxhImageEffect.h" +#include "render/videoparams.h" + #include #include #include @@ -34,9 +37,9 @@ struct PersistentErrors{ ErrorType type; QString message; }; -class OliveInstance : public OFX::Host::ImageEffect::Instance { +class OlivePluginInstance : public OFX::Host::ImageEffect::Instance { public: - OliveInstance( + OlivePluginInstance( OFX::Host::ImageEffect::ImageEffectPlugin* plugin, OFX::Host::ImageEffect::Descriptor& desc, const std::string& context, @@ -44,11 +47,15 @@ public: : OFX::Host::ImageEffect::Instance(plugin, desc, context, interactive) { } - ~OliveInstance() override = default; + ~OlivePluginInstance() override = default; const std::string &getDefaultOutputFielding() const{ return kOfxImageFieldNone; }; + void setVideoParam(VideoParams params) + { + this->params_=params; + } OFX::Host::ImageEffect::ClipInstance *newClipInstance( OFX::Host::ImageEffect::Instance *plugin, OFX::Host::ImageEffect::ClipDescriptor *descriptor, @@ -88,9 +95,62 @@ public: /// renderScale void getRenderScaleRecursive(double &x, double &y) const override; + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + // overridden for Param::SetInstance + + /// make a parameter instance + /// + /// Client host code needs to implement this + virtual OFX::Host::Param::Instance* newParam(const std::string& name, OFX::Host::Param::Descriptor& Descriptor); + + /// Triggered when the plug-in calls OfxParameterSuiteV1::paramEditBegin + /// + /// Client host code needs to implement this + virtual OfxStatus editBegin(const std::string& name); + + /// Triggered when the plug-in calls OfxParameterSuiteV1::paramEditEnd + /// + /// Client host code needs to implement this + virtual OfxStatus editEnd(); + + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + // overridden for Progress::ProgressI + + /// Start doing progress. + virtual void progressStart(const std::string &message, const std::string &messageid); + + /// finish yer progress + virtual void progressEnd(); + + /// set the progress to some level of completion, returns + /// false if you should abandon processing, true to continue + virtual bool progressUpdate(double t); + + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + // overridden for TimeLine::TimeLineI + + /// get the current time on the timeline. This is not necessarily the same + /// time as being passed to an action (eg render) + virtual double timeLineGetTime(); + + /// set the timeline to a specific time + virtual void timeLineGotoTime(double t); + + /// get the first and last times available on the effect's timeline + virtual void timeLineGetBounds(double &t1, double &t2); private: QList persistentErrors_; - + VideoParams params_; }; } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/app/pluginSupport/paraminstance.cpp b/app/pluginSupport/paraminstance.cpp new file mode 100644 index 000000000..63b594e04 --- /dev/null +++ b/app/pluginSupport/paraminstance.cpp @@ -0,0 +1,22 @@ +/* + * Olive Community Edition - 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 . + * + */ + + +#include "paraminstance.h" + diff --git a/app/pluginSupport/paraminstance.h b/app/pluginSupport/paraminstance.h new file mode 100644 index 000000000..e7b746dcd --- /dev/null +++ b/app/pluginSupport/paraminstance.h @@ -0,0 +1,183 @@ +/* + * Olive Community Edition - 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 "ofxhParam.h" +#include "node/plugins/Plugin.h" +namespace olive +{ +namespace plugin +{ +class PushbuttonInstance : public OFX::Host::Param::PushbuttonInstance { +protected: + PluginNode* node; + OFX::Host::Param::Descriptor *_descriptor; +public: + PushbuttonInstance(PluginNode *effect, const std::string &name, + OFX::Host::Param::Descriptor &descriptor) + : OFX::Host::Param::PushbuttonInstance(descriptor) + , node(effect) + { + _descriptor = &descriptor; + }; +}; + +class IntegerInstance : public OFX::Host::Param::IntegerInstance { +protected: + PluginNode* _node; + OFX::Host::Param::Descriptor& _descriptor; + QString id; +public: + IntegerInstance(PluginNode *node, OFX::Host::Param::Descriptor &descriptor) + : _node(node), _descriptor(descriptor), + OFX::Host::Param::IntegerInstance(_descriptor){} + OfxStatus get(int &a) + { + if (id.isEmpty()) { + return kOfxStatErrBadHandle; + } + QVariant variant=_node->GetStandardValue(id); + + if (variant.typeId()==QVariant::Int) { + a=variant.toInt(); + return kOfxStatOK; + } + a=0; + return kOfxStatErrValue; + } + OfxStatus get(OfxTime time, int &data) + { + if (id.isEmpty()) { + return kOfxStatErrBadHandle; + } + QVariant variant=_node->GetValueAtTime(id, rational::fromDouble(time)); + if (variant.typeId()==QVariant::Int) { + data=variant.toInt(); + return kOfxStatOK; + } + data=0; + return kOfxStatErrValue; + } + OfxStatus set(int data) + { + _node->SetStandardValue(_descriptor.getName().c_str(), data); + id=_descriptor.getName().c_str(); + return kOfxStatOK; + } + OfxStatus set(OfxTime time, int) + { + _node->SetValueAtTime() + } +}; + +class DoubleInstance : public OFX::Host::Param::DoubleInstance { +protected: + PluginNode* node; + OFX::Host::Param::Descriptor& _descriptor; +public: + DoubleInstance(PluginNode* effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor); + OfxStatus get(double&); + OfxStatus get(OfxTime time, double&); + OfxStatus set(double); + OfxStatus set(OfxTime time, double); + OfxStatus derive(OfxTime time, double&); + OfxStatus integrate(OfxTime time1, OfxTime time2, double&); +}; + +class BooleanInstance : public OFX::Host::Param::BooleanInstance { +protected: + PluginNode* node; + OFX::Host::Param::Descriptor& _descriptor; +public: + BooleanInstance(PluginNode* effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor); + OfxStatus get(bool&); + OfxStatus get(OfxTime time, bool&); + OfxStatus set(bool); + OfxStatus set(OfxTime time, bool); +}; + +class ChoiceInstance : public OFX::Host::Param::ChoiceInstance { +protected: + PluginNode* node; + OFX::Host::Param::Descriptor& _descriptor; +public: + ChoiceInstance(PluginNode* effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor); + OfxStatus get(int&); + OfxStatus get(OfxTime time, int&); + OfxStatus set(int); + OfxStatus set(OfxTime time, int); +}; + +class RGBAInstance : public OFX::Host::Param::RGBAInstance { +protected: + PluginNode* node; + OFX::Host::Param::Descriptor& _descriptor; +public: + RGBAInstance(PluginNode* effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor); + OfxStatus get(double&,double&,double&,double&); + OfxStatus get(OfxTime time, double&,double&,double&,double&); + OfxStatus set(double,double,double,double); + OfxStatus set(OfxTime time, double,double,double,double); +}; + + +class RGBInstance : public OFX::Host::Param::RGBInstance { +protected: + PluginNode* node; + OFX::Host::Param::Descriptor& _descriptor; +public: + RGBInstance(PluginNode* effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor); + OfxStatus get(double&,double&,double&); + OfxStatus get(OfxTime time, double&,double&,double&); + OfxStatus set(double,double,double); + OfxStatus set(OfxTime time, double,double,double); +}; + +class Double2DInstance : public OFX::Host::Param::Double2DInstance { +protected: + PluginNode* node; + OFX::Host::Param::Descriptor& _descriptor; +public: + Double2DInstance(PluginNode* effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor); + OfxStatus get(double&,double&); + OfxStatus get(OfxTime time,double&,double&); + OfxStatus set(double,double); + OfxStatus set(OfxTime time,double,double); +}; + +class Integer2DInstance : public OFX::Host::Param::Integer2DInstance { +protected: + PluginNode* node; + OFX::Host::Param::Descriptor& _descriptor; +public: + Integer2DInstance(PluginNode* effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor); + OfxStatus get(int&,int&); + OfxStatus get(OfxTime time,int&,int&); + OfxStatus set(int,int); + OfxStatus set(OfxTime time,int,int); +}; +} +} + + + +#endif // HOST_DEMO_PARAM_INSTANCE_H diff --git a/app/render/job/CMakeLists.txt b/app/render/job/CMakeLists.txt index 6ad233bbe..350257ee0 100644 --- a/app/render/job/CMakeLists.txt +++ b/app/render/job/CMakeLists.txt @@ -22,5 +22,7 @@ set(OLIVE_SOURCES render/job/generatejob.h render/job/samplejob.h render/job/shaderjob.h - PARENT_SCOPE + render/job/pluginjob.h + render/job/pluginjob.cpp + PARENT_SCOPE ) diff --git a/app/render/job/acceleratedjob.h b/app/render/job/acceleratedjob.h index 1724fa201..1a4f4053c 100644 --- a/app/render/job/acceleratedjob.h +++ b/app/render/job/acceleratedjob.h @@ -33,22 +33,22 @@ public: { } - NodeValue Get(const QString &input) const + virtual NodeValue Get(const QString &input) const { return value_map_.value(input); } - void Insert(const QString &input, const NodeValueRow &row) + virtual void Insert(const QString &input, const NodeValueRow &row) { value_map_.insert(input, row.value(input)); } - void Insert(const QString &input, const NodeValue &value) + virtual void Insert(const QString &input, const NodeValue &value) { value_map_.insert(input, value); } - void Insert(const NodeValueRow &row) + virtual void Insert(const NodeValueRow &row) { #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) value_map_.insert(row); @@ -59,16 +59,16 @@ public: #endif } - const NodeValueRow &GetValues() const + virtual const NodeValueRow &GetValues() const { return value_map_; } - NodeValueRow &GetValues() + virtual NodeValueRow &GetValues() { return value_map_; } -private: +protected: NodeValueRow value_map_; }; diff --git a/app/render/job/pluginjob.cpp b/app/render/job/pluginjob.cpp new file mode 100644 index 000000000..67c4e71d2 --- /dev/null +++ b/app/render/job/pluginjob.cpp @@ -0,0 +1,25 @@ +/* + * Olive Community Edition - 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 . + * + */ + +#include "pluginjob.h" + +namespace olive { +namespace plugin { +} // plugin +} // olive \ No newline at end of file diff --git a/app/render/job/pluginjob.h b/app/render/job/pluginjob.h new file mode 100644 index 000000000..757d0cfce --- /dev/null +++ b/app/render/job/pluginjob.h @@ -0,0 +1,49 @@ +/* + * Olive Community Edition - 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 . + * + */ + +#ifndef PLUGINJOB_H +#define PLUGINJOB_H +#include "acceleratedjob.h" +#include "pluginSupport/OlivePluginInstance.h" + +#include +#include + +namespace olive { +namespace plugin { + +class PluginJob :public AcceleratedJob{ +public: + explicit PluginJob(OFX::Host::ImageEffect::ImageEffectPlugin* pluginInstance, NodeValueRow row): AcceleratedJob() + { + this->pluginInstance = pluginInstance; + } + +private: + OFX::Host::ImageEffect::ImageEffectPlugin *pluginInstance=nullptr; + + QHash> paramsOnTime; + + QHash params; +}; + +} // plugin +} // olive + +#endif //PLUGINJOB_H diff --git a/app/render/plugin/CMakeLists.txt b/app/render/plugin/CMakeLists.txt new file mode 100644 index 000000000..89d6f2721 --- /dev/null +++ b/app/render/plugin/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(libolive-editor PRIVATE pluginrenderer.cpp pluginrenderer.h) \ No newline at end of file diff --git a/app/render/plugin/pluginrenderer.cpp b/app/render/plugin/pluginrenderer.cpp new file mode 100644 index 000000000..c6b26de69 --- /dev/null +++ b/app/render/plugin/pluginrenderer.cpp @@ -0,0 +1,33 @@ +/* + * Olive Community Edition - 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 . + * + */ + +// +// Created by mikesolar on 25-10-19. +// + +#include "pluginrenderer.h" + +#include "pluginSupport/OlivePluginInstance.h" +void olive::plugin::PluginRenderer::Blit(QVariant shader, ShaderJob job, + Texture *destination, + VideoParams destination_params, + bool clear_destination) +{ + +} \ No newline at end of file diff --git a/app/render/plugin/pluginrenderer.h b/app/render/plugin/pluginrenderer.h new file mode 100644 index 000000000..09e99f846 --- /dev/null +++ b/app/render/plugin/pluginrenderer.h @@ -0,0 +1,46 @@ +/* + * Olive Community Edition - 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 . + * + */ + +// +// Created by mikesolar on 25-10-19. +// + +#ifndef PLUGINRENDERER_H +#define PLUGINRENDERER_H +#include "render/renderer.h" +namespace olive +{ +namespace plugin{ +class PluginRenderer : public olive::Renderer{ + Q_OBJECT +public: + PluginRenderer(QObject *parent=nullptr):Renderer(parent){}; +protected: + void Blit(QVariant shader, + ShaderJob job, + Texture *destination, + VideoParams destination_params, + bool clear_destination) override; +}; +} +} + + + +#endif //PLUGINRENDERER_H diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index 530a06ccd..73f89d487 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -28,6 +28,8 @@ #include "node/block/transition/transition.h" #include "node/project.h" #include "rendermanager.h" +#include "pluginSupport/OliveClip.h" +#include "pluginSupport/OliveHost.h" namespace olive { @@ -157,6 +159,7 @@ void RenderProcessor::Run() SetCancelPointer(ticket_->GetCancelAtom()); + VideoParams params=ticket_->property("vparam").value(); SetCacheVideoParams(ticket_->property("vparam").value()); SetCacheAudioParams(ticket_->property("aparam").value()); @@ -165,6 +168,93 @@ void RenderProcessor::Run() return; } + // if is a plugin + /*Node *node=ticket_->property("node").value(); + if (node && node->getPlugin()) { + std::shared_ptr plugin + = node->getPlugin(); + std::unique_ptr instance(plugin->createInstance(kOfxImageEffectContextFilter, NULL)); + + OfxStatus stat; + stat = instance->createInstanceAction(); + if(stat != kOfxStatOK && stat != kOfxStatReplyDefault) { + ticket_->Finish(); + return; + } + // now we need to to call getClipPreferences on the instance so that it does the clip component/depth + // logic and caches away the components and depth on each clip. + bool ok = instance->getClipPreferences(); + if (!ok) { + ticket_->Finish(); + return; + } + + // current render scale of 1 + OfxPointD renderScale; + renderScale.x = renderScale.y = 1.0; + + // The render window is in pixel coordinates + // ie: render scale and a PAR of not 1 + OfxRectI renderWindow; + renderWindow.x1 = renderWindow.y1 = 0; + renderWindow.x2 = ticket_->property("size").value().width(); + renderWindow.y2 = ticket_->property("size").value().height(); + + /// RoI is in canonical coords, + OfxRectD regionOfInterest; + regionOfInterest.x1 = regionOfInterest.y1 = 0; + regionOfInterest.x2 = renderWindow.x2 * instance->getProjectPixelAspectRatio(); + regionOfInterest.y2 = renderWindow.y2 * instance->getProjectPixelAspectRatio(); + + OfxRectD regionOfDefinition; + regionOfDefinition.x1 = regionOfDefinition.y1 = 0; + regionOfDefinition.x2 = params.width(); + regionOfDefinition.y2 = params.height(); + + + int numFramesToRender=ticket_->property("time").value().toDouble() + * params.frame_rate().toDouble(); + stat = instance->beginRenderAction(0, numFramesToRender, 1.0, false, renderScale, /*sequential=#1#true, /*interactive=#1#false + ); + if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) { + ticket_->Finish(); + return; + } + + plugin::OliveClipInstance *clip=dynamic_cast(instance->getClip("Output")); + for(int t = 0; t <= numFramesToRender; ++t) + { + // call get region of interest on each of the inputs + OfxTime frame = t; + + // get the RoI for each input clip + // the regions of interest for each input clip are returned in a std::map + // on a real host, these will be the regions of each input clip that the + // effect needs to render a given frame (clipped to the RoD). + // + // In our example we are doing full frame fetches regardless. + std::map rois; + stat = instance->getRegionOfInterestAction(frame, renderScale, + regionOfInterest, rois); + assert(stat == kOfxStatOK || stat == kOfxStatReplyDefault); + + // render a frame + stat = instance->renderAction(t,kOfxImageFieldBoth,renderWindow, renderScale, /*sequential=#1#true, /*interactive=#1#false, /*draft=#1#false); + assert(stat == kOfxStatOK); + + // get the output image buffer + OFX::Host::ImageEffect::Image *outputImage = clip->getOutputImage(); + + std::ostringstream ss; + ss << "Output." << t << ".ppm"; + exportToPPM(ss.str(), outputImage); + } + + instance->endRenderAction(0, numFramesToRender, 1.0, false, renderScale, /*sequential=#1#true, /*interactive=#1#false + ); + } + */ + switch (type) { case RenderManager::kTypeVideo: { rational time = ticket_->property("time").value(); diff --git a/app/widget/nodeparamview/CMakeLists.txt b/app/widget/nodeparamview/CMakeLists.txt index 1b80edebc..4f7cf658e 100644 --- a/app/widget/nodeparamview/CMakeLists.txt +++ b/app/widget/nodeparamview/CMakeLists.txt @@ -15,28 +15,30 @@ # along with this program. If not, see . set(OLIVE_SOURCES - ${OLIVE_SOURCES} - widget/nodeparamview/nodeparamview.cpp - widget/nodeparamview/nodeparamview.h - widget/nodeparamview/nodeparamviewarraywidget.cpp - widget/nodeparamview/nodeparamviewarraywidget.h - widget/nodeparamview/nodeparamviewconnectedlabel.cpp - widget/nodeparamview/nodeparamviewconnectedlabel.h - widget/nodeparamview/nodeparamviewcontext.cpp - widget/nodeparamview/nodeparamviewcontext.h - widget/nodeparamview/nodeparamviewdockarea.cpp - widget/nodeparamview/nodeparamviewdockarea.h - widget/nodeparamview/nodeparamviewitem.cpp - widget/nodeparamview/nodeparamviewitem.h - widget/nodeparamview/nodeparamviewitembase.cpp - widget/nodeparamview/nodeparamviewitembase.h - widget/nodeparamview/nodeparamviewitemtitlebar.cpp - widget/nodeparamview/nodeparamviewitemtitlebar.h - widget/nodeparamview/nodeparamviewkeyframecontrol.cpp - widget/nodeparamview/nodeparamviewkeyframecontrol.h - widget/nodeparamview/nodeparamviewtextedit.cpp - widget/nodeparamview/nodeparamviewtextedit.h - widget/nodeparamview/nodeparamviewwidgetbridge.cpp - widget/nodeparamview/nodeparamviewwidgetbridge.h - PARENT_SCOPE + ${OLIVE_SOURCES} + widget/nodeparamview/nodeparamview.cpp + widget/nodeparamview/nodeparamview.h + widget/nodeparamview/nodeparamviewarraywidget.cpp + widget/nodeparamview/nodeparamviewarraywidget.h + widget/nodeparamview/nodeparamviewconnectedlabel.cpp + widget/nodeparamview/nodeparamviewconnectedlabel.h + widget/nodeparamview/nodeparamviewcontext.cpp + widget/nodeparamview/nodeparamviewcontext.h + widget/nodeparamview/nodeparamviewdockarea.cpp + widget/nodeparamview/nodeparamviewdockarea.h + widget/nodeparamview/nodeparamviewitem.cpp + widget/nodeparamview/nodeparamviewitem.h + widget/nodeparamview/nodeparamviewitembase.cpp + widget/nodeparamview/nodeparamviewitembase.h + widget/nodeparamview/nodeparamviewitemtitlebar.cpp + widget/nodeparamview/nodeparamviewitemtitlebar.h + widget/nodeparamview/nodeparamviewkeyframecontrol.cpp + widget/nodeparamview/nodeparamviewkeyframecontrol.h + widget/nodeparamview/nodeparamviewtextedit.cpp + widget/nodeparamview/nodeparamviewtextedit.h + widget/nodeparamview/nodeparamviewwidgetbridge.cpp + widget/nodeparamview/nodeparamviewwidgetbridge.h + widget/nodeparamview/nodeparambutton.h + widget/nodeparamview/nodeparambutton.cpp + PARENT_SCOPE ) diff --git a/app/widget/nodeparamview/nodeparambutton.cpp b/app/widget/nodeparamview/nodeparambutton.cpp new file mode 100644 index 000000000..2696e6d98 --- /dev/null +++ b/app/widget/nodeparamview/nodeparambutton.cpp @@ -0,0 +1,20 @@ +/* + * Olive Community Edition - 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 . + * + */ + +#include "nodeparambutton.h" diff --git a/app/widget/nodeparamview/nodeparambutton.h b/app/widget/nodeparamview/nodeparambutton.h new file mode 100644 index 000000000..cb06ce7f1 --- /dev/null +++ b/app/widget/nodeparamview/nodeparambutton.h @@ -0,0 +1,47 @@ +/* + * Olive Community Edition - 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 . + * + */ + +#ifndef NODEPARAMBUTTON_H +#define NODEPARAMBUTTON_H +#include "node/plugins/Plugin.h" + +#include + +class NodeParamButton : public QPushButton{ +Q_OBJECT +public: + NodeParamButton(QString name, QWidget *parent = nullptr):QPushButton(parent) + { + this->name_=name; + connect(this, &QPushButton::clicked, this, &NodeParamButton::pressed); + } +signals: + void onPressed(QString name); +private slots: + void pressed(){ + emit onPressed(name_); + } +private: + QString name_; + +}; + + + +#endif //NODEPARAMBUTTON_H diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index a9236698c..9f8eb4399 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -26,6 +26,7 @@ #include "common/qtutils.h" #include "core.h" +#include "nodeparambutton.h" #include "node/group/group.h" #include "node/node.h" #include "node/nodeundo.h" @@ -40,6 +41,8 @@ #include "widget/slider/integerslider.h" #include "widget/slider/rationalslider.h" +#include + namespace olive { @@ -179,6 +182,13 @@ void NodeParamViewWidgetBridge::CreateWidgets() &NodeParamViewWidgetBridge::WidgetCallback); break; } + case NodeValue::kPushButton: { + NodeInput input=GetInnerInput(); + NodeParamButton *button=new NodeParamButton(input.name(),parent); + widgets_.append(button); + plugin::PluginNode* plugin_node=dynamic_cast(input.node()); + connect(button, &NodeParamButton::onPressed, plugin_node, &plugin::PluginNode::pushButtonClicked); + } } // Check all properties diff --git a/ext/KDDockWidgets b/ext/KDDockWidgets index 0e9723b96..6b0ef44eb 160000 --- a/ext/KDDockWidgets +++ b/ext/KDDockWidgets @@ -1 +1 @@ -Subproject commit 0e9723b96b100deeb03977db0f587ad207d0bef4 +Subproject commit 6b0ef44eb189411d36c739ccde8a081a3e62034a