1 /*
2 Software License :
3 
4 Copyright (c) 2007-2009, The Open Effects Association Ltd. All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8 
9     * Redistributions of source code must retain the above copyright notice,
10       this list of conditions and the following disclaimer.
11     * Redistributions in binary form must reproduce the above copyright notice,
12       this list of conditions and the following disclaimer in the documentation
13       and/or other materials provided with the distribution.
14     * Neither the name The Open Effects Association Ltd, nor the names of its
15       contributors may be used to endorse or promote products derived from this
16       software without specific prior written permission.
17 
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 
30 #include <math.h>
31 
32 // ofx
33 #include "ofxCore.h"
34 #include "ofxImageEffect.h"
35 #ifdef OFX_SUPPORTS_DIALOG
36 #include "ofxDialog.h"
37 #endif
38 #ifdef OFX_EXTENSIONS_VEGAS
39 #include "ofxSonyVegas.h"
40 #endif
41 #ifdef OFX_EXTENSIONS_TUTTLE
42 #include "tuttle/ofxReadWrite.h"
43 #endif
44 #ifdef OFX_EXTENSIONS_NUKE
45 #include "nuke/fnOfxExtensions.h"
46 #endif
47 #ifdef OFX_EXTENSIONS_NATRON
48 #include "ofxNatron.h"
49 #endif
50 
51 // ofx host
52 #include "ofxhBinary.h"
53 #include "ofxhPropertySuite.h"
54 #include "ofxhClip.h"
55 #include "ofxhParam.h"
56 #include "ofxhMemory.h"
57 #include "ofxhImageEffect.h"
58 #include "ofxhPluginAPICache.h"
59 #include "ofxhPluginCache.h"
60 #include "ofxhHost.h"
61 #include "ofxhImageEffectAPI.h"
62 #include "ofxhUtilities.h"
63 #ifdef OFX_SUPPORTS_PARAMETRIC
64 #include "ofxhParametricParam.h"
65 #endif
66 #ifdef OFX_SUPPORTS_OPENGLRENDER
67 #include "ofxOpenGLRender.h"
68 #endif
69 #include "ofxOld.h" // old plugins may rely on deprecated properties being present
70 
71 #include <string.h>
72 #include <stdarg.h>
73 
74 namespace OFX {
75 
76   namespace Host {
77 
78     namespace ImageEffect {
79 
80       /// properties common on an effect and a descriptor
81       static const Property::PropSpec effectDescriptorStuff[] = {
82         /* name                                 type                   dim. r/o default value */
83         { kOfxPropType,                         Property::eString,     1, true,  kOfxTypeImageEffect },
84         { kOfxPropLabel,                        Property::eString,     1, false, "" },
85         { kOfxPropShortLabel,                   Property::eString,     1, false, "" },
86         { kOfxPropLongLabel,                    Property::eString,     1, false, "" },
87         { kOfxPropVersion,                      Property::eInt,        0, false, "0" },
88         { kOfxPropVersionLabel,                 Property::eString,     1, false, "" },
89         { kOfxPropPluginDescription,            Property::eString,     1, false, "" },
90         { kOfxImageEffectPropSupportedContexts, Property::eString,     0, false, "" },
91         { kOfxImageEffectPluginPropGrouping,    Property::eString,     1, false, "" },
92         { kOfxImageEffectPluginPropSingleInstance, Property::eInt,     1, false, "0" },
93         { kOfxImageEffectPluginRenderThreadSafety, Property::eString,  1, false, kOfxImageEffectRenderInstanceSafe },
94         { kOfxImageEffectPluginPropHostFrameThreading, Property::eInt, 1, false, "1" },
95         { kOfxImageEffectPluginPropOverlayInteractV1, Property::ePointer, 1, false, NULL },
96         { kOfxImageEffectPropSupportsMultiResolution, Property::eInt,  1, false, "1" } ,
97         { kOfxImageEffectPropSupportsTiles,     Property::eInt,        1, false, "1" },
98         { kOfxImageEffectPropTemporalClipAccess, Property::eInt,       1, false, "0" },
99         { kOfxImageEffectPropSupportedPixelDepths, Property::eString,  0, false, "" },
100         { kOfxImageEffectPluginPropFieldRenderTwiceAlways, Property::eInt, 1, false, "1" } ,
101         { kOfxImageEffectPropSupportsMultipleClipDepths, Property::eInt, 1, false, "0" },
102         { kOfxImageEffectPropSupportsMultipleClipPARs,   Property::eInt, 1, false, "0" },
103         { kOfxImageEffectPropClipPreferencesSlaveParam, Property::eString, 0, false, "" },
104         { kOfxImageEffectInstancePropSequentialRender, Property::eInt, 1, false, "0" },
105         { kOfxImageEffectPropRenderQualityDraft, Property::eInt, 1, false, "0" },
106         { kOfxPluginPropFilePath, Property::eString, 1, true, ""},
107 #ifdef OFX_SUPPORTS_OPENGLRENDER
108         { kOfxImageEffectPropOpenGLRenderSupported, Property::eString, 1, false, "false"}, // OFX 1.3
109         { kOfxOpenGLPropPixelDepth, Property::eString,  0, false, "" },
110 #endif
111 #ifdef OFX_EXTENSIONS_RESOLVE
112         { kOfxImageEffectPropOpenCLRenderSupported, Property::eString, 1, false, "false"},
113         { kOfxImageEffectPropCudaRenderSupported, Property::eString, 1, false, "false" },
114 #endif
115 #ifdef OFX_EXTENSIONS_NUKE
116         { kFnOfxImageEffectPropMultiPlanar,   Property::eInt, 1, false, "0" },
117         { kFnOfxImageEffectPropPassThroughComponents,   Property::eInt, 1, false, "0" },
118         { kFnOfxImageEffectPropViewAware,   Property::eInt, 1, false, "0" },
119         { kFnOfxImageEffectPropViewInvariance,   Property::eInt, 1, false, "0" },
120         { kFnOfxImageEffectCanTransform,   Property::eInt, 1, false, "0" },
121         //{ ".length", Property::eDouble, 1, false, ""}, // Unknown Nuke property
122 #endif
123 #ifdef OFX_EXTENSIONS_TUTTLE
124         { kTuttleOfxImageEffectPropSupportedExtensions, Property::eString,     0, false, "" },
125         { kTuttleOfxImageEffectPropEvaluation, Property::eDouble, 1, false, "-1" },
126 #endif
127 #ifdef OFX_EXTENSIONS_VEGAS
128         { kOfxProbPluginVegasPresetThumbnail,   Property::eString,     0, false, "" },
129         { kOfxImageEffectPropVegasUpliftGUID,   Property::eString,     0, false, "" },
130         { kOfxImageEffectPropHelpFile,          Property::eString,     1, false, "" },
131         { kOfxImageEffectPropHelpContextID,     Property::eInt,        1, false, "0" },
132 #endif
133 #ifdef OFX_EXTENSIONS_NATRON
134         { kNatronOfxImageEffectPluginUsesMultipleThread, Property::eInt, 1, true, "0" },
135         { kNatronOfxImageEffectPropChannelSelector, Property::eString, 1, true, kOfxImageComponentRGBA },
136         { kNatronOfxImageEffectPropHostMasking, Property::eInt, 1, true, "0" },
137         { kNatronOfxImageEffectPropHostMixing, Property::eInt, 1, true, "0" },
138         { kNatronOfxImageEffectPropDeprecated, Property::eInt, 1, true, "0" },
139         { kNatronOfxImageEffectPropProjectId, Property::eString, 1, true, "" },
140         { kNatronOfxImageEffectPropGroupId, Property::eString, 1, true, "" },
141         { kNatronOfxImageEffectPropInstanceId, Property::eString, 1, true, "" },
142         { kNatronOfxPropDescriptionIsMarkdown, Property::eInt,     1, false, "0" },
143         { kNatronOfxImageEffectSelectionRectangle, Property::eDouble,     4, true, "" },
144         { kNatronOfxImageEffectPropDefaultCursors, Property::eString,     0, true, "" },
145         { kNatronOfxImageEffectPropInViewerContextParamsOrder, Property::eString,     0, false, "" },
146         { kNatronOfxImageEffectPropInViewerContextDefaultShortcuts, Property::eString, 0, true, "" },
147         { kNatronOfxImageEffectPropInViewerContextShortcutSymbol, Property::eInt, 0, true, "" },
148         { kNatronOfxImageEffectPropInViewerContextShortcutHasControlModifier, Property::eInt, 0, true, "" },
149         { kNatronOfxImageEffectPropInViewerContextShortcutHasShiftModifier, Property::eInt, 0, true, "" },
150         { kNatronOfxImageEffectPropInViewerContextShortcutHasAltModifier, Property::eInt, 0, true, "" },
151         { kNatronOfxImageEffectPropInViewerContextShortcutHasMetaModifier, Property::eInt, 0, true, "" },
152         { kNatronOfxImageEffectPropInViewerContextShortcutHasKeypadModifier, Property::eInt, 0, true, "" },
153         { kNatronOfxPropNativeOverlays, Property::eString, 0, false, ""},
154         { kOfxImageEffectPropCanDistort, Property::eInt, 1, true, "0" },
155         { kOfxImageEffectPropRenderAllPlanes, Property::eInt, 1, true, "0"},
156 #endif
157         Property::propSpecEnd
158       };
159 
160       //
161       // Base
162       //
163 
Base(const Property::Set & set)164       Base::Base(const Property::Set &set)
165         : _properties(set)
166       {}
167 
Base(const Property::PropSpec * propSpec)168       Base::Base(const Property::PropSpec * propSpec)
169         : _properties(propSpec)
170       {}
171 
~Base()172       Base::~Base() {}
173 
174       /// obtain a handle on this for passing to the C api
getHandle() const175       OfxImageEffectHandle Base::getHandle() const {
176         return (OfxImageEffectHandle)this;
177       }
178 
179       /// get the properties set
getProps()180       Property::Set &Base::getProps() {
181         return _properties;
182       }
183 
184       /// get the properties set, const version
getProps() const185       const Property::Set &Base::getProps() const {
186         return _properties;
187       }
188 
189       /// name of the clip
getShortLabel() const190       const std::string &Base::getShortLabel() const
191       {
192         const std::string &s = _properties.getStringProperty(kOfxPropShortLabel);
193         if(s == "") {
194           const std::string &s2 = _properties.getStringProperty(kOfxPropLabel);
195           if(s2 == "") {
196             return _properties.getStringProperty(kOfxPropName);
197           }
198         }
199         return s;
200       }
201 
202       /// name of the clip
getLabel() const203       const std::string &Base::getLabel() const
204       {
205         const std::string &s = _properties.getStringProperty(kOfxPropLabel);
206         if(s == "") {
207           return _properties.getStringProperty(kOfxPropName);
208         }
209         return s;
210       }
211 
212       /// name of the clip
getLongLabel() const213       const std::string &Base::getLongLabel() const
214       {
215         const std::string &s = _properties.getStringProperty(kOfxPropLongLabel);
216         if(s == "") {
217           const std::string &s2 = _properties.getStringProperty(kOfxPropLabel);
218           if(s2 == "") {
219             return _properties.getStringProperty(kOfxPropName);
220           }
221         }
222         return s;
223       }
224 
225       /// is the given context supported
isContextSupported(const std::string & s) const226       bool Base::isContextSupported(const std::string &s) const
227       {
228         return _properties.findStringPropValueIndex(kOfxImageEffectPropSupportedContexts, s) != -1;
229       }
230 
231       /// what is the name of the group the plug-in belongs to
getPluginGrouping() const232       const std::string &Base::getPluginGrouping() const
233       {
234         return _properties.getStringProperty(kOfxImageEffectPluginPropGrouping);
235       }
236 
237       /// is the effect single instance
isSingleInstance() const238       bool Base::isSingleInstance() const
239       {
240         return _properties.getIntProperty(kOfxImageEffectPluginPropSingleInstance) != 0;
241       }
242 
243       /// what is the thread safety on this effect
getRenderThreadSafety() const244       const std::string &Base::getRenderThreadSafety() const
245       {
246         return _properties.getStringProperty(kOfxImageEffectPluginRenderThreadSafety);
247       }
248 
249 #ifdef OFX_EXTENSIONS_NATRON
getUsesMultiThreading() const250       bool Base::getUsesMultiThreading() const
251       {
252         return _properties.getIntProperty(kNatronOfxImageEffectPluginUsesMultipleThread) != 0;
253       }
254 #endif
255 
256       /// should the host attempt to managed multi-threaded rendering if it can
257       /// via tiling or some such
getHostFrameThreading() const258       bool Base::getHostFrameThreading() const
259       {
260         return _properties.getIntProperty(kOfxImageEffectPluginPropHostFrameThreading) != 0;
261       }
262 
263       /// get the overlay interact main entry if it exists
getOverlayInteractMainEntry() const264       OfxPluginEntryPoint *Base::getOverlayInteractMainEntry() const
265       {
266         return (OfxPluginEntryPoint *)(_properties.getPointerProperty(kOfxImageEffectPluginPropOverlayInteractV1));
267       }
268 
269       /// does the effect support images of differing sizes
supportsMultiResolution() const270       bool Base::supportsMultiResolution() const
271       {
272         return _properties.getIntProperty(kOfxImageEffectPropSupportsMultiResolution) != 0;
273       }
274 
275       /// does the effect support tiled rendering
supportsTiles() const276       bool Base::supportsTiles() const
277       {
278         return _properties.getIntProperty(kOfxImageEffectPropSupportsTiles) != 0;
279       }
280 
281       /// does this effect need random temporal access
temporalAccess() const282       bool Base::temporalAccess() const
283       {
284         return _properties.getIntProperty(kOfxImageEffectPropTemporalClipAccess) != 0;
285       }
286 
287       /// is the given RGBA/A pixel depth supported by the effect
isPixelDepthSupported(const std::string & s) const288       bool Base::isPixelDepthSupported(const std::string &s) const
289       {
290         return _properties.findStringPropValueIndex(kOfxImageEffectPropSupportedPixelDepths, s) != -1;
291       }
292 
293 #ifdef OFX_SUPPORTS_OPENGLRENDER
294       /// is the given RGBA/A OpenGL pixel depth supported by the effect
isOpenGLPixelDepthSupported(const std::string & s) const295       bool Base::isOpenGLPixelDepthSupported(const std::string &s) const
296       {
297         // if property is empty, all depths are supported
298         return _properties.getDimension(kOfxOpenGLPropPixelDepth) == 0 || _properties.findStringPropValueIndex(kOfxOpenGLPropPixelDepth, s) != -1;
299       }
300 #endif
301 
302       /// when field rendering, does the effect need to be called
303       /// twice to render a frame in all Base::circumstances (with different fields)
fieldRenderTwiceAlways() const304       bool Base::fieldRenderTwiceAlways() const
305       {
306         return _properties.getIntProperty(kOfxImageEffectPluginPropFieldRenderTwiceAlways) != 0;
307       }
308 
309       /// does the effect support multiple clip depths
supportsMultipleClipDepths() const310       bool Base::supportsMultipleClipDepths() const
311       {
312         return _properties.getIntProperty(kOfxImageEffectPropSupportsMultipleClipDepths) != 0;
313       }
314 
315       /// does the effect support multiple clip pixel aspect ratios
supportsMultipleClipPARs() const316       bool Base::supportsMultipleClipPARs() const
317       {
318         return _properties.getIntProperty(kOfxImageEffectPropSupportsMultipleClipPARs) != 0;
319       }
320 
321       /// does changing the named param re-tigger a clip preferences action
isClipPreferencesSlaveParam(const std::string & s) const322       bool Base::isClipPreferencesSlaveParam(const std::string &s) const
323       {
324         return _properties.findStringPropValueIndex(kOfxImageEffectPropClipPreferencesSlaveParam, s) != -1;
325       }
326 
327 
328       /// does the effect require sequential render
requiresSequentialRender() const329       bool Base::requiresSequentialRender() const
330       {
331         return _properties.getIntProperty(kOfxImageEffectInstancePropSequentialRender) == 1;
332       }
333 
334       /// does the effect prefer sequential render
prefersSequentialRender() const335       bool Base::prefersSequentialRender() const
336       {
337         return _properties.getIntProperty(kOfxImageEffectInstancePropSequentialRender) != 0;
338       }
339 
340       /// does the effect support render quality
supportsRenderQuality() const341       bool Base::supportsRenderQuality() const
342       {
343         return _properties.getIntProperty(kOfxImageEffectPropRenderQualityDraft) != 0;
344       }
345 
346 #ifdef OFX_EXTENSIONS_NUKE
347       /// does this effect handle transform effects
canTransform() const348       bool Base::canTransform() const
349       {
350         return _properties.getIntProperty(kFnOfxImageEffectCanTransform) != 0;
351       }
352 
isMultiPlanar() const353       bool Base::isMultiPlanar() const
354       {
355         return _properties.getIntProperty(kFnOfxImageEffectPropMultiPlanar) != 0;
356       }
357 
isHostMaskingEnabled() const358       bool Base::isHostMaskingEnabled() const
359       {
360         return _properties.getIntProperty(kNatronOfxImageEffectPropHostMasking) != 0;
361       }
362 
isHostMixingEnabled() const363       bool Base::isHostMixingEnabled() const
364       {
365         return _properties.getIntProperty(kNatronOfxImageEffectPropHostMixing) != 0;
366       }
367 
getPassThroughForNonRenderedPlanes() const368       Base::OfxPassThroughLevelEnum Base::getPassThroughForNonRenderedPlanes() const
369       {
370 
371           int p =  _properties.getIntProperty(kFnOfxImageEffectPropPassThroughComponents);
372           if (p == 2) {
373               return Base::ePassThroughLevelEnumRenderAllRequestedPlanes;
374           }
375           if (!isMultiPlanar()) {
376               return Base::ePassThroughLevelEnumPassThroughAllNonRenderedPlanes;
377           }
378           if (p == 0) {
379               return Base::ePassThroughLevelEnumBlockAllNonRenderedPlanes;
380           } else if (p == 1) {
381               return Base::ePassThroughLevelEnumPassThroughAllNonRenderedPlanes;
382           } else {
383               return Base::ePassThroughLevelEnumPassThroughAllNonRenderedPlanes;
384           }
385       }
386 
isViewAware() const387       bool Base::isViewAware() const
388       {
389         return _properties.getIntProperty(kFnOfxImageEffectPropViewAware) != 0;
390       }
391 
getViewInvariance() const392       int Base::getViewInvariance() const
393       {
394         return _properties.getIntProperty(kFnOfxImageEffectPropViewInvariance);
395       }
396 #endif
397 
398 #ifdef OFX_EXTENSIONS_NATRON
canDistort() const399       bool Base::canDistort() const
400       {
401         return _properties.getIntProperty(kOfxImageEffectPropCanDistort) != 0;
402       }
403 
404       /// does this effect handle transform effects
isDeprecated() const405       bool Base::isDeprecated() const
406       {
407         return _properties.getIntProperty(kNatronOfxImageEffectPropDeprecated) != 0;
408       }
409 
isPluginDescriptionInMarkdown() const410       bool Base::isPluginDescriptionInMarkdown() const
411       {
412         return _properties.getIntProperty(kNatronOfxPropDescriptionIsMarkdown) != 0;
413       }
414 
getPluginDefaultShortcuts(std::list<PluginShortcut> * shortcuts) const415       void Base::getPluginDefaultShortcuts(std::list<PluginShortcut>* shortcuts) const
416       {
417         if (!shortcuts) {
418           return;
419         }
420         const int nIds = _properties.getDimension(kNatronOfxImageEffectPropInViewerContextDefaultShortcuts);
421         const int nSyms = _properties.getDimension(kNatronOfxImageEffectPropInViewerContextShortcutSymbol);
422         const int nCtrl = _properties.getDimension(kNatronOfxImageEffectPropInViewerContextShortcutHasControlModifier);
423         const int nShift = _properties.getDimension(kNatronOfxImageEffectPropInViewerContextShortcutHasShiftModifier);
424         const int nAlt = _properties.getDimension(kNatronOfxImageEffectPropInViewerContextShortcutHasAltModifier);
425         const int nMeta = _properties.getDimension(kNatronOfxImageEffectPropInViewerContextShortcutHasMetaModifier);
426         const int nKeypad = _properties.getDimension(kNatronOfxImageEffectPropInViewerContextShortcutHasKeypadModifier);
427 
428         // Invalid properties
429         if (nIds != nSyms || nIds != nCtrl || nIds != nShift || nIds != nAlt || nIds != nMeta || nIds != nKeypad) {
430           return;
431         }
432 
433         for (int i = 0; i < nIds; ++i) {
434           PluginShortcut p;
435           p.shortcutID = _properties.getStringProperty(kNatronOfxImageEffectPropInViewerContextDefaultShortcuts, i);
436           p.symbol = _properties.getIntProperty(kNatronOfxImageEffectPropInViewerContextShortcutSymbol, i);
437           p.hasCtrlModifier = _properties.getIntProperty(kNatronOfxImageEffectPropInViewerContextShortcutHasControlModifier, i);
438           p.hasShiftModifier = _properties.getIntProperty(kNatronOfxImageEffectPropInViewerContextShortcutHasShiftModifier, i);
439           p.hasAltModifier = _properties.getIntProperty(kNatronOfxImageEffectPropInViewerContextShortcutHasAltModifier, i);
440           p.hasMetaModifier = _properties.getIntProperty(kNatronOfxImageEffectPropInViewerContextShortcutHasMetaModifier, i);
441           p.hasKeypadModifier = _properties.getIntProperty(kNatronOfxImageEffectPropInViewerContextShortcutHasKeypadModifier, i);
442           shortcuts->push_back(p);
443         }
444 
445       }
446 
447       // Get a list of the parameters name that are to be displayed in the viewport
getInViewportParametersName(std::list<std::string> * parameterNames) const448       void Base::getInViewportParametersName(std::list<std::string>* parameterNames) const
449       {
450         if (!parameterNames) {
451           return;
452         }
453         const int nItems = _properties.getDimension(kNatronOfxImageEffectPropInViewerContextParamsOrder);
454         for (int i = 0; i < nItems; ++i) {
455           std::string paramName = _properties.getStringProperty(kNatronOfxImageEffectPropInViewerContextParamsOrder, i);
456           parameterNames->push_back(paramName);
457         }
458       }
459 
460       // Get a list of the cursors used by this plug-in
getDefaultCursors(std::list<std::string> * cursors) const461       void Base::getDefaultCursors(std::list<std::string>* cursors) const
462       {
463         if (!cursors) {
464           return;
465         }
466         const int nItems = _properties.getDimension(kNatronOfxImageEffectPropDefaultCursors);
467         for (int i = 0; i < nItems; ++i) {
468           std::string cursor = _properties.getStringProperty(kNatronOfxImageEffectPropDefaultCursors, i);
469           cursors->push_back(cursor);
470         }
471       }
472 
473       // Update the selection rectangle property
setSelectionRectangleState(double x1,double y1,double x2,double y2)474       void Base::setSelectionRectangleState(double x1, double y1, double x2, double y2)
475       {
476         _properties.setDoubleProperty(kNatronOfxImageEffectSelectionRectangle, x1, 0);
477         _properties.setDoubleProperty(kNatronOfxImageEffectSelectionRectangle, y1, 1);
478         _properties.setDoubleProperty(kNatronOfxImageEffectSelectionRectangle, x2, 2);
479         _properties.setDoubleProperty(kNatronOfxImageEffectSelectionRectangle, y2, 3);
480       }
481 
482 #endif // OFX_EXTENSIONS_NATRON
483       ////////////////////////////////////////////////////////////////////////////////
484       // descriptor
485 
Descriptor(Plugin * plug)486       Descriptor::Descriptor(Plugin *plug)
487         : Base(effectDescriptorStuff)
488         , _plugin(plug)
489       {
490         _properties.setStringProperty(kOfxPluginPropFilePath, plug->getBinary()->getBundlePath());
491         gImageEffectHost->initDescriptor(this);
492       }
493 
Descriptor(const Descriptor & other,Plugin * plug)494       Descriptor::Descriptor(const Descriptor &other, Plugin *plug)
495         : Base(other._properties)
496         , _plugin(plug)
497       {
498         _properties.setStringProperty(kOfxPluginPropFilePath, plug->getBinary()->getBundlePath());
499         gImageEffectHost->initDescriptor(this);
500       }
501 
Descriptor(const std::string & bundlePath,Plugin * plug)502       Descriptor::Descriptor(const std::string &bundlePath, Plugin *plug)
503         : Base(effectDescriptorStuff)
504         , _plugin(plug)
505       {
506         _properties.setStringProperty(kOfxPluginPropFilePath, bundlePath);
507         gImageEffectHost->initDescriptor(this);
508       }
509 
~Descriptor()510       Descriptor::~Descriptor()
511       {
512         for(std::map<std::string, ClipDescriptor*>::iterator it = _clips.begin(); it != _clips.end(); ++it)
513           delete it->second;
514         _clips.clear();
515       }
516 
517 
518       /// create a new clip and add this to the clip map
defineClip(const std::string & name)519       ClipDescriptor *Descriptor::defineClip(const std::string &name) {
520         ClipDescriptor *c = new ClipDescriptor(name);
521         _clips[name] = c;
522         _clipsByOrder.push_back(c);
523         return c;
524       }
525 
526       /// implemented for Param::SetDescriptor
getParamSetProps()527       Property::Set &Descriptor::getParamSetProps()
528       {
529         return _properties;
530       }
531 
532       /// get the interact description, this will also call describe on the interact
getOverlayDescriptor(int bitDepthPerComponent,bool hasAlpha)533       Interact::Descriptor &Descriptor::getOverlayDescriptor(int bitDepthPerComponent, bool hasAlpha)
534       {
535         if(_overlayDescriptor.getState() == Interact::eUninitialised) {
536           // OK, we need to describe it, set the entry point and describe away
537           _overlayDescriptor.setEntryPoint(getOverlayInteractMainEntry());
538           _overlayDescriptor.describe(bitDepthPerComponent, hasAlpha);
539         }
540 
541         return _overlayDescriptor;
542       }
543 
544       /// get the clips
getClips() const545       const std::map<std::string, ClipDescriptor*> &Descriptor::getClips() const {
546         return _clips;
547       }
548 
addClip(const std::string & name,ClipDescriptor * clip)549       void Descriptor::addClip(const std::string &name, ClipDescriptor *clip) {
550         _clips[name] = clip;
551         _clipsByOrder.push_back(clip);
552       }
553 
554       //
555       // Instance
556       //
557 
558       static const Property::PropSpec effectInstanceStuff[] = {
559         /* name                                 type                   dim.   r/o    default value */
560         { kOfxImageEffectPropContext,           Property::eString,     1, true, "" },
561         { kOfxPropInstanceData,                 Property::ePointer,    1, false, NULL },
562         { kOfxImageEffectPropPluginHandle,      Property::ePointer,    1, false, NULL },
563         { kOfxImageEffectPropProjectSize,       Property::eDouble,     2, true,  "0" },
564         { kOfxImageEffectPropProjectOffset,     Property::eDouble,     2, true,  "0" },
565         { kOfxImageEffectPropProjectExtent,     Property::eDouble,     2, true,  "0" },
566         { kOfxImageEffectPropProjectPixelAspectRatio, Property::eDouble, 1, true,  "0" },
567         { kOfxImageEffectInstancePropEffectDuration, Property::eDouble, 1, true,  "0" },
568         { kOfxImageEffectPropFrameRate ,        Property::eDouble,     1, true,  "0" },
569         { kOfxPropIsInteractive,                Property::eInt,        1, true, "0" },
570 #     ifdef kOfxImageEffectPropInAnalysis
571         { kOfxImageEffectPropInAnalysis,        Property::eInt,        1, false, "0" }, // removed in OFX 1.4
572 #     endif
573 #     ifdef OFX_EXTENSIONS_NUKE
574         //{ ".verbosityProp",                Property::eInt,        2, true, "0" }, // Unknown Nuke property
575 #     endif
576 #     ifdef OFX_EXTENSIONS_VEGAS
577         { kOfxImageEffectPropVegasContext,      Property::eString,     1, true, "" },
578 #     endif
579 #     ifdef OFX_EXTENSIONS_NATRON
580         { kNatronOfxExtraCreatedPlanes,         Property::eString,    0, true, ""},
581 #     endif
582         Property::propSpecEnd
583       };
584 
Instance(ImageEffectPlugin * plugin,Descriptor & other,const std::string & context,bool interactive)585       Instance::Instance(ImageEffectPlugin* plugin,
586                          Descriptor         &other,
587                          const std::string  &context,
588                          bool               interactive)
589         : Base(other)
590         , _plugin(plugin)
591         , _context(context)
592         , _descriptor(&other)
593         , _interactive(interactive)
594         , _created(false)
595         , _ownsData(true)
596         , _clipPrefsDirty(true)
597         , _continuousSamples(false)
598         , _frameVarying(false)
599         , _outputFrameRate(24)
600       {
601         int i = 0;
602 
603         // this will add parameters that are needed in an instance but not a Descriptor
604         _properties.addProperties(effectInstanceStuff);
605         _properties.setChainedSet(&other.getProps());
606 
607         _properties.setPointerProperty(kOfxImageEffectPropPluginHandle, _plugin->getPluginHandle()->getOfxPlugin());
608 
609         _properties.setStringProperty(kOfxImageEffectPropContext,context);
610         _properties.setIntProperty(kOfxPropIsInteractive,interactive);
611 
612         while(effectInstanceStuff[i].name) {
613 
614           // don't set hooks for context or isinteractive or kOfxImageEffectInstancePropSequentialRender
615           // since we only set hook on the double properties anyway, don't do these comparisons since these properties
616           // are not of type Property::eDouble
617 
618           //if(strcmp(effectInstanceStuff[i].name,kOfxImageEffectPropContext) &&
619           //   strcmp(effectInstanceStuff[i].name,kOfxPropIsInteractive) &&
620           //   strcmp(effectInstanceStuff[i].name,kOfxImageEffectInstancePropSequentialRender) )
621             {
622               const Property::PropSpec& spec = effectInstanceStuff[i];
623               switch (spec.type) {
624               case Property::eDouble:
625                 _properties.setGetHook(spec.name, this);
626                 break;
627               default:
628                 break;
629               }
630             }
631           i++;
632         }
633       }
634 
Instance(const Instance & other)635       Instance::Instance(const Instance& other)
636       : Base(other)
637       , Param::SetInstance(other)
638       , _plugin(other._plugin)
639       , _context(other._context)
640       , _descriptor(other._descriptor)
641       , _clips(other._clips)
642       , _interactive(other._interactive)
643       , _created(false)
644       , _ownsData(false)
645       , _clipPrefsDirty(other._clipPrefsDirty)
646       , _continuousSamples(other._continuousSamples)
647       , _frameVarying(other._frameVarying)
648       , _outputPreMultiplication(other._outputPreMultiplication)
649       , _outputFielding(other._outputFielding)
650       , _outputFrameRate(other._outputFrameRate)
651       {
652 
653       }
654 
655       /// implemented for Param::SetDescriptor
getParamSetProps()656       Property::Set &Instance::getParamSetProps()
657       {
658         return _properties;
659       }
660 
661       /// called after construction to populate clips and params
populate()662       OfxStatus Instance::populate()
663       {
664         const std::vector<ClipDescriptor*>& clips = _descriptor->getClipsByOrder();
665 
666         int counter = 0;
667         for(std::vector<ClipDescriptor*>::const_iterator it=clips.begin();
668             it!=clips.end();
669             ++it, ++counter) {
670             const std::string &name =  (*it)->getName();
671             // foreach clip descriptor make a clip instance
672             ClipInstance* instance = newClipInstance(this, *it, counter);
673             if(!instance) return kOfxStatFailed;
674 
675             _clips[name] = instance;
676           }
677 
678         const std::list<Param::Descriptor*>& map = _descriptor->getParamList();
679 
680         std::map<std::string,std::vector<Param::Instance*> > parameters;
681         std::map<std::string, Param::Instance*> groups;
682 
683         for(std::list<Param::Descriptor*>::const_iterator it=map.begin();
684             it!=map.end();
685             ++it) {
686             Param::Descriptor* descriptor = (*it);
687             // get the param descriptor
688             if(!descriptor) return kOfxStatErrValue;
689 
690             // name of the parameter
691             std::string name = descriptor->getName();
692 
693             // get a param instance from a param descriptor
694             Param::Instance* instance = newParam(name,*descriptor);
695             if(!instance) return kOfxStatFailed;
696 
697             // add the value into the param set instance
698             OfxStatus st = addParam(name,instance);
699             if(st != kOfxStatOK) return st;
700 
701             std::string parent = instance->getParentName();
702 
703             if(parent!="")
704               parameters[parent].push_back(instance);
705 
706             if(instance->getType()==kOfxParamTypeGroup){
707               groups[instance->getName()]=instance;
708             }
709           }
710 
711         // for each group parameter made
712         for(std::map<std::string, Param::Instance*>::iterator it=groups.begin();
713             it!=groups.end();
714             ++it) {
715             // cast to a group instance
716             Param::GroupInstance* group = dynamic_cast<Param::GroupInstance*>(it->second);
717 
718             // if cast ok
719             if(group){
720               // find the parameters whose parent was this group
721               std::map<std::string,std::vector<Param::Instance*> >::iterator it2 = parameters.find(group->getName());
722               if(it2!=parameters.end()){
723                 // associate the group with its children, and the children with its parent group
724                 group->setChildren(it2->second);
725               }
726             }
727           }
728 
729         return kOfxStatOK;
730       }
731 
732       // do nothing
getDimension(const std::string & name) const733       int Instance::getDimension(const std::string &name) const OFX_EXCEPTION_SPEC {
734         printf("failing in %s with name=%s\n", __PRETTY_FUNCTION__, name.c_str());
735         throw Property::Exception(kOfxStatErrMissingHostFeature);
736       }
737 
upperGetDimension(const std::string & name)738       int Instance::upperGetDimension(const std::string &name) {
739         return _properties.getDimension(name);
740       }
741 
notify(const std::string &,bool,int)742       void Instance::notify(const std::string &/*name*/, bool /*singleValue*/, int /*indexOrN*/) OFX_EXCEPTION_SPEC
743       {
744         printf("failing in %s\n", __PRETTY_FUNCTION__);
745       }
746 
747       // don't know what to do
reset(const std::string &)748       void Instance::reset(const std::string &/*name*/) OFX_EXCEPTION_SPEC {
749         printf("failing in %s\n", __PRETTY_FUNCTION__);
750         throw Property::Exception(kOfxStatErrMissingHostFeature);
751       }
752 
753       // get the virutals for viewport size, pixel scale, background colour
getDoubleProperty(const std::string & name,int index) const754       double Instance::getDoubleProperty(const std::string &name, int index) const OFX_EXCEPTION_SPEC
755       {
756         if(name==kOfxImageEffectPropProjectSize){
757           if(index>=2) throw Property::Exception(kOfxStatErrBadIndex);
758           double values[2];
759           getProjectSize(values[0],values[1]);
760           return values[index];
761         }
762         else if(name==kOfxImageEffectPropProjectOffset){
763           if(index>=2) throw Property::Exception(kOfxStatErrBadIndex);
764           double values[2];
765           getProjectOffset(values[0],values[1]);
766           return values[index];
767         }
768         else if(name==kOfxImageEffectPropProjectExtent){
769           if(index>=2) throw Property::Exception(kOfxStatErrBadIndex);
770           double values[2];
771           getProjectExtent(values[0],values[1]);
772           return values[index];
773         }
774         else if(name==kOfxImageEffectPropProjectPixelAspectRatio){
775           if(index>=1) throw Property::Exception(kOfxStatErrBadIndex);
776           return getProjectPixelAspectRatio();
777         }
778         else if(name==kOfxImageEffectInstancePropEffectDuration){
779           if(index>=1) throw Property::Exception(kOfxStatErrBadIndex);
780           return getEffectDuration();
781         }
782         else if(name==kOfxImageEffectPropFrameRate){
783           if(index>=1) throw Property::Exception(kOfxStatErrBadIndex);
784           return getFrameRate();
785         }
786         else
787           throw Property::Exception(kOfxStatErrUnknown);
788       }
789 
getDoublePropertyN(const std::string & name,double * first,int n) const790       void Instance::getDoublePropertyN(const std::string &name, double* first, int n) const OFX_EXCEPTION_SPEC
791       {
792         if(name==kOfxImageEffectPropProjectSize){
793           if(n>2) throw Property::Exception(kOfxStatErrBadIndex);
794           getProjectSize(first[0],first[1]);
795         }
796         else if(name==kOfxImageEffectPropProjectOffset){
797           if(n>2) throw Property::Exception(kOfxStatErrBadIndex);
798           getProjectOffset(first[0],first[1]);
799         }
800         else if(name==kOfxImageEffectPropProjectExtent){
801           if(n>2) throw Property::Exception(kOfxStatErrBadIndex);
802           getProjectExtent(first[0],first[1]);
803         }
804         else if(name==kOfxImageEffectPropProjectPixelAspectRatio){
805           if(n>1) throw Property::Exception(kOfxStatErrBadIndex);
806           *first = getProjectPixelAspectRatio();
807         }
808         else if(name==kOfxImageEffectInstancePropEffectDuration){
809           if(n>1) throw Property::Exception(kOfxStatErrBadIndex);
810           *first = getEffectDuration();
811         }
812         else if(name==kOfxImageEffectPropFrameRate){
813           if(n>1) throw Property::Exception(kOfxStatErrBadIndex);
814           *first = getFrameRate();
815         }
816         else
817           throw Property::Exception(kOfxStatErrUnknown);
818       }
819 
getStringProperty(const std::string & name,int n) const820       const std::string &Instance::getStringProperty(const std::string &name, int n) const OFX_EXCEPTION_SPEC
821       {
822 #ifdef OFX_EXTENSIONS_NUKE
823         if (name==kNatronOfxExtraCreatedPlanes) {
824           const std::vector<std::string>& userPlanes = getUserCreatedPlanes();
825           if (n >= 0 && n < (int)userPlanes.size()) {
826             return userPlanes[n];
827           } else {
828             throw Property::Exception(kOfxStatErrBadIndex);
829           }
830         }
831 #endif
832         throw Property::Exception(kOfxStatErrValue);
833       }
834 
getStringPropertyN(const std::string & name,const char ** values,int count) const835       void Instance::getStringPropertyN(const std::string &name, const char** values, int count) const OFX_EXCEPTION_SPEC
836       {
837         if (count <= 0) throw Property::Exception(kOfxStatErrValue);
838 #ifdef OFX_EXTENSIONS_NATRON
839         if (name==kNatronOfxExtraCreatedPlanes) {
840           const std::vector<std::string>& componentsPresents = getUserCreatedPlanes();
841           int minCount = (int)componentsPresents.size() < count ? (int)componentsPresents.size() : count;
842           for (int i = 0; i < minCount; ++i) {
843             values[i] = componentsPresents[i].c_str();
844           }
845           return;
846         }
847 #endif
848         throw Property::Exception(kOfxStatErrValue);
849       }
850 
851 #ifdef OFX_EXTENSIONS_NATRON
getUserCreatedPlanes() const852       const std::vector<std::string>& Instance::getUserCreatedPlanes() const
853       {
854         static const std::vector<std::string> emptyVec;
855         return emptyVec;
856       }
857 
858 #endif
859 
~Instance()860       Instance::~Instance(){
861         // destroy the instance, only if succesfully created
862         if (_created) {
863 #         ifdef OFX_DEBUG_ACTIONS
864           std::cout << "OFX WARNING: OFX::Host::ImageEffect::Instance::destroyInstanceAction() was not called before the OFX::Host::ImageEffect::Instance destructor."<<std::endl;
865 #         endif
866           destroyInstanceAction();
867         }
868         /// clobber my clips
869         if (_ownsData) {
870           std::map<std::string, ClipInstance*>::iterator i;
871           for(i = _clips.begin(); i != _clips.end(); ++i) {
872             if(i->second)
873               delete i->second;
874             i->second = NULL;
875           }
876         }
877       }
878 
879       /// this is used to populate with any extra action in argumnents that may be needed
setCustomInArgs(const std::string &,Property::Set &)880       void Instance::setCustomInArgs(const std::string &/*action*/, Property::Set &/*inArgs*/)
881       {
882       }
883 
884       /// this is used to populate with any extra action out argumnents that may be needed
setCustomOutArgs(const std::string &,Property::Set &)885       void Instance::setCustomOutArgs(const std::string &/*action*/, Property::Set &/*outArgs*/)
886       {
887       }
888 
889       /// this is used to populate with any extra action out argumnents that may be needed
examineOutArgs(const std::string &,OfxStatus,const Property::Set &)890       void Instance::examineOutArgs(const std::string &/*action*/, OfxStatus, const Property::Set &/*outArgs*/)
891       {
892       }
893 
894       /// check for connection
checkClipConnectionStatus() const895       bool Instance::checkClipConnectionStatus() const
896       {
897         std::map<std::string, ClipInstance*>::const_iterator i;
898         for(i = _clips.begin(); i != _clips.end(); ++i) {
899           if(!i->second->isOptional() && !i->second->getConnected()) {
900             return false;
901           }
902         }
903         return true;
904       }
905 
906       // override this to make processing abort, return 1 to abort processing
abort()907       int Instance::abort() {
908         return 0;
909       }
910 
911       // override this to use your own memory instance - must inherrit from memory::instance
newMemoryInstance(size_t)912       Memory::Instance* Instance::newMemoryInstance(size_t /*nBytes*/) {
913         return 0;
914       }
915 
916       // return an memory::instance calls makeMemoryInstance that can be overriden
imageMemoryAlloc(size_t nBytes)917       Memory::Instance* Instance::imageMemoryAlloc(size_t nBytes){
918         Memory::Instance* instance = newMemoryInstance(nBytes);
919         if(instance)
920           return instance;
921         else{
922           Memory::Instance* instance = new Memory::Instance;
923           instance->alloc(nBytes);
924           return instance;
925         }
926       }
927 
928       // call the effect entry point
mainEntry(const char * action,const void * handle,Property::Set * inArgs,Property::Set * outArgs)929       OfxStatus Instance::mainEntry(const char *action,
930                                     const void *handle,
931                                     Property::Set *inArgs,
932                                     Property::Set *outArgs)
933       {
934         if(_plugin){
935           PluginHandle* pHandle = _plugin->getPluginHandle();
936           if(pHandle){
937             OfxPlugin* ofxPlugin = pHandle->getOfxPlugin();
938             if(ofxPlugin){
939 
940               OfxPropertySetHandle inHandle = 0;
941               if(inArgs) {
942                 setCustomInArgs(action, *inArgs);
943                 inHandle = inArgs->getHandle();
944               }
945 
946               OfxPropertySetHandle outHandle = 0;
947               if(outArgs) {
948                 setCustomOutArgs(action, *outArgs);
949                 outHandle = outArgs->getHandle();
950               }
951 
952               OfxStatus stat;
953               try {
954                  stat = ofxPlugin->mainEntry(action, handle, inHandle, outHandle);
955               } CatchAllSetStatus(stat, gImageEffectHost, ofxPlugin, action);
956 
957               if(outArgs)
958                 examineOutArgs(action, stat, *outArgs);
959 
960               return stat;
961             }
962             return kOfxStatFailed;
963           }
964           return kOfxStatFailed;
965         }
966         return kOfxStatFailed;
967       }
968 
969       // get the nth clip, in order of declaration
getNthClip(int index)970       ClipInstance* Instance::getNthClip(int index)
971       {
972         const std::string name = _descriptor->getClipsByOrder()[index]->getName();
973         return _clips[name];
974       }
975 
getClip(const std::string & name) const976       ClipInstance* Instance::getClip(const std::string& name) const {
977         std::map<std::string,ClipInstance*>::const_iterator it = _clips.find(name);
978         if(it!=_clips.end()){
979           return it->second;
980         }
981         return 0;
982       }
983 
984       // create an image effect instance
createInstanceAction()985       OfxStatus Instance::createInstanceAction()
986       {
987         /// we need to init the clips before we call create instance incase
988         /// they try and fetch something in create instance, which they are allowed
989         setDefaultClipPreferences();
990 
991 #       ifdef OFX_DEBUG_ACTIONS
992           OfxPlugin *ofxp = _plugin->getPluginHandle()->getOfxPlugin();
993           const char* id = ofxp->pluginIdentifier;
994           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxActionCreateInstance<<"()"<<std::endl;
995 #       endif
996         // now tell the plug-in to create instance
997         OfxStatus st = mainEntry(kOfxActionCreateInstance,this->getHandle(),0,0);
998 #       ifdef OFX_DEBUG_ACTIONS
999           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxActionCreateInstance<<"()->"<<StatStr(st)<<std::endl;
1000 #       endif
1001 
1002         if (st == kOfxStatOK) {
1003           _created = true;
1004         }
1005 
1006         return st;
1007       }
1008 
1009       // destroy the instance, only if succesfully created
destroyInstanceAction()1010       OfxStatus Instance::destroyInstanceAction()
1011       {
1012         OfxStatus st = kOfxStatFailed;
1013         if (_created) {
1014 #         ifdef OFX_DEBUG_ACTIONS
1015             OfxPlugin *ofxp = _plugin->getPluginHandle()->getOfxPlugin();
1016             const char* id = ofxp->pluginIdentifier;
1017             std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxActionDestroyInstance<<"()"<<std::endl;
1018 #         endif
1019           OfxStatus st = mainEntry(kOfxActionDestroyInstance,this->getHandle(),0,0);
1020 #         ifdef OFX_DEBUG_ACTIONS
1021             std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxActionDestroyInstance<<"()->"<<StatStr(st)<<std::endl;
1022 #         endif
1023           if (st == kOfxStatOK) {
1024             _created = false;
1025           }
1026         }
1027 
1028         return st;
1029       }
1030 
1031       // begin/change/end instance changed
beginInstanceChangedAction(const std::string & why)1032       OfxStatus Instance::beginInstanceChangedAction(const std::string & why)
1033       {
1034         Property::PropSpec stuff[] = {
1035           { kOfxPropChangeReason, Property::eString, 1, true, why.c_str() },
1036           Property::propSpecEnd
1037         };
1038 
1039         Property::Set inArgs(stuff);
1040 
1041 #       ifdef OFX_DEBUG_ACTIONS
1042           std::cout << "OFX: "<<(void*)this<<"->"<<kOfxActionBeginInstanceChanged<<"("<<why<<")"<<std::endl;
1043 #       endif
1044         OfxStatus st = mainEntry(kOfxActionBeginInstanceChanged,this->getHandle(), &inArgs, 0);
1045 #       ifdef OFX_DEBUG_ACTIONS
1046           std::cout << "OFX: "<<(void*)this<<"->"<<kOfxActionBeginInstanceChanged<<"("<<why<<")->"<<StatStr(st)<<std::endl;
1047 #       endif
1048         return st;
1049       }
1050 
paramInstanceChangedAction(const std::string & paramName,const std::string & why,OfxTime time,OfxPointD renderScale)1051       OfxStatus Instance::paramInstanceChangedAction(const std::string & paramName,
1052                                                      const std::string & why,
1053                                                      OfxTime     time,
1054                                                      OfxPointD   renderScale)
1055       {
1056         Param::Instance* param = getParam(paramName);
1057 
1058         if(isClipPreferencesSlaveParam(paramName))
1059           _clipPrefsDirty = true;
1060 
1061         if (!param) {
1062           return kOfxStatFailed;
1063         }
1064         if ( OFX::IsNaN(time) ) {
1065           return kOfxStatFailed;
1066         }
1067 
1068         Property::PropSpec stuff[] = {
1069           { kOfxPropType, Property::eString, 1, true, kOfxTypeParameter },
1070           { kOfxPropName, Property::eString, 1, true, paramName.c_str() },
1071           { kOfxPropChangeReason, Property::eString, 1, true, why.c_str() },
1072           { kOfxPropTime, Property::eDouble, 1, true, "0" },
1073           { kOfxImageEffectPropRenderScale, Property::eDouble, 2, true, "0" },
1074 #       ifdef OFX_EXTENSIONS_NUKE
1075           { kFnOfxImageEffectPropView, Property::eInt, 1, true, "0" },
1076 #       endif
1077           Property::propSpecEnd
1078         };
1079 
1080         Property::Set inArgs(stuff);
1081 
1082         // add the second dimension of the render scale
1083         inArgs.setDoubleProperty(kOfxPropTime,time);
1084 
1085         inArgs.setDoublePropertyN(kOfxImageEffectPropRenderScale, &renderScale.x, 2);
1086 #       ifdef OFX_DEBUG_ACTIONS
1087           std::cout << "OFX: "<<(void*)this<<"->"<<kOfxActionInstanceChanged<<"("<<kOfxTypeParameter<<","<<paramName<<","<<why<<","<<time<<",("<<renderScale.x<<","<<renderScale.y<<"))"<<std::endl;
1088 #       endif
1089 
1090         OfxStatus st = mainEntry(kOfxActionInstanceChanged,this->getHandle(), &inArgs, 0);
1091 #       ifdef OFX_DEBUG_ACTIONS
1092           std::cout << "OFX: "<<(void*)this<<"->"<<kOfxActionInstanceChanged<<"("<<kOfxTypeParameter<<","<<paramName<<","<<why<<","<<time<<",("<<renderScale.x<<","<<renderScale.y<<"))->"<<StatStr(st)<<std::endl;
1093 #       endif
1094         return st;
1095       }
1096 
clipInstanceChangedAction(const std::string & clipName,const std::string & why,OfxTime time,OfxPointD renderScale)1097       OfxStatus Instance::clipInstanceChangedAction(const std::string & clipName,
1098                                                     const std::string & why,
1099                                                     OfxTime     time,
1100                                                     OfxPointD   renderScale)
1101       {
1102         if ( OFX::IsNaN(time) ) {
1103           return kOfxStatFailed;
1104         }
1105         _clipPrefsDirty = true;
1106         std::map<std::string,ClipInstance*>::iterator it=_clips.find(clipName);
1107         if(it!=_clips.end())
1108           return (it->second)->instanceChangedAction(why,time,renderScale);
1109         else
1110           return kOfxStatFailed;
1111       }
1112 
endInstanceChangedAction(const std::string & why)1113       OfxStatus Instance::endInstanceChangedAction(const std::string & why)
1114       {
1115         Property::PropSpec whyStuff[] = {
1116           { kOfxPropChangeReason, Property::eString, 1, true, why.c_str() },
1117           Property::propSpecEnd
1118         };
1119 
1120         Property::Set inArgs(whyStuff);
1121 #       ifdef OFX_DEBUG_ACTIONS
1122           std::cout << "OFX: "<<(void*)this<<"->"<<kOfxActionEndInstanceChanged<<"("<<why<<")"<<std::endl;
1123 #       endif
1124 
1125         OfxStatus st = mainEntry(kOfxActionEndInstanceChanged,this->getHandle(), &inArgs, 0);
1126 #       ifdef OFX_DEBUG_ACTIONS
1127           std::cout << "OFX: "<<(void*)this<<"->"<<kOfxActionEndInstanceChanged<<"("<<why<<")->"<<StatStr(st)<<std::endl;
1128 #       endif
1129         return st;
1130       }
1131 
1132       // purge your caches
purgeCachesAction()1133       OfxStatus Instance::purgeCachesAction(){
1134 #       ifdef OFX_DEBUG_ACTIONS
1135           std::cout << "OFX: "<<(void*)this<<"->"<<kOfxActionPurgeCaches<<"()"<<std::endl;
1136 #       endif
1137         OfxStatus st = mainEntry(kOfxActionPurgeCaches ,this->getHandle(),0,0);
1138 #       ifdef OFX_DEBUG_ACTIONS
1139           std::cout << "OFX: "<<(void*)this<<"->"<<kOfxActionPurgeCaches<<"()->"<<StatStr(st)<<std::endl;
1140 #       endif
1141         return st;
1142       }
1143 
1144       // sync your private data
syncPrivateDataAction()1145       OfxStatus Instance::syncPrivateDataAction(){
1146 #       ifdef OFX_DEBUG_ACTIONS
1147           std::cout << "OFX: "<<(void*)this<<"->"<<kOfxActionSyncPrivateData<<"()"<<std::endl;
1148 #       endif
1149         // Only call kOfxActionSyncPrivateData if kOfxPropParamSetNeedsSyncing is not set,
1150         // or if it is set to 1.
1151         // see http://openfx.sourceforge.net/Documentation/1.3/ofxProgrammingReference.html#kOfxPropParamSetNeedsSyncing
1152         Property::Int* s = _properties.fetchIntProperty(kOfxPropParamSetNeedsSyncing);
1153         bool needsSyncing = s ? s->getValue() : true;
1154         OfxStatus st = kOfxStatReplyDefault;
1155         if (needsSyncing) {
1156           st = mainEntry(kOfxActionSyncPrivateData,this->getHandle(),0,0);
1157           if (s) {
1158             s->setValue(0);
1159           }
1160         }
1161 #       ifdef OFX_DEBUG_ACTIONS
1162           std::cout << "OFX: "<<(void*)this<<"->"<<kOfxActionSyncPrivateData<<"()->"<<StatStr(st)<<std::endl;
1163 #       endif
1164         return st;
1165       }
1166 
1167       // begin/end edit instance
beginInstanceEditAction()1168       OfxStatus Instance::beginInstanceEditAction(){
1169 #       ifdef OFX_DEBUG_ACTIONS
1170           std::cout << "OFX: "<<(void*)this<<"->"<<kOfxActionBeginInstanceEdit<<"()"<<std::endl;
1171 #       endif
1172         OfxStatus st = mainEntry(kOfxActionBeginInstanceEdit,this->getHandle(),0,0);
1173 #       ifdef OFX_DEBUG_ACTIONS
1174           std::cout << "OFX: "<<(void*)this<<"->"<<kOfxActionBeginInstanceEdit<<"()->"<<StatStr(st)<<std::endl;
1175 #       endif
1176         return st;
1177       }
1178 
endInstanceEditAction()1179       OfxStatus Instance::endInstanceEditAction(){
1180 #       ifdef OFX_DEBUG_ACTIONS
1181           std::cout << "OFX: "<<(void*)this<<"->"<<kOfxActionEndInstanceEdit<<"()"<<std::endl;
1182 #       endif
1183         OfxStatus st = mainEntry(kOfxActionEndInstanceEdit,this->getHandle(),0,0);
1184 #       ifdef OFX_DEBUG_ACTIONS
1185           std::cout << "OFX: "<<(void*)this<<"->"<<kOfxActionEndInstanceEdit<<"()->"<<StatStr(st)<<std::endl;
1186 #       endif
1187         return st;
1188       }
1189 
1190 #   ifdef OFX_SUPPORTS_OPENGLRENDER
1191       // attach/detach OpenGL context
contextAttachedAction(void * & contextData)1192       OfxStatus Instance::contextAttachedAction(
1193 #                                              ifdef OFX_EXTENSIONS_NATRON
1194                                                 void* &contextData
1195 #                                              endif
1196                                                 )
1197       {
1198         static const Property::PropSpec outStuff[] = {
1199 #ifdef OFX_EXTENSIONS_NATRON
1200           { kNatronOfxImageEffectPropOpenGLContextData , Property::ePointer, 1, false, NULL },
1201 #endif
1202           Property::propSpecEnd
1203         };
1204 
1205         Property::Set outArgs(outStuff);
1206 
1207 #       ifdef OFX_DEBUG_ACTIONS
1208           std::cout << "OFX: "<<(void*)this<<"->"<<kOfxActionOpenGLContextAttached<<"()"<<std::endl;
1209 #       endif
1210         OfxStatus st = mainEntry(kOfxActionOpenGLContextAttached,this->getHandle(), 0, &outArgs);
1211         if(st == kOfxStatOK || st == kOfxStatReplyDefault) {
1212 #        ifdef OFX_EXTENSIONS_NATRON
1213           contextData = outArgs.getPointerProperty(kNatronOfxImageEffectPropOpenGLContextData);
1214 #        endif
1215         }
1216 #       ifdef OFX_DEBUG_ACTIONS
1217         std::cout << "OFX: "<<(void*)this<<"->"<<kOfxActionOpenGLContextAttached<<"()->"<<StatStr(st);
1218 #        ifdef OFX_EXTENSIONS_NATRON
1219         if(st == kOfxStatOK) {
1220           std::cout << ": (" << contextData << ")";
1221         }
1222 #        endif
1223         std::cout << std::endl;
1224 #       endif
1225         return st;
1226       }
1227 
contextDetachedAction(void * contextData)1228       OfxStatus Instance::contextDetachedAction(
1229 #                                              ifdef OFX_EXTENSIONS_NATRON
1230                                                 void* contextData
1231 #                                              endif
1232                                                 )
1233       {
1234         static const Property::PropSpec inStuff[] = {
1235 #ifdef OFX_EXTENSIONS_NATRON
1236           { kNatronOfxImageEffectPropOpenGLContextData , Property::ePointer, 1, false, NULL },
1237 #endif
1238           Property::propSpecEnd
1239         };
1240 
1241         Property::Set inArgs(inStuff);
1242 
1243 #ifdef OFX_EXTENSIONS_NATRON
1244         inArgs.setPointerProperty(kNatronOfxImageEffectPropOpenGLContextData, contextData);
1245 #endif
1246 
1247 #       ifdef OFX_DEBUG_ACTIONS
1248         std::cout << "OFX: "<<(void*)this<<"->"<<kOfxActionOpenGLContextDetached<<"(";
1249 #       ifdef OFX_EXTENSIONS_NATRON
1250         std:: cout << contextData;
1251 #       endif
1252         std::cout << ")" <<std::endl;
1253 #       endif
1254         OfxStatus st = mainEntry(kOfxActionOpenGLContextDetached,this->getHandle(),&inArgs,0);
1255 #       ifdef OFX_DEBUG_ACTIONS
1256           std::cout << "OFX: "<<(void*)this<<"->"<<kOfxActionOpenGLContextDetached<<"()->"<<StatStr(st)<<std::endl;
1257 #       endif
1258         return st;
1259       }
1260 #   endif
1261 
beginRenderAction(OfxTime startFrame,OfxTime endFrame,OfxTime step,bool interactive,OfxPointD renderScale,bool sequentialRender,bool interactiveRender,bool openGLRender,void * contextData,bool draftRender,int view)1262       OfxStatus Instance::beginRenderAction(OfxTime  startFrame,
1263                                             OfxTime  endFrame,
1264                                             OfxTime  step,
1265                                             bool     interactive,
1266                                             OfxPointD   renderScale,
1267                                             bool     sequentialRender,
1268                                             bool     interactiveRender,
1269 #                                         ifdef OFX_SUPPORTS_OPENGLRENDER
1270                                             bool     openGLRender,
1271 #                                          ifdef OFX_EXTENSIONS_NATRON
1272                                             void*    contextData,
1273 #                                          endif
1274 #                                         endif
1275                                             bool     draftRender
1276 #                                         ifdef OFX_EXTENSIONS_NUKE
1277                                             ,
1278                                             int view
1279 #                                         endif
1280                                             )
1281       {
1282         if ( OFX::IsNaN(startFrame) ||
1283              OFX::IsNaN(endFrame) ||
1284              OFX::IsNaN(step) ) {
1285           return kOfxStatFailed;
1286         }
1287         Property::PropSpec stuff[] = {
1288           { kOfxImageEffectPropFrameRange, Property::eDouble, 2, true, "0" },
1289           { kOfxImageEffectPropFrameStep, Property::eDouble, 1, true, "0" },
1290           { kOfxPropIsInteractive, Property::eInt, 1, true, "0" },
1291           { kOfxImageEffectPropRenderScale, Property::eDouble, 2, true, "0" },
1292           { kOfxImageEffectPropSequentialRenderStatus, Property::eInt, 1, true, "0" },
1293           { kOfxImageEffectPropInteractiveRenderStatus, Property::eInt, 1, true, "0" },
1294 #       ifdef OFX_SUPPORTS_OPENGLRENDER
1295           { kOfxImageEffectPropOpenGLEnabled, Property::eInt, 1, true, "0" }, // OFX 1.3
1296 #        ifdef OFX_EXTENSIONS_NATRON
1297           { kNatronOfxImageEffectPropOpenGLContextData , Property::ePointer, 1, false, NULL },
1298 #        endif
1299 #       endif
1300           { kOfxImageEffectPropRenderQualityDraft, Property::eInt, 1, true, "0" }, // OFX 1.4
1301 #       ifdef OFX_EXTENSIONS_RESOLVE
1302           { kOfxImageEffectPropOpenCLEnabled, Property::eInt, 1, true, "0" },
1303           { kOfxImageEffectPropCudaEnabled, Property::eInt, 1, true, "0" },
1304           { kOfxImageEffectPropOpenCLCommandQueue, Property::ePointer, 1, false, "0" },
1305 #       endif
1306 #       ifdef OFX_EXTENSIONS_NUKE
1307           { kFnOfxImageEffectPropView, Property::eInt, 1, true, "0" },
1308 #       endif
1309           Property::propSpecEnd
1310         };
1311 
1312         Property::Set inArgs(stuff);
1313 
1314         // set up second dimension for frame range and render scale
1315         inArgs.setDoubleProperty(kOfxImageEffectPropFrameRange,startFrame, 0);
1316         inArgs.setDoubleProperty(kOfxImageEffectPropFrameRange,endFrame, 1);
1317 
1318         inArgs.setDoubleProperty(kOfxImageEffectPropFrameStep,step);
1319 
1320         inArgs.setIntProperty(kOfxPropIsInteractive,interactive);
1321 
1322         inArgs.setDoublePropertyN(kOfxImageEffectPropRenderScale, &renderScale.x, 2);
1323 
1324         inArgs.setIntProperty(kOfxImageEffectPropSequentialRenderStatus,sequentialRender);
1325         inArgs.setIntProperty(kOfxImageEffectPropInteractiveRenderStatus,interactiveRender);
1326 #     ifdef OFX_SUPPORTS_OPENGLRENDER
1327         inArgs.setIntProperty(kOfxImageEffectPropOpenGLEnabled,openGLRender);
1328 #      ifdef OFX_EXTENSIONS_NATRON
1329         inArgs.setPointerProperty(kNatronOfxImageEffectPropOpenGLContextData, contextData);
1330 #      endif
1331 #     endif
1332         inArgs.setIntProperty(kOfxImageEffectPropRenderQualityDraft,draftRender);
1333 
1334 #     ifdef OFX_EXTENSIONS_NUKE
1335         inArgs.setIntProperty(kFnOfxImageEffectPropView,view);
1336 #     endif
1337 
1338 #       ifdef OFX_DEBUG_ACTIONS
1339           std::cout << "OFX: "<<(void*)this<<"->"<<kOfxImageEffectActionBeginSequenceRender<<"(("<<startFrame<<","<<endFrame<<"),"<<step<<","<<interactive<<",("<<renderScale.x<<","<<renderScale.y<<"),"<<sequentialRender<<","<<interactiveRender<<","<<draftRender
1340 #         ifdef OFX_EXTENSIONS_NUKE
1341           <<","<<view
1342 #         endif
1343           <<")"<<std::endl;
1344 #       endif
1345 
1346         OfxStatus st = mainEntry(kOfxImageEffectActionBeginSequenceRender, this->getHandle(), &inArgs, 0);
1347 #       ifdef OFX_DEBUG_ACTIONS
1348           std::cout << "OFX: "<<(void*)this<<"->"<<kOfxImageEffectActionBeginSequenceRender<<"(("<<startFrame<<","<<endFrame<<"),"<<step<<","<<interactive<<",("<<renderScale.x<<","<<renderScale.y<<"),"<<sequentialRender<<","<<interactiveRender<<","<<draftRender
1349 #         ifdef OFX_EXTENSIONS_NUKE
1350           <<","<<view
1351 #         endif
1352           <<")->"<<StatStr(st)<<std::endl;
1353 #       endif
1354         return st;
1355       }
1356 
renderAction(OfxTime time,const std::string & field,const OfxRectI & renderRoI,OfxPointD renderScale,bool sequentialRender,bool interactiveRender,bool openGLRender,void * contextData,bool draftRender,int view,int nViews,const std::list<std::string> & planes)1357       OfxStatus Instance::renderAction(OfxTime      time,
1358                                        const std::string &  field,
1359                                        const OfxRectI    &renderRoI,
1360                                        OfxPointD   renderScale,
1361                                        bool     sequentialRender,
1362                                        bool     interactiveRender,
1363 #                                    ifdef OFX_SUPPORTS_OPENGLRENDER
1364                                        bool     openGLRender,
1365 #                                     ifdef OFX_EXTENSIONS_NATRON
1366                                        void*    contextData,
1367 #                                     endif
1368 #                                    endif
1369                                        bool     draftRender
1370 #if defined(OFX_EXTENSIONS_VEGAS) || defined(OFX_EXTENSIONS_NUKE)
1371                                        ,
1372                                        int view
1373 #endif
1374 #ifdef OFX_EXTENSIONS_VEGAS
1375                                        ,
1376                                        int nViews
1377 #endif
1378 #ifdef OFX_EXTENSIONS_NUKE
1379                                         ,
1380                                         const std::list<std::string>& planes
1381 #endif
1382                                        )
1383       {
1384         if ( OFX::IsNaN(time) ) {
1385           return kOfxStatFailed;
1386         }
1387         static const Property::PropSpec inStuff[] = {
1388           { kOfxPropTime, Property::eDouble, 1, true, "0" },
1389           { kOfxImageEffectPropFieldToRender, Property::eString, 1, true, "" },
1390           { kOfxImageEffectPropRenderWindow, Property::eInt, 4, true, "0" },
1391           { kOfxImageEffectPropRenderScale, Property::eDouble, 2, true, "0" },
1392           { kOfxImageEffectPropSequentialRenderStatus, Property::eInt, 1, true, "0" },
1393           { kOfxImageEffectPropInteractiveRenderStatus, Property::eInt, 1, true, "0" },
1394 #       ifdef OFX_SUPPORTS_OPENGLRENDER
1395           { kOfxImageEffectPropOpenGLEnabled, Property::eInt, 1, true, "0" }, // OFX 1.3
1396 #        ifdef OFX_EXTENSIONS_NATRON
1397           { kNatronOfxImageEffectPropOpenGLContextData , Property::ePointer, 1, false, "0" },
1398 #        endif
1399 #       endif
1400           { kOfxImageEffectPropRenderQualityDraft, Property::eInt, 1, true, "0" }, // OFX 1.4
1401 #       ifdef OFX_EXTENSIONS_RESOLVE
1402           { kOfxImageEffectPropOpenCLEnabled, Property::eInt, 1, true, "0" },
1403           { kOfxImageEffectPropCudaEnabled, Property::eInt, 1, true, "0" },
1404           { kOfxImageEffectPropOpenCLCommandQueue, Property::ePointer, 1, false, "0" },
1405 #       endif
1406 #       ifdef OFX_EXTENSIONS_VEGAS
1407           { kOfxImageEffectPropRenderView, Property::eInt, 1, true, "0" },
1408           { kOfxImageEffectPropViewsToRender, Property::eInt, 1, true, "1" },
1409           { kOfxImageEffectPropRenderQuality, Property::eString, 1, true, "" },
1410 #       endif
1411 #       ifdef OFX_EXTENSIONS_NUKE
1412           { kFnOfxImageEffectPropView, Property::eInt, 1, true, "0" },
1413           { kOfxImageEffectPropRenderPlanes, Property::eString, 0, true, "" },
1414 #       endif
1415           Property::propSpecEnd
1416         };
1417 
1418         Property::Set inArgs(inStuff);
1419 
1420         inArgs.setStringProperty(kOfxImageEffectPropFieldToRender,field);
1421         inArgs.setDoubleProperty(kOfxPropTime,time);
1422         inArgs.setIntPropertyN(kOfxImageEffectPropRenderWindow, &renderRoI.x1, 4);
1423         inArgs.setDoublePropertyN(kOfxImageEffectPropRenderScale, &renderScale.x, 2);
1424         inArgs.setIntProperty(kOfxImageEffectPropSequentialRenderStatus,sequentialRender);
1425         inArgs.setIntProperty(kOfxImageEffectPropInteractiveRenderStatus,interactiveRender);
1426 #     ifdef OFX_SUPPORTS_OPENGLRENDER
1427         inArgs.setIntProperty(kOfxImageEffectPropOpenGLEnabled,openGLRender);
1428 #      ifdef OFX_EXTENSIONS_NATRON
1429         inArgs.setPointerProperty(kNatronOfxImageEffectPropOpenGLContextData, contextData);
1430 #      endif
1431 #     endif
1432         inArgs.setIntProperty(kOfxImageEffectPropRenderQualityDraft,draftRender);
1433 #     ifdef OFX_EXTENSIONS_VEGAS
1434         inArgs.setIntProperty(kOfxImageEffectPropRenderView,view);
1435         inArgs.setIntProperty(kOfxImageEffectPropViewsToRender,nViews);
1436 #     endif
1437 #     ifdef OFX_EXTENSIONS_NUKE
1438         inArgs.setIntProperty(kFnOfxImageEffectPropView,view);
1439         int k = 0;
1440         for (std::list<std::string>::const_iterator it = planes.begin(); it != planes.end(); ++it,++k) {
1441             inArgs.setStringProperty(kOfxImageEffectPropRenderPlanes,*it,k);
1442         }
1443 #     endif
1444 #     if defined(OFX_EXTENSIONS_VEGAS) || defined(OFX_EXTENSIONS_NUKE)
1445         for(std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
1446             it!=_clips.end();
1447             ++it) {
1448             it->second->setView(view);
1449         }
1450 #     endif
1451 
1452 #       ifdef OFX_DEBUG_ACTIONS
1453           OfxPlugin *ofxp = _plugin->getPluginHandle()->getOfxPlugin();
1454           const char* id = ofxp->pluginIdentifier;
1455           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxImageEffectActionRender<<"("<<time<<","<<field<<",("<<renderRoI.x1<<","<<renderRoI.y1<<","<<renderRoI.x2<<","<<renderRoI.y2<<"),("<<renderScale.x<<","<<renderScale.y<<"),"<<sequentialRender<<","<<interactiveRender<<","<<draftRender
1456 #         if defined(OFX_EXTENSIONS_VEGAS) || defined(OFX_EXTENSIONS_NUKE)
1457           <<","<<view
1458 #         endif
1459 #         ifdef OFX_EXTENSIONS_VEGAS
1460           <<","<<nViews
1461 #         endif
1462           <<")"<<std::endl;
1463 #       endif
1464 
1465         OfxStatus st = mainEntry(kOfxImageEffectActionRender,this->getHandle(), &inArgs, 0);
1466 #       ifdef OFX_DEBUG_ACTIONS
1467           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxImageEffectActionRender<<"("<<time<<","<<field<<",("<<renderRoI.x1<<","<<renderRoI.y1<<","<<renderRoI.x2<<","<<renderRoI.y2<<"),("<<renderScale.x<<","<<renderScale.y<<"),"<<sequentialRender<<","<<interactiveRender<<","<<draftRender
1468 #         if defined(OFX_EXTENSIONS_VEGAS) || defined(OFX_EXTENSIONS_NUKE)
1469           <<","<<view
1470 #         endif
1471 #         ifdef OFX_EXTENSIONS_VEGAS
1472           <<","<<nViews
1473 #         endif
1474           <<")->"<<StatStr(st)<<std::endl;
1475 #       endif
1476         return st;
1477       }
1478 
endRenderAction(OfxTime startFrame,OfxTime endFrame,OfxTime step,bool interactive,OfxPointD renderScale,bool sequentialRender,bool interactiveRender,bool openGLRender,void * contextData,bool draftRender,int view)1479       OfxStatus Instance::endRenderAction(OfxTime  startFrame,
1480                                           OfxTime  endFrame,
1481                                           OfxTime  step,
1482                                           bool     interactive,
1483                                           OfxPointD   renderScale,
1484                                           bool     sequentialRender,
1485                                           bool     interactiveRender,
1486 #                                       ifdef OFX_SUPPORTS_OPENGLRENDER
1487                                           bool     openGLRender,
1488 #                                        ifdef OFX_EXTENSIONS_NATRON
1489                                           void*    contextData,
1490 #                                        endif
1491 #                                       endif
1492                                           bool     draftRender
1493 #                                       ifdef OFX_EXTENSIONS_NUKE
1494                                           ,
1495                                           int view
1496 #                                       endif
1497                                           )
1498       {
1499         if ( OFX::IsNaN(startFrame) ||
1500              OFX::IsNaN(endFrame) ||
1501              OFX::IsNaN(step) ) {
1502           return kOfxStatFailed;
1503         }
1504         static const Property::PropSpec inStuff[] = {
1505           { kOfxImageEffectPropFrameRange, Property::eDouble, 2, true, "0" },
1506           { kOfxImageEffectPropFrameStep, Property::eDouble, 1, true, "0" },
1507           { kOfxPropIsInteractive, Property::eInt, 1, true, "0" },
1508           { kOfxImageEffectPropRenderScale, Property::eDouble, 2, true, "0" },
1509           { kOfxImageEffectPropSequentialRenderStatus, Property::eInt, 1, true, "0" },
1510           { kOfxImageEffectPropInteractiveRenderStatus, Property::eInt, 1, true, "0" },
1511 #       ifdef OFX_SUPPORTS_OPENGLRENDER
1512           { kOfxImageEffectPropOpenGLEnabled, Property::eInt, 1, true, "0" }, // OFX 1.3
1513 #        ifdef OFX_EXTENSIONS_NATRON
1514           { kNatronOfxImageEffectPropOpenGLContextData , Property::ePointer, 1, false, "0" },
1515 #        endif
1516 #       endif
1517           { kOfxImageEffectPropRenderQualityDraft, Property::eInt, 1, true, "0" }, // OFX 1.4
1518 #       ifdef OFX_EXTENSIONS_RESOLVE
1519           { kOfxImageEffectPropOpenCLEnabled, Property::eInt, 1, true, "0" },
1520           { kOfxImageEffectPropCudaEnabled, Property::eInt, 1, true, "0" },
1521           { kOfxImageEffectPropOpenCLCommandQueue, Property::ePointer, 1, false, "0" },
1522 #       endif
1523 #       ifdef OFX_EXTENSIONS_NUKE
1524           { kFnOfxImageEffectPropView, Property::eInt, 1, true, "0" },
1525 #       endif
1526           Property::propSpecEnd
1527         };
1528 
1529         Property::Set inArgs(inStuff);
1530 
1531         inArgs.setDoubleProperty(kOfxImageEffectPropFrameStep,step);
1532 
1533         inArgs.setDoubleProperty(kOfxImageEffectPropFrameRange,startFrame, 0);
1534         inArgs.setDoubleProperty(kOfxImageEffectPropFrameRange,endFrame, 1);
1535         inArgs.setIntProperty(kOfxPropIsInteractive,interactive);
1536         inArgs.setDoublePropertyN(kOfxImageEffectPropRenderScale, &renderScale.x, 2);
1537         inArgs.setIntProperty(kOfxImageEffectPropSequentialRenderStatus,sequentialRender);
1538         inArgs.setIntProperty(kOfxImageEffectPropInteractiveRenderStatus,interactiveRender);
1539 #     ifdef OFX_SUPPORTS_OPENGLRENDER
1540         inArgs.setIntProperty(kOfxImageEffectPropOpenGLEnabled,openGLRender);
1541 #      ifdef OFX_EXTENSIONS_NATRON
1542         inArgs.setPointerProperty(kNatronOfxImageEffectPropOpenGLContextData, contextData);
1543 #      endif
1544 #     endif
1545         inArgs.setIntProperty(kOfxImageEffectPropRenderQualityDraft,draftRender);
1546 #     ifdef OFX_EXTENSIONS_NUKE
1547         inArgs.setIntProperty(kFnOfxImageEffectPropView,view);
1548 #     endif
1549 #       ifdef OFX_DEBUG_ACTIONS
1550           OfxPlugin *ofxp = _plugin->getPluginHandle()->getOfxPlugin();
1551           const char* id = ofxp->pluginIdentifier;
1552           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxImageEffectActionEndSequenceRender<<"(("<<startFrame<<","<<endFrame<<"),"<<step<<","<<interactive<<",("<<renderScale.x<<","<<renderScale.y<<"),"<<sequentialRender<<","<<interactiveRender<<","<<draftRender
1553 #         ifdef OFX_EXTENSIONS_NUKE
1554           <<","<<view
1555 #         endif
1556           <<")"<<std::endl;
1557 #       endif
1558 
1559         OfxStatus st = mainEntry(kOfxImageEffectActionEndSequenceRender,this->getHandle(), &inArgs, 0);
1560 #       ifdef OFX_DEBUG_ACTIONS
1561           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxImageEffectActionEndSequenceRender<<"(("<<startFrame<<","<<endFrame<<"),"<<step<<","<<interactive<<",("<<renderScale.x<<","<<renderScale.y<<"),"<<sequentialRender<<","<<interactiveRender<<","<<draftRender
1562 #         ifdef OFX_EXTENSIONS_NUKE
1563           <<","<<view
1564 #         endif
1565           <<")->"<<StatStr(st)<<std::endl;
1566 #       endif
1567         return st;
1568       }
1569 
1570 #ifdef OFX_EXTENSIONS_NUKE
getTransformAction(OfxTime time,const std::string & field,OfxPointD renderScale,bool draftRender,int view,std::string & clip,double transform[9])1571       OfxStatus Instance::getTransformAction(OfxTime time,
1572                                              const std::string& field,
1573                                              OfxPointD renderScale,
1574                                              bool draftRender,
1575                                              int view,
1576                                              std::string& clip,
1577                                              double transform[9])
1578       {
1579         if ( OFX::IsNaN(time) ) {
1580           return kOfxStatFailed;
1581         }
1582         static const Property::PropSpec inStuff[] = {
1583           { kOfxPropTime, Property::eDouble, 1, true, "0" },
1584           { kOfxImageEffectPropFieldToRender, Property::eString, 1, true, "" },
1585           { kOfxImageEffectPropRenderScale, Property::eDouble, 2, true, "0" },
1586           { kOfxImageEffectPropRenderQualityDraft, Property::eInt, 1, true, "0" }, // OFX 1.4
1587           { kFnOfxImageEffectPropView, Property::eInt, 1, true, "0" },
1588           Property::propSpecEnd
1589         };
1590 
1591         static const Property::PropSpec outStuff[] = {
1592           { kOfxPropName, Property::eString, 1, false, "" },
1593           { kFnOfxPropMatrix2D, Property::eDouble, 9, false, "0.0" },
1594           Property::propSpecEnd
1595         };
1596 
1597         Property::Set inArgs(inStuff);
1598         Property::Set outArgs(outStuff);
1599 
1600         inArgs.setStringProperty(kOfxImageEffectPropFieldToRender,field);
1601         inArgs.setDoubleProperty(kOfxPropTime,time);
1602         inArgs.setDoublePropertyN(kOfxImageEffectPropRenderScale, &renderScale.x, 2);
1603         inArgs.setIntProperty(kOfxImageEffectPropRenderQualityDraft,draftRender);
1604         inArgs.setIntProperty(kFnOfxImageEffectPropView, view);
1605         for(std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
1606             it!=_clips.end();
1607             ++it) {
1608             it->second->setView(view);
1609         }
1610 
1611 #       ifdef OFX_DEBUG_ACTIONS
1612           OfxPlugin *ofxp = _plugin->getPluginHandle()->getOfxPlugin();
1613           const char* id = ofxp->pluginIdentifier;
1614           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kFnOfxImageEffectActionGetTransform<<"("<<time<<","<<field<<",("<<renderScale.x<<","<<renderScale.y<<"),"<<view<<")"<<std::endl;
1615 #       endif
1616 
1617         OfxStatus st = mainEntry(kFnOfxImageEffectActionGetTransform,this->getHandle(), &inArgs, &outArgs);
1618 #       ifdef OFX_DEBUG_ACTIONS
1619           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kFnOfxImageEffectActionGetTransform<<"("<<time<<","<<field<<",("<<renderScale.x<<","<<renderScale.y<<"),"<<view<<")->"<<StatStr(st)<<std::endl;
1620 #       endif
1621 
1622         if(st == kOfxStatOK) {
1623           clip = outArgs.getStringProperty(kOfxPropName);
1624           outArgs.getDoublePropertyN(kFnOfxPropMatrix2D, transform, 9);
1625         }
1626 
1627         return st;
1628       }
1629 #endif // OFX_EXTENSIONS_NUKE
1630 
1631 #ifdef OFX_EXTENSIONS_NATRON
getInverseDistortionAction(OfxTime time,const std::string & field,OfxPointD renderScale,bool draftRender,int view,std::string & clip,double transform[9],OfxInverseDistortionFunctionV1 * distortionFunc,void ** distortionFunctionData,int * distortionFunctionDataSize,OfxInverseDistortionDataFreeFunctionV1 * freeDataFunction)1632       OfxStatus Instance::getInverseDistortionAction(OfxTime time,
1633                                               const std::string& field,
1634                                               OfxPointD renderScale,
1635                                               bool draftRender,
1636                                               int view,
1637                                               std::string& clip,
1638                                               double transform[9],
1639                                               OfxInverseDistortionFunctionV1* distortionFunc,
1640                                               void** distortionFunctionData,
1641                                               int* distortionFunctionDataSize,
1642                                               OfxInverseDistortionDataFreeFunctionV1* freeDataFunction)
1643       {
1644         if ( OFX::IsNaN(time) ) {
1645           return kOfxStatFailed;
1646         }
1647         static const Property::PropSpec inStuff[] = {
1648           { kOfxPropTime, Property::eDouble, 1, true, "0" },
1649           { kOfxImageEffectPropFieldToRender, Property::eString, 1, true, "" },
1650           { kOfxImageEffectPropRenderScale, Property::eDouble, 2, true, "0" },
1651           { kOfxImageEffectPropRenderQualityDraft, Property::eInt, 1, true, "0" }, // OFX 1.4
1652           { kFnOfxImageEffectPropView, Property::eInt, 1, true, "0" },
1653           Property::propSpecEnd
1654         };
1655 
1656         static const Property::PropSpec outStuff[] = {
1657           { kOfxPropName, Property::eString, 1, false, "" },
1658           { kOfxPropMatrix3x3, Property::eDouble, 9, false, "0.0" },
1659           { kOfxPropInverseDistortionFunction, Property::ePointer, 1, false, NULL },
1660           { kOfxPropInverseDistortionFunctionData, Property::ePointer, 1, false, NULL },
1661           { kOfxPropInverseDistortionFunctionDataSize, Property::eInt, 1, false, "0" },
1662           { kOfxPropInverseDistortionDataFreeFunction, Property::ePointer, 1, false, NULL },
1663           Property::propSpecEnd
1664         };
1665 
1666         Property::Set inArgs(inStuff);
1667         Property::Set outArgs(outStuff);
1668 
1669         inArgs.setStringProperty(kOfxImageEffectPropFieldToRender,field);
1670         inArgs.setDoubleProperty(kOfxPropTime,time);
1671         inArgs.setDoublePropertyN(kOfxImageEffectPropRenderScale, &renderScale.x, 2);
1672         inArgs.setIntProperty(kOfxImageEffectPropRenderQualityDraft,draftRender);
1673         inArgs.setIntProperty(kFnOfxImageEffectPropView, view);
1674         for(std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
1675             it!=_clips.end();
1676             ++it) {
1677           it->second->setView(view);
1678         }
1679 
1680 #       ifdef OFX_DEBUG_ACTIONS
1681         OfxPlugin *ofxp = _plugin->getPluginHandle()->getOfxPlugin();
1682         const char* id = ofxp->pluginIdentifier;
1683         std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxImageEffectActionGetInverseDistortion<<"("<<time<<","<<field<<",("<<renderScale.x<<","<<renderScale.y<<"),"<<view<<")"<<std::endl;
1684 #       endif
1685 
1686         OfxStatus st = mainEntry(kOfxImageEffectActionGetInverseDistortion,this->getHandle(), &inArgs, &outArgs);
1687 #       ifdef OFX_DEBUG_ACTIONS
1688         std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxImageEffectActionGetInverseDistortion<<"("<<time<<","<<field<<",("<<renderScale.x<<","<<renderScale.y<<"),"<<view<<")->"<<StatStr(st)<<std::endl;
1689 #       endif
1690 
1691         if (st == kOfxStatOK) {
1692           clip = outArgs.getStringProperty(kOfxPropName);
1693           outArgs.getDoublePropertyN(kOfxPropMatrix3x3, transform, 9);
1694           *distortionFunc = (OfxInverseDistortionFunctionV1)outArgs.getPointerProperty(kOfxPropInverseDistortionFunction);
1695           *distortionFunctionData = outArgs.getPointerProperty(kOfxPropInverseDistortionFunctionData);
1696           *distortionFunctionDataSize = outArgs.getIntProperty(kOfxPropInverseDistortionFunctionDataSize);
1697           *freeDataFunction = (OfxInverseDistortionDataFreeFunctionV1)outArgs.getPointerProperty(kOfxPropInverseDistortionDataFreeFunction);
1698         }
1699 
1700         return st;
1701       }
1702 #endif // OFX_EXTENSIONS_NATRON
1703 
1704       /// calculate the default rod for this effect instance
calcDefaultRegionOfDefinition(OfxTime time,OfxPointD,int view) const1705       OfxRectD Instance::calcDefaultRegionOfDefinition(OfxTime  time,
1706                                                        OfxPointD   /*renderScale*/
1707 #                                                      ifdef OFX_EXTENSIONS_NUKE
1708                                                        ,
1709                                                        int view
1710 #                                                      endif
1711                                                        ) const
1712       {
1713         OfxRectD rod;
1714         if ( OFX::IsNaN(time) ) {
1715           rod.x1 = rod. x2 = rod.y1 = rod.y2 = 0.;
1716           return rod;
1717         }
1718 
1719         // figure out the default contexts
1720         if(
1721 #ifdef OFX_EXTENSIONS_TUTTLE
1722            _context == kOfxImageEffectContextReader ||
1723 #endif
1724            _context == kOfxImageEffectContextGenerator) {
1725           // generator is the extent
1726           rod.x1 = rod.y1 = 0;
1727           getProjectExtent(rod.x2, rod.y2);
1728         }
1729         else if(_context == kOfxImageEffectContextFilter ||
1730 #ifdef OFX_EXTENSIONS_TUTTLE
1731                 _context == kOfxImageEffectContextWriter ||
1732 #endif
1733                 _context == kOfxImageEffectContextPaint) {
1734           // filter and paint default to the input clip
1735           ClipInstance *clip = getClip(kOfxImageEffectSimpleSourceClipName);
1736           if(clip) {
1737 #          ifdef OFX_EXTENSIONS_NUKE
1738             rod = clip->getRegionOfDefinition(time, view);
1739 #          else
1740             rod = clip->getRegionOfDefinition(time);
1741 #          endif
1742           } else {
1743             throw Property::Exception(kOfxStatFailed);
1744           }
1745         }
1746         else if(_context == kOfxImageEffectContextTransition) {
1747           // transition is the union of the two clips
1748           ClipInstance *clipFrom = getClip(kOfxImageEffectTransitionSourceFromClipName);
1749           ClipInstance *clipTo = getClip(kOfxImageEffectTransitionSourceToClipName);
1750           if(clipFrom && clipTo) {
1751 #          ifdef OFX_EXTENSIONS_NUKE
1752             rod = clipFrom->getRegionOfDefinition(time, view);
1753             rod = Union(rod, clipTo->getRegionOfDefinition(time, view));
1754 #          else
1755             rod = clipFrom->getRegionOfDefinition(time);
1756             rod = Union(rod, clipTo->getRegionOfDefinition(time));
1757 #          endif
1758           } else {
1759             throw Property::Exception(kOfxStatFailed);
1760           }
1761         }
1762         else if(_context == kOfxImageEffectContextGeneral
1763 #ifdef OFX_EXTENSIONS_NATRON
1764             || _context == kNatronOfxImageEffectContextTracker
1765 #endif
1766                 ) {
1767           // general context is the union of all the non optional clips
1768           bool gotOne = false;
1769           for(std::map<std::string, ClipInstance*>::const_iterator it=_clips.begin();
1770               it!=_clips.end();
1771               ++it) {
1772             ClipInstance *clip = it->second;
1773             if(!clip->isOutput() && (!clip->isOptional() || (clip->getConnected() && clip->getName() == kOfxImageEffectSimpleSourceClipName))) {
1774 #            ifdef OFX_EXTENSIONS_NUKE
1775               if(!gotOne)
1776                 rod = clip->getRegionOfDefinition(time, view);
1777               else
1778                 rod = Union(rod, clip->getRegionOfDefinition(time, view));
1779 #            else
1780               if(!gotOne)
1781                 rod = clip->getRegionOfDefinition(time);
1782               else
1783                 rod = Union(rod, clip->getRegionOfDefinition(time));
1784 #            endif
1785               gotOne = true;
1786             }
1787           }
1788 
1789           if(!gotOne) {
1790             /// no non optionals? then be the extent
1791             rod.x1 = rod.y1 = 0;
1792             getProjectExtent(rod.x2, rod.y2);
1793           }
1794 
1795         }
1796         else if(_context == kOfxImageEffectContextRetimer) {
1797           // retimer
1798           ClipInstance *clip = getClip(kOfxImageEffectSimpleSourceClipName);
1799           if(clip) {
1800             Param::DoubleInstance *param = dynamic_cast<Param::DoubleInstance *>(getParam(kOfxImageEffectRetimerParamName));
1801             if(param) {
1802               double srctime;
1803               OfxStatus stat = param->get(time, srctime);
1804               if (stat != kOfxStatOK) {
1805                 throw Property::Exception(stat);
1806               }
1807 #            ifdef OFX_EXTENSIONS_NUKE
1808               rod = clip->getRegionOfDefinition(floor(srctime), view);
1809               rod = Union(rod, clip->getRegionOfDefinition(ceil(srctime), view));
1810 #            else
1811               rod = clip->getRegionOfDefinition(floor(srctime));
1812               rod = Union(rod, clip->getRegionOfDefinition(ceil(srctime)));
1813 #            endif
1814             } else {
1815                 throw Property::Exception(kOfxStatFailed);
1816             }
1817           } else {
1818             throw Property::Exception(kOfxStatFailed);
1819           }
1820         }
1821         else {
1822           // unknown context
1823           throw Property::Exception(kOfxStatErrMissingHostFeature);
1824         }
1825 
1826         return rod;
1827       }
1828 
1829       ////////////////////////////////////////////////////////////////////////////////
1830       // RoD call
getRegionOfDefinitionAction(OfxTime time,OfxPointD renderScale,int view,OfxRectD & rod)1831       OfxStatus Instance::getRegionOfDefinitionAction(OfxTime  time,
1832                                                       OfxPointD   renderScale,
1833 #ifdef OFX_EXTENSIONS_NUKE
1834                                                       int view,
1835 #endif
1836                                                       OfxRectD &rod)
1837       {
1838         if ( OFX::IsNaN(time) ) {
1839           return kOfxStatFailed;
1840         }
1841         static const Property::PropSpec inStuff[] = {
1842           { kOfxPropTime, Property::eDouble, 1, true, "0" },
1843           { kOfxImageEffectPropRenderScale, Property::eDouble, 2, true, "0" },
1844 #ifdef OFX_EXTENSIONS_NUKE
1845           { kFnOfxImageEffectPropView, Property::eInt, 1, true, "0" },
1846 #endif
1847           Property::propSpecEnd
1848         };
1849 
1850         static const Property::PropSpec outStuff[] = {
1851           { kOfxImageEffectPropRegionOfDefinition , Property::eDouble, 4, false, "0" },
1852           Property::propSpecEnd
1853         };
1854 
1855         Property::Set inArgs(inStuff);
1856         Property::Set outArgs(outStuff);
1857 
1858         inArgs.setDoubleProperty(kOfxPropTime,time);
1859 #ifdef OFX_EXTENSIONS_NUKE
1860         inArgs.setIntProperty(kFnOfxImageEffectPropView, view);
1861 #endif
1862         inArgs.setDoublePropertyN(kOfxImageEffectPropRenderScale, &renderScale.x, 2);
1863 
1864 #       ifdef OFX_DEBUG_ACTIONS
1865           OfxPlugin *ofxp = _plugin->getPluginHandle()->getOfxPlugin();
1866           const char* id = ofxp->pluginIdentifier;
1867           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxImageEffectActionGetRegionOfDefinition<<"("<<time<<",("<<renderScale.x<<","<<renderScale.y<<"))"<<std::endl;
1868 #       endif
1869         OfxStatus stat = mainEntry(kOfxImageEffectActionGetRegionOfDefinition,
1870                                    this->getHandle(),
1871                                    &inArgs,
1872                                    &outArgs);
1873         if(stat == kOfxStatOK) {
1874           outArgs.getDoublePropertyN(kOfxImageEffectPropRegionOfDefinition, &rod.x1, 4);
1875         }
1876         else if(stat == kOfxStatReplyDefault) {
1877           rod = calcDefaultRegionOfDefinition(time, renderScale
1878 #                                             ifdef OFX_EXTENSIONS_NUKE
1879                                               ,
1880                                               view
1881 #                                             endif
1882                                               );
1883         }
1884 
1885 
1886 #       ifdef OFX_DEBUG_ACTIONS
1887           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxImageEffectActionGetRegionOfDefinition<<"("<<time<<",("<<renderScale.x<<","<<renderScale.y<<"))->"<<StatStr(stat);
1888           if(stat == kOfxStatOK) {
1889               std::cout << ": ("<<rod.x1<<","<<rod.y1<<","<<rod.x2<<","<<rod.y2<<")";
1890           }
1891           std::cout << std::endl;
1892 #       endif
1893 
1894         return stat;
1895       }
1896 
1897       /// get the region of interest for each input and return it in the given std::map
getRegionOfInterestAction(OfxTime time,OfxPointD renderScale,int view,const OfxRectD & roi,std::map<ClipInstance *,OfxRectD> & rois)1898       OfxStatus Instance::getRegionOfInterestAction(OfxTime  time,
1899                                                     OfxPointD   renderScale,
1900 #ifdef OFX_EXTENSIONS_NUKE
1901                                                     int view,
1902 #endif
1903                                                     const OfxRectD &roi,
1904                                                     std::map<ClipInstance *, OfxRectD>& rois)
1905       {
1906         if ( OFX::IsNaN(time) ) {
1907           return kOfxStatFailed;
1908         }
1909         OfxStatus stat = kOfxStatReplyDefault;
1910 
1911         // reset the map
1912         rois.clear();
1913 
1914         // If an effect does not support tiles, it cannot *render* tiles, but it still may implement
1915         // kOfxImageEffectActionGetRegionsOfInterest. For example, if an input clip is not needed, it can
1916         // set the roi to an empty region on that input. On it can set the roi on each input to the
1917         // renderwindow instead of the input region of definition.
1918         // The only difference between effects that support tiles and thos that don't is the defaut
1919         // region set on each input:
1920         // - for effects that support tiles, it is the renderwindow
1921         // - for effect that don't, it is the region of definition of the input clip
1922         //
1923         // Same goes for the input clips: if an input clip does not support tiles, then set the default
1924         // RoI for this clip to its RoD, but still call action and let the effect have the final decision.
1925         bool supportstiles = supportsTiles();
1926 
1927         /// set up the in args
1928         static const Property::PropSpec inStuff[] = {
1929           { kOfxPropTime, Property::eDouble, 1, true, "0" },
1930           { kOfxImageEffectPropRenderScale, Property::eDouble, 2, true, "0" },
1931           { kOfxImageEffectPropRegionOfInterest , Property::eDouble, 4, true, 0 },
1932 #         ifdef OFX_EXTENSIONS_NUKE
1933           { kFnOfxImageEffectPropView, Property::eInt, 1, true, "0" },
1934 #         endif
1935           Property::propSpecEnd
1936         };
1937         Property::Set inArgs(inStuff);
1938 
1939         inArgs.setDoublePropertyN(kOfxImageEffectPropRenderScale, &renderScale.x, 2);
1940         inArgs.setDoubleProperty(kOfxPropTime,time);
1941         inArgs.setDoublePropertyN(kOfxImageEffectPropRegionOfInterest, &roi.x1, 4);
1942 #       ifdef OFX_EXTENSIONS_NUKE
1943         inArgs.setIntProperty(kFnOfxImageEffectPropView, view);
1944 #       endif
1945 
1946         Property::Set outArgs;
1947         for (std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
1948             it!=_clips.end();
1949             ++it) {
1950           if (!it->second->isOutput() ||
1951 #             ifdef OFX_EXTENSIONS_TUTTLE
1952               getContext() == kOfxImageEffectContextReader ||
1953 #             endif
1954               getContext() == kOfxImageEffectContextGenerator) {
1955             Property::PropSpec s;
1956             std::string name = "OfxImageClipPropRoI_"+it->first;
1957 
1958             s.name = name.c_str();
1959             s.type = Property::eDouble;
1960             s.dimension = 4;
1961             s.readonly = false;
1962             s.defaultValue = "";
1963             outArgs.createProperty(s);
1964 
1965             /// initialise to the default
1966             if (supportstiles && it->second->supportsTiles()) {
1967               outArgs.setDoublePropertyN(s.name, &roi.x1, 4);
1968             } else {
1969               OfxRectD rod = roi;
1970               // needed to be able to fetch the RoD
1971               if (it->second->isOutput() || it->second->getConnected()) {
1972 #               ifdef OFX_EXTENSIONS_NUKE
1973                 rod = it->second->getRegionOfDefinition(time, view);
1974 #               else
1975                 rod = it->second->getRegionOfDefinition(time);
1976 #               endif
1977               }
1978               outArgs.setDoublePropertyN(s.name, &rod.x1, 4);
1979             }
1980           }
1981         }
1982 
1983 #       ifdef OFX_DEBUG_ACTIONS
1984         OfxPlugin *ofxp = _plugin->getPluginHandle()->getOfxPlugin();
1985         const char* id = ofxp->pluginIdentifier;
1986         std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxImageEffectActionGetRegionsOfInterest<<"("<<time<<",("<<renderScale.x<<","<<renderScale.y<<"),("<<roi.x1<<","<<roi.y1<<","<<roi.x2<<","<<roi.y2<<"))"<<std::endl;
1987 #       endif
1988         /// call the action
1989         stat = mainEntry(kOfxImageEffectActionGetRegionsOfInterest,
1990                          this->getHandle(),
1991                          &inArgs,
1992                          &outArgs);
1993 
1994 #       ifdef OFX_DEBUG_ACTIONS
1995         std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxImageEffectActionGetRegionsOfInterest<<"("<<time<<",("<<renderScale.x<<","<<renderScale.y<<"),("<<roi.x1<<","<<roi.y1<<","<<roi.x2<<","<<roi.y2<<"))->"<<StatStr(stat);
1996         if (stat == kOfxStatOK) {
1997           std::cout << ": ";
1998           for(std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
1999               it!=_clips.end();
2000               ++it) {
2001             std::string name = "OfxImageClipPropRoI_"+it->first;
2002             OfxRectD thisRoi;
2003             thisRoi.x1 = outArgs.getDoubleProperty(name,0);
2004             thisRoi.y1 = outArgs.getDoubleProperty(name,1);
2005             thisRoi.x2 = outArgs.getDoubleProperty(name,2);
2006             thisRoi.y2 = outArgs.getDoubleProperty(name,3);
2007             std::cout << it->first << "->("<<thisRoi.x1<<","<<thisRoi.y1<<","<<thisRoi.x2<<","<<thisRoi.y2<<") ";
2008           }
2009         }
2010         std::cout << std::endl;
2011 #       endif
2012         // get the results
2013         for (std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
2014              it!=_clips.end();
2015              ++it) {
2016           if (!it->second->isOutput() ||
2017 #ifdef OFX_EXTENSIONS_TUTTLE
2018               getContext() == kOfxImageEffectContextReader ||
2019 #endif
2020               getContext() == kOfxImageEffectContextGenerator) {
2021             if (it->second->isOutput() || it->second->getConnected()) { // needed to be able to fetch the RoD
2022 
2023               std::string name = "OfxImageClipPropRoI_"+it->first;
2024               OfxRectD thisRoi;
2025               thisRoi.x1 = outArgs.getDoubleProperty(name,0);
2026               thisRoi.y1 = outArgs.getDoubleProperty(name,1);
2027               thisRoi.x2 = outArgs.getDoubleProperty(name,2);
2028               thisRoi.y2 = outArgs.getDoubleProperty(name,3);
2029 
2030               // and DON'T clamp it to the clip's rod
2031               // We cannot clip it against the RoD because the RoI may be used for frames
2032               // at different a time or view than the current time and view passed to this action
2033               // which would result in a wrong clipping. Unfortunately only the implementation of
2034               // the host can do the correct clipping.
2035               //thisRoi = Clamp(thisRoi, rod);
2036               rois[it->second] = thisRoi;
2037             }
2038           }
2039         }
2040         return stat;
2041       }
2042 
2043 #ifdef OFX_EXTENSIONS_NUKE
getClipComponentsAction(OfxTime time,int view,ComponentsMap & clipComponents,ClipInstance * & passThroughClip,OfxTime & passThroughTime,int & passThroughView)2044       OfxStatus Instance::getClipComponentsAction(OfxTime time,
2045                                                   int view,
2046                                                   ComponentsMap& clipComponents,
2047                                                   ClipInstance*& passThroughClip,
2048                                                   OfxTime& passThroughTime,
2049                                                   int& passThroughView)
2050       {
2051           if ( OFX::IsNaN(time) ) {
2052               return kOfxStatFailed;
2053           }
2054           OfxStatus stat = kOfxStatReplyDefault;
2055 
2056 
2057           Property::PropSpec inStuff[] = {
2058               { kOfxPropTime, Property::eDouble, 1, true, "0" },
2059               { kFnOfxImageEffectPropView, Property::eInt, 1, true, "0" },
2060               Property::propSpecEnd
2061           };
2062           Property::Set inArgs(inStuff);
2063           inArgs.setDoubleProperty(kOfxPropTime,time);
2064 
2065 
2066           Property::PropSpec outStuff[] = {
2067               { kFnOfxImageEffectPropPassThroughClip, Property::eString, 1, false, "" },
2068               { kFnOfxImageEffectPropPassThroughTime, Property::eDouble, 1, false, "0" },
2069               { kFnOfxImageEffectPropPassThroughView, Property::eInt, 1, false, "0" },
2070               Property::propSpecEnd
2071           };
2072           Property::Set outArgs(outStuff);
2073 
2074           outArgs.setDoubleProperty(kFnOfxImageEffectPropPassThroughTime,time);
2075           outArgs.setIntProperty(kFnOfxImageEffectPropPassThroughView, view);
2076 
2077           bool passThroughSet = false;
2078           ClipInstance* firstNonOptional = 0;
2079 
2080           for(std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
2081               it!=_clips.end();
2082               ++it) {
2083 
2084               if (it->first == kOfxImageEffectSimpleSourceClipName) {
2085                   outArgs.setStringProperty(kFnOfxImageEffectPropPassThroughClip, it->first);
2086                   passThroughSet = true;
2087               } else if (it->first == "A" && !it->second->isOptional()) {
2088                   outArgs.setStringProperty(kFnOfxImageEffectPropPassThroughClip, it->first);
2089                   passThroughSet = true;
2090               }
2091 
2092               if (!passThroughSet && !it->second->isOptional()) {
2093                   firstNonOptional = it->second;
2094               }
2095               Property::PropSpec s;
2096               std::string name = kFnOfxImageEffectActionGetClipComponentsPropString + it->first;
2097 
2098               s.name = name.c_str();
2099               s.type = Property::eString;
2100               s.dimension = 0;
2101               s.readonly = false;
2102               s.defaultValue = "";
2103               outArgs.createProperty(s);
2104 
2105           }
2106           if (firstNonOptional && !passThroughSet) {
2107               outArgs.setStringProperty(kFnOfxImageEffectPropPassThroughClip, firstNonOptional->getName());
2108           }
2109 
2110 #         ifdef OFX_DEBUG_ACTIONS
2111           OfxPlugin *ofxp = _plugin->getPluginHandle()->getOfxPlugin();
2112           const char* id = ofxp->pluginIdentifier;
2113           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kFnOfxImageEffectActionGetClipComponents<<"("<<time<<"," <<  view << ")"<<std::endl;
2114 #         endif
2115 
2116           stat = mainEntry(kFnOfxImageEffectActionGetClipComponents,
2117                            this->getHandle(),
2118                            &inArgs,
2119                            &outArgs);
2120 
2121 #         ifdef OFX_DEBUG_ACTIONS
2122           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kFnOfxImageEffectActionGetClipComponents<<"("<<time<<"," <<  view << ")->"<<StatStr(stat);
2123           if (stat == kOfxStatOK) {
2124               std::cout << ": ";
2125               for(std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
2126                   it!=_clips.end();
2127                   ++it) {
2128                   std::string name = kFnOfxImageEffectActionGetClipComponentsPropString + it->first;
2129                   std::cout << it->first << "->[";
2130 
2131                   int nRanges = outArgs.getDimension(name);
2132                   for(int r=0;r<nRanges;++r){
2133                       std::string component = outArgs.getStringProperty(name,r);
2134                       std::cout <<"("<< component <<")";
2135                       if (r < nRanges-1) {
2136                           std::cout << ",";
2137                       }
2138                   }
2139                   std::cout << "]";
2140 
2141               }
2142           }
2143           std::cout << std::endl;
2144 #         endif
2145 
2146           if (stat == kOfxStatOK) {
2147 
2148               std::string passthroughClipName = outArgs.getStringProperty(kFnOfxImageEffectPropPassThroughClip);
2149 
2150               for(std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
2151                   it!=_clips.end();
2152                   ++it) {
2153                   ClipInstance *clip = it->second;
2154                   std::string name = kFnOfxImageEffectActionGetClipComponentsPropString + it->first;
2155                   int nRanges = outArgs.getDimension(name);
2156                   std::list<std::string> components;
2157                   for (int r = 0 ; r < nRanges; ++r) {
2158                       std::string component = outArgs.getStringProperty(name,r);
2159                       components.push_back(component);
2160                   }
2161                   clipComponents.insert(std::make_pair(clip, components));
2162 
2163                   if (it->first == passthroughClipName) {
2164                       passThroughClip = it->second;
2165                   }
2166               }
2167 
2168               passThroughTime = outArgs.getDoubleProperty(kFnOfxImageEffectPropPassThroughTime);
2169               passThroughView = outArgs.getIntProperty(kFnOfxImageEffectPropPassThroughView);
2170           }
2171           return stat;
2172       }
2173 
getFrameViewsNeeded(OfxTime time,int view,ViewsRangeMap & rangeMap)2174       OfxStatus Instance::getFrameViewsNeeded(OfxTime time,
2175                                               int view,
2176                                               ViewsRangeMap& rangeMap)
2177       {
2178           if ( OFX::IsNaN(time) ) {
2179               return kOfxStatFailed;
2180           }
2181           OfxStatus stat = kOfxStatReplyDefault;
2182           Property::Set outArgs;
2183 
2184 
2185           Property::PropSpec inStuff[] = {
2186               { kOfxPropTime, Property::eDouble, 1, true, "0" },
2187               { kFnOfxImageEffectPropView, Property::eInt, 1, true, "0" },
2188               Property::propSpecEnd
2189           };
2190           Property::Set inArgs(inStuff);
2191           inArgs.setDoubleProperty(kOfxPropTime, time);
2192           inArgs.setIntProperty(kFnOfxImageEffectPropView, view);
2193 
2194           for (std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
2195                it!=_clips.end();
2196                ++it) {
2197               if (!it->second->isOutput()) {
2198                   Property::PropSpec s;
2199                   std::string name = "OfxImageClipPropFrameRangeView_" + it->first;
2200 
2201                   s.name = name.c_str();
2202                   s.type = Property::eDouble;
2203                   s.dimension = 0;
2204                   s.readonly = false;
2205                   s.defaultValue = "";
2206                   outArgs.createProperty(s);
2207                   outArgs.setDoubleProperty(name, time, 0);
2208                   outArgs.setDoubleProperty(name, time, 1);
2209                   outArgs.setDoubleProperty(name, view, 2);
2210               }
2211           }
2212 
2213 #         ifdef OFX_DEBUG_ACTIONS
2214           OfxPlugin *ofxp = _plugin->getPluginHandle()->getOfxPlugin();
2215           const char* id = ofxp->pluginIdentifier;
2216           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kFnOfxImageEffectActionGetFrameViewsNeeded<<"("<<time<<"," <<  view << ")"<<std::endl;
2217 #         endif
2218 
2219           stat = mainEntry(kFnOfxImageEffectActionGetFrameViewsNeeded,
2220                            this->getHandle(),
2221                            &inArgs,
2222                            &outArgs);
2223 
2224 #         ifdef OFX_DEBUG_ACTIONS
2225           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kFnOfxImageEffectActionGetFrameViewsNeeded<<"("<<time<<"," <<  view << ")->"<<StatStr(stat);
2226           if (stat == kOfxStatOK) {
2227               std::cout << ": ";
2228               for(std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
2229                   it!=_clips.end();
2230                   ++it) {
2231                   std::string name = "OfxImageClipPropFrameRangeView_" + it->first;
2232                   std::cout << it->first << "->[";
2233 
2234                   int nRanges = outArgs.getDimension(name);
2235                   for(int r=0;r<nRanges;){
2236                       double min = outArgs.getDoubleProperty(name,r);
2237                       double max = outArgs.getDoubleProperty(name,r+1);
2238                       int view = (int)outArgs.getDoubleProperty(name, r+2);
2239                       r += 3;
2240                       std::cout <<"("<< min <<"," <<max<<","<<view <<")";
2241                       if (r < nRanges-1) {
2242                           std::cout << ",";
2243                       }
2244                   }
2245                   std::cout << "]";
2246 
2247               }
2248           }
2249           std::cout << std::endl;
2250 #         endif
2251 
2252           OfxRangeD defaultRange;
2253           defaultRange.min =
2254           defaultRange.max = time;
2255           int defaultView = view;
2256 
2257           std::vector<OfxRangeD> defaultRangeV;
2258           defaultRangeV.push_back(defaultRange);
2259           std::map<int,std::vector<OfxRangeD> > defaultFrameViewMap;
2260           defaultFrameViewMap.insert(std::make_pair(defaultView, defaultRangeV));
2261 
2262           for(std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
2263               it!=_clips.end();
2264               ++it) {
2265 
2266               if (it->second->isOutput()) {
2267                   continue;
2268               }
2269 
2270               ClipInstance *clip = it->second;
2271               if (stat != kOfxStatOK) {
2272                   rangeMap.insert(std::make_pair(clip, defaultFrameViewMap));
2273               } else {
2274 
2275                   std::map<int,std::vector<OfxRangeD> > frameViewMap;
2276 
2277                   std::string name = "OfxImageClipPropFrameRangeView_" + it->first;
2278                   int nRanges = outArgs.getDimension(name);
2279                   for (int r = 0 ; r < nRanges; ){
2280                       OfxRangeD range;
2281                       range.min = outArgs.getDoubleProperty(name,r);
2282                       range.max = outArgs.getDoubleProperty(name,r+1);
2283                       int view = (int)outArgs.getDoubleProperty(name, r+2);
2284                       r += 3;
2285 
2286 
2287                       std::map<int,std::vector<OfxRangeD> >::iterator foundView = frameViewMap.find(view);
2288                       if (foundView != frameViewMap.end()) {
2289                           foundView->second.push_back(range);
2290                       } else {
2291                           std::vector<OfxRangeD> rangeV;
2292                           rangeV.push_back(range);
2293                           frameViewMap.insert(std::make_pair(view, rangeV));
2294                       }
2295 
2296                   }
2297                   rangeMap.insert(std::make_pair(clip, frameViewMap));
2298               }
2299           }
2300           return stat;
2301       }
2302 #endif
2303 
2304       ////////////////////////////////////////////////////////////////////////////////
2305       /// see how many frames are needed from each clip to render the indicated frame
getFrameNeededAction(OfxTime time,RangeMap & rangeMap)2306       OfxStatus Instance::getFrameNeededAction(OfxTime time,
2307                                                RangeMap &rangeMap)
2308       {
2309         if ( OFX::IsNaN(time) ) {
2310           return kOfxStatFailed;
2311         }
2312         OfxStatus stat = kOfxStatReplyDefault;
2313         Property::Set outArgs;
2314 
2315         if(temporalAccess()) {
2316           static const Property::PropSpec inStuff[] = {
2317             { kOfxPropTime, Property::eDouble, 1, true, "0" },
2318 #ifdef OFX_EXTENSIONS_NUKE
2319             { kFnOfxImageEffectPropView, Property::eInt, 1, true, "0" },
2320 #endif
2321             Property::propSpecEnd
2322           };
2323           Property::Set inArgs(inStuff);
2324           inArgs.setDoubleProperty(kOfxPropTime,time);
2325 
2326 
2327           for(std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
2328               it!=_clips.end();
2329               ++it) {
2330             if(!it->second->isOutput()) {
2331               Property::PropSpec s;
2332               std::string name = "OfxImageClipPropFrameRange_"+it->first;
2333 
2334               s.name = name.c_str();
2335               s.type = Property::eDouble;
2336               s.dimension = 0;
2337               s.readonly = false;
2338               s.defaultValue = "";
2339               outArgs.createProperty(s);
2340               /// intialise it to the current frame
2341               outArgs.setDoubleProperty(name, time, 0);
2342               outArgs.setDoubleProperty(name, time, 1);
2343             }
2344           }
2345 
2346 #         ifdef OFX_DEBUG_ACTIONS
2347             OfxPlugin *ofxp = _plugin->getPluginHandle()->getOfxPlugin();
2348             const char* id = ofxp->pluginIdentifier;
2349             std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxImageEffectActionGetFramesNeeded<<"("<<time<<")"<<std::endl;
2350 #         endif
2351           stat = mainEntry(kOfxImageEffectActionGetFramesNeeded,
2352                            this->getHandle(),
2353                            &inArgs,
2354                            &outArgs);
2355 #         ifdef OFX_DEBUG_ACTIONS
2356             std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxImageEffectActionGetFramesNeeded<<"("<<time<<")->"<<StatStr(stat);
2357             if (stat == kOfxStatOK) {
2358                 std::cout << ": ";
2359                 for(std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
2360                     it!=_clips.end();
2361                     ++it) {
2362                     ClipInstance *clip = it->second;
2363 
2364                     if(!clip->isOutput()) {
2365                         std::string name = "OfxImageClipPropFrameRange_"+it->first;
2366                         std::cout << it->first << "->[";
2367 
2368                         int nRanges = outArgs.getDimension(name);
2369                         for(int r=0;r<nRanges;){
2370                             double min = outArgs.getDoubleProperty(name,r);
2371                             double max = outArgs.getDoubleProperty(name,r+1);
2372                             r += 2;
2373                             std::cout <<"("<<min<<","<<max<<")";
2374                             if (r < nRanges-1) {
2375                                 std::cout << ",";
2376                             }
2377                         }
2378                         std::cout << "]";
2379                     }
2380                 }
2381             }
2382             std::cout << std::endl;
2383 #         endif
2384         }
2385 
2386         OfxRangeD defaultRange;
2387         defaultRange.min =
2388           defaultRange.max = time;
2389 
2390         for(std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
2391             it!=_clips.end();
2392             ++it) {
2393           ClipInstance *clip = it->second;
2394 
2395           if(!clip->isOutput()) {
2396             if(stat != kOfxStatOK) {
2397               rangeMap[clip].push_back(defaultRange);
2398             }
2399             else {
2400               std::string name = "OfxImageClipPropFrameRange_"+it->first;
2401 
2402               int nRanges = outArgs.getDimension(name);
2403               if(nRanges%2 != 0)
2404                 return kOfxStatFailed; // bad! needs to be divisible by 2
2405 
2406               if(nRanges == 0) {
2407                 rangeMap[clip].push_back(defaultRange);
2408               }
2409               else {
2410                 for(int r=0;r<nRanges;){
2411                   double min = outArgs.getDoubleProperty(name,r);
2412                   double max = outArgs.getDoubleProperty(name,r+1);
2413                   r += 2;
2414 
2415                   OfxRangeD range;
2416                   range.min = min;
2417                   range.max = max;
2418                   rangeMap[clip].push_back(range);
2419                 }
2420               }
2421             }
2422           }
2423         }
2424 
2425         return stat;
2426       }
2427 
isIdentityAction(OfxTime & time,const std::string & field,const OfxRectI & renderRoI,OfxPointD renderScale,int & view,std::string & plane,std::string & clip)2428       OfxStatus Instance::isIdentityAction(OfxTime     &time,
2429                                            const std::string &  field,
2430                                            const OfxRectI &renderRoI,
2431                                            OfxPointD   renderScale,
2432 #ifdef OFX_EXTENSIONS_NUKE
2433                                            int& view,
2434                                            std::string& plane,
2435 #endif
2436                                            std::string &clip)
2437       {
2438         if ( OFX::IsNaN(time) ) {
2439           return kOfxStatFailed;
2440         }
2441         static const Property::PropSpec inStuff[] = {
2442           { kOfxPropTime, Property::eDouble, 1, true, "0" },
2443           { kOfxImageEffectPropFieldToRender, Property::eString, 1, true, "" },
2444           { kOfxImageEffectPropRenderWindow, Property::eInt, 4, true, "0" },
2445           { kOfxImageEffectPropRenderScale, Property::eDouble, 2, true, "0" },
2446 #ifdef OFX_EXTENSIONS_NUKE
2447           { kFnOfxImageEffectPropView, Property::eInt, 1, true, "0" },
2448           { kOfxImageEffectPropIdentityPlane, Property::eString, 1, true, ""},
2449 #endif
2450           Property::propSpecEnd
2451         };
2452 
2453         static const Property::PropSpec outStuff[] = {
2454           { kOfxPropTime, Property::eDouble, 1, false, "0.0" },
2455           { kOfxPropName, Property::eString, 1, false, "" },
2456 #ifdef OFX_EXTENSIONS_NUKE
2457           { kFnOfxImageEffectPropView, Property::eInt, 1, true, "0" },
2458           { kOfxImageEffectPropIdentityPlane, Property::eString, 1, true, ""},
2459 #endif
2460           Property::propSpecEnd
2461         };
2462 
2463         Property::Set inArgs(inStuff);
2464 
2465         inArgs.setStringProperty(kOfxImageEffectPropFieldToRender,field);
2466         inArgs.setDoubleProperty(kOfxPropTime,time);
2467         inArgs.setIntPropertyN(kOfxImageEffectPropRenderWindow, &renderRoI.x1, 4);
2468         inArgs.setDoublePropertyN(kOfxImageEffectPropRenderScale, &renderScale.x, 2);
2469 #ifdef OFX_EXTENSIONS_NUKE
2470         inArgs.setIntProperty(kFnOfxImageEffectPropView, view);
2471         inArgs.setStringProperty(kOfxImageEffectPropIdentityPlane, plane);
2472 #endif
2473 
2474         Property::Set outArgs(outStuff);
2475 #ifdef OFX_EXTENSIONS_NUKE
2476         // set the default value on outArgs for backward compatibility
2477         outArgs.setIntProperty(kFnOfxImageEffectPropView, view);
2478         outArgs.setStringProperty(kOfxImageEffectPropIdentityPlane, plane);
2479 #endif
2480 
2481 #       ifdef OFX_DEBUG_ACTIONS
2482           OfxPlugin *ofxp = _plugin->getPluginHandle()->getOfxPlugin();
2483           const char* id = ofxp->pluginIdentifier;
2484           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxImageEffectActionIsIdentity<<"("<<time<<","<<field<<",("<<renderRoI.x1<<","<<renderRoI.y1<<","<<renderRoI.x2<<","<<renderRoI.y2<<"),("<<renderScale.x<<","<<renderScale.y<<"))"<<std::endl;
2485 #       endif
2486         outArgs.setDoubleProperty(kOfxPropTime,time);
2487 
2488         OfxStatus st = mainEntry(kOfxImageEffectActionIsIdentity,
2489                                  this->getHandle(),
2490                                  &inArgs,
2491                                  &outArgs);
2492 
2493 #       ifdef OFX_DEBUG_ACTIONS
2494           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxImageEffectActionIsIdentity<<"("<<time<<","<<field<<",("<<renderRoI.x1<<","<<renderRoI.y1<<","<<renderRoI.x2<<","<<renderRoI.y2<<"),("<<renderScale.x<<","<<renderScale.y<<"))->"<<StatStr(st);
2495           if(st==kOfxStatOK){
2496               std::cout << ": "<<outArgs.getDoubleProperty(kOfxPropTime)<<","<<outArgs.getStringProperty(kOfxPropName);
2497           }
2498           std::cout<<std::endl;
2499 #       endif
2500 
2501         if(st==kOfxStatOK){
2502           time = outArgs.getDoubleProperty(kOfxPropTime);
2503           clip = outArgs.getStringProperty(kOfxPropName);
2504 #ifdef OFX_EXTENSIONS_NUKE
2505           view = outArgs.getIntProperty(kFnOfxImageEffectPropView);
2506           plane = outArgs.getStringProperty(kOfxImageEffectPropIdentityPlane);
2507 #endif
2508         }
2509 
2510         return st;
2511       }
2512 
2513       /// Get whether the component is a supported 'chromatic' component (RGBA or alpha) in
2514       /// the base API.
2515       /// Override this if you have extended your chromatic colour types (eg RGB) and want
2516       /// the clip preferences logic to still work
isChromaticComponent(const std::string & str) const2517       bool Instance::isChromaticComponent(const std::string &str) const
2518       {
2519         if(str == kOfxImageComponentRGBA)
2520           return true;
2521         if(str == kOfxImageComponentRGB)
2522           return true;
2523 #      ifdef OFX_EXTENSIONS_NATRON
2524         if(str == kNatronOfxImageComponentXY)
2525           return true;
2526 #      endif
2527         if(str == kOfxImageComponentAlpha)
2528           return true;
2529         return false;
2530       }
2531 
2532       /// function to check for multiple bit depth support
2533       /// The answer will depend on host, plugin and context
canCurrentlyHandleMultipleClipDepths() const2534       bool Instance::canCurrentlyHandleMultipleClipDepths() const
2535       {
2536         /// does the host support 'em
2537         bool hostSupports = gImageEffectHost->getProperties().getIntProperty(kOfxImageEffectPropSupportsMultipleClipDepths) != 0;;
2538 
2539         /// does the plug-in support 'em
2540         bool pluginSupports = supportsMultipleClipDepths();
2541 
2542         /// no support, so no
2543         if(!hostSupports || !pluginSupports)
2544           return false;
2545 
2546         /// if filter context, no support, tempted to change this though
2547         if(_context == kOfxImageEffectContextFilter)
2548           return false;
2549 
2550         /// if filter context, no support
2551         if(_context == kOfxImageEffectContextGenerator ||
2552            _context == kOfxImageEffectContextTransition ||
2553            _context == kOfxImageEffectContextPaint ||
2554            _context == kOfxImageEffectContextRetimer)
2555           return false;
2556 
2557         /// OK we're cool
2558         return true;
2559       }
2560 
2561       /// Setup the default clip preferences on the clips
setDefaultClipPreferences()2562       void Instance::setDefaultClipPreferences()
2563       {
2564         /// is there multiple bit depth support? Depends on host, plugin and context
2565         bool multiBitDepth = canCurrentlyHandleMultipleClipDepths();
2566 
2567         /// OK find the deepest chromatic component on our input clips and the one with the
2568         /// most components
2569         bool hasSetCompsAndDepth = false;
2570         std::string deepestBitDepth = kOfxBitDepthNone;
2571         std::string mostComponents  = kOfxImageComponentNone;
2572         double frameRate = getFrameRate(); //< default to the project frame rate
2573         std::string premult;
2574         for(std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
2575             it!=_clips.end();
2576             ++it) {
2577           ClipInstance *clip = it->second;
2578 
2579           if(!clip->isOutput()) {
2580             bool connected = clip->getConnected();
2581 
2582             if (connected) {
2583               frameRate = Maximum(frameRate, clip->getFrameRate());
2584             }
2585 
2586             std::string rawComp  = clip->getUnmappedComponents();
2587             rawComp = clip->findSupportedComp(rawComp); // turn that into a comp the plugin expects on that clip
2588 
2589             const std::string &rawDepth = clip->getUnmappedBitDepth();
2590             const std::string &rawPreMult = clip->getPremult();
2591 
2592             if(isChromaticComponent(rawComp)) {
2593               // Note: first chromatic input gives the default output premult too, even if not connected
2594               // (else the output of generators may be opaque even if the host default is premultiplied)
2595               if(rawComp == kOfxImageComponentRGBA && (connected || premult.empty())) {
2596                 if(rawPreMult == kOfxImagePreMultiplied)
2597                   premult = kOfxImagePreMultiplied;
2598                 else if(rawPreMult == kOfxImageUnPreMultiplied && premult != kOfxImagePreMultiplied)
2599                   premult = kOfxImageUnPreMultiplied;
2600               }
2601 
2602               if(connected) {
2603                 //Update deepest bitdepth and most components only if the infos are relevant, i.e: only if the clip is connected
2604                 hasSetCompsAndDepth = true;
2605                 deepestBitDepth = FindDeepestBitDepth(deepestBitDepth, rawDepth);
2606                 bool mostIsAlpha = (mostComponents == kOfxImageComponentAlpha);
2607                 bool rawIsAlpha = (rawComp == kOfxImageComponentAlpha);
2608                 if (mostIsAlpha != rawIsAlpha) {
2609                   // one is alpha, the other is anything else than just alpha: the union is RGBA
2610                   mostComponents = kOfxImageComponentRGBA;
2611                 }
2612                 mostComponents  = findMostChromaticComponents(mostComponents, rawComp);
2613               }
2614             }
2615           }
2616         }
2617         if (!hasSetCompsAndDepth) {
2618           mostComponents = kOfxImageComponentRGBA;
2619           deepestBitDepth = kOfxBitDepthFloat;
2620         }
2621 
2622         /// set some stuff up
2623         _outputFrameRate           = frameRate;
2624         _outputFielding            = getDefaultOutputFielding();
2625         _continuousSamples         = false;
2626         _frameVarying              = false;
2627 
2628         /// now find the best depth that the plugin supports
2629         deepestBitDepth = bestSupportedDepth(deepestBitDepth);
2630 
2631         /// now add the clip gubbins to the out args
2632         for(std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
2633             it!=_clips.end();
2634             ++it) {
2635           ClipInstance *clip = it->second;
2636 
2637           std::string comp, depth;
2638 
2639           std::string rawComp  = clip->getUnmappedComponents();
2640           rawComp = clip->findSupportedComp(rawComp); // turn that into a comp the plugin expects on that clip
2641           const std::string &rawDepth = clip->getUnmappedBitDepth();
2642 
2643           if(isChromaticComponent(rawComp)) {
2644 
2645             if(clip->isOutput() || clip->isOptional()) {
2646               // "Optional input clips can always have their component types remapped"
2647               // http://openfx.sourceforge.net/Documentation/1.3/ofxProgrammingReference.html#id482755
2648               depth = deepestBitDepth;
2649               comp = clip->findSupportedComp(mostComponents);
2650 
2651               clip->setPixelDepth(depth);
2652               clip->setComponents(comp);
2653               if(clip->isOutput() && premult.empty() &&
2654                  (comp == kOfxImageComponentRGBA || comp == kOfxImageComponentAlpha)) {
2655                 premult = kOfxImagePreMultiplied;
2656               }
2657             }
2658             else {
2659               comp  = rawComp;
2660               depth = multiBitDepth ? bestSupportedDepth(rawDepth) : deepestBitDepth;
2661 
2662               clip->setPixelDepth(depth);
2663               clip->setComponents(comp);
2664             }
2665           }
2666           else {
2667             /// hmm custom component type, don't touch it and pass it through
2668             clip->setPixelDepth(rawDepth);
2669             clip->setComponents(rawComp);
2670           }
2671         }
2672         // default to a reasonable value if there is no input
2673         if (premult.empty()) {
2674           premult = kOfxImageOpaque;
2675         }
2676         // set output premultiplication
2677         _outputPreMultiplication = premult;
2678       }
2679 
2680       /// Initialise the clip preferences arguments, override this to do
2681       /// stuff with wierd components etc...
setupClipPreferencesArgs(Property::Set & outArgs)2682       void Instance::setupClipPreferencesArgs(Property::Set &outArgs)
2683       {
2684         /// reset all the clip prefs stuff to their defaults
2685         setDefaultClipPreferences();
2686 
2687         static const Property::PropSpec clipPrefsStuffs []=
2688           {
2689             { kOfxImageEffectPropFrameRate,          Property::eDouble,  1, false,  "1" },
2690             { kOfxImageEffectPropPreMultiplication,  Property::eString,  1, false,  "" },
2691             { kOfxImageClipPropFieldOrder,           Property::eString,  1, false,  "" },
2692             { kOfxImageClipPropContinuousSamples,    Property::eInt,     1, false,  "0" },
2693             { kOfxImageEffectFrameVarying,           Property::eInt,     1, false,  "0" },
2694 #ifdef OFX_EXTENSIONS_NATRON
2695             { kOfxImageClipPropFormat,             Property::eInt,     4, false,   "0"},
2696 #endif
2697             Property::propSpecEnd
2698           };
2699 
2700         outArgs.addProperties(clipPrefsStuffs);
2701 
2702         /// set the default for those
2703 
2704         /// is there multiple bit depth support? Depends on host, plugin and context
2705         bool multiBitDepth = canCurrentlyHandleMultipleClipDepths();
2706 
2707         outArgs.setStringProperty(kOfxImageClipPropFieldOrder, _outputFielding);
2708         outArgs.setStringProperty(kOfxImageEffectPropPreMultiplication, _outputPreMultiplication);
2709 
2710         /// now add the clip gubbins to the out args
2711         double projectPAR = getProjectPixelAspectRatio();
2712 
2713 #ifdef OFX_EXTENSIONS_NATRON
2714         double projectExtent[2];
2715         double projectOffset[2];
2716         getProjectOffset(projectOffset[0], projectOffset[1]);
2717         getProjectExtent(projectExtent[0], projectExtent[1]);
2718         // Project format is in canonical coordinates, so divide by PAR
2719         if (projectPAR != 0.) {
2720           projectOffset[0] /= projectPAR;
2721           projectExtent[0] /= projectPAR;
2722         }
2723         bool outputFormatSet = false;
2724         OfxRectI outputFormat = { (int)(projectOffset[0] + 0.5),
2725                                   (int)(projectOffset[1] + 0.5),
2726                                   (int)(projectOffset[0] + projectExtent[0] + 0.5),
2727                                   (int)(projectOffset[1] + projectExtent[1] + 0.5)};
2728 #endif
2729 
2730 
2731 
2732 
2733         bool multipleClipsPAR = supportsMultipleClipPARs();
2734         /// get the PAR of inputs, if it has different PARs and the effect does not support multiple clips PAR, throw an exception
2735         double inputPar = 1.;
2736 
2737         bool inputParSet = false;
2738         for (std::map<std::string, ClipInstance*>::iterator it2 = _clips.begin(); it2 != _clips.end(); ++it2) {
2739           if (!it2->second->isOutput() && it2->second->getConnected()) {
2740             if (!inputParSet) {
2741               inputPar = it2->second->getAspectRatio();
2742               inputParSet = true;
2743             } else if (!multipleClipsPAR && inputPar != it2->second->getAspectRatio()) {
2744               // We have several inputs with different aspect ratio, which should be forbidden by the host.
2745               throw Property::Exception(kOfxStatErrValue);
2746             }
2747 #ifdef OFX_EXTENSIONS_NATRON
2748             if (!outputFormatSet && !it2->second->isOptional()) {
2749               outputFormat = it2->second->getFormat();
2750               outputFormatSet = true;
2751             }
2752 #endif
2753           }
2754         }
2755 
2756 
2757         for(std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
2758             it!=_clips.end();
2759             ++it) {
2760           ClipInstance *clip = it->second;
2761 
2762           std::string componentParamName = "OfxImageClipPropComponents_"+it->first;
2763           std::string depthParamName     = "OfxImageClipPropDepth_"+it->first;
2764           std::string parParamName       = "OfxImageClipPropPAR_"+it->first;
2765 
2766           Property::PropSpec specComp = {componentParamName.c_str(),  Property::eString, 0, false,          ""}; // note the support for multi-planar clips
2767           outArgs.createProperty(specComp);
2768           outArgs.setStringProperty(componentParamName.c_str(), clip->getComponents().c_str()); // as it is variable dimension, there is no default value, so we have to set it explicitly
2769 
2770           Property::PropSpec specDep = {depthParamName.c_str(),       Property::eString, 1, !multiBitDepth, clip->getPixelDepth().c_str()};
2771           outArgs.createProperty(specDep);
2772 
2773           Property::PropSpec specPAR = {parParamName.c_str(),         Property::eDouble, 1, false,          "1"};
2774           outArgs.createProperty(specPAR);
2775           if (!clip->isOutput()) {
2776             // If the clip is input, use the same par for all inputs unless the plug-in supports multiple clips PAR
2777             double par;
2778             if (!multipleClipsPAR && inputParSet) {
2779                 par = inputPar;
2780             } else if (multipleClipsPAR) {
2781                 par = clip->getAspectRatio();
2782             } else {
2783                 par = projectPAR;
2784             }
2785             outArgs.setDoubleProperty(parParamName, par);
2786           } else {
2787             // If the clip is output we should propagate the pixel aspect ratio of the inputs
2788             outArgs.setDoubleProperty(parParamName, inputParSet ? inputPar : projectPAR);
2789           }
2790         }
2791 
2792         //Set the output frame rate according to what input clips have. Several inputs with different frame rates should be
2793         //forbidden by the host.
2794         bool outputFrameRateSet = false;
2795         double outputFrameRate = _outputFrameRate;
2796         for (std::map<std::string, ClipInstance*>::iterator it2 = _clips.begin(); it2 != _clips.end(); ++it2) {
2797             if (!it2->second->isOutput() && it2->second->getConnected()) {
2798                 if (!outputFrameRateSet) {
2799                     outputFrameRate = it2->second->getFrameRate();
2800                     outputFrameRateSet = true;
2801                 } else if (outputFrameRate != it2->second->getFrameRate()) {
2802                     // We have several inputs with different frame rates
2803                     throw Property::Exception(kOfxStatErrValue);
2804                 }
2805             }
2806         }
2807 
2808         outArgs.setDoubleProperty(kOfxImageEffectPropFrameRate, outputFrameRate);
2809 #ifdef OFX_EXTENSIONS_NATRON
2810         outArgs.setIntPropertyN(kOfxImageClipPropFormat, (const int*)&outputFormat.x1, 4);
2811 #endif
2812 
2813       }
2814 
2815       /// the idea here is the clip prefs live as active props on the effect
2816       /// and are set up by clip preferences. The action manages the clip
2817       /// preferences bits. We also monitor clip and param changes and
2818       /// flag when clip prefs is dirty.
2819       /// call the clip preferences action
getClipPreferences()2820       bool Instance::getClipPreferences()
2821       {
2822         /// create the out args with the stuff that does not depend on individual clips
2823         Property::Set outArgs;
2824 
2825         setupClipPreferencesArgs(outArgs);
2826 
2827 
2828 #       ifdef OFX_DEBUG_ACTIONS
2829           OfxPlugin *ofxp = _plugin->getPluginHandle()->getOfxPlugin();
2830           const char* id = ofxp->pluginIdentifier;
2831           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxImageEffectActionGetClipPreferences<<"()"<<std::endl;
2832 #       endif
2833         OfxStatus st = mainEntry(kOfxImageEffectActionGetClipPreferences,
2834                                  this->getHandle(),
2835                                  0,
2836                                  &outArgs);
2837 #       ifdef OFX_DEBUG_ACTIONS
2838           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxImageEffectActionGetClipPreferences<<"()->"<<StatStr(st);
2839 #       endif
2840 
2841         if(st!=kOfxStatOK && st!=kOfxStatReplyDefault) {
2842 #       ifdef OFX_DEBUG_ACTIONS
2843             std::cout << std::endl;
2844 #       endif
2845           /// ouch
2846           return false;
2847         }
2848 
2849 #       ifdef OFX_DEBUG_ACTIONS
2850           std::cout << ": ";
2851 #       endif
2852         /// OK, go pump the components/depths back into the clips themselves
2853         for(std::map<std::string, ClipInstance*>::iterator it=_clips.begin();
2854             it!=_clips.end();
2855             ++it) {
2856             ClipInstance *clip = it->second;
2857 
2858             std::string componentParamName = "OfxImageClipPropComponents_"+it->first;
2859             std::string depthParamName = "OfxImageClipPropDepth_"+it->first;
2860             std::string parParamName = "OfxImageClipPropPAR_"+it->first;
2861 
2862 #       ifdef OFX_DEBUG_ACTIONS
2863             std::cout << it->first<<"->"<<outArgs.getStringProperty(depthParamName)<<","<<outArgs.getStringProperty(componentParamName)<<","<<outArgs.getDoubleProperty(parParamName)<<" ";
2864 #       endif
2865 
2866             clip->setPixelDepth(outArgs.getStringProperty(depthParamName));
2867             clip->setComponents(outArgs.getStringProperty(componentParamName));
2868             //clip->setPixelAspect(outArgs.getDoubleProperty(parParamName));
2869           }
2870 
2871         _outputFrameRate           = outArgs.getDoubleProperty(kOfxImageEffectPropFrameRate);
2872         _outputFielding            = outArgs.getStringProperty(kOfxImageClipPropFieldOrder);
2873         _outputPreMultiplication   = outArgs.getStringProperty(kOfxImageEffectPropPreMultiplication);
2874         _continuousSamples = outArgs.getIntProperty(kOfxImageClipPropContinuousSamples) != 0;
2875         _frameVarying      = outArgs.getIntProperty(kOfxImageEffectFrameVarying) != 0;
2876 #       ifdef OFX_DEBUG_ACTIONS
2877           std::cout << _outputFrameRate<<","<<_outputFielding<<","<<_outputPreMultiplication<<","<<_continuousSamples<<","<<_frameVarying<<std::endl;
2878 #       endif
2879 
2880         _clipPrefsDirty  = false;
2881 
2882         return true;
2883       }
2884 
2885       /// find the most chromatic components out of the two. Override this if you define
2886       /// more chromatic components
findMostChromaticComponents(const std::string & a,const std::string & b) const2887       const std::string &Instance::findMostChromaticComponents(const std::string &a, const std::string &b) const
2888       {
2889         if(a == kOfxImageComponentNone)
2890           return b;
2891         if(a == kOfxImageComponentRGBA)
2892           return a;
2893         if(b == kOfxImageComponentRGBA)
2894           return b;
2895         if(a == kOfxImageComponentRGB)
2896           return a;
2897         if(b == kOfxImageComponentRGB)
2898           return b;
2899         return a;
2900       }
2901 
2902       /// given the bit depth, find the best match for it.
bestSupportedDepth(const std::string & depth) const2903       const std::string &Instance::bestSupportedDepth(const std::string &depth) const
2904       {
2905         static const std::string none(kOfxBitDepthNone);
2906         static const std::string bytes(kOfxBitDepthByte);
2907         static const std::string shorts(kOfxBitDepthShort);
2908         static const std::string halfs(kOfxBitDepthHalf);
2909         static const std::string floats(kOfxBitDepthFloat);
2910 
2911         if(depth == none)
2912           return none;
2913 
2914         if(isPixelDepthSupported(depth))
2915           return depth;
2916 
2917         if(depth == floats) {
2918           if(isPixelDepthSupported(shorts))
2919             return shorts;
2920           if(isPixelDepthSupported(bytes))
2921             return bytes;
2922         }
2923 
2924         if(depth == halfs) {
2925           if(isPixelDepthSupported(floats))
2926             return floats;
2927           if(isPixelDepthSupported(shorts))
2928             return shorts;
2929           if(isPixelDepthSupported(bytes))
2930             return bytes;
2931         }
2932 
2933         if(depth == shorts) {
2934           if(isPixelDepthSupported(floats))
2935             return floats;
2936           if(isPixelDepthSupported(bytes))
2937             return bytes;
2938         }
2939 
2940         if(depth == bytes) {
2941           if(isPixelDepthSupported(shorts))
2942             return shorts;
2943           if(isPixelDepthSupported(floats))
2944             return floats;
2945         }
2946 
2947         /// WTF? Something wrong here
2948         return none;
2949       }
2950 
2951 #ifdef OFX_EXTENSIONS_NATRON
isInViewportParam(const std::string & paramName) const2952       bool Instance::isInViewportParam(const std::string& paramName) const
2953       {
2954         int nDim = getProps().getDimension(kNatronOfxImageEffectPropInViewerContextParamsOrder);
2955         for (int i = 0; nDim; ++i) {
2956           const std::string& p = getProps().getStringProperty(kNatronOfxImageEffectPropInViewerContextParamsOrder, i);
2957           if (paramName == p) {
2958             return true;
2959           }
2960         }
2961         return false;
2962       }
2963 #endif
2964 
2965       /// get the interact description, this will also call describe on the interact
getOverlayDescriptor(int bitDepthPerComponent,bool hasAlpha)2966       Interact::Descriptor &Instance::getOverlayDescriptor(int bitDepthPerComponent, bool hasAlpha)
2967       {
2968         return _descriptor->getOverlayDescriptor(bitDepthPerComponent, hasAlpha);
2969       }
2970 
getTimeDomainAction(OfxRangeD & range)2971       OfxStatus Instance::getTimeDomainAction(OfxRangeD& range)
2972       {
2973         static const Property::PropSpec outStuff[] = {
2974           { kOfxImageEffectPropFrameRange , Property::eDouble, 2, false, "0.0" },
2975           Property::propSpecEnd
2976         };
2977 
2978         Property::Set outArgs(outStuff);
2979 
2980 #       ifdef OFX_DEBUG_ACTIONS
2981           OfxPlugin *ofxp = _plugin->getPluginHandle()->getOfxPlugin();
2982           const char* id = ofxp->pluginIdentifier;
2983           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxImageEffectActionGetTimeDomain<<"()"<<std::endl;
2984 #       endif
2985         OfxStatus st = mainEntry(kOfxImageEffectActionGetTimeDomain,
2986                                  this->getHandle(),
2987                                  0,
2988                                  &outArgs);
2989 #       ifdef OFX_DEBUG_ACTIONS
2990           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxImageEffectActionGetTimeDomain<<"()->"<<StatStr(st);
2991           if (st == kOfxStatOK) {
2992               std::cout << ": ("<<outArgs.getDoubleProperty(kOfxImageEffectPropFrameRange,0)<<","<<outArgs.getDoubleProperty(kOfxImageEffectPropFrameRange,1)<<")";
2993           }          std::cout << std::endl;
2994 #       endif
2995         if(st!=kOfxStatOK) return st;
2996 
2997         range.min = outArgs.getDoubleProperty(kOfxImageEffectPropFrameRange,0);
2998         range.max = outArgs.getDoubleProperty(kOfxImageEffectPropFrameRange,1);
2999 
3000         return kOfxStatOK;
3001       }
3002 
3003  #ifdef OFX_SUPPORTS_DIALOG
3004       // OfxDialogSuite
3005       /// @see kOfxActionDialog
dialog(void * instanceData)3006       OfxStatus Instance::dialog(void *instanceData)
3007       {
3008         static const Property::PropSpec inStuff[] = {
3009           { kOfxPropInstanceData, Property::ePointer, 1, true, NULL },
3010           Property::propSpecEnd
3011         };
3012 
3013         Property::Set inArgs(inStuff);
3014 
3015         inArgs.setPointerProperty(kOfxPropInstanceData, instanceData);
3016 
3017 #       ifdef OFX_DEBUG_ACTIONS
3018           OfxPlugin *ofxp = _plugin->getPluginHandle()->getOfxPlugin();
3019           const char* id = ofxp->pluginIdentifier;
3020           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxActionDialog<<"("<<instanceData<<")"<<std::endl;
3021 #       endif
3022         OfxStatus st = mainEntry(kOfxActionDialog,
3023                                  this->getHandle(),
3024                                  &inArgs,
3025                                  0);
3026 #       ifdef OFX_DEBUG_ACTIONS
3027           std::cout << "OFX: "<<id<<"("<<(void*)ofxp<<")->"<<kOfxActionDialog<<"("<<instanceData<<")->"<<StatStr(st);
3028           std::cout << std::endl;
3029 #       endif
3030 
3031         return st;
3032       }
3033 #endif
3034 
3035       /// implemented for Param::SetInstance
paramChangedByPlugin(Param::Instance * param)3036       void Instance::paramChangedByPlugin(Param::Instance *param)
3037       {
3038         if (!_created) {
3039           // setValue() was probably called from kOfxActionCreateInstance
3040           // this is legal according to http://openfx.sourceforge.net/Documentation/1.3/ofxProgrammingReference.html#SettingParams
3041           // but kOfxActionInstanceChanged should not be called according to the preconditions of http://openfx.sourceforge.net/Documentation/1.3/ofxProgrammingReference.html#kOfxActionInstanceChanged
3042           return;
3043         }
3044         double frame  = getFrameRecursive();
3045         OfxPointD renderScale; getRenderScaleRecursive(renderScale.x, renderScale.y);
3046 
3047         beginInstanceChangedAction(kOfxChangePluginEdited);
3048         paramInstanceChangedAction(param->getName(), kOfxChangePluginEdited, frame, renderScale);
3049         endInstanceChangedAction(kOfxChangePluginEdited);
3050       }
3051 
3052       ////////////////////////////////////////////////////////////////////////////////
3053       ////////////////////////////////////////////////////////////////////////////////
3054       ////////////////////////////////////////////////////////////////////////////////
3055       /// The image effect suite functions
getPropertySet(OfxImageEffectHandle h1,OfxPropertySetHandle * h2)3056       static OfxStatus getPropertySet(OfxImageEffectHandle h1,
3057                                       OfxPropertySetHandle *h2)
3058       {
3059 #       ifdef OFX_DEBUG_PROPERTIES
3060         std::cout << "OFX: getPropertySet - " << h1 << " = ...";
3061 #       endif
3062         try {
3063         if (!h2) {
3064 #         ifdef OFX_DEBUG_PROPERTIES
3065           std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl;
3066 #         endif
3067           return kOfxStatErrBadHandle;
3068         }
3069 
3070         Base *effectBase = reinterpret_cast<Base*>(h1);
3071 
3072         if (!effectBase || !effectBase->verifyMagic()) {
3073           *h2 = NULL;
3074 
3075 #         ifdef OFX_DEBUG_PROPERTIES
3076           std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl;
3077 #         endif
3078           return kOfxStatErrBadHandle;
3079         }
3080 
3081         *h2 = effectBase->getProps().getHandle();
3082 
3083 #       ifdef OFX_DEBUG_PROPERTIES
3084         std::cout << *h2 << ' ' << StatStr(kOfxStatOK) << std::endl;
3085 #       endif
3086         return kOfxStatOK;
3087         } catch (...) {
3088           *h2 = NULL;
3089 
3090 #         ifdef OFX_DEBUG_PROPERTIES
3091           std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl;
3092 #         endif
3093           return kOfxStatErrBadHandle;
3094         }
3095       }
3096 
getParamSet(OfxImageEffectHandle h1,OfxParamSetHandle * h2)3097       static OfxStatus getParamSet(OfxImageEffectHandle h1,
3098                                    OfxParamSetHandle *h2)
3099       {
3100 #       ifdef OFX_DEBUG_PARAMETERS
3101         std::cout << "OFX: getParamSet - " << h1 << " = ...";
3102 #       endif
3103         try {
3104         if (!h2) {
3105           return kOfxStatErrBadHandle;
3106         }
3107 
3108         ImageEffect::Base *effectBase = reinterpret_cast<ImageEffect::Base*>(h1);
3109 
3110         if (!effectBase || !effectBase->verifyMagic()) {
3111           *h2 = NULL;
3112 
3113 #         ifdef OFX_DEBUG_PARAMETERS
3114           std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl;
3115 #         endif
3116           return kOfxStatErrBadHandle;
3117         }
3118 
3119         ImageEffect::Descriptor *effectDescriptor = dynamic_cast<ImageEffect::Descriptor*>(effectBase);
3120 
3121         if(effectDescriptor) {
3122           *h2 = effectDescriptor->getParamSetHandle();
3123 
3124 #         ifdef OFX_DEBUG_PARAMETERS
3125           std::cout << *h2 << ' ' << StatStr(kOfxStatOK) << std::endl;
3126 #         endif
3127           return kOfxStatOK;
3128         }
3129 
3130         ImageEffect::Instance *effectInstance = dynamic_cast<ImageEffect::Instance*>(effectBase);
3131 
3132         if(effectInstance) {
3133           *h2 = effectInstance->getParamSetHandle();
3134 
3135 #         ifdef OFX_DEBUG_PARAMETERS
3136           std::cout << *h2 << ' ' << StatStr(kOfxStatOK) << std::endl;
3137 #         endif
3138           return kOfxStatOK;
3139         }
3140 
3141         *h2 = NULL;
3142 
3143 #       ifdef OFX_DEBUG_PARAMETERS
3144         std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl;
3145 #       endif
3146         return kOfxStatErrBadHandle;
3147         } catch (...) {
3148           *h2 = NULL;
3149 
3150 #         ifdef OFX_DEBUG_PARAMETERS
3151           std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl;
3152 #         endif
3153           return kOfxStatErrBadHandle;
3154         }
3155       }
3156 
clipDefine(OfxImageEffectHandle h1,const char * name,OfxPropertySetHandle * h2)3157       static OfxStatus clipDefine(OfxImageEffectHandle h1,
3158                                   const char *name,
3159                                   OfxPropertySetHandle *h2)
3160       {
3161         try {
3162         if (!h2) {
3163           return kOfxStatErrBadHandle;
3164         }
3165 
3166         ImageEffect::Base *effectBase = reinterpret_cast<ImageEffect::Base*>(h1);
3167 
3168         if (!effectBase || !effectBase->verifyMagic()) {
3169           *h2 = NULL;
3170 
3171           return kOfxStatErrBadHandle;
3172         }
3173 
3174         ImageEffect::Descriptor *effectDescriptor = dynamic_cast<ImageEffect::Descriptor*>(effectBase);
3175 
3176         if(effectDescriptor){
3177           ClipDescriptor *clip = effectDescriptor->defineClip(name);
3178           *h2 = clip->getPropHandle();
3179 
3180           return kOfxStatOK;
3181         }
3182 
3183         *h2 = NULL;
3184 
3185         return kOfxStatErrBadHandle;
3186         } catch (...) {
3187           *h2 = NULL;
3188 
3189           return kOfxStatErrBadHandle;
3190         }
3191       }
3192 
clipGetPropertySet(OfxImageClipHandle clip,OfxPropertySetHandle * propHandle)3193       static OfxStatus clipGetPropertySet(OfxImageClipHandle clip,
3194                                           OfxPropertySetHandle *propHandle){
3195 #       ifdef OFX_DEBUG_PROPERTIES
3196         std::cout << "OFX: clipGetPropertySet - " << clip << " = ...";
3197 #       endif
3198         try {
3199         if (!propHandle) {
3200           return kOfxStatErrBadHandle;
3201         }
3202 
3203         ClipInstance *clipInstance = reinterpret_cast<ClipInstance*>(clip);
3204 
3205         if (!clipInstance || !clipInstance->verifyMagic()) {
3206           *propHandle = NULL;
3207 
3208 #         ifdef OFX_DEBUG_PROPERTIES
3209           std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl;
3210 #         endif
3211           return kOfxStatErrBadHandle;
3212         }
3213 
3214         *propHandle = clipInstance->getPropHandle();
3215 #       ifdef OFX_DEBUG_PROPERTIES
3216         std::cout << *propHandle << ' ' << StatStr(kOfxStatOK) << std::endl;
3217 #       endif
3218         return kOfxStatOK;
3219         } catch (...) {
3220           *propHandle = NULL;
3221 
3222 #         ifdef OFX_DEBUG_PROPERTIES
3223           std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl;
3224 #         endif
3225           return kOfxStatErrBadHandle;
3226         }
3227       }
3228 
clipGetImage(OfxImageClipHandle h1,OfxTime time,const OfxRectD * h2,OfxPropertySetHandle * h3)3229       static OfxStatus clipGetImage(OfxImageClipHandle h1,
3230                                     OfxTime time,
3231                                     const OfxRectD *h2,
3232                                     OfxPropertySetHandle *h3)
3233       {
3234         if ( OFX::IsNaN(time) ) {
3235           return kOfxStatFailed;
3236         }
3237         try {
3238         if (!h3) {
3239           return kOfxStatErrBadHandle;
3240         }
3241 
3242         ClipInstance *clipInstance = reinterpret_cast<ClipInstance*>(h1);
3243 
3244         if (!clipInstance || !clipInstance->verifyMagic()) {
3245           *h3 = NULL;
3246           return kOfxStatErrBadHandle;
3247         }
3248 
3249         Image* image = clipInstance->getImage(time,h2);
3250         if(!image) {
3251           *h3 = NULL;
3252 
3253           return kOfxStatFailed;
3254         }
3255 
3256         *h3 = image->getPropHandle();
3257 
3258         return kOfxStatOK;
3259         } catch (...) {
3260           *h3 = NULL;
3261 
3262           return kOfxStatErrBadHandle;
3263         }
3264       }
3265 
3266 #ifdef OFX_EXTENSIONS_VEGAS
clipGetStereoscopicImage(OfxImageClipHandle h1,OfxTime time,int view,OfxRectD * h2,OfxPropertySetHandle * h3)3267       static OfxStatus clipGetStereoscopicImage(OfxImageClipHandle h1,
3268                                                 OfxTime time,
3269                                                 int view,
3270                                                 OfxRectD *h2,
3271                                                 OfxPropertySetHandle *h3)
3272       {
3273         if ( OFX::IsNaN(time) ) {
3274           return kOfxStatFailed;
3275         }
3276         try {
3277         if (!h3) {
3278           return kOfxStatErrBadHandle;
3279         }
3280         ClipInstance *clipInstance = reinterpret_cast<ClipInstance*>(h1);
3281 
3282         if (!clipInstance || !clipInstance->verifyMagic()) {
3283           *h3 = NULL;
3284 
3285           return kOfxStatErrBadHandle;
3286         }
3287 
3288         Image* image = clipInstance->getStereoscopicImage(time,view,h2);
3289         if(!image) {
3290           *h3 = NULL;
3291 
3292           return kOfxStatFailed;
3293         }
3294 
3295         *h3 = image->getPropHandle();
3296 
3297         return kOfxStatOK;
3298         } catch (...) {
3299           *h3 = NULL;
3300 
3301           return kOfxStatErrBadHandle;
3302         }
3303       }
3304 #endif
3305 
clipReleaseImage(OfxPropertySetHandle h1)3306       static OfxStatus clipReleaseImage(OfxPropertySetHandle h1)
3307       {
3308         try {
3309         Property::Set *pset = reinterpret_cast<Property::Set*>(h1);
3310 
3311         if (!pset || !pset->verifyMagic()) {
3312           return kOfxStatErrBadHandle;
3313         }
3314 
3315         Image *image = dynamic_cast<Image*>(pset);
3316 
3317         if(image){
3318           // clip::image has a virtual destructor for derived classes
3319           image->releaseReference();
3320 
3321           return kOfxStatOK;
3322         }
3323 
3324         return kOfxStatErrBadHandle;
3325         } catch (...) {
3326           return kOfxStatErrBadHandle;
3327         }
3328       }
3329 
clipGetHandle(OfxImageEffectHandle imageEffect,const char * name,OfxImageClipHandle * clip,OfxPropertySetHandle * propertySet)3330       static OfxStatus clipGetHandle(OfxImageEffectHandle imageEffect,
3331                                      const char *name,
3332                                      OfxImageClipHandle *clip,
3333                                      OfxPropertySetHandle *propertySet)
3334       {
3335         try {
3336         if (!clip) {
3337           return kOfxStatErrBadHandle;
3338         }
3339 
3340         ImageEffect::Base *effectBase = reinterpret_cast<ImageEffect::Base*>(imageEffect);
3341 
3342         if (!effectBase || !effectBase->verifyMagic()) {
3343           return kOfxStatErrBadHandle;
3344         }
3345 
3346         ImageEffect::Instance *effectInstance = reinterpret_cast<ImageEffect::Instance*>(effectBase);
3347 
3348         if(effectInstance){
3349           ClipInstance* instance = effectInstance->getClip(name);
3350           if(!instance)
3351             return kOfxStatErrBadHandle;
3352           *clip = instance->getHandle();
3353           if(propertySet)
3354             *propertySet = instance->getPropHandle();
3355           return kOfxStatOK;
3356         }
3357 
3358         return kOfxStatErrBadHandle;
3359         } catch (...) {
3360           return kOfxStatErrBadHandle;
3361         }
3362       }
3363 
clipGetRegionOfDefinition(OfxImageClipHandle clip,OfxTime time,OfxRectD * bounds)3364       static OfxStatus clipGetRegionOfDefinition(OfxImageClipHandle clip,
3365                                                  OfxTime time,
3366                                                  OfxRectD *bounds)
3367       {
3368         if ( OFX::IsNaN(time) ) {
3369           return kOfxStatFailed;
3370         }
3371         try {
3372         if (!bounds) {
3373           return kOfxStatErrBadHandle;
3374         }
3375 
3376         ClipInstance *clipInstance = reinterpret_cast<ClipInstance*>(clip);
3377 
3378         if (!clipInstance || !clipInstance->verifyMagic()) {
3379           bounds->x1 = bounds->y1 = bounds->x2 = bounds->y2 = 0.;
3380 
3381           return kOfxStatErrBadHandle;
3382         }
3383 
3384         *bounds = clipInstance->getRegionOfDefinition(time);
3385         if (bounds->x2 < bounds->x1 || bounds->y2 < bounds->y1) {
3386           // the RoD is invalid (empty is OK)
3387 
3388           return kOfxStatFailed;
3389         }
3390 
3391         return kOfxStatOK;
3392         } catch (...) {
3393           return kOfxStatErrBadHandle;
3394         }
3395       }
3396 
3397       // should processing be aborted?
abort(OfxImageEffectHandle imageEffect)3398       static int abort(OfxImageEffectHandle imageEffect)
3399       {
3400         try {
3401         ImageEffect::Base *effectBase = reinterpret_cast<ImageEffect::Base*>(imageEffect);
3402 
3403         if (!effectBase || !effectBase->verifyMagic()) {
3404           return kOfxStatErrBadHandle;
3405         }
3406 
3407         ImageEffect::Instance *effectInstance = dynamic_cast<ImageEffect::Instance*>(effectBase);
3408 
3409         if(effectInstance)
3410           return effectInstance->abort();
3411         else
3412           return kOfxStatErrBadHandle;
3413         } catch (...) {
3414           return kOfxStatErrBadHandle;
3415         }
3416       }
3417 
imageMemoryAlloc(OfxImageEffectHandle instanceHandle,size_t nBytes,OfxImageMemoryHandle * memoryHandle)3418       static OfxStatus imageMemoryAlloc(OfxImageEffectHandle instanceHandle,
3419                                         size_t nBytes,
3420                                         OfxImageMemoryHandle *memoryHandle)
3421       {
3422         try {
3423         if (!memoryHandle) {
3424           return kOfxStatErrBadHandle;
3425         }
3426 
3427         ImageEffect::Base *effectBase = reinterpret_cast<ImageEffect::Base*>(instanceHandle);
3428         ImageEffect::Instance *effectInstance = reinterpret_cast<ImageEffect::Instance*>(effectBase);
3429         Memory::Instance* memory;
3430 
3431         if(effectInstance){
3432 
3433           if (!effectInstance->verifyMagic()) {
3434             *memoryHandle = NULL;
3435             return kOfxStatErrBadHandle;
3436           }
3437 
3438           memory = effectInstance->imageMemoryAlloc(nBytes);
3439         }
3440         else {
3441           memory = gImageEffectHost->imageMemoryAlloc(nBytes);
3442         }
3443 
3444         if (memory) {
3445           *memoryHandle = memory->getHandle();
3446           return kOfxStatOK;
3447         } else {
3448           *memoryHandle = NULL;
3449           return kOfxStatErrMemory;
3450         }
3451         } catch (std::bad_alloc) {
3452           *memoryHandle = NULL;
3453           return kOfxStatErrMemory;
3454         } catch (...) {
3455           *memoryHandle = NULL;
3456           return kOfxStatErrBadHandle;
3457         }
3458       }
3459 
imageMemoryFree(OfxImageMemoryHandle memoryHandle)3460       static OfxStatus imageMemoryFree(OfxImageMemoryHandle memoryHandle){
3461         try {
3462         Memory::Instance *memoryInstance = reinterpret_cast<Memory::Instance*>(memoryHandle);
3463 
3464         if(memoryInstance && memoryInstance->verifyMagic()) {
3465           if (memoryInstance->freeMem()) {
3466             delete memoryInstance;
3467           }
3468           return kOfxStatOK;
3469         }
3470         else
3471           return kOfxStatErrBadHandle;
3472         } catch (...) {
3473           return kOfxStatErrBadHandle;
3474         }
3475       }
3476 
3477       static
imageMemoryLock(OfxImageMemoryHandle memoryHandle,void ** returnedPtr)3478       OfxStatus imageMemoryLock(OfxImageMemoryHandle memoryHandle,
3479                                 void **returnedPtr){
3480         try {
3481         if (!returnedPtr) {
3482           return kOfxStatErrBadHandle;
3483         }
3484 
3485         Memory::Instance *memoryInstance = reinterpret_cast<Memory::Instance*>(memoryHandle);
3486 
3487         if(memoryInstance && memoryInstance->verifyMagic()) {
3488           memoryInstance->lock();
3489           *returnedPtr = memoryInstance->getPtr();
3490 
3491           return (*returnedPtr) ? kOfxStatOK : kOfxStatErrMemory;
3492         }
3493 
3494         *returnedPtr = NULL;
3495 
3496         return kOfxStatErrBadHandle;
3497         } catch (...) {
3498           *returnedPtr = NULL;
3499           return kOfxStatErrBadHandle;
3500         }
3501       }
3502 
imageMemoryUnlock(OfxImageMemoryHandle memoryHandle)3503       static OfxStatus imageMemoryUnlock(OfxImageMemoryHandle memoryHandle){
3504         try {
3505         Memory::Instance *memoryInstance = reinterpret_cast<Memory::Instance*>(memoryHandle);
3506 
3507         if(memoryInstance && memoryInstance->verifyMagic()){
3508           memoryInstance->unlock();
3509 
3510           return kOfxStatOK;
3511         }
3512 
3513         return kOfxStatErrBadHandle;
3514         } catch (...) {
3515           return kOfxStatErrBadHandle;
3516         }
3517       }
3518 
3519       static const struct OfxImageEffectSuiteV1 gImageEffectSuite = {
3520         getPropertySet,
3521         getParamSet,
3522         clipDefine,
3523         clipGetHandle,
3524         clipGetPropertySet,
3525         clipGetImage,
3526         clipReleaseImage,
3527         clipGetRegionOfDefinition,
3528         abort,
3529         imageMemoryAlloc,
3530         imageMemoryFree,
3531         imageMemoryLock,
3532         imageMemoryUnlock
3533       };
3534 
3535 #   ifdef OFX_EXTENSIONS_VEGAS
3536       static const struct OfxVegasStereoscopicImageEffectSuiteV1 gVegasStereoscopicImageEffectSuite = {
3537         clipGetStereoscopicImage
3538       };
3539 #   endif
3540 
3541 #   ifdef OFX_EXTENSIONS_NUKE
3542 
clipGetImagePlane(OfxImageClipHandle clip,OfxTime time,int view,const char * plane,const OfxRectD * region,OfxPropertySetHandle * imageHandle)3543       static OfxStatus clipGetImagePlane(OfxImageClipHandle clip,
3544                                          OfxTime       time,
3545                                          int           view,
3546                                          const char   *plane,
3547                                          const OfxRectD *region,
3548                                          OfxPropertySetHandle   *imageHandle)
3549       {
3550         try {
3551           if (!imageHandle) {
3552             return kOfxStatErrBadHandle;
3553           }
3554 
3555           ClipInstance *clipInstance = reinterpret_cast<ClipInstance*>(clip);
3556           if (!clipInstance || !clipInstance->verifyMagic()) {
3557             *imageHandle = NULL;
3558 
3559             return kOfxStatErrBadHandle;
3560           }
3561           if ( OFX::IsNaN(time) ) {
3562             *imageHandle = NULL;
3563 
3564             return kOfxStatFailed;
3565           }
3566           Image* image = clipInstance->getImagePlane(time, view, plane, region);
3567           if(!image) {
3568             *imageHandle = NULL;
3569 
3570             return kOfxStatFailed;
3571           }
3572 
3573           *imageHandle = image->getPropHandle();
3574 
3575           return kOfxStatOK;
3576 
3577 
3578         } catch (...) {
3579           *imageHandle = NULL;
3580           return kOfxStatErrBadHandle;
3581         }
3582 
3583       }
3584 
clipGetImagePlane(OfxImageClipHandle clip,OfxTime time,const char * plane,const OfxRectD * region,OfxPropertySetHandle * imageHandle)3585       static OfxStatus clipGetImagePlane(OfxImageClipHandle clip,
3586                                          OfxTime       time,
3587                                          const char   *plane,
3588                                          const OfxRectD *region,
3589                                          OfxPropertySetHandle   *imageHandle)
3590       {
3591         return clipGetImagePlane(clip, time, -1, plane, region, imageHandle);
3592       }
3593 
3594 
3595 
3596       /// get the rod on the given clip at the given time for the given view
clipGetRegionOfDefinition(OfxImageClipHandle clip,OfxTime time,int view,OfxRectD * bounds)3597       static OfxStatus clipGetRegionOfDefinition(OfxImageClipHandle clip,
3598                                                  OfxTime            time,
3599                                                  int                view,
3600                                                  OfxRectD           *bounds)
3601       {
3602         try {
3603           if (!bounds) {
3604             return kOfxStatErrBadHandle;
3605           }
3606 
3607           ClipInstance *clipInstance = reinterpret_cast<ClipInstance*>(clip);
3608 
3609           if (!clipInstance || !clipInstance->verifyMagic()) {
3610             bounds->x1 = bounds->y1 = bounds->x2 = bounds->y2 = 0.;
3611 
3612             return kOfxStatErrBadHandle;
3613           }
3614 
3615           if ( OFX::IsNaN(time) ) {
3616             return kOfxStatFailed;
3617           }
3618           *bounds = clipInstance->getRegionOfDefinition(time, view);
3619           if (bounds->x2 < bounds->x1 || bounds->y2 < bounds->y1) {
3620             // the RoD is invalid (empty is OK)
3621 
3622             return kOfxStatFailed;
3623           }
3624 
3625           return kOfxStatOK;
3626         } catch (...) {
3627           return kOfxStatErrBadHandle;
3628         }
3629 
3630       }
3631 
3632       /// get the textual representation of the view
getViewName(OfxImageEffectHandle effect,int view,const char ** viewName)3633       static OfxStatus getViewName(OfxImageEffectHandle effect,
3634                                    int                  view,
3635                                    const char         **viewName)
3636       {
3637         try {
3638           if (!viewName) {
3639             return kOfxStatErrBadHandle;
3640           }
3641 
3642           ImageEffect::Base *effectBase = reinterpret_cast<ImageEffect::Base*>(effect);
3643 
3644           if (!effectBase || !effectBase->verifyMagic()) {
3645             *viewName = 0;
3646             return kOfxStatErrBadHandle;
3647           }
3648 
3649           ImageEffect::Instance *effectInstance = dynamic_cast<ImageEffect::Instance*>(effectBase);
3650           if (!effectInstance) {
3651             *viewName = 0;
3652             return kOfxStatErrBadHandle;
3653           }
3654 
3655           effectInstance->getViewName(view, viewName);
3656           return kOfxStatOK;
3657         } catch (...) {
3658           *viewName = 0;
3659           return kOfxStatErrBadHandle;
3660         }
3661       }
3662 
3663       /// get the number of views
getViewCount(OfxImageEffectHandle effect,int * nViews)3664       static OfxStatus getViewCount(OfxImageEffectHandle effect,
3665                                     int                 *nViews)
3666       {
3667         try {
3668           if (!nViews) {
3669             return kOfxStatErrBadHandle;
3670           }
3671 
3672           ImageEffect::Base *effectBase = reinterpret_cast<ImageEffect::Base*>(effect);
3673 
3674           if (!effectBase || !effectBase->verifyMagic()) {
3675             *nViews = 0;
3676             return kOfxStatErrBadHandle;
3677           }
3678 
3679           ImageEffect::Instance *effectInstance = dynamic_cast<ImageEffect::Instance*>(effectBase);
3680           if (!effectInstance) {
3681             *nViews = 0;
3682             return kOfxStatErrBadHandle;
3683           }
3684 
3685           effectInstance->getViewCount(nViews);
3686           return kOfxStatOK;
3687         } catch (...) {
3688           *nViews = 0;
3689           return kOfxStatErrBadHandle;
3690         }
3691       }
3692 
3693       static const struct FnOfxImageEffectPlaneSuiteV1 gPlaneSuiteV1 = {
3694         clipGetImagePlane
3695       };
3696 
3697       static const struct FnOfxImageEffectPlaneSuiteV2 gPlaneSuiteV2 = {
3698         clipGetImagePlane,
3699         clipGetRegionOfDefinition,
3700         getViewName,
3701         getViewCount
3702       };
3703 #   endif
3704 
3705 #   ifdef OFX_SUPPORTS_OPENGLRENDER
3706       ////////////////////////////////////////////////////////////////////////////////
3707       ////////////////////////////////////////////////////////////////////////////////
3708       ////////////////////////////////////////////////////////////////////////////////
3709       /// The OpenGL render suite functions
3710 
clipLoadTexture(OfxImageClipHandle h1,OfxTime time,const char * format,const OfxRectD * h2,OfxPropertySetHandle * h3)3711       static OfxStatus clipLoadTexture(OfxImageClipHandle h1,
3712                                        OfxTime time,
3713                                        const char   *format,
3714                                        const OfxRectD *h2,
3715                                        OfxPropertySetHandle *h3)
3716       {
3717         try {
3718         if (!h3) {
3719           return kOfxStatErrBadHandle;
3720         }
3721 
3722         ClipInstance *clipInstance = reinterpret_cast<ClipInstance*>(h1);
3723 
3724         if (!clipInstance || !clipInstance->verifyMagic()) {
3725           return kOfxStatErrBadHandle;
3726         }
3727 
3728         if(clipInstance){
3729           if ( OFX::IsNaN(time) ) {
3730             *h3 = NULL;
3731 
3732             return kOfxStatFailed;
3733           }
3734           Texture* texture = clipInstance->loadTexture(time,format,h2);
3735           if(!texture) {
3736             *h3 = NULL;
3737 
3738             return kOfxStatFailed;
3739           }
3740 
3741           *h3 = texture->getPropHandle();
3742 
3743           return kOfxStatOK;
3744         }
3745 
3746         return kOfxStatErrBadHandle;
3747         } catch (...) {
3748           *h3 = NULL;
3749 
3750           return kOfxStatErrBadHandle;
3751         }
3752       }
3753 
clipFreeTexture(OfxPropertySetHandle h1)3754       static OfxStatus clipFreeTexture(OfxPropertySetHandle h1)
3755       {
3756         try {
3757         Property::Set *pset = reinterpret_cast<Property::Set*>(h1);
3758 
3759         if (!pset || !pset->verifyMagic()) {
3760           return kOfxStatErrBadHandle;
3761         }
3762 
3763         Texture *texture = dynamic_cast<Texture*>(pset);
3764 
3765         if(texture){
3766           // clip::texture has a virtual destructor for derived classes
3767           texture->releaseReference();
3768           return kOfxStatOK;
3769         }
3770         else
3771           return kOfxStatErrBadHandle;
3772         } catch (...) {
3773           return kOfxStatErrBadHandle;
3774         }
3775       }
3776 
flushResources()3777       static OfxStatus flushResources( )
3778       {
3779         return gImageEffectHost->flushOpenGLResources();
3780       }
3781 
3782       static const struct OfxImageEffectOpenGLRenderSuiteV1 gOpenGLRenderSuite = {
3783         clipLoadTexture,
3784         clipFreeTexture,
3785         flushResources
3786       };
3787 #   endif
3788 
3789       /// message suite function for an image effect
message(void * handle,const char * type,const char * id,const char * format,...)3790       static OfxStatus message(void *handle, const char *type, const char *id, const char *format, ...)
3791       {
3792         try {
3793         ImageEffect::Instance *effectInstance = reinterpret_cast<ImageEffect::Instance*>(handle);
3794         OfxStatus stat;
3795         if(effectInstance){
3796           va_list args;
3797           va_start(args,format);
3798           stat = effectInstance->vmessage(type,id,format,args);
3799           va_end(args);
3800         }
3801         else{
3802           va_list args;
3803           va_start(args,format);
3804           vprintf(format,args);
3805           va_end(args);
3806           stat = kOfxStatErrBadHandle;
3807         }
3808         return stat;
3809         } catch (...) {
3810           return kOfxStatFailed;
3811         }
3812       }
3813 
setPersistentMessage(void * handle,const char * type,const char * id,const char * format,...)3814       static OfxStatus setPersistentMessage(void *handle, const char *type, const char *id, const char *format, ...)
3815       {
3816         try {
3817           ImageEffect::Instance *effectInstance = reinterpret_cast<ImageEffect::Instance*>(handle);
3818           OfxStatus stat;
3819           if(effectInstance){
3820             va_list args;
3821             va_start(args,format);
3822             stat = effectInstance->setPersistentMessage(type,id,format,args);
3823             va_end(args);
3824           }
3825           else{
3826             va_list args;
3827             va_start(args,format);
3828             vprintf(format,args);
3829             va_end(args);
3830             stat = kOfxStatErrBadHandle;
3831           }
3832           return stat;
3833         } catch (...) {
3834           return kOfxStatFailed;
3835         }
3836       }
3837 
clearPersistentMessage(void * handle)3838       static OfxStatus clearPersistentMessage(void *handle)
3839       {
3840         try {
3841           ImageEffect::Instance *effectInstance = reinterpret_cast<ImageEffect::Instance*>(handle);
3842           OfxStatus stat;
3843           if(effectInstance){
3844             stat = effectInstance->clearPersistentMessage();
3845           }
3846           else{
3847             stat = kOfxStatErrBadHandle;
3848           }
3849           return stat;
3850         } catch (...) {
3851           return kOfxStatFailed;
3852         }
3853       }
3854 
3855       /// message suite for an image effect plugin (backward-compatible with OfxMessageSuiteV1)
3856       static const struct OfxMessageSuiteV2 gMessageSuite = {
3857         message,
3858         setPersistentMessage,
3859         clearPersistentMessage
3860       };
3861 
3862 #ifdef OFX_SUPPORTS_DIALOG
3863 
3864 #ifdef OFX_SUPPORTS_DIALOG_V1
3865       ////////////////////////////////////////////////////////////////////////////////
3866       ////////////////////////////////////////////////////////////////////////////////
3867       // Dialog suite functions
requestDialogV1(void * user_data)3868       static OfxStatus requestDialogV1(void *user_data)
3869       {
3870         // In OfxDialogSuiteV1, only the host can figure out which effect instance triggered
3871         // that request.
3872         return gImageEffectHost->requestDialog(NULL, NULL, user_data);
3873       }
3874 
notifyredrawPendingV1()3875       static OfxStatus notifyredrawPendingV1()
3876       {
3877         return gImageEffectHost->notifyRedrawPending(NULL, NULL);
3878       }
3879 
3880 
3881       /// dialog suite for an image effect plugin
3882       static const struct OfxDialogSuiteV1 gDialogSuiteV1 = {
3883         requestDialogV1,
3884         notifyredrawPendingV1
3885       };
3886 #endif
3887 
requestDialog(OfxImageEffectHandle instance,OfxPropertySetHandle inArgs,void * instanceData)3888       static OfxStatus requestDialog(OfxImageEffectHandle instance, OfxPropertySetHandle inArgs, void *instanceData)
3889       {
3890         // In OfxDialogSuiteV1, only the host can figure out which effect instance triggered
3891         // that request.
3892         return gImageEffectHost->requestDialog(instance, inArgs, instanceData);
3893       }
3894 
notifyredrawPending(OfxImageEffectHandle instance,OfxPropertySetHandle inArgs)3895       static OfxStatus notifyredrawPending(OfxImageEffectHandle instance, OfxPropertySetHandle inArgs)
3896       {
3897         return gImageEffectHost->notifyRedrawPending(instance, inArgs);
3898       }
3899 
3900       /// dialog suite for an image effect plugin
3901       static const struct OfxDialogSuiteV2 gDialogSuiteV2 = {
3902         requestDialog,
3903         notifyredrawPending
3904       };
3905 #endif // OFX_SUPPORTS_DIALOG
3906 
3907       ////////////////////////////////////////////////////////////////////////////////
3908       /// make an overlay interact for an image effect
OverlayInteract(ImageEffect::Instance & effect,int bitDepthPerComponent,bool hasAlpha)3909       OverlayInteract::OverlayInteract(ImageEffect::Instance &effect, int bitDepthPerComponent, bool hasAlpha)
3910         :  Interact::Instance(effect.getOverlayDescriptor(bitDepthPerComponent, hasAlpha),
3911                               (void *)(effect.getHandle()))
3912         , _instance(effect)
3913       {
3914       }
3915 
3916       ////////////////////////////////////////////////////////////////////////////////
3917       ////////////////////////////////////////////////////////////////////////////////
3918       // Progress suite functions
3919 
3920       /// begin progressing
ProgressStartV1(void * effectInstance,const char * label)3921       static OfxStatus ProgressStartV1(void *effectInstance,
3922                                        const char *label)
3923       {
3924         if (!effectInstance)
3925           return kOfxStatErrBadHandle;
3926         Instance *me = reinterpret_cast<Instance *>(effectInstance);
3927         me->progressStart(label, "");
3928         return kOfxStatOK;
3929       }
3930 
3931 
3932       /// begin progressing
ProgressStart(void * effectInstance,const char * message,const char * messageid)3933       static OfxStatus ProgressStart(void *effectInstance,
3934                                      const char *message,
3935                                      const char *messageid)
3936       {
3937         if (!effectInstance)
3938           return kOfxStatErrBadHandle;
3939         Instance *me = reinterpret_cast<Instance *>(effectInstance);
3940         me->progressStart(message, messageid);
3941         return kOfxStatOK;
3942       }
3943 
3944       /// finish progressing
ProgressEnd(void * effectInstance)3945       static OfxStatus ProgressEnd(void *effectInstance)
3946       {
3947         if (!effectInstance)
3948           return kOfxStatErrBadHandle;
3949         Instance *me = reinterpret_cast<Instance *>(effectInstance);
3950         me->progressEnd();
3951         return kOfxStatOK;
3952       }
3953 
3954       /// update progressing
ProgressUpdate(void * effectInstance,double progress)3955       static OfxStatus ProgressUpdate(void *effectInstance, double progress)
3956       {
3957         if (!effectInstance)
3958           return kOfxStatErrBadHandle;
3959         Instance *me = reinterpret_cast<Instance *>(effectInstance);
3960         bool v = me->progressUpdate(progress);
3961         return v ? kOfxStatOK : kOfxStatReplyNo;
3962       }
3963 
3964       /// our progress suite
3965       struct OfxProgressSuiteV1 gProgressSuiteV1 = {
3966         ProgressStartV1,
3967         ProgressUpdate,
3968         ProgressEnd
3969       };
3970 
3971       struct OfxProgressSuiteV2 gProgressSuiteV2 = {
3972         ProgressStart,
3973         ProgressUpdate,
3974         ProgressEnd
3975       };
3976 
3977 
3978       ////////////////////////////////////////////////////////////////////////////////
3979       ////////////////////////////////////////////////////////////////////////////////
3980       // timeline suite functions
3981 
3982       /// timeline suite function
TimeLineGetTime(void * effectInstance,double * time)3983       static OfxStatus TimeLineGetTime(void *effectInstance, double *time)
3984       {
3985         if (!effectInstance)
3986           return kOfxStatErrBadHandle;
3987         Instance *me = reinterpret_cast<Instance *>(effectInstance);
3988         *time = me->timeLineGetTime();
3989         return kOfxStatOK;
3990       }
3991 
3992       /// timeline suite function
TimeLineGotoTime(void * effectInstance,double time)3993       static OfxStatus TimeLineGotoTime(void *effectInstance, double time)
3994       {
3995         if (!effectInstance)
3996           return kOfxStatErrBadHandle;
3997         Instance *me = reinterpret_cast<Instance *>(effectInstance);
3998         me->timeLineGotoTime(time);
3999         return kOfxStatOK;
4000       }
4001 
4002       /// timeline suite function
TimeLineGetBounds(void * effectInstance,double * firstTime,double * lastTime)4003       static OfxStatus TimeLineGetBounds(void *effectInstance, double *firstTime, double *lastTime)
4004       {
4005         if (!effectInstance)
4006           return kOfxStatErrBadHandle;
4007         Instance *me = reinterpret_cast<Instance *>(effectInstance);
4008         me->timeLineGetBounds(*firstTime, *lastTime);
4009         return kOfxStatOK;
4010       }
4011 
4012       /// our progress suite
4013       struct OfxTimeLineSuiteV1 gTimelineSuite = {
4014         TimeLineGetTime,
4015         TimeLineGotoTime,
4016         TimeLineGetBounds
4017       };
4018 
4019       ////////////////////////////////////////////////////////////////////////////////
4020 #ifdef OFX_SUPPORTS_MULTITHREAD
4021       // Forward all multithread suite calls to the host implementation.
4022 
multiThread(OfxThreadFunctionV1 func,unsigned int nThreads,void * customArg)4023       static OfxStatus multiThread(OfxThreadFunctionV1 func,
4024                                    unsigned int nThreads,
4025                                    void *customArg)
4026       {
4027         return gImageEffectHost->multiThread(func, nThreads, customArg);
4028       }
4029 
multiThreadNumCPUs(unsigned int * nCPUs)4030       static OfxStatus multiThreadNumCPUs(unsigned int *nCPUs)
4031       {
4032         return gImageEffectHost->multiThreadNumCPUS(nCPUs);
4033       }
4034 
multiThreadIndex(unsigned int * threadIndex)4035       static OfxStatus multiThreadIndex(unsigned int *threadIndex){
4036         return gImageEffectHost->multiThreadIndex(threadIndex);
4037       }
4038 
multiThreadIsSpawnedThread(void)4039       static int multiThreadIsSpawnedThread(void){
4040         return gImageEffectHost->multiThreadIsSpawnedThread();
4041       }
4042 
mutexCreate(OfxMutexHandle * mutex,int lockCount)4043       static OfxStatus mutexCreate(OfxMutexHandle *mutex, int lockCount)
4044       {
4045         return gImageEffectHost->mutexCreate(mutex, lockCount);
4046       }
4047 
mutexDestroy(const OfxMutexHandle mutex)4048       static OfxStatus mutexDestroy(const OfxMutexHandle mutex)
4049       {
4050         return gImageEffectHost->mutexDestroy(mutex);
4051       }
4052 
mutexLock(const OfxMutexHandle mutex)4053       static OfxStatus mutexLock(const OfxMutexHandle mutex){
4054         return gImageEffectHost->mutexLock(mutex);
4055       }
4056 
mutexUnLock(const OfxMutexHandle mutex)4057       static OfxStatus mutexUnLock(const OfxMutexHandle mutex){
4058         return gImageEffectHost->mutexUnLock(mutex);
4059       }
4060 
mutexTryLock(const OfxMutexHandle mutex)4061       static OfxStatus mutexTryLock(const OfxMutexHandle mutex){
4062         return gImageEffectHost->mutexTryLock(mutex);
4063       }
4064 #else // !OFX_SUPPORTS_MULTITHREAD
4065       /// a simple multithread suite
multiThread(OfxThreadFunctionV1 func,unsigned int,void * customArg)4066       static OfxStatus multiThread(OfxThreadFunctionV1 func,
4067                                    unsigned int /*nThreads*/,
4068                                    void *customArg)
4069       {
4070         if (!func)
4071           return kOfxStatFailed;
4072         func(0,1,customArg);
4073         return kOfxStatOK;
4074       }
4075 
multiThreadNumCPUs(unsigned int * nCPUs)4076       static OfxStatus multiThreadNumCPUs(unsigned int *nCPUs)
4077       {
4078         if (!nCPUs)
4079           return kOfxStatFailed;
4080         *nCPUs = 1;
4081         return kOfxStatOK;
4082       }
4083 
multiThreadIndex(unsigned int * threadIndex)4084       static OfxStatus multiThreadIndex(unsigned int *threadIndex){
4085         if (!threadIndex)
4086           return kOfxStatFailed;
4087         *threadIndex = 0;
4088         return kOfxStatOK;
4089       }
4090 
multiThreadIsSpawnedThread(void)4091       static int multiThreadIsSpawnedThread(void){
4092         return false;
4093       }
4094 
mutexCreate(OfxMutexHandle * mutex,int)4095       static OfxStatus mutexCreate(OfxMutexHandle *mutex, int /*lockCount*/)
4096       {
4097         if (!mutex)
4098           return kOfxStatFailed;
4099         // do nothing single threaded
4100         *mutex = 0;
4101         return kOfxStatOK;
4102       }
4103 
mutexDestroy(const OfxMutexHandle mutex)4104       static OfxStatus mutexDestroy(const OfxMutexHandle mutex)
4105       {
4106         if (mutex != 0)
4107           return kOfxStatErrBadHandle;
4108         // do nothing single threaded
4109         return kOfxStatOK;
4110       }
4111 
mutexLock(const OfxMutexHandle mutex)4112       static OfxStatus mutexLock(const OfxMutexHandle mutex){
4113         if (mutex != 0)
4114           return kOfxStatErrBadHandle;
4115         // do nothing single threaded
4116         return kOfxStatOK;
4117       }
4118 
mutexUnLock(const OfxMutexHandle mutex)4119       static OfxStatus mutexUnLock(const OfxMutexHandle mutex){
4120         if (mutex != 0)
4121           return kOfxStatErrBadHandle;
4122         // do nothing single threaded
4123         return kOfxStatOK;
4124       }
4125 
mutexTryLock(const OfxMutexHandle mutex)4126       static OfxStatus mutexTryLock(const OfxMutexHandle mutex){
4127         if (mutex != 0)
4128           return kOfxStatErrBadHandle;
4129         // do nothing single threaded
4130         return kOfxStatOK;
4131       }
4132 #endif // !OFX_SUPPORTS_MULTITHREAD
4133 
4134       static const struct OfxMultiThreadSuiteV1 gMultiThreadSuite = {
4135         multiThread,
4136         multiThreadNumCPUs,
4137         multiThreadIndex,
4138         multiThreadIsSpawnedThread,
4139         mutexCreate,
4140         mutexDestroy,
4141         mutexLock,
4142         mutexUnLock,
4143         mutexTryLock
4144       };
4145 
4146 
4147       ////////////////////////////////////////////////////////////////////////////////
4148       /// The image effect host
4149 
4150       /// properties for the image effect host
4151       static const Property::PropSpec hostStuffs[] = {
4152         { kOfxImageEffectHostPropIsBackground, Property::eInt, 1, true, "0" },
4153         { kOfxImageEffectPropSupportsOverlays, Property::eInt, 1, true, "1" },
4154         { kOfxImageEffectPropSupportsMultiResolution, Property::eInt, 1, true, "1" },
4155         { kOfxImageEffectPropSupportsTiles, Property::eInt, 1, true, "1" },
4156         { kOfxImageEffectPropTemporalClipAccess, Property::eInt, 1, true, "1"  },
4157 
4158 
4159 
4160         /// xxx this needs defaulting manually
4161         { kOfxImageEffectPropSupportedComponents, Property::eString, 0, true, "" },
4162         /// xxx this needs defaulting manually
4163 
4164         { kOfxImageEffectPropSupportedPixelDepths, Property::eString, 0, true, "" },
4165 
4166         /// xxx this needs defaulting manually
4167 
4168         { kOfxImageEffectPropSupportedContexts, Property::eString, 0, true, "" },
4169         /// xxx this needs defaulting manually
4170 
4171         { kOfxImageEffectPropSupportsMultipleClipDepths, Property::eInt, 1, true, "1" },
4172         { kOfxImageEffectPropSupportsMultipleClipPARs, Property::eInt, 1, true, "0" },
4173         { kOfxImageEffectPropSetableFrameRate, Property::eInt, 1, true, "0" },
4174         { kOfxImageEffectPropSetableFielding, Property::eInt, 1, true, "0"  },
4175         { kOfxParamHostPropSupportsCustomInteract, Property::eInt, 1, true, "0" },
4176         { kOfxParamHostPropSupportsStringAnimation, Property::eInt, 1, true, "0" },
4177         { kOfxParamHostPropSupportsChoiceAnimation, Property::eInt, 1, true, "0"  },
4178 #     ifdef OFX_EXTENSIONS_RESOLVE
4179         { kOfxParamHostPropSupportsStrChoiceAnimation, Property::eInt, 1, true, "0"  },
4180 #     endif
4181         { kOfxParamHostPropSupportsBooleanAnimation, Property::eInt, 1, true, "0" },
4182         { kOfxParamHostPropSupportsCustomAnimation, Property::eInt, 1, true, "0" },
4183         { kOfxPropHostOSHandle, Property::ePointer, 1, true, NULL },
4184 #     ifdef OFX_SUPPORTS_PARAMETRIC
4185         { kOfxParamHostPropSupportsParametricAnimation, Property::eInt, 1, true, "0"},
4186 #      ifdef OFX_SUPPORTS_PARAMETRIC_V2
4187         { kOfxHostPropSupportedParametricInterpolations, Property::eString, 0, true, ""},
4188 #      endif
4189 #     endif
4190         { kOfxParamHostPropMaxParameters, Property::eInt, 1, true, "-1" },
4191         { kOfxParamHostPropMaxPages, Property::eInt, 1, true, "0" },
4192         { kOfxParamHostPropPageRowColumnCount, Property::eInt, 2, true, "0" },
4193         { kOfxImageEffectInstancePropSequentialRender, Property::eInt, 1, true, "0" }, // OFX 1.2
4194 #     ifdef OFX_SUPPORTS_OPENGLRENDER
4195         { kOfxImageEffectPropOpenGLRenderSupported, Property::eString, 1, true, "false"}, // OFX 1.3
4196 #     endif
4197         { kOfxImageEffectPropRenderQualityDraft, Property::eInt, 1, true, "0" }, // OFX 1.4
4198         { kOfxImageEffectHostPropNativeOrigin, Property::eString, 0, true, kOfxHostNativeOriginBottomLeft }, // OFX 1.4
4199 #     ifdef OFX_EXTENSIONS_RESOLVE
4200         { kOfxImageEffectPropOpenCLRenderSupported, Property::eString, 1, false, "false"},
4201         { kOfxImageEffectPropCudaRenderSupported, Property::eString, 1, false, "false" },
4202 #     endif
4203 #     ifdef OFX_EXTENSIONS_NUKE
4204         { kFnOfxImageEffectPropMultiPlanar,   Property::eInt, 1, false, "0" },
4205         { kFnOfxImageEffectCanTransform,      Property::eInt, 1, true, "0" },
4206 #     endif
4207 #     ifdef OFX_EXTENSIONS_NATRON
4208         { kNatronOfxHostIsNatron, Property::eInt, 1, true, "0" },
4209         { kNatronOfxParamHostPropSupportsDynamicChoices, Property::eInt, 1, true, "0" },
4210         { kNatronOfxParamPropChoiceCascading, Property::eInt, 1, true, "0" },
4211         { kNatronOfxImageEffectPropChannelSelector, Property::eString, 1, true, kOfxImageComponentNone },
4212         { kNatronOfxImageEffectPropHostMasking, Property::eInt, 1, true, "0" },
4213         { kNatronOfxImageEffectPropHostMixing, Property::eInt, 1, true, "0" },
4214         { kNatronOfxPropDescriptionIsMarkdown, Property::eInt, 1, true, "0" },
4215         { kNatronOfxImageEffectPropDefaultCursors, Property::eString, 0, true, "" },
4216         { kNatronOfxPropNativeOverlays, Property::eString, 0, true, ""},
4217         { kOfxImageEffectPropCanDistort, Property::eInt, 1, false, "0" },
4218 #    endif
4219         Property::propSpecEnd
4220       };
4221 
4222       /// ctor
Host()4223       Host::Host()
4224       {
4225         /// add the properties for an image effect host, derived classs to set most of them
4226         _properties.addProperties(hostStuffs);
4227       }
4228 
4229       /// optionally over-ridden function to register the creation of a new descriptor in the host app
initDescriptor(Descriptor *)4230       void Host::initDescriptor(Descriptor* /*desc*/)
4231       {
4232       }
4233 
4234       /// Use this in any dialogue etc... showing progress
loadingStatus(bool,const std::string &,int,int)4235       void Host::loadingStatus(bool /*loading*/, const std::string &/*id*/, int /*versionMajor*/, int /*versionMinor*/)
4236       {
4237       }
4238 
pluginSupported(ImageEffectPlugin *,std::string &) const4239       bool Host::pluginSupported(ImageEffectPlugin */*plugin*/, std::string &/*reason*/) const
4240       {
4241         return true;
4242       }
4243 
4244       // override this to use your own memory instance - must inherrit from memory::instance
newMemoryInstance(size_t)4245       Memory::Instance* Host::newMemoryInstance(size_t /*nBytes*/) {
4246         return 0;
4247       }
4248 
4249       // return an memory::instance calls makeMemoryInstance that can be overriden
imageMemoryAlloc(size_t nBytes)4250       Memory::Instance* Host::imageMemoryAlloc(size_t nBytes){
4251         Memory::Instance* instance = newMemoryInstance(nBytes);
4252         if(instance)
4253           return instance;
4254         else{
4255           Memory::Instance* instance = new Memory::Instance;
4256           instance->alloc(nBytes);
4257           return instance;
4258         }
4259       }
4260 
4261       /// our suite fetcher
fetchSuite(const char * suiteName,int suiteVersion)4262       const void *Host::fetchSuite(const char *suiteName, int suiteVersion)
4263       {
4264         if (strcmp(suiteName, kOfxImageEffectSuite)==0) {
4265           if(suiteVersion==1)
4266             return (void *)&gImageEffectSuite;
4267           else
4268             return NULL;
4269         }
4270         else if (strcmp(suiteName, kOfxParameterSuite)==0) {
4271           return Param::GetSuite(suiteVersion);
4272         }
4273         else if (strcmp(suiteName, kOfxMessageSuite)==0) {
4274           // version 2 is backward-compatible
4275           if(suiteVersion==1 || suiteVersion==2)
4276             return (void *)&gMessageSuite;
4277           else
4278             return NULL;
4279         }
4280 #ifdef OFX_SUPPORTS_DIALOG
4281         else if (strcmp(suiteName, kOfxDialogSuite)==0) {
4282           if(suiteVersion==1)
4283 #ifdef OFX_SUPPORTS_DIALOG_V1
4284             return (void *)&gDialogSuiteV1;
4285 #else
4286             return (void *)0;
4287 #endif
4288           else if(suiteVersion==2)
4289             return (void *)&gDialogSuiteV2;
4290           else
4291             return NULL;
4292         }
4293 #endif
4294         else if (strcmp(suiteName, kOfxInteractSuite)==0) {
4295           return Interact::GetSuite(suiteVersion);
4296         }
4297         else if (strcmp(suiteName, kOfxProgressSuite)==0) {
4298           if(suiteVersion==1)
4299             return (void*)&gProgressSuiteV1;
4300           else if(suiteVersion==2)
4301             return (void*)&gProgressSuiteV2;
4302           else
4303             return 0;
4304         }
4305 #     ifdef OFX_EXTENSIONS_VEGAS
4306         else if (strcmp(suiteName, kOfxVegasProgressSuite)==0) {
4307             if(suiteVersion == 1)
4308                 return (void*)&gProgressSuiteV2;
4309             //if(suiteVersion == 2)
4310             //    return (void*)&gVegasProgressSuiteV2;
4311             else
4312                 return NULL;
4313         }
4314 #     endif
4315         else if (strcmp(suiteName, kOfxTimeLineSuite)==0) {
4316           if(suiteVersion==1)
4317             return (void*)&gTimelineSuite;
4318           else
4319             return 0;
4320         }
4321         else if (strcmp(suiteName, kOfxMultiThreadSuite)==0) {
4322           if(suiteVersion == 1)
4323             return (void*)&gMultiThreadSuite;
4324           else
4325             return NULL;
4326         }
4327 #     ifdef OFX_SUPPORTS_OPENGLRENDER
4328         else if (strcmp(suiteName, kOfxOpenGLRenderSuite)==0) {
4329           if(suiteVersion == 1)
4330             return (void*)&gOpenGLRenderSuite;
4331           else
4332             return NULL;
4333         }
4334 #     endif
4335 #     ifdef OFX_EXTENSIONS_VEGAS
4336 #      if 0
4337         else if (strcmp(suiteName, kOfxVegasKeyframeSuite)==0) {
4338             if(suiteVersion == 1)
4339                 return (void*)&gVegasKeyframeSuite;
4340             else
4341                 return NULL;
4342         }
4343 #      endif
4344         else if (strcmp(suiteName, kOfxVegasStereoscopicImageEffectSuite)==0) {
4345             if(suiteVersion == 1)
4346                 return (void*)&gVegasStereoscopicImageEffectSuite;
4347             else
4348                 return NULL;
4349         }
4350 #     endif
4351 #     ifdef OFX_SUPPORTS_PARAMETRIC
4352         else if (strcmp(suiteName, kOfxParametricParameterSuite)==0) {
4353           return ParametricParam::GetSuite(suiteVersion);
4354         }
4355 #     endif
4356 #     ifdef OFX_EXTENSIONS_NUKE
4357         else if (strcmp(suiteName,kFnOfxImageEffectPlaneSuite) == 0 && suiteVersion == 1) {
4358             return (void*)&gPlaneSuiteV1;
4359         }
4360         else if (strcmp(suiteName,kFnOfxImageEffectPlaneSuite) == 0 && suiteVersion == 2) {
4361             return (void*)&gPlaneSuiteV2;
4362         }
4363 #     endif
4364         else  /// otherwise just grab the base class one, which is props and memory
4365           return OFX::Host::Host::fetchSuite(suiteName, suiteVersion);
4366       }
4367 
4368     } // ImageEffect
4369 
4370   } // Host
4371 
4372 } // OFX
4373