1 /* ***** BEGIN LICENSE BLOCK *****
2  * This file is part of openfx-misc <https://github.com/devernay/openfx-misc>,
3  * Copyright (C) 2013-2018 INRIA
4  *
5  * openfx-misc is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * openfx-misc is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with openfx-misc.  If not, see <http://www.gnu.org/licenses/gpl-2.0.html>
17  * ***** END LICENSE BLOCK ***** */
18 
19 /*
20  * OFX NoOp plugin.
21  * Does nothing.
22  */
23 
24 #include <sstream> // stringstream
25 
26 #include "ofxsProcessing.H"
27 #include "ofxsMacros.h"
28 #include "ofxsCopier.h"
29 #include "ofxsCoords.h"
30 #include "ofxsGenerator.h" // for format-related parameters
31 #include "ofxsFormatResolution.h" // for format-related enums
32 
33 #ifdef OFX_EXTENSIONS_NUKE
34 #include "nuke/fnOfxExtensions.h"
35 #endif
36 
37 using namespace OFX;
38 
39 OFXS_NAMESPACE_ANONYMOUS_ENTER
40 
41 #define kPluginName "NoOpOFX"
42 #define kPluginGrouping "Other"
43 #define kPluginDescription "Copies the input to the ouput.\n" \
44     "This effect does not modify the actual content of the image, but can be used to modify the metadata associated with the clip (premultiplication, field order, format, pixel aspect ratio, frame rate).\n" \
45     "This plugin concatenates transforms."
46 #define kPluginIdentifier "net.sf.openfx.NoOpPlugin"
47 
48 // History:
49 // Version 2.0: introduce setFormat, deprecate setPixelAspectRatio on Natron
50 #define kPluginVersionMajor 2 // Incrementing this number means that you have broken backwards compatibility of the plug-in.
51 #define kPluginVersionMinor 0 // Increment this when you have fixed a bug or made it faster.
52 
53 #define kSupportsTiles 1
54 #define kSupportsMultiResolution 1
55 #define kSupportsRenderScale 1
56 #define kSupportsMultipleClipPARs true
57 #define kSupportsMultipleClipDepths true
58 #define kRenderThreadSafety eRenderFullySafe
59 
60 #define kParamClipInfo "clipInfo"
61 #define kParamClipInfoLabel "Clip Info..."
62 #define kParamClipInfoHint "Display information about the inputs"
63 
64 #define kParamForceCopy "forceCopy"
65 #define kParamForceCopyLabel "Force Copy"
66 #define kParamForceCopyHint "Force copy from input to output"
67 
68 #define kParamSetPremult "setPremult"
69 #define kParamSetPremultLabel "Set Premultiplication"
70 #define kParamSetPremultHint "Set the premultiplication state of the output clip, without modifying the raw content. Use the Premult or UnPremult plu-gins to affect the content."
71 
72 #define kParamOutputPremult "outputPremult"
73 #define kParamOutputPremultLabel "Output Premultiplication"
74 #define kParamOutputPremultHint "Premultiplication state of the output clip."
75 
76 #define kParamSetFieldOrder "setFieldOrder"
77 #define kParamSetFieldOrderLabel "Set Field Order"
78 #define kParamSetFieldOrderHint "Set the field order state of the output clip, without modifying the raw content."
79 
80 #define kParamOutputFieldOrder "outputFieldOrder"
81 #define kParamOutputFieldOrderLabel "Output Field Order"
82 #define kParamOutputFieldOrderHint "Field order state of the output clip."
83 
84 #ifdef OFX_EXTENSIONS_NATRON
85 #define kParamSetFormat "setFormat"
86 #define kParamSetFormatLabel "Set Format"
87 #define kParamSetFormatHint "Set the format of the output clip, without modifying the raw content."
88 #endif
89 
90 #define kParamSetPixelAspectRatio "setPixelAspectRatio"
91 #define kParamSetPixelAspectRatioLabel "Set Pixel Aspect Ratio"
92 #define kParamSetPixelAspectRatioHint "Set the pixel aspect ratio of the output clip, without modifying the raw content."
93 
94 #define kParamOutputPixelAspectRatio "outputPixelAspectRatio"
95 #define kParamOutputPixelAspectRatioLabel "Output Pixel Aspect Ratio"
96 #define kParamOutputPixelAspectRatioHint "Pixel aspect ratio of the output clip."
97 
98 #define kParamSetFrameRate "setFrameRate"
99 #define kParamSetFrameRateLabel "Set Frame Rate"
100 #define kParamSetFrameRateHint "Set the frame rate state of the output clip, without modifying the raw content."
101 
102 #define kParamOutputFrameRate "outputFrameRate"
103 #define kParamOutputFrameRateLabel "Output Frame Rate"
104 #define kParamOutputFrameRateHint "Frame rate of the output clip."
105 
106 // Some hosts (e.g. Resolve) may not support normalized defaults (setDefaultCoordinateSystem(eCoordinatesNormalised))
107 #define kParamDefaultsNormalised "defaultsNormalised"
108 
109 static bool gHostSupportsDefaultCoordinateSystem = true; // for kParamDefaultsNormalised
110 
111 ////////////////////////////////////////////////////////////////////////////////
112 /** @brief The plugin that does our work */
113 class NoOpPlugin
114     : public ImageEffect
115 {
116 public:
117     /** @brief ctor */
NoOpPlugin(OfxImageEffectHandle handle)118     NoOpPlugin(OfxImageEffectHandle handle)
119         : ImageEffect(handle)
120         , _dstClip(NULL)
121         , _srcClip(NULL)
122         , _forceCopy(NULL)
123         , _setPremult(NULL)
124         , _premult(NULL)
125         , _setFieldOrder(NULL)
126         , _fieldOrder(NULL)
127 #ifdef OFX_EXTENSIONS_NATRON
128         , _setFormat(NULL)
129         , _extent(NULL)
130         , _format(NULL)
131         , _formatSize(NULL)
132         , _formatPar(NULL)
133         , _btmLeft(NULL)
134         , _size(NULL)
135         , _recenter(NULL)
136 #endif
137         , _setPixelAspectRatio(NULL)
138         , _pixelAspectRatio(NULL)
139         , _setFrameRate(NULL)
140         , _frameRate(NULL)
141     {
142         _dstClip = fetchClip(kOfxImageEffectOutputClipName);
143         _srcClip = getContext() == eContextGenerator ? NULL : fetchClip(kOfxImageEffectSimpleSourceClipName);
144         _forceCopy = fetchBooleanParam(kParamForceCopy);
145         _setPremult = fetchBooleanParam(kParamSetPremult);
146         _premult = fetchChoiceParam(kParamOutputPremult);
147         assert(_forceCopy && _setPremult && _premult);
148 
149         const ImageEffectHostDescription &gHostDescription = *getImageEffectHostDescription();
150         if (gHostDescription.supportsSetableFielding) {
151             _setFieldOrder = fetchBooleanParam(kParamSetFieldOrder);
152             _fieldOrder = fetchChoiceParam(kParamOutputFieldOrder);
153             assert(_setFieldOrder && _fieldOrder);
154         }
155 #ifdef OFX_EXTENSIONS_NATRON
156         if (gHostDescription.isNatron) {
157             _setFormat = fetchBooleanParam(kParamSetFormat);
158             _extent = fetchChoiceParam(kParamGeneratorExtent);
159             _format = fetchChoiceParam(kParamGeneratorFormat);
160             _formatSize = fetchInt2DParam(kParamGeneratorSize);
161             _formatPar = fetchDoubleParam(kParamGeneratorPAR);
162             _btmLeft = fetchDouble2DParam(kParamRectangleInteractBtmLeft);
163             _size = fetchDouble2DParam(kParamRectangleInteractSize);
164             _recenter = fetchPushButtonParam(kParamGeneratorCenter);
165         }
166 #endif
167         if (gHostDescription.supportsMultipleClipPARs) {
168             _setPixelAspectRatio = fetchBooleanParam(kParamSetPixelAspectRatio);
169             _pixelAspectRatio = fetchDoubleParam(kParamOutputPixelAspectRatio);
170             assert(_setPixelAspectRatio && _pixelAspectRatio);
171         }
172         if (gHostDescription.supportsSetableFrameRate) {
173             _setFrameRate = fetchBooleanParam(kParamSetFrameRate);
174             _frameRate = fetchDoubleParam(kParamOutputFrameRate);
175             assert(_setFrameRate && _frameRate);
176         }
177 
178 #ifdef OFX_EXTENSIONS_NATRON
179         // honor kParamDefaultsNormalised
180         if ( paramExists(kParamDefaultsNormalised) ) {
181             // Some hosts (e.g. Resolve) may not support normalized defaults (setDefaultCoordinateSystem(eCoordinatesNormalised))
182             // handle these ourselves!
183             BooleanParam* param = fetchBooleanParam(kParamDefaultsNormalised);
184             assert(param);
185             bool normalised = param->getValue();
186             if (normalised) {
187                 OfxPointD size = getProjectExtent();
188                 OfxPointD origin = getProjectOffset();
189                 OfxPointD p;
190                 // we must denormalise all parameters for which setDefaultCoordinateSystem(eCoordinatesNormalised) couldn't be done
191                 beginEditBlock(kParamDefaultsNormalised);
192                 p = _btmLeft->getValue();
193                 _btmLeft->setValue(p.x * size.x + origin.x, p.y * size.y + origin.y);
194                 p = _size->getValue();
195                 _size->setValue(p.x * size.x, p.y * size.y);
196                 param->setValue(false);
197                 endEditBlock();
198             }
199         }
200 #endif
201 
202         // finally
203         syncPrivateData();
204     }
205 
206 private:
207     // override the roi call
208     virtual void getRegionsOfInterest(const RegionsOfInterestArguments &args, RegionOfInterestSetter &rois) OVERRIDE FINAL;
209     virtual bool getRegionOfDefinition(const RegionOfDefinitionArguments &args, OfxRectD &rod) OVERRIDE FINAL;
210 
211     /* Override the render */
212     virtual void render(const RenderArguments &args) OVERRIDE FINAL;
213     virtual bool isIdentity(const IsIdentityArguments &args, Clip * &identityClip, double &identityTime, int& view, std::string& plane) OVERRIDE FINAL;
214 
215     /** @brief get the clip preferences */
216     virtual void getClipPreferences(ClipPreferencesSetter &clipPreferences) OVERRIDE FINAL;
217 
218 #ifdef OFX_EXTENSIONS_NUKE
219     /** @brief recover a transform matrix from an effect */
220     virtual bool getTransform(const TransformArguments & args, Clip * &transformClip, double transformMatrix[9]) OVERRIDE FINAL;
221 #endif
222 
223     virtual void changedParam(const InstanceChangedArgs &args, const std::string &paramName) OVERRIDE FINAL;
224 
225     /** @brief The sync private data action, called when the effect needs to sync any private data to persistent parameters */
syncPrivateData(void)226     virtual void syncPrivateData(void) OVERRIDE FINAL
227     {
228         updateVisibility();
229     }
230 
updateVisibility()231     void updateVisibility()
232     {
233         const ImageEffectHostDescription &gHostDescription = *getImageEffectHostDescription();
234 
235         _premult->setEnabled( _setPremult->getValue() );
236         if (gHostDescription.supportsSetableFielding) {
237             _fieldOrder->setEnabled( _setFieldOrder->getValue() );
238         }
239 #ifdef OFX_EXTENSIONS_NATRON
240         if (gHostDescription.isNatron) {
241             GeneratorExtentEnum extent = (GeneratorExtentEnum)_extent->getValue();
242             bool hasFormat = (extent == eGeneratorExtentFormat);
243             bool hasSize = (extent == eGeneratorExtentSize);
244 
245             _format->setIsSecret(!hasFormat);
246             _size->setIsSecret(!hasSize);
247             _recenter->setIsSecret(!hasSize);
248             _btmLeft->setIsSecret(!hasSize);
249 
250             bool setFormat = _setFormat->getValue();
251             _extent->setEnabled(setFormat);
252             _format->setEnabled(setFormat);
253             _size->setEnabled(setFormat);
254             _recenter->setEnabled(setFormat);
255             _btmLeft->setEnabled(setFormat);
256         }
257 #endif
258         if (gHostDescription.supportsMultipleClipPARs) {
259             _pixelAspectRatio->setEnabled( _setPixelAspectRatio->getValue() );
260         }
261         if (gHostDescription.supportsSetableFrameRate) {
262             _frameRate->setEnabled( _setFrameRate->getValue() );
263         }
264     }
265 
266 private:
267     // do not need to delete these, the ImageEffect is managing them for us
268     Clip *_dstClip;
269     Clip *_srcClip;
270     BooleanParam *_forceCopy;
271     BooleanParam *_setPremult;
272     ChoiceParam *_premult;
273     BooleanParam *_setFieldOrder;
274     ChoiceParam *_fieldOrder;
275 #ifdef OFX_EXTENSIONS_NATRON
276     BooleanParam *_setFormat;
277     ChoiceParam* _extent;
278     ChoiceParam* _format;
279     Int2DParam* _formatSize;
280     DoubleParam* _formatPar;
281     Double2DParam* _btmLeft;
282     Double2DParam* _size;
283     PushButtonParam *_recenter;
284 #endif
285     BooleanParam *_setPixelAspectRatio;
286     DoubleParam *_pixelAspectRatio;
287     BooleanParam *_setFrameRate;
288     DoubleParam *_frameRate;
289 };
290 
291 
292 ////////////////////////////////////////////////////////////////////////////////
293 /** @brief render for the filter */
294 
295 ////////////////////////////////////////////////////////////////////////////////
296 // basic plugin render function, just a skelington to instantiate templates from
297 
298 // override the roi call
299 // Required if the plugin requires a region from the inputs which is different from the rendered region of the output.
300 // (this is the case here)
301 void
getRegionsOfInterest(const RegionsOfInterestArguments & args,RegionOfInterestSetter & rois)302 NoOpPlugin::getRegionsOfInterest(const RegionsOfInterestArguments &args,
303                                  RegionOfInterestSetter &rois)
304 {
305     if (!_srcClip || !_srcClip->isConnected()) {
306         return;
307     }
308     if (!_setPixelAspectRatio) {
309         return;
310     }
311     bool setPixelAspectRatio;
312     _setPixelAspectRatio->getValueAtTime(args.time, setPixelAspectRatio);
313     if (!setPixelAspectRatio) {
314         return;
315     }
316     double srcPAR = _srcClip->getPixelAspectRatio();
317     double pixelAspectRatio = 1.;
318     _pixelAspectRatio->getValueAtTime(args.time, pixelAspectRatio);
319     if ( (srcPAR <= 0) || (pixelAspectRatio <= 0) ) {
320         return;
321     }
322 
323     OfxRectD srcRoI = args.regionOfInterest;
324     srcRoI.x1 *= srcPAR / pixelAspectRatio;
325     srcRoI.x2 *= srcPAR / pixelAspectRatio;
326 
327     rois.setRegionOfInterest(*_srcClip, srcRoI);
328 }
329 
330 bool
getRegionOfDefinition(const RegionOfDefinitionArguments & args,OfxRectD & rod)331 NoOpPlugin::getRegionOfDefinition(const RegionOfDefinitionArguments &args,
332                                   OfxRectD &rod)
333 {
334     if (!_srcClip || !_srcClip->isConnected()) {
335         return false;
336     }
337     if (!_setPixelAspectRatio) {
338         return false;
339     }
340     bool setPixelAspectRatio;
341     _setPixelAspectRatio->getValueAtTime(args.time, setPixelAspectRatio);
342     if (!setPixelAspectRatio) {
343         return false;
344     }
345     double srcPAR = _srcClip->getPixelAspectRatio();
346     double pixelAspectRatio = 1.;
347     if (_pixelAspectRatio) {
348         _pixelAspectRatio->getValueAtTime(args.time, pixelAspectRatio);
349     }
350 #ifdef OFX_EXTENSIONS_NATRON
351     if (_formatPar) {
352         _formatPar->getValueAtTime(args.time, pixelAspectRatio);
353     }
354 #endif
355     if ( (srcPAR <= 0) || (pixelAspectRatio <= 0) ) {
356         return false;
357     }
358 
359     const OfxRectD srcRoD = _srcClip->getRegionOfDefinition(args.time);
360     if ( Coords::rectIsEmpty(srcRoD) ) {
361         return false;
362     }
363     rod = srcRoD;
364     rod.x1 *= pixelAspectRatio / srcPAR;
365     rod.x2 *= pixelAspectRatio / srcPAR;
366 
367     return true;
368 }
369 
370 // the overridden render function
371 void
render(const RenderArguments & args)372 NoOpPlugin::render(const RenderArguments &args)
373 {
374     const double time = args.time;
375     bool forceCopy;
376 
377     _forceCopy->getValueAtTime(time, forceCopy);
378 
379 #ifdef DEBUG
380     if (!forceCopy) {
381         setPersistentMessage(Message::eMessageError, "", "OFX Host should not render");
382         throwSuiteStatusException(kOfxStatFailed);
383     }
384 #endif
385 
386     assert( kSupportsMultipleClipPARs   || !_srcClip || _srcClip->getPixelAspectRatio() == _dstClip->getPixelAspectRatio() );
387     assert( kSupportsMultipleClipDepths || !_srcClip || _srcClip->getPixelDepth()       == _dstClip->getPixelDepth() );
388     // do the rendering
389     auto_ptr<Image> dst( _dstClip->fetchImage(args.time) );
390     if ( !dst.get() ) {
391         throwSuiteStatusException(kOfxStatFailed);
392     }
393     if ( (dst->getRenderScale().x != args.renderScale.x) ||
394          ( dst->getRenderScale().y != args.renderScale.y) ||
395          ( ( dst->getField() != eFieldNone) /* for DaVinci Resolve */ && ( dst->getField() != args.fieldToRender) ) ) {
396         setPersistentMessage(Message::eMessageError, "", "OFX Host gave image with wrong scale or field properties");
397         throwSuiteStatusException(kOfxStatFailed);
398     }
399     BitDepthEnum dstBitDepth       = dst->getPixelDepth();
400     PixelComponentEnum dstComponents  = dst->getPixelComponents();
401     auto_ptr<const Image> src( ( _srcClip && _srcClip->isConnected() ) ?
402                                     _srcClip->fetchImage(args.time) : 0 );
403     if ( src.get() ) {
404         if ( (src->getRenderScale().x != args.renderScale.x) ||
405              ( src->getRenderScale().y != args.renderScale.y) ||
406              ( ( src->getField() != eFieldNone) /* for DaVinci Resolve */ && ( src->getField() != args.fieldToRender) ) ) {
407             setPersistentMessage(Message::eMessageError, "", "OFX Host gave image with wrong scale or field properties");
408             throwSuiteStatusException(kOfxStatFailed);
409         }
410         BitDepthEnum srcBitDepth      = src->getPixelDepth();
411         PixelComponentEnum srcComponents = src->getPixelComponents();
412         if ( (srcBitDepth != dstBitDepth) || (srcComponents != dstComponents) ) {
413             throwSuiteStatusException(kOfxStatErrImageFormat);
414         }
415     }
416     copyPixels( *this, args.renderWindow, src.get(), dst.get() );
417 }
418 
419 bool
isIdentity(const IsIdentityArguments & args,Clip * & identityClip,double &,int &,std::string &)420 NoOpPlugin::isIdentity(const IsIdentityArguments &args,
421                        Clip * &identityClip,
422                        double & /*identityTime*/
423                        , int& /*view*/, std::string& /*plane*/)
424 {
425     const double time = args.time;
426     bool forceCopy;
427 
428     _forceCopy->getValueAtTime(time, forceCopy);
429 
430     if (!forceCopy) {
431         identityClip = _srcClip;
432 
433         return true;
434     } else {
435         return false;
436     }
437 }
438 
439 #ifdef OFX_EXTENSIONS_NUKE
440 // overridden getTransform
441 bool
getTransform(const TransformArguments & args,Clip * & transformClip,double transformMatrix[9])442 NoOpPlugin::getTransform(const TransformArguments &args,
443                          Clip * &transformClip,
444                          double transformMatrix[9])
445 {
446     const double time = args.time;
447     bool forceCopy;
448 
449     _forceCopy->getValueAtTime(time, forceCopy);
450     if (forceCopy) {
451         return false;
452     }
453     transformClip = _srcClip;
454     transformMatrix[0] = 1.;
455     transformMatrix[1] = 0.;
456     transformMatrix[2] = 0.;
457     transformMatrix[3] = 0.;
458     transformMatrix[4] = 1.;
459     transformMatrix[5] = 0.;
460     transformMatrix[6] = 0.;
461     transformMatrix[7] = 0.;
462     transformMatrix[8] = 1.;
463 
464     return true;
465 }
466 
467 #endif
468 
469 
470 static const char*
bitDepthString(BitDepthEnum bitDepth)471 bitDepthString(BitDepthEnum bitDepth)
472 {
473     switch (bitDepth) {
474     case eBitDepthUByte:
475 
476         return "8u";
477     case eBitDepthUShort:
478 
479         return "16u";
480     case eBitDepthHalf:
481 
482         return "16f";
483     case eBitDepthFloat:
484 
485         return "32f";
486     case eBitDepthCustom:
487 
488         return "x";
489     case eBitDepthNone:
490 
491         return "0";
492 #ifdef OFX_EXTENSIONS_VEGAS
493     case eBitDepthUByteBGRA:
494 
495         return "8uBGRA";
496     case eBitDepthUShortBGRA:
497 
498         return "16uBGRA";
499     case eBitDepthFloatBGRA:
500 
501         return "32fBGRA";
502 #endif
503     default:
504 
505         return "[unknown bit depth]";
506     }
507 }
508 
509 static std::string
pixelComponentString(const std::string & p)510 pixelComponentString(const std::string& p)
511 {
512     const std::string prefix = "OfxImageComponent";
513 
514     std::string s = p;
515 
516     return s.replace(s.find(prefix), prefix.length(), "");
517 }
518 
519 static const char*
premultString(PreMultiplicationEnum e)520 premultString(PreMultiplicationEnum e)
521 {
522     switch (e) {
523     case eImageOpaque:
524 
525         return "Opaque";
526     case eImagePreMultiplied:
527 
528         return "PreMultiplied";
529     case eImageUnPreMultiplied:
530 
531         return "UnPreMultiplied";
532     default:
533 
534         return "[unknown premult]";
535     }
536 }
537 
538 #ifdef OFX_EXTENSIONS_VEGAS
539 static const char*
pixelOrderString(PixelOrderEnum e)540 pixelOrderString(PixelOrderEnum e)
541 {
542     switch (e) {
543     case ePixelOrderRGBA:
544 
545         return "RGBA";
546     case ePixelOrderBGRA:
547 
548         return "BGRA";
549     default:
550 
551         return "[unknown pixel order]";
552     }
553 }
554 
555 #endif
556 
557 static const char*
fieldOrderString(FieldEnum e)558 fieldOrderString(FieldEnum e)
559 {
560     switch (e) {
561     case eFieldNone:
562 
563         return "None";
564     case eFieldBoth:
565 
566         return "Both";
567     case eFieldLower:
568 
569         return "Lower";
570     case eFieldUpper:
571 
572         return "Upper";
573     case eFieldSingle:
574 
575         return "Single";
576     case eFieldDoubled:
577 
578         return "Doubled";
579     default:
580 
581         return "[unknown field order]";
582     }
583 }
584 
585 void
changedParam(const InstanceChangedArgs & args,const std::string & paramName)586 NoOpPlugin::changedParam(const InstanceChangedArgs &args,
587                          const std::string &paramName)
588 {
589     if (paramName == kParamSetPremult) {
590         updateVisibility();
591     } else if (paramName == kParamSetFieldOrder) {
592         updateVisibility();
593     } else if (paramName == kParamSetFieldOrder) {
594         updateVisibility();
595 #ifdef OFX_EXTENSIONS_NATRON
596     } else if (paramName == kParamSetFormat) {
597         updateVisibility();
598     } else if (paramName == kParamGeneratorExtent) {
599         updateVisibility();
600     } else if (paramName == kParamGeneratorFormat) {
601         //the host does not handle the format itself, do it ourselves
602         EParamFormat format = (EParamFormat)_format->getValue();
603         int w = 0, h = 0;
604         double par = -1;
605         getFormatResolution(format, &w, &h, &par);
606         assert(par != -1);
607         _formatPar->setValue(par);
608         _formatSize->setValue(w, h);
609     } else if (paramName == kParamGeneratorCenter) {
610         Clip* srcClip = _srcClip;
611         OfxRectD srcRoD;
612         if ( srcClip && srcClip->isConnected() ) {
613             srcRoD = srcClip->getRegionOfDefinition(args.time);
614         } else {
615             OfxPointD siz = getProjectSize();
616             OfxPointD off = getProjectOffset();
617             srcRoD.x1 = off.x;
618             srcRoD.x2 = off.x + siz.x;
619             srcRoD.y1 = off.y;
620             srcRoD.y2 = off.y + siz.y;
621         }
622         OfxPointD center;
623         center.x = (srcRoD.x2 + srcRoD.x1) / 2.;
624         center.y = (srcRoD.y2 + srcRoD.y1) / 2.;
625 
626         OfxRectD rectangle;
627         _size->getValue(rectangle.x2, rectangle.y2);
628         _btmLeft->getValue(rectangle.x1, rectangle.y1);
629         rectangle.x2 += rectangle.x1;
630         rectangle.y2 += rectangle.y1;
631 
632         OfxRectD newRectangle;
633         newRectangle.x1 = center.x - (rectangle.x2 - rectangle.x1) / 2.;
634         newRectangle.y1 = center.y - (rectangle.y2 - rectangle.y1) / 2.;
635         newRectangle.x2 = newRectangle.x1 + (rectangle.x2 - rectangle.x1);
636         newRectangle.y2 = newRectangle.y1 + (rectangle.y2 - rectangle.y1);
637 
638         _size->setValue(newRectangle.x2 - newRectangle.x1, newRectangle.y2 - newRectangle.y1);
639         _btmLeft->setValue(newRectangle.x1, newRectangle.y1);
640 #endif
641     } else if (paramName == kParamSetPixelAspectRatio) {
642         updateVisibility();
643     } else if (paramName == kParamSetFrameRate) {
644         updateVisibility();
645     } else if (paramName == kParamClipInfo) {
646         std::ostringstream oss;
647         oss << "Clip Info:\n\n";
648         oss << "Input: ";
649         if (!_srcClip) {
650             oss << "N/A";
651         } else {
652             Clip &c = *_srcClip;
653             oss << pixelComponentString( c.getPixelComponentsProperty() );
654             oss << bitDepthString( c.getPixelDepth() );
655             oss << " (unmapped: ";
656             oss << pixelComponentString( c.getUnmappedPixelComponentsProperty() );
657             oss << bitDepthString( c.getUnmappedPixelDepth() );
658             oss << ")\npremultiplication: ";
659             oss << premultString( c.getPreMultiplication() );
660 #ifdef OFX_EXTENSIONS_VEGAS
661             oss << "\npixel order: ";
662             oss << pixelOrderString( c.getPixelOrder() );
663 #endif
664             oss << "\nfield order: ";
665             oss << fieldOrderString( c.getFieldOrder() );
666             oss << "\n";
667             oss << (c.isConnected() ? "connected" : "not connected");
668             oss << "\n";
669             oss << (c.hasContinuousSamples() ? "continuous samples" : "discontinuous samples");
670 #ifdef OFX_EXTENSIONS_NATRON
671             oss << "\nformat: ";
672             OfxRectI format;
673             c.getFormat(format);
674             oss << format.x2 - format.x1 << 'x' << format.y2 - format.y1;
675             if ( (format.x1 != 0) && (format.y1 != 0) ) {
676                 if (format.x1 < 0) {
677                     oss << format.x1;
678                 } else {
679                     oss << '+' << format.x1;
680                 }
681                 if (format.y1 < 0) {
682                     oss << format.y1;
683                 } else {
684                     oss << '+' << format.y1;
685                 }
686             }
687 #endif
688             oss << "\npixel aspect ratio: ";
689             oss << c.getPixelAspectRatio();
690             oss << "\nframe rate: ";
691             oss << c.getFrameRate();
692             oss << " (unmapped: ";
693             oss << c.getUnmappedFrameRate();
694             oss << ")";
695             OfxRangeD range = c.getFrameRange();
696             oss << "\nframe range: ";
697             oss << range.min << "..." << range.max;
698             oss << " (unmapped: ";
699             range = c.getUnmappedFrameRange();
700             oss << range.min << "..." << range.max;
701             oss << ")";
702             oss << "\nregion of definition: ";
703             OfxRectD rod = c.getRegionOfDefinition(args.time);
704             oss << rod.x1 << ' ' << rod.y1 << ' ' << rod.x2 << ' ' << rod.y2;
705         }
706         oss << "\n\n";
707         oss << "Output: ";
708         if (!_dstClip) {
709             oss << "N/A";
710         } else {
711             Clip &c = *_dstClip;
712             oss << pixelComponentString( c.getPixelComponentsProperty() );
713             oss << bitDepthString( c.getPixelDepth() );
714             oss << " (unmapped: ";
715             oss << pixelComponentString( c.getUnmappedPixelComponentsProperty() );
716             oss << bitDepthString( c.getUnmappedPixelDepth() );
717             oss << ")\npremultiplication: ";
718             oss << premultString( c.getPreMultiplication() );
719 #ifdef OFX_EXTENSIONS_VEGAS
720             oss << "\npixel order: ";
721             oss << pixelOrderString( c.getPixelOrder() );
722 #endif
723             oss << "\nfield order: ";
724             oss << fieldOrderString( c.getFieldOrder() );
725             oss << "\n";
726             oss << (c.isConnected() ? "connected" : "not connected");
727             oss << "\n";
728             oss << (c.hasContinuousSamples() ? "continuous samples" : "discontinuous samples");
729 #ifdef OFX_EXTENSIONS_NATRON
730             oss << "\nformat: ";
731             OfxRectI format;
732             c.getFormat(format);
733             oss << format.x2 - format.x1 << 'x' << format.y2 - format.y1;
734             if ( (format.x1 != 0) && (format.y1 != 0) ) {
735                 if (format.x1 < 0) {
736                     oss << format.x1;
737                 } else {
738                     oss << '+' << format.x1;
739                 }
740                 if (format.y1 < 0) {
741                     oss << format.y1;
742                 } else {
743                     oss << '+' << format.y1;
744                 }
745             }
746 #endif
747             oss << "\npixel aspect ratio: ";
748             oss << c.getPixelAspectRatio();
749             oss << "\nframe rate: ";
750             oss << c.getFrameRate();
751             oss << " (unmapped: ";
752             oss << c.getUnmappedFrameRate();
753             oss << ")";
754             OfxRangeD range = c.getFrameRange();
755             oss << "\nframe range: ";
756             oss << range.min << "..." << range.max;
757             oss << " (unmapped: ";
758             range = c.getUnmappedFrameRange();
759             oss << range.min << "..." << range.max;
760             oss << ")";
761             oss << "\nregion of definition: ";
762             OfxRectD rod = c.getRegionOfDefinition(args.time);
763             oss << rod.x1 << ' ' << rod.y1 << ' ' << rod.x2 << ' ' << rod.y2;
764         }
765         oss << "\n\n";
766         oss << "time: " << args.time << ", renderscale: " << args.renderScale.x << 'x' << args.renderScale.y << '\n';
767 
768         sendMessage( Message::eMessageMessage, "", oss.str() );
769     }
770 } // NoOpPlugin::changedParam
771 
772 /* Override the clip preferences */
773 void
getClipPreferences(ClipPreferencesSetter & clipPreferences)774 NoOpPlugin::getClipPreferences(ClipPreferencesSetter &clipPreferences)
775 {
776     // set the premultiplication of _dstClip
777     bool setPremult = _setPremult->getValue();
778 
779     if (setPremult) {
780         PreMultiplicationEnum premult = (PreMultiplicationEnum)_premult->getValue();
781 
782         clipPreferences.setOutputPremultiplication(premult);
783     }
784     if (_setFieldOrder) {
785         // set the field order of _dstClip
786         bool setFieldOrder = _setFieldOrder->getValue();
787         if (setFieldOrder) {
788             FieldEnum fieldOrder = (FieldEnum)_fieldOrder->getValue();
789 
790             clipPreferences.setOutputFielding(fieldOrder);
791         }
792     }
793 #ifdef OFX_EXTENSIONS_NATRON
794     if (_setFormat) {
795         bool setFormat = _setFormat->getValue();
796         if (setFormat) {
797             GeneratorExtentEnum extent = (GeneratorExtentEnum)_extent->getValue();
798 
799             switch (extent) {
800             case eGeneratorExtentFormat: {
801                 int w, h;
802                 _formatSize->getValue(w, h);
803                 double par = _formatPar->getValue();
804                 OfxRectI pixelFormat;
805                 pixelFormat.x1 = pixelFormat.y1 = 0;
806                 pixelFormat.x2 = w;
807                 pixelFormat.y2 = h;
808                 clipPreferences.setOutputFormat(pixelFormat);
809                 clipPreferences.setPixelAspectRatio(*_dstClip, par);
810                 break;
811             }
812             case eGeneratorExtentSize: {
813                 OfxRectD rod;
814                 _size->getValue(rod.x2, rod.y2);
815                 _btmLeft->getValue(rod.x1, rod.y1);
816                 rod.x2 += rod.x1;
817                 rod.y2 += rod.y1;
818                 double par = _srcClip->getPixelAspectRatio();
819                 OfxPointD renderScale = {1., 1.};
820                 OfxRectI pixelFormat;
821                 Coords::toPixelNearest(rod, renderScale, par, &pixelFormat);
822                 clipPreferences.setOutputFormat(pixelFormat);
823                 //clipPreferences.setPixelAspectRatio(*_dstClip, par); // should be the default
824                 break;
825             }
826             case eGeneratorExtentProject: {
827                 OfxRectD rod;
828                 OfxPointD siz = getProjectSize();
829                 OfxPointD off = getProjectOffset();
830                 rod.x1 = off.x;
831                 rod.x2 = off.x + siz.x;
832                 rod.y1 = off.y;
833                 rod.y2 = off.y + siz.y;
834                 double par = getProjectPixelAspectRatio();
835                 OfxPointD renderScale = {1., 1.};
836                 OfxRectI pixelFormat;
837                 Coords::toPixelNearest(rod, renderScale, par, &pixelFormat);
838                 clipPreferences.setOutputFormat(pixelFormat);
839                 clipPreferences.setPixelAspectRatio(*_dstClip, par);
840                 break;
841             }
842             case eGeneratorExtentDefault:
843                 break;
844             }
845         }
846     }
847 #endif // ifdef OFX_EXTENSIONS_NATRON
848     if (_setPixelAspectRatio) {
849         bool setPixelAspectRatio = _setPixelAspectRatio->getValue();
850         if (setPixelAspectRatio) {
851             double pixelAspectRatio = _pixelAspectRatio->getValue();
852             clipPreferences.setPixelAspectRatio(*_dstClip, pixelAspectRatio);
853         }
854     }
855     if (_setFrameRate) {
856         bool setFrameRate = _setFrameRate->getValue();
857         if (setFrameRate) {
858             double frameRate = _frameRate->getValue();
859             clipPreferences.setOutputFrameRate(frameRate);
860         }
861     }
862 } // NoOpPlugin::getClipPreferences
863 
864 mDeclarePluginFactory(NoOpPluginFactory, {ofxsThreadSuiteCheck();}, {});
865 void
describe(ImageEffectDescriptor & desc)866 NoOpPluginFactory::describe(ImageEffectDescriptor &desc)
867 {
868     // basic labels
869     desc.setLabel(kPluginName);
870     desc.setPluginGrouping(kPluginGrouping);
871     desc.setPluginDescription(kPluginDescription);
872 
873     // add the supported contexts, only filter at the moment
874     desc.addSupportedContext(eContextFilter);
875 
876     // add supported pixel depths
877     desc.addSupportedBitDepth(eBitDepthNone);
878     desc.addSupportedBitDepth(eBitDepthUByte);
879     desc.addSupportedBitDepth(eBitDepthUShort);
880     desc.addSupportedBitDepth(eBitDepthHalf);
881     desc.addSupportedBitDepth(eBitDepthFloat);
882     desc.addSupportedBitDepth(eBitDepthCustom);
883 #ifdef OFX_EXTENSIONS_VEGAS
884     desc.addSupportedBitDepth(eBitDepthUByteBGRA);
885     desc.addSupportedBitDepth(eBitDepthUShortBGRA);
886     desc.addSupportedBitDepth(eBitDepthFloatBGRA);
887 #endif
888 
889     // set a few flags
890     desc.setSingleInstance(false);
891     desc.setHostFrameThreading(false);
892     desc.setSupportsMultiResolution(kSupportsMultiResolution);
893     desc.setSupportsTiles(kSupportsTiles);
894     desc.setTemporalClipAccess(false);
895     desc.setRenderTwiceAlways(false);
896     desc.setSupportsMultipleClipPARs(kSupportsMultipleClipPARs);
897     desc.setSupportsMultipleClipDepths(kSupportsMultipleClipDepths);
898     desc.setRenderThreadSafety(kRenderThreadSafety);
899 #ifdef OFX_EXTENSIONS_NUKE
900     // Enable transform by the host.
901     // It is only possible for transforms which can be represented as a 3x3 matrix.
902     desc.setCanTransform(true);
903     // ask the host to render all planes
904     desc.setPassThroughForNotProcessedPlanes(ePassThroughLevelRenderAllRequestedPlanes);
905 #endif
906 #ifdef OFX_EXTENSIONS_NATRON
907     desc.setChannelSelector(ePixelComponentNone);
908 #endif
909     desc.setOverlayInteractDescriptor(new GeneratorOverlayDescriptor);
910 }
911 
912 void
describeInContext(ImageEffectDescriptor & desc,ContextEnum)913 NoOpPluginFactory::describeInContext(ImageEffectDescriptor &desc,
914                                      ContextEnum /*context*/)
915 {
916     // Source clip only in the filter context
917     // create the mandated source clip
918     ClipDescriptor *srcClip = desc.defineClip(kOfxImageEffectSimpleSourceClipName);
919 
920     srcClip->addSupportedComponent(ePixelComponentNone);
921     srcClip->addSupportedComponent(ePixelComponentRGBA);
922     srcClip->addSupportedComponent(ePixelComponentRGB);
923     srcClip->addSupportedComponent(ePixelComponentAlpha);
924 #ifdef OFX_EXTENSIONS_NATRON
925     srcClip->addSupportedComponent(ePixelComponentXY);
926 #endif
927 #ifdef OFX_EXTENSIONS_NUKE
928     srcClip->setCanTransform(true);
929 #endif
930     srcClip->setTemporalClipAccess(false);
931     srcClip->setSupportsTiles(kSupportsTiles);
932     srcClip->setIsMask(false);
933 
934     // create the mandated output clip
935     ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName);
936     dstClip->addSupportedComponent(ePixelComponentNone);
937     dstClip->addSupportedComponent(ePixelComponentRGBA);
938     dstClip->addSupportedComponent(ePixelComponentRGB);
939     dstClip->addSupportedComponent(ePixelComponentAlpha);
940 #ifdef OFX_EXTENSIONS_NATRON
941     dstClip->addSupportedComponent(ePixelComponentXY);
942 #endif
943     dstClip->setSupportsTiles(kSupportsTiles);
944 
945     // make some pages and to things in
946     PageParamDescriptor *page = desc.definePageParam("Controls");
947 
948     // forceCopy
949     {
950         BooleanParamDescriptor *param = desc.defineBooleanParam(kParamForceCopy);
951         param->setLabel(kParamForceCopyLabel);
952         param->setHint(kParamForceCopyHint);
953         param->setDefault(false);
954         param->setAnimates(false);
955         if (page) {
956             page->addChild(*param);
957         }
958     }
959 
960     //// setPremult
961     {
962         BooleanParamDescriptor* param = desc.defineBooleanParam(kParamSetPremult);
963         param->setLabel(kParamSetPremultLabel);
964         param->setHint(kParamSetPremultHint);
965         param->setDefault(false);
966         param->setAnimates(false);
967         desc.addClipPreferencesSlaveParam(*param);
968         if (page) {
969             page->addChild(*param);
970         }
971     }
972 
973     //// premult
974     {
975         ChoiceParamDescriptor* param = desc.defineChoiceParam(kParamOutputPremult);
976         param->setLabel(kParamOutputPremultLabel);
977         param->setHint(kParamOutputPremultHint);
978         assert(param->getNOptions() == eImageOpaque);
979         param->appendOption( premultString(eImageOpaque) );
980         assert(param->getNOptions() == eImagePreMultiplied);
981         param->appendOption( premultString(eImagePreMultiplied) );
982         assert(param->getNOptions() == eImageUnPreMultiplied);
983         param->appendOption( premultString(eImageUnPreMultiplied) );
984         param->setDefault(eImagePreMultiplied); // images should be premultiplied in a compositing context
985         param->setAnimates(false);
986         desc.addClipPreferencesSlaveParam(*param);
987         if (page) {
988             page->addChild(*param);
989         }
990     }
991     const ImageEffectHostDescription &gHostDescription = *getImageEffectHostDescription();
992 
993     if (gHostDescription.supportsSetableFielding) {
994         //// setFieldOrder
995         {
996             BooleanParamDescriptor* param = desc.defineBooleanParam(kParamSetFieldOrder);
997             param->setLabel(kParamSetFieldOrderLabel);
998             param->setHint(kParamSetFieldOrderHint);
999             param->setDefault(false);
1000             param->setAnimates(false);
1001             desc.addClipPreferencesSlaveParam(*param);
1002             if (page) {
1003                 page->addChild(*param);
1004             }
1005         }
1006 
1007         //// fieldOrder
1008         {
1009             ChoiceParamDescriptor* param = desc.defineChoiceParam(kParamOutputFieldOrder);
1010             param->setLabel(kParamOutputFieldOrderLabel);
1011             param->setHint(kParamOutputFieldOrderHint);
1012             assert(param->getNOptions() == eFieldNone);
1013             param->appendOption( fieldOrderString(eFieldNone) );
1014             assert(param->getNOptions() == eFieldBoth);
1015             param->appendOption( fieldOrderString(eFieldBoth) );
1016             assert(param->getNOptions() == eFieldLower);
1017             param->appendOption( fieldOrderString(eFieldLower) );
1018             assert(param->getNOptions() == eFieldUpper);
1019             param->appendOption( fieldOrderString(eFieldUpper) );
1020             assert(param->getNOptions() == eFieldSingle);
1021             param->appendOption( fieldOrderString(eFieldSingle) );
1022             assert(param->getNOptions() == eFieldDoubled);
1023             param->appendOption( fieldOrderString(eFieldDoubled) );
1024             param->setDefault(eFieldNone);
1025             param->setAnimates(false);
1026             desc.addClipPreferencesSlaveParam(*param);
1027             if (page) {
1028                 page->addChild(*param);
1029             }
1030         }
1031     }
1032 
1033 #ifdef OFX_EXTENSIONS_NATRON
1034     if (gHostDescription.isNatron) {
1035         //// setFormat
1036         {
1037             BooleanParamDescriptor* param = desc.defineBooleanParam(kParamSetFormat);
1038             param->setLabel(kParamSetFormatLabel);
1039             param->setHint(kParamSetFormatHint);
1040             param->setDefault(false);
1041             param->setAnimates(false);
1042             desc.addClipPreferencesSlaveParam(*param);
1043             if (page) {
1044                 page->addChild(*param);
1045             }
1046         }
1047         // extent
1048         {
1049             ChoiceParamDescriptor* param = desc.defineChoiceParam(kParamGeneratorExtent);
1050             param->setLabel(kParamGeneratorExtentLabel);
1051             param->setHint(kParamGeneratorExtentHint);
1052             assert(param->getNOptions() == eGeneratorExtentFormat);
1053             param->appendOption(kParamGeneratorExtentOptionFormat);
1054             assert(param->getNOptions() == eGeneratorExtentSize);
1055             param->appendOption(kParamGeneratorExtentOptionSize);
1056             assert(param->getNOptions() == eGeneratorExtentProject);
1057             param->appendOption(kParamGeneratorExtentOptionProject);
1058             //assert(param->getNOptions() == eGeneratorExtentDefault);
1059             //param->appendOption(kParamGeneratorExtentOptionDefault);
1060             param->setDefault(eGeneratorExtentFormat);
1061             param->setLayoutHint(eLayoutHintNoNewLine, 1);
1062             param->setAnimates(false);
1063             desc.addClipPreferencesSlaveParam(*param);
1064             if (page) {
1065                 page->addChild(*param);
1066             }
1067         }
1068 
1069         // recenter
1070         {
1071             PushButtonParamDescriptor* param = desc.definePushButtonParam(kParamGeneratorCenter);
1072             param->setLabel(kParamGeneratorCenterLabel);
1073             param->setHint(kParamGeneratorCenterHint);
1074             param->setLayoutHint(eLayoutHintNoNewLine, 1);
1075             if (page) {
1076                 page->addChild(*param);
1077             }
1078         }
1079 
1080         // format
1081         {
1082             ChoiceParamDescriptor* param = desc.defineChoiceParam(kParamGeneratorFormat);
1083             param->setLabel(kParamGeneratorFormatLabel);
1084             assert(param->getNOptions() == eParamFormatPCVideo);
1085             param->appendOption(kParamFormatPCVideoLabel, "", kParamFormatPCVideo);
1086             assert(param->getNOptions() == eParamFormatNTSC);
1087             param->appendOption(kParamFormatNTSCLabel, "", kParamFormatNTSC);
1088             assert(param->getNOptions() == eParamFormatPAL);
1089             param->appendOption(kParamFormatPALLabel, "", kParamFormatPAL);
1090             assert(param->getNOptions() == eParamFormatNTSC169);
1091             param->appendOption(kParamFormatNTSC169Label, "", kParamFormatNTSC169);
1092             assert(param->getNOptions() == eParamFormatPAL169);
1093             param->appendOption(kParamFormatPAL169Label, "", kParamFormatPAL169);
1094             assert(param->getNOptions() == eParamFormatHD720);
1095             param->appendOption(kParamFormatHD720Label, "", kParamFormatHD720);
1096             assert(param->getNOptions() == eParamFormatHD);
1097             param->appendOption(kParamFormatHDLabel, "", kParamFormatHD);
1098             assert(param->getNOptions() == eParamFormatUHD4K);
1099             param->appendOption(kParamFormatUHD4KLabel, "", kParamFormatUHD4K);
1100             assert(param->getNOptions() == eParamFormat1kSuper35);
1101             param->appendOption(kParamFormat1kSuper35Label, "", kParamFormat1kSuper35);
1102             assert(param->getNOptions() == eParamFormat1kCinemascope);
1103             param->appendOption(kParamFormat1kCinemascopeLabel, "", kParamFormat1kCinemascope);
1104             assert(param->getNOptions() == eParamFormat2kSuper35);
1105             param->appendOption(kParamFormat2kSuper35Label, "", kParamFormat2kSuper35);
1106             assert(param->getNOptions() == eParamFormat2kCinemascope);
1107             param->appendOption(kParamFormat2kCinemascopeLabel, "", kParamFormat2kCinemascope);
1108             assert(param->getNOptions() == eParamFormat2kDCP);
1109             param->appendOption(kParamFormat2kDCPLabel, "", kParamFormat2kDCP);
1110             assert(param->getNOptions() == eParamFormat4kSuper35);
1111             param->appendOption(kParamFormat4kSuper35Label, "", kParamFormat4kSuper35);
1112             assert(param->getNOptions() == eParamFormat4kCinemascope);
1113             param->appendOption(kParamFormat4kCinemascopeLabel, "", kParamFormat4kCinemascope);
1114             assert(param->getNOptions() == eParamFormat4kDCP);
1115             param->appendOption(kParamFormat4kDCPLabel, "", kParamFormat4kDCP);
1116             assert(param->getNOptions() == eParamFormatSquare256);
1117             param->appendOption(kParamFormatSquare256Label, "", kParamFormatSquare256);
1118             assert(param->getNOptions() == eParamFormatSquare512);
1119             param->appendOption(kParamFormatSquare512Label, "", kParamFormatSquare512);
1120             assert(param->getNOptions() == eParamFormatSquare1k);
1121             param->appendOption(kParamFormatSquare1kLabel, "", kParamFormatSquare1k);
1122             assert(param->getNOptions() == eParamFormatSquare2k);
1123             param->appendOption(kParamFormatSquare2kLabel, "", kParamFormatSquare2k);
1124             param->setDefault(eParamFormatPCVideo);
1125             param->setHint(kParamGeneratorFormatHint);
1126             param->setAnimates(false);
1127             desc.addClipPreferencesSlaveParam(*param);
1128             if (page) {
1129                 page->addChild(*param);
1130             }
1131         }
1132 
1133         {
1134             int w = 0, h = 0;
1135             double par = -1.;
1136             getFormatResolution(eParamFormatPCVideo, &w, &h, &par);
1137             assert(par != -1);
1138             {
1139                 Int2DParamDescriptor* param = desc.defineInt2DParam(kParamGeneratorSize);
1140                 param->setLabel(kParamGeneratorSizeLabel);
1141                 param->setHint(kParamGeneratorSizeHint);
1142                 param->setIsSecretAndDisabled(true);
1143                 param->setDefault(w, h);
1144                 if (page) {
1145                     page->addChild(*param);
1146                 }
1147             }
1148 
1149             {
1150                 DoubleParamDescriptor* param = desc.defineDoubleParam(kParamGeneratorPAR);
1151                 param->setLabel(kParamGeneratorPARLabel);
1152                 param->setHint(kParamGeneratorPARHint);
1153                 param->setIsSecretAndDisabled(true);
1154                 param->setRange(0., DBL_MAX);
1155                 param->setDisplayRange(0.5, 2.);
1156                 param->setDefault(par);
1157                 if (page) {
1158                     page->addChild(*param);
1159                 }
1160             }
1161         }
1162 
1163         // btmLeft
1164         {
1165             Double2DParamDescriptor* param = desc.defineDouble2DParam(kParamRectangleInteractBtmLeft);
1166             param->setLabel(kParamRectangleInteractBtmLeftLabel);
1167             param->setDoubleType(eDoubleTypeXYAbsolute);
1168             if ( param->supportsDefaultCoordinateSystem() ) {
1169                 param->setDefaultCoordinateSystem(eCoordinatesNormalised); // no need of kParamDefaultsNormalised
1170             } else {
1171                 gHostSupportsDefaultCoordinateSystem = false; // no multithread here, see kParamDefaultsNormalised
1172             }
1173             param->setDefault(0., 0.);
1174             param->setRange(-DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
1175             param->setDisplayRange(-10000, -10000, 10000, 10000); // Resolve requires display range or values are clamped to (-1,1)
1176             param->setIncrement(1.);
1177             param->setLayoutHint(eLayoutHintNoNewLine, 1);
1178             param->setHint("Coordinates of the bottom left corner of the size rectangle.");
1179             param->setDigits(0);
1180             if (page) {
1181                 page->addChild(*param);
1182             }
1183         }
1184 
1185         // size
1186         {
1187             Double2DParamDescriptor* param = desc.defineDouble2DParam(kParamRectangleInteractSize);
1188             param->setLabel(kParamRectangleInteractSizeLabel);
1189             param->setDoubleType(eDoubleTypeXY);
1190             if ( param->supportsDefaultCoordinateSystem() ) {
1191                 param->setDefaultCoordinateSystem(eCoordinatesNormalised); // no need of kParamDefaultsNormalised
1192             } else {
1193                 gHostSupportsDefaultCoordinateSystem = false; // no multithread here, see kParamDefaultsNormalised
1194             }
1195             param->setDefault(1., 1.);
1196             param->setRange(0., 0., DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
1197             param->setDisplayRange(0, 0, 10000, 10000); // Resolve requires display range or values are clamped to (-1,1)
1198             param->setIncrement(1.);
1199             param->setDimensionLabels(kParamRectangleInteractSizeDim1, kParamRectangleInteractSizeDim2);
1200             param->setHint("Width and height of the size rectangle.");
1201             param->setIncrement(1.);
1202             param->setDigits(0);
1203             if (page) {
1204                 page->addChild(*param);
1205             }
1206         }
1207     }
1208 #endif // OFX_EXTENSIONS_NATRON
1209 
1210     if (gHostDescription.supportsMultipleClipPARs) {
1211         //// setPixelAspectRatio
1212         {
1213             BooleanParamDescriptor* param = desc.defineBooleanParam(kParamSetPixelAspectRatio);
1214             param->setLabel(kParamSetPixelAspectRatioLabel);
1215             param->setHint(kParamSetPixelAspectRatioHint);
1216             param->setDefault(false);
1217             param->setAnimates(false);
1218             desc.addClipPreferencesSlaveParam(*param);
1219             if (page) {
1220                 page->addChild(*param);
1221             }
1222         }
1223         //// pixelAspectRatio
1224         {
1225             DoubleParamDescriptor* param = desc.defineDoubleParam(kParamOutputPixelAspectRatio);
1226             param->setLabel(kParamOutputPixelAspectRatioLabel);
1227             param->setHint(kParamOutputPixelAspectRatioHint);
1228             param->setDefault(1.);
1229             param->setAnimates(false);
1230             desc.addClipPreferencesSlaveParam(*param);
1231             if (page) {
1232                 page->addChild(*param);
1233             }
1234         }
1235     }
1236 
1237     if (gHostDescription.supportsSetableFrameRate) {
1238         //// setFrameRate
1239         {
1240             BooleanParamDescriptor* param = desc.defineBooleanParam(kParamSetFrameRate);
1241             param->setLabel(kParamSetFrameRateLabel);
1242             param->setHint(kParamSetFrameRateHint);
1243             param->setDefault(false);
1244             param->setAnimates(false);
1245             desc.addClipPreferencesSlaveParam(*param);
1246             if (page) {
1247                 page->addChild(*param);
1248             }
1249         }
1250 
1251         //// frameRate
1252         {
1253             DoubleParamDescriptor* param = desc.defineDoubleParam(kParamOutputFrameRate);
1254             param->setLabel(kParamOutputFrameRateLabel);
1255             param->setHint(kParamOutputFrameRateHint);
1256             param->setDefault(24.);
1257             param->setAnimates(false);
1258             desc.addClipPreferencesSlaveParam(*param);
1259             if (page) {
1260                 page->addChild(*param);
1261             }
1262         }
1263     }
1264 
1265     // clipInfo
1266     {
1267         PushButtonParamDescriptor *param = desc.definePushButtonParam(kParamClipInfo);
1268         param->setLabel(kParamClipInfoLabel);
1269         param->setHint(kParamClipInfoHint);
1270         if (page) {
1271             page->addChild(*param);
1272         }
1273     }
1274 } // NoOpPluginFactory::describeInContext
1275 
1276 ImageEffect*
createInstance(OfxImageEffectHandle handle,ContextEnum)1277 NoOpPluginFactory::createInstance(OfxImageEffectHandle handle,
1278                                   ContextEnum /*context*/)
1279 {
1280     return new NoOpPlugin(handle);
1281 }
1282 
1283 static NoOpPluginFactory p(kPluginIdentifier, kPluginVersionMajor, kPluginVersionMinor);
1284 mRegisterPluginFactoryInstance(p)
1285 
1286 OFXS_NAMESPACE_ANONYMOUS_EXIT
1287