1 /*
2 OFX Support Library, a library that skins the OFX plug-in API with C++ classes.
3 Copyright (C) 2004-2007 The Open Effects Association Ltd
4 Author Bruno Nicoletti bruno@thefoundry.co.uk
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 The Open Effects Association Ltd
30 1 Wardour St
31 London W1D 6PA
32 England
33
34
35 */
36
37 /** @brief This file contains code that skins the ofx effect suite */
38
39 #include "ofxsSupportPrivate.h"
40 #include <algorithm> // for find, min, max
41 #include <cstring> // for strlen
42 #include <sstream> // stringstream
43 #include <set>
44 #ifdef DEBUG
45 #include <iostream>
46 #endif
47 #include <stdexcept>
48 #ifdef OFX_EXTENSIONS_NUKE
49 #include "nuke/fnOfxExtensions.h"
50 #endif
51 #ifdef OFX_EXTENSIONS_NATRON
52 #include "ofxNatron.h"
53 #endif
54 #ifdef OFX_SUPPORTS_OPENGLRENDER
55 #include "ofxOpenGLRender.h"
56 #endif
57 #include "ofxsCore.h"
58
59 #if defined __APPLE__ || defined __linux__ || defined __DragonFly__
60 # if __GNUC__ >= 4
61 # define EXPORT __attribute__((visibility("default")))
62 # define LOCAL __attribute__((visibility("hidden")))
63 # else
64 # define EXPORT
65 # define LOCAL
66 # endif
67 #elif defined _WIN32
68 # define EXPORT OfxExport
69 # define LOCAL
70 #else
71 # error Not building on your operating system quite yet
72 #endif
73
74 // string utility functions
ends_with(std::string const & value,std::string const & ending)75 static bool ends_with(std::string const & value, std::string const & ending)
76 {
77 if (ending.size() > value.size()) return false;
78 return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
79 }
80
starts_with(std::string const & value,std::string const & beginning)81 static bool starts_with(std::string const & value, std::string const & beginning)
82 {
83 if (beginning.size() > value.size()) return false;
84 return std::equal(beginning.begin(), beginning.end(), value.begin());
85 }
86
87 template<typename T>
88 static inline void
unused(const T &)89 unused(const T&) {}
90
91 #ifdef DEBUG
92 //table for xml encoding compatibility with expat decoding
93 //see expat/src/xmltok_impl.h
94 //and expat/src/asciitab.h
95 static const int charXMLCompatiblity[] =
96 {
97 /* 0x00 */ 0, 0, 0, 0,
98 /* 0x04 */ 0, 0, 0, 0,
99 /* 0x08 */ 0, 1, 1, 0,
100 /* 0x0C */ 0, 1, 0, 0,
101 /* 0x10 */ 0, 0, 0, 0,
102 /* 0x14 */ 0, 0, 0, 0,
103 /* 0x18 */ 0, 0, 0, 0,
104 /* 0x1C */ 0, 0, 0, 0,
105 };
106
107 // Check the effect descriptor for potentially bad XML in the OFX Plugin cache.
108 //
109 // The function that wrote string properties to the OFX plugin cache used to
110 // escape only que quote (") character. As a result, if one of the string
111 // properties in the Image Effect descriptor contains special characters,
112 // the host may be unable to read the plugin cache, giving an "xml error 4"
113 // (error 4 is XML_ERROR_INVALID_TOKEN).
114 //
115 // The plugin label and grouping may not contain any of these bad characters.
116 // The plugin description may contain characters that do not corrupt the XML,
117 // because kOfxActionDescribe is usually called at plugin loading.
118 //
119 // Version with the bug:
120 // https://github.com/ofxa/openfx/blob/34ff595a2918e9e4065603d7fc4d500ae9efc421/HostSupport/include/ofxhXml.h
121 // Version without the bug:
122 // https://github.com/ofxa/openfx/blob/64ba52fff61894759fbf3942b92659b02b2b17cd/HostSupport/include/ofxhXml.h
123 //
124 // With the old version:
125 // - All characters within 0x01..0x1f and 0x7F..0x9F, except \t \b \r (0x09 0x0A 0X0D) are forbidden
126 // in label and grouping, because these may be used to build the GUI before loading the plugin.
127 // They may appear in the description, although it is not recommended.
128 // - The '<' and '&' characters generate bad XML in all cases
129 // - The '>' and '\'' characters are tolerated by the expat parser, although the XML is not valid
validateXMLString(std::string const & s,bool strict)130 static void validateXMLString(std::string const & s, bool strict)
131 {
132 int lt = 0;
133 int amp = 0;
134 int ctrl = 0;
135 char ctrllast = 0;
136 int ctrlexpatbug = 0; // control characters which expat can not decode anyway, because of a bug in xmltok.c:checkCharRefNumber
137 char ctrlexpatbuglast = 0;
138 for (size_t i=0;i<s.size();i++) {
139 // The are exactly five characters which must be escaped
140 // http://www.w3.org/TR/xml/#syntax
141 switch (s[i]) {
142 case '\t':
143 case '\n':
144 case '\r':
145 case '"':
146 case '\'':
147 case '>':
148 break;
149 case '<':
150 ++lt;
151 break;
152 case '&':
153 ++amp;
154 break;
155 default: {
156 unsigned char c = (unsigned char)(s[i]);
157 if ((0x01 <= c && c <= 0x1f) || (0x7F <= c && c <= 0x9F)) {
158 ++ctrl;
159 ctrllast = c;
160 //characters such ase eot (0x04) and stx (0x02) make expat parser bail
161 //see xmltok.c in expat checkCharRefNumber() to see how expat bails on these chars.
162 //also see expat/src/asciitab.h to see which characters are nonxml compatible post decode
163 //(we can still encode '&' and '<' with this table, but it prevents us from encoding eot)
164 //everything is compatible past ascii 0x20, so we don't check higher than this.
165 if(c <= 0x1F && charXMLCompatiblity[c] == 0) {
166 ++ctrlexpatbug;
167 ctrlexpatbuglast = c;
168 }
169 }
170 } break;
171 }
172 }
173 if (lt || amp || ctrl) {
174 std::cout << "Warning: the following string value may break the OFX plugin cache on older hosts,\n";
175 std::cout << "because it contains:\n";
176 if (lt) {
177 std::cout << lt << " '<' characters\n";
178 }
179 if (amp) {
180 std::cout << amp << " '&' characters\n";
181 }
182 if (ctrl) {
183 if (!strict) {
184 std::cout << "(nonfatal) ";
185 }
186 std::cout << ctrl << " invalid characters in the range 0x01..0x1f or 0x7F..0x9F, last one was ASCII=" << (int)ctrllast << std::endl;
187 }
188 if (ctrlexpatbug) {
189 if (!strict) {
190 std::cout << "(nonfatal) ";
191 }
192 std::cout << ctrlexpatbug << " invalid characters in the range 0x01..0x1f which expat cannot decode (will cause xml error 'reference to invalid character number (14)'), last one was ASCII=" << (int)ctrlexpatbuglast << std::endl;
193
194 }
195 std::cout << "Raw string value (length=" << s.size() << "):\n";
196 std::cout << s << std::endl;
197 }
198 }
199 #else
200 #define validateXMLString(s,b) (void)0;
201 #endif
202
203 /** @brief The core 'OFX Support' namespace, used by plugin implementations. All code for these are defined in the common support libraries. */
204 namespace OFX {
205
206 //Put it all into a map, so we know when to delete what!
207 struct OfxPlugInfo
208 {
OfxPlugInfoOFX::OfxPlugInfo209 OfxPlugInfo(): _factory(NULL), _plug(NULL) {}
OfxPlugInfoOFX::OfxPlugInfo210 OfxPlugInfo(OFX::PluginFactory* f, OfxPlugin* p):_factory(f), _plug(p){}
211 OFX::PluginFactory* _factory;
212 OfxPlugin* _plug;
213 };
214 typedef std::map<std::string, OfxPlugInfo> OfxPlugInfoMap;
215 OfxPlugInfoMap plugInfoMap;
216
217 typedef std::vector<OfxPlugin*> OfxPluginArray;
218 OfxPluginArray ofxPlugs;
219
220 /** @brief the global host description */
221 ImageEffectHostDescription gHostDescription;
222 bool gHostDescriptionHasInit = false;
223
supportsPixelComponent(const PixelComponentEnum component) const224 bool ImageEffectHostDescription::supportsPixelComponent(const PixelComponentEnum component) const
225 {
226 return std::find(_supportedComponents.begin(), _supportedComponents.end(), component) != _supportedComponents.end();
227 }
supportsBitDepth(const BitDepthEnum bitDepth) const228 bool ImageEffectHostDescription::supportsBitDepth( const BitDepthEnum bitDepth) const
229 {
230 return std::find(_supportedPixelDepths.begin(), _supportedPixelDepths.end(), bitDepth) != _supportedPixelDepths.end();
231 }
supportsContext(const ContextEnum context) const232 bool ImageEffectHostDescription::supportsContext(const ContextEnum context) const
233 {
234 return std::find(_supportedContexts.begin(), _supportedContexts.end(), context) != _supportedContexts.end();
235 }
236
237 /** @return default pixel depth supported by host application. */
getDefaultPixelDepth() const238 BitDepthEnum ImageEffectHostDescription::getDefaultPixelDepth() const
239 {
240 if(!_supportedPixelDepths.empty()) {
241 return _supportedPixelDepths[0];
242 } else {
243 OFX::Log::warning(true, "The host doesn't define supported pixel depth. (size: %d)", (int)_supportedPixelDepths.size());
244 return eBitDepthFloat;
245 }
246 }
247
248 /** @return default pixel component supported by host application. */
getDefaultPixelComponent() const249 PixelComponentEnum ImageEffectHostDescription::getDefaultPixelComponent() const
250 {
251 if(! _supportedComponents.empty()) {
252 return _supportedComponents[0];
253 } else {
254 OFX::Log::warning(true, "The host doesn't define supported pixel component. (size: %d)", _supportedComponents.size());
255 return ePixelComponentRGBA;
256 }
257 }
258
getImageEffectHostDescription()259 ImageEffectHostDescription* getImageEffectHostDescription()
260 {
261 if(gHostDescriptionHasInit)
262 return &gHostDescription;
263 return NULL;
264 }
265
266 namespace Private {
267 // Suite and host pointers
268 OfxHost *gHost = 0;
269 OfxImageEffectSuiteV1 *gEffectSuite = 0;
270 OfxPropertySuiteV1 *gPropSuite = 0;
271 OfxInteractSuiteV1 *gInteractSuite = 0;
272 OfxParameterSuiteV1 *gParamSuite = 0;
273 OfxMemorySuiteV1 *gMemorySuite = 0;
274 OfxMultiThreadSuiteV1 *gThreadSuite = 0;
275 OfxMessageSuiteV1 *gMessageSuite = 0;
276 OfxMessageSuiteV2 *gMessageSuiteV2 = 0;
277 OfxProgressSuiteV1 *gProgressSuiteV1 = 0;
278 OfxProgressSuiteV2 *gProgressSuiteV2 = 0;
279 #ifdef OFX_SUPPORTS_DIALOG
280 OfxDialogSuiteV1 *gDialogSuiteV1 = 0;
281 OfxDialogSuiteV2 *gDialogSuiteV2 = 0;
282 #endif
283 OfxTimeLineSuiteV1 *gTimeLineSuite = 0;
284 OfxParametricParameterSuiteV1 *gParametricParameterSuite = 0;
285 #ifdef OFX_SUPPORTS_OPENGLRENDER
286 OfxImageEffectOpenGLRenderSuiteV1 *gOpenGLRenderSuite = 0;
287 #endif
288 #ifdef OFX_EXTENSIONS_NUKE
289 NukeOfxCameraSuiteV1* gCameraSuite = 0;
290 FnOfxImageEffectPlaneSuiteV1* gImageEffectPlaneSuiteV1 = 0;
291 FnOfxImageEffectPlaneSuiteV2* gImageEffectPlaneSuiteV2 = 0;
292 #endif
293 #ifdef OFX_EXTENSIONS_VEGAS
294 #if defined(WIN32) || defined(WIN64)
295 OfxHWNDInteractSuiteV1 *gHWNDInteractSuite = 0;
296 #endif // #if defined(WIN32) || defined(WIN64)
297 OfxVegasProgressSuiteV1 *gVegasProgressSuite = 0;
298 OfxVegasStereoscopicImageSuiteV1 *gVegasStereoscopicImageSuite = 0;
299 OfxVegasKeyframeSuiteV1 *gVegasKeyframeSuite = 0;
300 #endif
301
302 // @brief the set of descriptors, one per context used by kOfxActionDescribeInContext,
303 //'eContextNone' is the one used by the kOfxActionDescribe
304 EffectDescriptorMap gEffectDescriptors;
305 };
306
307 /** @brief map a std::string to a context */
mapToContextEnum(const std::string & s)308 ContextEnum mapToContextEnum(const std::string &s) OFX_THROW(std::invalid_argument)
309 {
310 if(s == kOfxImageEffectContextGenerator) return eContextGenerator;
311 if(s == kOfxImageEffectContextFilter) return eContextFilter;
312 if(s == kOfxImageEffectContextTransition) return eContextTransition;
313 if(s == kOfxImageEffectContextPaint) return eContextPaint;
314 if(s == kOfxImageEffectContextGeneral) return eContextGeneral;
315 if(s == kOfxImageEffectContextRetimer) return eContextRetimer;
316 #ifdef OFX_EXTENSIONS_TUTTLE
317 if(s == kOfxImageEffectContextReader) return eContextReader;
318 if(s == kOfxImageEffectContextWriter) return eContextWriter;
319 #endif
320 #ifdef OFX_EXTENSIONS_NATRON
321 if(s == kNatronOfxImageEffectContextTracker) return eContextTracker;
322 #endif
323 OFX::Log::error(true, "Unknown image effect context '%s'", s.c_str());
324 throw std::invalid_argument(s);
325 }
326
mapContextEnumToStr(ContextEnum context)327 const char* mapContextEnumToStr(ContextEnum context) OFX_THROW(std::invalid_argument)
328 {
329 switch (context) {
330 case eContextGenerator:
331 return kOfxImageEffectContextGenerator;
332 case eContextFilter:
333 return kOfxImageEffectContextFilter;
334 case eContextTransition:
335 return kOfxImageEffectContextTransition;
336 case eContextPaint:
337 return kOfxImageEffectContextPaint;
338 case eContextGeneral:
339 return kOfxImageEffectContextGeneral;
340 case eContextRetimer:
341 return kOfxImageEffectContextRetimer;
342 #ifdef OFX_EXTENSIONS_TUTTLE
343 case eContextReader:
344 return kOfxImageEffectContextReader;
345 case eContextWriter:
346 return kOfxImageEffectContextWriter;
347 #endif
348 #ifdef OFX_EXTENSIONS_NATRON
349 case eContextTracker:
350 return kNatronOfxImageEffectContextTracker;
351 #endif
352 default:
353 OFX::Log::error(true, "Unknown context enum '%d'", (int)context);
354 throw std::invalid_argument("unknown ContextEnum");
355 }
356 }
357
mapMessageTypeEnumToStr(OFX::Message::MessageTypeEnum type)358 const char* mapMessageTypeEnumToStr(OFX::Message::MessageTypeEnum type)
359 {
360 if(type == OFX::Message::eMessageFatal)
361 return kOfxMessageFatal;
362 else if(type == OFX::Message::eMessageError)
363 return kOfxMessageError;
364 else if(type == OFX::Message::eMessageMessage)
365 return kOfxMessageMessage;
366 else if(type == OFX::Message::eMessageWarning)
367 return kOfxMessageWarning;
368 else if(type == OFX::Message::eMessageLog)
369 return kOfxMessageLog;
370 else if(type == OFX::Message::eMessageQuestion)
371 return kOfxMessageQuestion;
372 OFX::Log::error(true, "Unknown message type enum '%d'", type);
373 return 0;
374 }
375
mapToMessageReplyEnum(OfxStatus stat)376 OFX::Message::MessageReplyEnum mapToMessageReplyEnum(OfxStatus stat)
377 {
378 if(stat == kOfxStatOK)
379 return OFX::Message::eMessageReplyOK;
380 else if(stat == kOfxStatReplyYes)
381 return OFX::Message::eMessageReplyYes;
382 else if(stat == kOfxStatReplyNo)
383 return OFX::Message::eMessageReplyNo;
384 else if(stat == kOfxStatFailed)
385 return OFX::Message::eMessageReplyFailed;
386 OFX::Log::error(true, "Unknown message reply status enum '%d'", stat);
387 return OFX::Message::eMessageReplyFailed;
388 }
389
390 /** @brief map a std::string to a context */
mapToInstanceChangedReason(const std::string & s)391 InstanceChangeReason mapToInstanceChangedReason(const std::string &s) OFX_THROW(std::invalid_argument)
392 {
393 if(s == kOfxChangePluginEdited) return eChangePluginEdit;
394 if(s == kOfxChangeUserEdited) return eChangeUserEdit;
395 if(s == kOfxChangeTime) return eChangeTime;
396 OFX::Log::error(true, "Unknown instance changed reason '%s'", s.c_str());
397 throw std::invalid_argument(s);
398 }
399
400 /** @brief turns a bit depth string into and enum */
mapStrToBitDepthEnum(const std::string & str)401 BitDepthEnum mapStrToBitDepthEnum(const std::string &str) OFX_THROW(std::invalid_argument)
402 {
403 if(str == kOfxBitDepthByte) {
404 return eBitDepthUByte;
405 }
406 else if(str == kOfxBitDepthShort) {
407 return eBitDepthUShort;
408 }
409 else if(str == kOfxBitDepthHalf) {
410 return eBitDepthHalf;
411 }
412 else if(str == kOfxBitDepthFloat) {
413 return eBitDepthFloat;
414 }
415 #ifdef OFX_EXTENSIONS_VEGAS
416 else if(str == kOfxBitDepthByteBGR) {
417 return eBitDepthUByteBGRA;
418 }
419 else if(str == kOfxBitDepthShortBGR) {
420 return eBitDepthUShortBGRA;
421 }
422 else if(str == kOfxBitDepthFloatBGR) {
423 return eBitDepthFloatBGRA;
424 }
425 #endif
426 else if(str == kOfxBitDepthNone) {
427 return eBitDepthNone;
428 }
429 else {
430 return eBitDepthCustom;
431 }
432 }
433
434 /** @brief turns a bit depth string into and enum */
mapBitDepthEnumToStr(BitDepthEnum bitDepth)435 const char* mapBitDepthEnumToStr(BitDepthEnum bitDepth) OFX_THROW(std::invalid_argument)
436 {
437 switch (bitDepth) {
438 case eBitDepthUByte:
439 return kOfxBitDepthByte;
440 case eBitDepthUShort:
441 return kOfxBitDepthShort;
442 case eBitDepthHalf:
443 return kOfxBitDepthHalf;
444 case eBitDepthFloat:
445 return kOfxBitDepthFloat;
446 #ifdef OFX_EXTENSIONS_VEGAS
447 case eBitDepthUByteBGRA:
448 return kOfxBitDepthByteBGR;
449 case eBitDepthUShortBGRA:
450 return kOfxBitDepthShortBGR;
451 case eBitDepthFloatBGRA:
452 return kOfxBitDepthFloatBGR;
453 #endif
454 case eBitDepthNone:
455 return kOfxBitDepthNone;
456 case eBitDepthCustom:
457 return "OfxBitDepthCustom";
458 default:
459 OFX::Log::error(true, "Unknown bit depth enum '%d'", (int)bitDepth);
460 throw std::invalid_argument("unknown BitDepthEnum");
461 }
462 }
463
464 /** @brief turns a pixel component string into and enum */
mapStrToPixelComponentEnum(const std::string & str)465 PixelComponentEnum mapStrToPixelComponentEnum(const std::string &str) OFX_THROW(std::invalid_argument)
466 {
467 if(str == kOfxImageComponentRGBA) {
468 return ePixelComponentRGBA;
469 }
470 else if(str == kOfxImageComponentRGB) {
471 return ePixelComponentRGB;
472 }
473 else if(str == kOfxImageComponentAlpha) {
474 return ePixelComponentAlpha;
475 }
476 else if(str == kOfxImageComponentNone) {
477 return ePixelComponentNone;
478 }
479 #ifdef OFX_EXTENSIONS_NUKE
480 else if(str == kFnOfxImageComponentMotionVectors) {
481 return ePixelComponentMotionVectors;
482 }
483 else if(str == kFnOfxImageComponentStereoDisparity) {
484 return ePixelComponentStereoDisparity;
485 }
486 #endif
487 #ifdef OFX_EXTENSIONS_NATRON
488 else if (str == kNatronOfxImageComponentXY) {
489 return ePixelComponentXY;
490 }
491 #endif
492 else {
493 return ePixelComponentCustom;
494 }
495 }
496
497 /** @brief turns a pixel component string into and enum */
mapPixelComponentEnumToStr(PixelComponentEnum pixelComponent)498 const char* mapPixelComponentEnumToStr(PixelComponentEnum pixelComponent) OFX_THROW(std::invalid_argument)
499 {
500 switch (pixelComponent) {
501 case ePixelComponentRGBA:
502 return kOfxImageComponentRGBA;
503 case ePixelComponentRGB:
504 return kOfxImageComponentRGB;
505 case ePixelComponentAlpha:
506 return kOfxImageComponentAlpha;
507 case ePixelComponentNone:
508 return kOfxImageComponentNone;
509 #ifdef OFX_EXTENSIONS_NUKE
510 case ePixelComponentMotionVectors:
511 return kFnOfxImageComponentMotionVectors;
512 case ePixelComponentStereoDisparity:
513 return kFnOfxImageComponentStereoDisparity;
514 #endif
515 #ifdef OFX_EXTENSIONS_NATRON
516 case ePixelComponentXY:
517 return kNatronOfxImageComponentXY;
518 #endif
519 case ePixelComponentCustom:
520 return "OfxImageComponentCustom";
521 default:
522 OFX::Log::error(true, "Unknown pixel component enum '%d'", (int)pixelComponent);
523 throw std::invalid_argument("unknown PixelComponentEnum");
524 }
525 }
526
527 /** @brief turns a premultiplication string into and enum */
mapStrToPreMultiplicationEnum(const std::string & str)528 static PreMultiplicationEnum mapStrToPreMultiplicationEnum(const std::string &str) OFX_THROW(std::invalid_argument)
529 {
530 if(str == kOfxImageOpaque) {
531 return eImageOpaque;
532 }
533 else if(str == kOfxImagePreMultiplied) {
534 return eImagePreMultiplied;
535 }
536 else if(str == kOfxImageUnPreMultiplied) {
537 return eImageUnPreMultiplied;
538 }
539 else {
540 throw std::invalid_argument("");
541 }
542 }
543
544 /** @brief turns a field string into and enum */
mapStrToFieldEnum(const std::string & str)545 FieldEnum mapStrToFieldEnum(const std::string &str) OFX_THROW(std::invalid_argument)
546 {
547 if(str == kOfxImageFieldNone) {
548 return eFieldNone;
549 }
550 else if(str == kOfxImageFieldBoth) {
551 return eFieldBoth;
552 }
553 else if(str == kOfxImageFieldLower) {
554 return eFieldLower;
555 }
556 else if(str == kOfxImageFieldUpper) {
557 return eFieldUpper;
558 }
559 else {
560 throw std::invalid_argument("");
561 }
562 }
563
564 #ifdef OFX_EXTENSIONS_VEGAS
565 /** @brief map a std::string to a RenderQuality */
mapToVegasRenderQualityEnum(const std::string & s)566 VegasRenderQualityEnum mapToVegasRenderQualityEnum(const std::string &s) OFX_THROW(std::invalid_argument)
567 {
568 if(s == kOfxImageEffectPropRenderQualityDraft ) return eVegasRenderQualityDraft;
569 if(s == kOfxImageEffectPropRenderQualityPreview) return eVegasRenderQualityPreview;
570 if(s == kOfxImageEffectPropRenderQualityGood ) return eVegasRenderQualityGood;
571 if(s.empty() || s == kOfxImageEffectPropRenderQualityBest ) return eVegasRenderQualityBest;
572 OFX::Log::error(true, "Unknown Vegas RenderQuality '%s'", s.c_str());
573 throw std::invalid_argument(s);
574 }
575
576 /** @brief map a std::string to a context */
mapToVegasContextEnum(const std::string & s)577 VegasContextEnum mapToVegasContextEnum(const std::string &s) OFX_THROW(std::invalid_argument)
578 {
579 if(s.empty() || s == kOfxImageEffectPropVegasContextUnknown) return eVegasContextUnknown;
580 if(s == kOfxImageEffectPropVegasContextMedia) return eVegasContextMedia;
581 if(s == kOfxImageEffectPropVegasContextTrack) return eVegasContextTrack;
582 if(s == kOfxImageEffectPropVegasContextEvent) return eVegasContextEvent;
583 if(s == kOfxImageEffectPropVegasContextEventFadeIn) return eVegasContextEventFadeIn;
584 if(s == kOfxImageEffectPropVegasContextEventFadeOut) return eVegasContextEventFadeOut;
585 if(s == kOfxImageEffectPropVegasContextProject) return eVegasContextProject;
586 if(s == kOfxImageEffectPropVegasContextGenerator) return eVegasContextGenerator;
587 OFX::Log::error(true, "Unknown Vegas image effect context '%s'", s.c_str());
588 throw std::invalid_argument(s);
589 }
590 #endif
591
592 #if defined(OFX_EXTENSIONS_NATRON)
593 /** @brief extract a custom Natron plane defined in the multi-plane extension from the kOfxImageEffectPropComponents property value, @see getPixelComponentsProperty() */
extractCustomPlane(const std::string & comp,std::string * layerName,std::string * layerLabel,std::string * channelsLabel,std::vector<std::string> * channels)594 bool extractCustomPlane(const std::string& comp, std::string* layerName, std::string* layerLabel, std::string* channelsLabel, std::vector<std::string>* channels)
595 {
596
597 // Find the plane unique identifier
598 const std::size_t foundPlaneLen = std::strlen(kNatronOfxImageComponentsPlaneName);
599 std::size_t foundPlane = comp.find(kNatronOfxImageComponentsPlaneName);
600 if (foundPlane == std::string::npos) {
601 return false;
602 }
603
604 const std::size_t planeNameStartIdx = foundPlane + foundPlaneLen;
605
606 // Find the optionnal plane label
607 // If planeLabelStartIdx = 0, there's no plane label.
608 std::size_t planeLabelStartIdx = 0;
609
610
611 const std::size_t foundPlaneLabelLen = std::strlen(kNatronOfxImageComponentsPlaneLabel);
612 std::size_t foundPlaneLabel = comp.find(kNatronOfxImageComponentsPlaneLabel, planeNameStartIdx);
613 if (foundPlaneLabel != std::string::npos) {
614 planeLabelStartIdx = foundPlaneLabel + foundPlaneLabelLen;
615 }
616
617
618
619 // Find the optionnal channels label
620 // If channelsLabelStartIdx = 0, there's no channels label.
621 std::size_t channelsLabelStartIdx = 0;
622
623
624 const std::size_t foundChannelsLabelLen = std::strlen(kNatronOfxImageComponentsPlaneChannelsLabel);
625
626 // If there was a plane label before, pick from there otherwise pick from the name
627 std::size_t findChannelsLabelStart = planeLabelStartIdx > 0 ? planeLabelStartIdx : planeNameStartIdx;
628 std::size_t foundChannelsLabel = comp.find(kNatronOfxImageComponentsPlaneChannelsLabel, findChannelsLabelStart);
629 if (foundChannelsLabel != std::string::npos) {
630 channelsLabelStartIdx = foundChannelsLabel + foundChannelsLabelLen;
631 }
632
633
634
635 // Find the first channel
636 // If there was a channels label before, find from there, otherwise if there was a plane label before
637 // find from there, otherwise find from the name.
638 std::size_t findChannelStart = 0;
639 if (channelsLabelStartIdx > 0) {
640 findChannelStart = channelsLabelStartIdx;
641 } else if (planeLabelStartIdx > 0) {
642 findChannelStart = planeLabelStartIdx;
643 } else {
644 findChannelStart = planeNameStartIdx;
645 }
646
647 const std::size_t foundChannelLen = std::strlen(kNatronOfxImageComponentsPlaneChannel);
648 std::size_t foundChannel = comp.find(kNatronOfxImageComponentsPlaneChannel, findChannelStart);
649 if (foundChannel == std::string::npos) {
650 // There needs to be at least one channel.
651 return false;
652 }
653
654 // Extract channels label
655 if (channelsLabelStartIdx > 0) {
656 *channelsLabel = comp.substr(channelsLabelStartIdx, foundChannel - channelsLabelStartIdx);
657 }
658
659 // Extract plane label
660 if (planeLabelStartIdx > 0) {
661 std::size_t endIndex = (foundChannelsLabel != std::string::npos) ? foundChannelsLabel : foundChannel;
662 *layerLabel = comp.substr(planeLabelStartIdx, endIndex - planeLabelStartIdx);
663 }
664
665 // Extract plane name
666 {
667 std::size_t endIndex;
668 if (foundPlaneLabel != std::string::npos) {
669 // There's a plane label
670 endIndex = foundPlaneLabel;
671 } else if (foundChannelsLabel != std::string::npos) {
672 // There's no plane label but a channels label
673 endIndex = foundChannelsLabel;
674 } else {
675 // No plane label and no channels label
676 endIndex = foundChannel;
677 }
678 *layerName = comp.substr(planeNameStartIdx, endIndex - planeNameStartIdx);
679 }
680
681 while (foundChannel != std::string::npos) {
682 if (channels->size() >= 4) {
683 // A plane must have between 1 and 4 channels.
684 return false;
685 }
686 findChannelStart = foundChannel + foundChannelLen;
687 std::size_t nextChannel = comp.find(kNatronOfxImageComponentsPlaneChannel, findChannelStart);
688 std::string chan = comp.substr(findChannelStart, nextChannel - findChannelStart);
689 channels->push_back(chan);
690 foundChannel = nextChannel;
691 }
692
693 return true;
694 } // extractCustomPlane
695 #endif // OFX_EXTENSIONS_NATRON
696
697
698 ////////////////////////////////////////////////////////////////////////////////
699 // clip descriptor
700
701 /** @brief hidden constructor */
ClipDescriptor(const std::string & name,OfxPropertySetHandle props)702 ClipDescriptor::ClipDescriptor(const std::string &name, OfxPropertySetHandle props)
703 : _clipName(name)
704 , _clipProps(props)
705 {
706 OFX::Validation::validateClipDescriptorProperties(props);
707 }
708
709 /** @brief set the label properties */
setLabel(const std::string & label)710 void ClipDescriptor::setLabel(const std::string &label)
711 {
712 _clipProps.propSetString(kOfxPropLabel, label);
713 }
714
715 /** @brief set the label properties */
setLabels(const std::string & label,const std::string & shortLabel,const std::string & longLabel)716 void ClipDescriptor::setLabels(const std::string &label, const std::string &shortLabel, const std::string &longLabel)
717 {
718 setLabel(label);
719 _clipProps.propSetString(kOfxPropShortLabel, shortLabel, false);
720 _clipProps.propSetString(kOfxPropLongLabel, longLabel, false);
721 }
722
723 #ifdef OFX_EXTENSIONS_NATRON
724 /** @brief set the secretness of the clip, defaults to false */
setIsSecret(bool v)725 void ClipDescriptor::setIsSecret(bool v)
726 {
727 _clipProps.propSetInt(kOfxParamPropSecret, v, false);
728 }
729
730 /** @brief set the clip hint */
731 void
setHint(const std::string & v)732 ClipDescriptor::setHint(const std::string &v)
733 {
734 _clipProps.propSetString(kOfxParamPropHint, v, false);
735 }
736
737 /** @brief set the clip label and hint */
738 void
setLabelAndHint(const std::string & label,const std::string & hint)739 ClipDescriptor::setLabelAndHint(const std::string &label, const std::string &hint)
740 {
741 setLabel(label);
742 setHint(hint);
743 }
744 #endif
745
746 /** @brief set how fielded images are extracted from the clip defaults to eFieldExtractDoubled */
setFieldExtraction(FieldExtractionEnum v)747 void ClipDescriptor::setFieldExtraction(FieldExtractionEnum v)
748 {
749 switch(v)
750 {
751 case eFieldExtractBoth :
752 _clipProps.propSetString(kOfxImageClipPropFieldExtraction, kOfxImageFieldBoth);
753 break;
754
755 case eFieldExtractSingle :
756 _clipProps.propSetString(kOfxImageClipPropFieldExtraction, kOfxImageFieldSingle);
757 break;
758
759 case eFieldExtractDoubled :
760 _clipProps.propSetString(kOfxImageClipPropFieldExtraction, kOfxImageFieldDoubled);
761 break;
762 }
763 }
764
765 /** @brief set which components are supported, defaults to none set, this must be called at least once! */
addSupportedComponent(PixelComponentEnum v)766 void ClipDescriptor::addSupportedComponent(PixelComponentEnum v)
767 {
768 int n = _clipProps.propGetDimension(kOfxImageEffectPropSupportedComponents);
769 switch(v)
770 {
771 case ePixelComponentNone :
772 _clipProps.propSetString(kOfxImageEffectPropSupportedComponents, kOfxImageComponentNone, n);
773 break;
774
775 case ePixelComponentRGBA :
776 _clipProps.propSetString(kOfxImageEffectPropSupportedComponents, kOfxImageComponentRGBA, n);
777 break;
778
779 case ePixelComponentRGB :
780 _clipProps.propSetString(kOfxImageEffectPropSupportedComponents, kOfxImageComponentRGB, n);
781 break;
782
783 case ePixelComponentAlpha :
784 _clipProps.propSetString(kOfxImageEffectPropSupportedComponents, kOfxImageComponentAlpha, n);
785 break;
786 #ifdef OFX_EXTENSIONS_NUKE
787 case ePixelComponentMotionVectors :
788 _clipProps.propSetString(kOfxImageEffectPropSupportedComponents, kFnOfxImageComponentMotionVectors, n);
789 break;
790
791 case ePixelComponentStereoDisparity :
792 _clipProps.propSetString(kOfxImageEffectPropSupportedComponents, kFnOfxImageComponentStereoDisparity, n);
793 break;
794 #endif
795 #ifdef OFX_EXTENSIONS_NATRON
796 case ePixelComponentXY:
797 _clipProps.propSetString(kOfxImageEffectPropSupportedComponents, kNatronOfxImageComponentXY, n);
798 break;
799 #endif
800 case ePixelComponentCustom :
801 break;
802 }
803 }
804
805 /** @brief set which components are supported, defaults to none set, this must be called at least once! */
addSupportedComponent(const std::string & comp)806 void ClipDescriptor::addSupportedComponent(const std::string &comp)
807 {
808 int n = _clipProps.propGetDimension(kOfxImageEffectPropSupportedComponents);
809 _clipProps.propSetString(kOfxImageEffectPropSupportedComponents, comp, n);
810
811 }
812
813 /** @brief say whether we are going to do random temporal access on this clip, defaults to false */
setTemporalClipAccess(bool v)814 void ClipDescriptor::setTemporalClipAccess(bool v)
815 {
816 _clipProps.propSetInt(kOfxImageEffectPropTemporalClipAccess, int(v));
817 }
818
819 /** @brief say whether if the clip is optional, defaults to false */
setOptional(bool v)820 void ClipDescriptor::setOptional(bool v)
821 {
822 _clipProps.propSetInt(kOfxImageClipPropOptional, int(v));
823 }
824
825 /** @brief say whether this clip supports tiling, defaults to true */
setSupportsTiles(bool v)826 void ClipDescriptor::setSupportsTiles(bool v)
827 {
828 _clipProps.propSetInt(kOfxImageEffectPropSupportsTiles, int(v));
829 }
830
831 /** @brief say whether this clip is a 'mask', so the host can know to replace with a roto or similar, defaults to false */
setIsMask(bool v)832 void ClipDescriptor::setIsMask(bool v)
833 {
834 _clipProps.propSetInt(kOfxImageClipPropIsMask, int(v));
835 }
836
837 #ifdef OFX_EXTENSIONS_NATRON
838 /** @brief say whether this clip may contain images with a distortion function attached */
setCanDistort(bool v)839 void ClipDescriptor::setCanDistort(bool v)
840 {
841 _clipProps.propSetInt(kOfxImageEffectPropCanDistort, int(v), false);
842 }
843 #endif
844
845 #ifdef OFX_EXTENSIONS_NUKE
846 /** @brief say whether this clip may contain images with a transform attached */
setCanTransform(bool v)847 void ClipDescriptor::setCanTransform(bool v)
848 {
849 _clipProps.propSetInt(kFnOfxImageEffectCanTransform, int(v), false);
850 }
851 #endif
852
853 #ifdef OFX_EXTENSIONS_NUKE
854 ////////////////////////////////////////////////////////////////////////////////
855 // camera descriptor
856
857 /** @brief hidden constructor */
CameraDescriptor(const std::string & name,OfxPropertySetHandle props)858 CameraDescriptor::CameraDescriptor(const std::string &name, OfxPropertySetHandle props)
859 : _cameraName(name)
860 , _cameraProps(props)
861 {
862 OFX::Validation::validateCameraDescriptorProperties(props);
863 }
864
865 /** @brief set the label properties */
setLabel(const std::string & label)866 void CameraDescriptor::setLabel(const std::string &label)
867 {
868 _cameraProps.propSetString(kOfxPropLabel, label);
869 }
870
871 /** @brief set the label properties */
setLabels(const std::string & label,const std::string & shortLabel,const std::string & longLabel)872 void CameraDescriptor::setLabels(const std::string &label, const std::string &shortLabel, const std::string &longLabel)
873 {
874 setLabel(label);
875 _cameraProps.propSetString(kOfxPropShortLabel, shortLabel, false);
876 _cameraProps.propSetString(kOfxPropLongLabel, longLabel, false);
877 }
878
879 #ifdef OFX_EXTENSIONS_NATRON
880 /** @brief set the secretness of the camera, defaults to false */
setIsSecret(bool v)881 void CameraDescriptor::setIsSecret(bool v)
882 {
883 _cameraProps.propSetInt(kOfxParamPropSecret, v, false);
884 }
885
886 /** @brief set the camera hint */
887 void
setHint(const std::string & v)888 CameraDescriptor::setHint(const std::string &v)
889 {
890 _cameraProps.propSetString(kOfxParamPropHint, v, false);
891 }
892
893 /** @brief set the camera label and hint */
894 void
setLabelAndHint(const std::string & label,const std::string & hint)895 CameraDescriptor::setLabelAndHint(const std::string &label, const std::string &hint)
896 {
897 setLabel(label);
898 setHint(hint);
899 }
900 #endif
901
902
903 /** @brief say whether if the camera is optional, defaults to false */
setOptional(bool v)904 void CameraDescriptor::setOptional(bool v)
905 {
906 _cameraProps.propSetInt(kOfxImageClipPropOptional, int(v));
907 }
908 #endif
909
910 ////////////////////////////////////////////////////////////////////////////////
911 // image effect descriptor
912
913 /** @brief effect descriptor ctor */
ImageEffectDescriptor(OfxImageEffectHandle handle)914 ImageEffectDescriptor::ImageEffectDescriptor(OfxImageEffectHandle handle)
915 : _effectHandle(handle)
916 {
917 // fetch the property set handle of the effect
918 OfxPropertySetHandle props;
919 OfxStatus stat = OFX::Private::gEffectSuite->getPropertySet(handle, &props);
920 throwSuiteStatusException(stat);
921 _effectProps.propSetHandle(props);
922
923 OFX::Validation::validatePluginDescriptorProperties(props);
924
925 // fetch the param set handle and set it in our ParamSetDescriptor base
926 OfxParamSetHandle paramSetHandle;
927 stat = OFX::Private::gEffectSuite->getParamSet(handle, ¶mSetHandle);
928 throwSuiteStatusException(stat);
929 setParamSetHandle(paramSetHandle);
930 }
931
932
933 /** @brief dtor */
~ImageEffectDescriptor()934 ImageEffectDescriptor::~ImageEffectDescriptor()
935 {
936 // delete any clip descriptors we may have constructed
937 std::map<std::string, ClipDescriptor *>::iterator iter;
938 for(iter = _definedClips.begin(); iter != _definedClips.end(); ++iter) {
939 if(iter->second) {
940 delete iter->second;
941 iter->second = NULL;
942 }
943 }
944 #ifdef OFX_EXTENSIONS_NUKE
945 std::map<std::string, CameraDescriptor *>::iterator it;
946 for(it = _definedCameras.begin(); it != _definedCameras.end(); ++it) {
947 if(it->second) {
948 delete it->second;
949 it->second = NULL;
950 }
951 }
952 #endif
953 }
954
955 /** @brief, set the label properties in a plugin */
setLabel(const std::string & label)956 void ImageEffectDescriptor::setLabel(const std::string &label)
957 {
958 validateXMLString(label, true);
959 _effectProps.propSetString(kOfxPropLabel, label);
960 }
961
962 /** @brief, set the label properties in a plugin */
setLabels(const std::string & label,const std::string & shortLabel,const std::string & longLabel)963 void ImageEffectDescriptor::setLabels(const std::string &label, const std::string &shortLabel, const std::string &longLabel)
964 {
965 setLabel(label);
966 validateXMLString(shortLabel, false);
967 _effectProps.propSetString(kOfxPropShortLabel, shortLabel, false);
968 validateXMLString(longLabel, false);
969 _effectProps.propSetString(kOfxPropLongLabel, longLabel, false);
970 }
971
972
973 /** @brief, set the version properties in a plugin */
setVersion(int major,int minor,int micro,int build,const std::string & versionLabel)974 void ImageEffectDescriptor::setVersion(int major, int minor, int micro, int build, const std::string &versionLabel)
975 {
976 _effectProps.propSetInt(kOfxPropVersion, major, 0, false); // introduced in OFX 1.2
977 if (minor || micro || build) {
978 _effectProps.propSetInt(kOfxPropVersion, minor, 1, false); // introduced in OFX 1.2
979 if (micro || build) {
980 _effectProps.propSetInt(kOfxPropVersion, micro, 2, false); // introduced in OFX 1.2
981 if (build) {
982 _effectProps.propSetInt(kOfxPropVersion, build, 3, false); // introduced in OFX 1.2
983 }
984 }
985 }
986 if (!versionLabel.empty()) {
987 validateXMLString(versionLabel, false);
988 _effectProps.propSetString(kOfxPropVersionLabel, versionLabel, false);
989 }
990 }
991
992 /** @brief Set the plugin grouping */
setPluginGrouping(const std::string & group)993 void ImageEffectDescriptor::setPluginGrouping(const std::string &group)
994 {
995 validateXMLString(group, true);
996 _effectProps.propSetString(kOfxImageEffectPluginPropGrouping, group);
997 }
998
999 /** @brief Set the plugin description, defaults to "" */
setPluginDescription(const std::string & description,bool validate)1000 void ImageEffectDescriptor::setPluginDescription(const std::string &description, bool validate)
1001 {
1002 if (validate) {
1003 validateXMLString(description, false);
1004 }
1005 _effectProps.propSetString(kOfxPropPluginDescription, description, false); // introduced in OFX 1.2
1006 }
1007
1008 /** @brief Add a context to those supported */
addSupportedContext(ContextEnum v)1009 void ImageEffectDescriptor::addSupportedContext(ContextEnum v)
1010 {
1011 int n = _effectProps.propGetDimension(kOfxImageEffectPropSupportedContexts);
1012 switch (v)
1013 {
1014 case eContextNone :
1015 break;
1016 case eContextGenerator :
1017 _effectProps.propSetString(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextGenerator, n);
1018 break;
1019 case eContextFilter :
1020 _effectProps.propSetString(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextFilter, n);
1021 break;
1022 case eContextTransition :
1023 _effectProps.propSetString(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextTransition, n);
1024 break;
1025 case eContextPaint :
1026 _effectProps.propSetString(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextPaint, n);
1027 break;
1028 case eContextGeneral :
1029 _effectProps.propSetString(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextGeneral, n);
1030 break;
1031 case eContextRetimer :
1032 _effectProps.propSetString(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextRetimer, n);
1033 break;
1034 #ifdef OFX_EXTENSIONS_TUTTLE
1035 case eContextReader :
1036 _effectProps.propSetString(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextReader, n);
1037 break;
1038 case eContextWriter :
1039 _effectProps.propSetString(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextWriter, n);
1040 break;
1041 #endif
1042 #ifdef OFX_EXTENSIONS_NATRON
1043 case eContextTracker:
1044 _effectProps.propSetString(kOfxImageEffectPropSupportedContexts, kNatronOfxImageEffectContextTracker, n);
1045 break;
1046 #endif
1047 }
1048 }
1049
setOverlayInteractDescriptor(EffectOverlayDescriptor * desc)1050 void ImageEffectDescriptor::setOverlayInteractDescriptor(EffectOverlayDescriptor* desc)
1051 {
1052 _overlayDescriptor.reset(desc);
1053 if(OFX::gHostDescription.supportsOverlays && desc->getMainEntry())
1054 _effectProps.propSetPointer(kOfxImageEffectPluginPropOverlayInteractV1, (void*)desc->getMainEntry());
1055 }
1056
1057 #ifdef OFX_EXTENSIONS_VEGAS
1058 #if defined(WIN32) || defined(WIN64)
setHWNDInteractDescriptor(HWNDInteractDescriptor * desc)1059 void ImageEffectDescriptor::setHWNDInteractDescriptor(HWNDInteractDescriptor* desc)
1060 {
1061 _hwndInteractDescriptor.reset(desc);
1062 if(desc->getMainEntry())
1063 _effectProps.propSetPointer(kOfxImageEffectPluginPropHWndInteractV1, (void*)desc->getMainEntry());
1064 }
1065 #endif // #if defined(WIN32) || defined(WIN64)
1066 #endif
1067
1068 /** @brief Add a pixel depth to those supported */
addSupportedBitDepth(BitDepthEnum v)1069 void ImageEffectDescriptor::addSupportedBitDepth(BitDepthEnum v)
1070 {
1071 int n = _effectProps.propGetDimension(kOfxImageEffectPropSupportedPixelDepths);
1072 switch(v)
1073 {
1074 case eBitDepthNone :
1075 _effectProps.propSetString(kOfxImageEffectPropSupportedPixelDepths, kOfxBitDepthNone , n);
1076 break;
1077 case eBitDepthUByte :
1078 _effectProps.propSetString(kOfxImageEffectPropSupportedPixelDepths, kOfxBitDepthByte , n);
1079 break;
1080 case eBitDepthUShort :
1081 _effectProps.propSetString(kOfxImageEffectPropSupportedPixelDepths, kOfxBitDepthShort , n);
1082 break;
1083 case eBitDepthHalf :
1084 _effectProps.propSetString(kOfxImageEffectPropSupportedPixelDepths, kOfxBitDepthHalf , n);
1085 break;
1086 case eBitDepthFloat :
1087 _effectProps.propSetString(kOfxImageEffectPropSupportedPixelDepths, kOfxBitDepthFloat , n);
1088 break;
1089 #ifdef OFX_EXTENSIONS_VEGAS
1090 case eBitDepthUByteBGRA :
1091 _effectProps.propSetString(kOfxImageEffectPropSupportedPixelDepths, kOfxBitDepthByteBGR , n);
1092 break;
1093 case eBitDepthUShortBGRA :
1094 _effectProps.propSetString(kOfxImageEffectPropSupportedPixelDepths, kOfxBitDepthShortBGR , n);
1095 break;
1096 case eBitDepthFloatBGRA :
1097 _effectProps.propSetString(kOfxImageEffectPropSupportedPixelDepths, kOfxBitDepthFloatBGR , n);
1098 break;
1099 #endif
1100 case eBitDepthCustom :
1101 break;
1102 }
1103 }
1104
1105 #ifdef OFX_SUPPORTS_OPENGLRENDER
1106 /** @brief Add a pixel depth to those supported */
addSupportedOpenGLBitDepth(BitDepthEnum v)1107 void ImageEffectDescriptor::addSupportedOpenGLBitDepth(BitDepthEnum v)
1108 {
1109 int n = _effectProps.propGetDimension(kOfxOpenGLPropPixelDepth);
1110 switch(v)
1111 {
1112 case eBitDepthNone :
1113 _effectProps.propSetString(kOfxOpenGLPropPixelDepth, kOfxBitDepthNone , n);
1114 break;
1115 case eBitDepthUByte :
1116 _effectProps.propSetString(kOfxOpenGLPropPixelDepth, kOfxBitDepthByte , n);
1117 break;
1118 case eBitDepthUShort :
1119 _effectProps.propSetString(kOfxOpenGLPropPixelDepth, kOfxBitDepthShort , n);
1120 break;
1121 case eBitDepthHalf :
1122 _effectProps.propSetString(kOfxOpenGLPropPixelDepth, kOfxBitDepthHalf , n);
1123 break;
1124 case eBitDepthFloat :
1125 _effectProps.propSetString(kOfxOpenGLPropPixelDepth, kOfxBitDepthFloat , n);
1126 break;
1127 default:
1128 break;
1129 }
1130 }
1131 #endif
1132
1133 #ifdef OFX_EXTENSIONS_TUTTLE
1134 /** @brief Add a file extension to those supported */
addSupportedExtension(const std::string & extension)1135 void ImageEffectDescriptor::addSupportedExtension(const std::string& extension)
1136 {
1137 validateXMLString(extension, false);
1138 // only Tuttle support this property ( out of standard )
1139 //if( OFX::Private::gHostDescription.hostName == "TuttleOfx" ) {
1140 const int n = _effectProps.propGetDimension(kTuttleOfxImageEffectPropSupportedExtensions, false);
1141 _effectProps.propSetString(kTuttleOfxImageEffectPropSupportedExtensions, extension, n, false);
1142 }
1143
addSupportedExtensions(const std::vector<std::string> & extensions)1144 void ImageEffectDescriptor::addSupportedExtensions(const std::vector<std::string>& extensions)
1145 {
1146 // only Tuttle support this property ( out of standard )
1147 //if( OFX::Private::gHostDescription.hostName == "TuttleOfx" ) {
1148 int n = _effectProps.propGetDimension(kTuttleOfxImageEffectPropSupportedExtensions, false);
1149
1150 for (std::vector<std::string>::const_iterator it = extensions.begin(); it != extensions.end(); ++it, ++n) {
1151 validateXMLString(*it, false);
1152 _effectProps.propSetString(kTuttleOfxImageEffectPropSupportedExtensions, *it, n, false);
1153 }
1154 }
1155
addSupportedExtensions(const char * extensions[])1156 void ImageEffectDescriptor::addSupportedExtensions(const char*extensions[])
1157 {
1158 // only Tuttle support this property ( out of standard )
1159 //if( OFX::Private::gHostDescription.hostName == "TuttleOfx" ) {
1160 int n = _effectProps.propGetDimension(kTuttleOfxImageEffectPropSupportedExtensions, false);
1161
1162 while (*extensions) {
1163 validateXMLString(*extensions, false);
1164 _effectProps.propSetString(kTuttleOfxImageEffectPropSupportedExtensions, *extensions, n, false);
1165 ++extensions;
1166 ++n;
1167 }
1168 }
1169
setPluginEvaluation(double evaluation)1170 void ImageEffectDescriptor::setPluginEvaluation(double evaluation)
1171 {
1172 // This property is an extension, so it's optional.
1173 _effectProps.propSetDouble(kTuttleOfxImageEffectPropEvaluation, evaluation, false);
1174 }
1175 #endif
1176
1177 /** @brief Is the plugin single instance only ? */
setSingleInstance(bool v)1178 void ImageEffectDescriptor::setSingleInstance(bool v)
1179 {
1180 _effectProps.propSetInt(kOfxImageEffectPluginPropSingleInstance, int(v));
1181 }
1182
1183 /** @brief Does the plugin expect the host to perform per frame SMP threading */
setHostFrameThreading(bool v)1184 void ImageEffectDescriptor::setHostFrameThreading(bool v)
1185 {
1186 _effectProps.propSetInt(kOfxImageEffectPluginPropHostFrameThreading, int(v));
1187 }
1188
1189 /** @brief Does the plugin support multi resolution images */
setSupportsMultiResolution(bool v)1190 void ImageEffectDescriptor::setSupportsMultiResolution(bool v)
1191 {
1192 _effectProps.propSetInt(kOfxImageEffectPropSupportsMultiResolution, int(v));
1193 }
1194
1195 /** @brief set the instance to be sequentially renderred, this should have been part of clip preferences! */
setSequentialRender(bool v)1196 void ImageEffectDescriptor::setSequentialRender(bool v)
1197 {
1198 _effectProps.propSetInt(kOfxImageEffectInstancePropSequentialRender, int(v), false); // missing in Resolve
1199 }
1200
1201 /** @brief Have we informed the host we want to be seqentially renderred ? */
getSequentialRender(void) const1202 bool ImageEffectDescriptor::getSequentialRender(void) const
1203 {
1204 return _effectProps.propGetInt(kOfxImageEffectInstancePropSequentialRender) != 0;
1205 }
1206
1207 /** @brief Does the plugin support image tiling */
setSupportsTiles(bool v)1208 void ImageEffectDescriptor::setSupportsTiles(bool v)
1209 {
1210 _effectProps.propSetInt(kOfxImageEffectPropSupportsTiles, int(v));
1211 }
1212
1213 /** @brief Does the plugin handles render quality */
setSupportsRenderQuality(bool v)1214 void ImageEffectDescriptor::setSupportsRenderQuality(bool v)
1215 {
1216 _effectProps.propSetInt(kOfxImageEffectPropRenderQualityDraft, int(v), false); // OFX 1.4+
1217 }
1218
1219 /** @brief Does the plugin perform temporal clip access */
setTemporalClipAccess(bool v)1220 void ImageEffectDescriptor::setTemporalClipAccess(bool v)
1221 {
1222 _effectProps.propSetInt(kOfxImageEffectPropTemporalClipAccess, int(v));
1223 }
1224
1225 /** @brief Does the plugin want to have render called twice per frame in all circumanstances for fielded images ? */
setRenderTwiceAlways(bool v)1226 void ImageEffectDescriptor::setRenderTwiceAlways(bool v)
1227 {
1228 _effectProps.propSetInt(kOfxImageEffectPluginPropFieldRenderTwiceAlways, int(v));
1229 }
1230
1231 /** @brief Does the plugin support inputs and output clips of differing depths */
setSupportsMultipleClipDepths(bool v)1232 void ImageEffectDescriptor::setSupportsMultipleClipDepths(bool v)
1233 {
1234 _effectProps.propSetInt(kOfxImageEffectPropSupportsMultipleClipDepths, int(v));
1235 }
1236
1237 /** @brief Does the plugin support inputs and output clips of pixel aspect ratios */
setSupportsMultipleClipPARs(bool v)1238 void ImageEffectDescriptor::setSupportsMultipleClipPARs(bool v)
1239 {
1240 _effectProps.propSetInt(kOfxImageEffectPropSupportsMultipleClipPARs, int(v));
1241 }
1242
1243 /** @brief What kind of thread safety does the plugin have */
setRenderThreadSafety(RenderSafetyEnum v)1244 void ImageEffectDescriptor::setRenderThreadSafety(RenderSafetyEnum v)
1245 {
1246 switch(v)
1247 {
1248 case eRenderUnsafe :
1249 _effectProps.propSetString(kOfxImageEffectPluginRenderThreadSafety, kOfxImageEffectRenderUnsafe);
1250 break;
1251 case eRenderInstanceSafe :
1252 _effectProps.propSetString(kOfxImageEffectPluginRenderThreadSafety, kOfxImageEffectRenderInstanceSafe);
1253 break;
1254 case eRenderFullySafe :
1255 _effectProps.propSetString(kOfxImageEffectPluginRenderThreadSafety, kOfxImageEffectRenderFullySafe);
1256 break;
1257 }
1258 }
1259
1260 #ifdef OFX_EXTENSIONS_NATRON
1261
setUsesMultiThreading(bool isMultiThreaded)1262 void ImageEffectDescriptor::setUsesMultiThreading(bool isMultiThreaded)
1263 {
1264 _effectProps.propSetInt(kNatronOfxImageEffectPluginUsesMultipleThread, (int)isMultiThreaded, 0, false);
1265 }
1266
1267 /*Indicates if the host may add a mask that will be handled automatically.*/
setHostMaskingEnabled(bool enabled)1268 void ImageEffectDescriptor::setHostMaskingEnabled(bool enabled)
1269 {
1270 _effectProps.propSetInt(kNatronOfxImageEffectPropHostMasking, (int)enabled, 0, false);
1271 }
1272
1273 /*Indicates if the host may add a "Mix" double parameter that will dissolve
1274 between the source image at 0 and the full effect at 1.*/
setHostMixingEnabled(bool enabled)1275 void ImageEffectDescriptor::setHostMixingEnabled(bool enabled)
1276 {
1277 _effectProps.propSetInt(kNatronOfxImageEffectPropHostMixing, (int)enabled, 0, false);
1278 }
1279
1280 /*Indicates if the plug-in description is written in markdown or plain-text otherwise */
setDescriptionIsMarkdown(bool markdown)1281 void ImageEffectDescriptor::setDescriptionIsMarkdown(bool markdown)
1282 {
1283 _effectProps.propSetInt(kNatronOfxPropDescriptionIsMarkdown, (int)markdown, 0, false);
1284 }
1285
1286 /*The current selection rectangle drawn by the user on the host viewport.
1287 This property is refreshed whenever calling the kOfxActionInstanceChanged action for the parameter kNatronOfxParamSelectionRectangleState to let the plug-in a change to correctly synchronized its selection.
1288 */
getSelectionRectangle()1289 OfxRectI ImageEffectDescriptor::getSelectionRectangle()
1290 {
1291 OfxRectI bounds = { 0, 0, 0, 0 };
1292 bounds.x1 = _effectProps.propGetInt(kNatronOfxImageEffectSelectionRectangle, 0, false);
1293 bounds.y1 = _effectProps.propGetInt(kNatronOfxImageEffectSelectionRectangle, 1, false);
1294 bounds.x2 = _effectProps.propGetInt(kNatronOfxImageEffectSelectionRectangle, 2, false);
1295 bounds.y2 = _effectProps.propGetInt(kNatronOfxImageEffectSelectionRectangle, 3, false);
1296
1297 return bounds;
1298 }
1299
addInViewportParam(const std::string & paramName)1300 void ImageEffectDescriptor::addInViewportParam(const std::string& paramName)
1301 {
1302 int n = _effectProps.propGetDimension(kNatronOfxImageEffectPropInViewerContextParamsOrder, false);
1303 _effectProps.propSetString(kNatronOfxImageEffectPropInViewerContextParamsOrder, paramName, n, false);
1304 }
1305
setDefaultParamInViewportShortcut(const std::string & paramName,int symbolKey,ShortcutModifierEnum modifiers)1306 void ImageEffectDescriptor::setDefaultParamInViewportShortcut(const std::string& paramName, int symbolKey, ShortcutModifierEnum modifiers)
1307 {
1308 int n = _effectProps.propGetDimension(kNatronOfxImageEffectPropInViewerContextDefaultShortcuts, false);
1309 _effectProps.propSetString(kNatronOfxImageEffectPropInViewerContextDefaultShortcuts, paramName, n, false);
1310 _effectProps.propSetInt(kNatronOfxImageEffectPropInViewerContextShortcutSymbol, symbolKey, n, false);
1311 _effectProps.propSetInt(kNatronOfxImageEffectPropInViewerContextShortcutHasControlModifier, (int)(modifiers & eShortcutModifierCtrl), n, false);
1312 _effectProps.propSetInt(kNatronOfxImageEffectPropInViewerContextShortcutHasShiftModifier, (int)(modifiers & eShortcutModifierShift), n, false);
1313 _effectProps.propSetInt(kNatronOfxImageEffectPropInViewerContextShortcutHasAltModifier, (int)(modifiers & eShortcutModifierAlt), n, false);
1314 _effectProps.propSetInt(kNatronOfxImageEffectPropInViewerContextShortcutHasMetaModifier, (int)(modifiers & eShortcutModifierMeta), n, false);
1315 }
1316
1317 void
addNativeOverlayInteractForParameters(const std::string & interactType,const std::list<ParamDescriptor * > & parameters)1318 ImageEffectDescriptor::addNativeOverlayInteractForParameters(const std::string& interactType, const std::list<ParamDescriptor*>& parameters)
1319 {
1320 std::stringstream ss;
1321 ss << kNatronNativeOverlayType << '_' << interactType;
1322 for (std::list<ParamDescriptor*>::const_iterator it = parameters.begin(); it != parameters.end(); ++it) {
1323 ss << '_' << kNatronNativeOverlayParameterName << '_';
1324 ss << (*it)->getName();
1325 (*it)->setUseHostNativeOverlayHandle(true); // also set the OFX 1.2 property
1326 }
1327 int n = _effectProps.propGetDimension(kNatronOfxPropNativeOverlays, false);
1328 _effectProps.propSetString(kNatronOfxPropNativeOverlays, ss.str(), n, false);
1329 }
1330 #endif
1331
1332 #ifdef OFX_EXTENSIONS_VEGAS
setPresetThumbnailHint(VegasPresetThumbnailEnum v)1333 void ImageEffectDescriptor::setPresetThumbnailHint(VegasPresetThumbnailEnum v)
1334 {
1335 switch(v)
1336 {
1337 case eVegasPresetThumbnailDefault :
1338 _effectProps.propSetString(kOfxProbPluginVegasPresetThumbnail, kOfxProbPluginVegasPresetThumbnailDefault, false);
1339 break;
1340 case eVegasPresetThumbnailSolidImage :
1341 _effectProps.propSetString(kOfxProbPluginVegasPresetThumbnail, kOfxProbPluginVegasPresetThumbnailSolidImage, false);
1342 break;
1343 case eVegasPresetThumbnailImageWithAlpha :
1344 _effectProps.propSetString(kOfxProbPluginVegasPresetThumbnail, kOfxProbPluginVegasPresetThumbnailImageWithAlpha, false);
1345 break;
1346 }
1347 }
1348 #endif
1349
1350 #ifdef OFX_EXTENSIONS_RESOLVE
1351 /** @brief Does the plugin support OpenCL Render */
setSupportsOpenCLRender(bool v)1352 void ImageEffectDescriptor::setSupportsOpenCLRender(bool v)
1353 {
1354 _effectProps.propSetString(kOfxImageEffectPropOpenCLRenderSupported, (v ? "true" : "false"), false);
1355 }
1356
1357 /** @brief Does the plugin support CUDA Render */
setSupportsCudaRender(bool v)1358 void ImageEffectDescriptor::setSupportsCudaRender(bool v)
1359 {
1360 _effectProps.propSetString(kOfxImageEffectPropCudaRenderSupported, (v ? "true" : "false"), false);
1361 }
1362 #endif
1363
1364 #ifdef OFX_SUPPORTS_OPENGLRENDER
1365 /** @brief Does the plugin support OpenGL accelerated rendering (but is also capable of CPU rendering) ? */
setSupportsOpenGLRender(bool v)1366 void ImageEffectDescriptor::setSupportsOpenGLRender(bool v) {
1367 if (gHostDescription.supportsOpenGLRender) {
1368 _effectProps.propSetString(kOfxImageEffectPropOpenGLRenderSupported, (v ? "true" : "false"));
1369 }
1370 }
1371
1372 /** @brief Does the plugin require OpenGL accelerated rendering ? */
setNeedsOpenGLRender(bool v)1373 void ImageEffectDescriptor::setNeedsOpenGLRender(bool v) {
1374 if (gHostDescription.supportsOpenGLRender) {
1375 _effectProps.propSetString(kOfxImageEffectPropOpenGLRenderSupported, (v ? "needed" : "false"));
1376 }
1377 }
1378
addOpenGLBitDepth(BitDepthEnum v)1379 void ImageEffectDescriptor::addOpenGLBitDepth(BitDepthEnum v) {
1380 int n = _effectProps.propGetDimension(kOfxImageEffectPropSupportedPixelDepths);
1381 std::string value = mapBitDepthEnumToStr(v);
1382 if (!value.empty()) {
1383 _effectProps.propSetString(kOfxOpenGLPropPixelDepth, value, n);
1384 }
1385 }
1386 #endif
1387
1388 #ifdef OFX_EXTENSIONS_NUKE
1389 /** @brief indicate that a plugin or host can handle transform effects */
setCanTransform(bool v)1390 void ImageEffectDescriptor::setCanTransform(bool v)
1391 {
1392 // the header says this property is on the effect instance, but on Nuke it only exists on the effect descriptor
1393 if (gHostDescription.canTransform) {
1394 _effectProps.propSetInt(kFnOfxImageEffectCanTransform, int(v), false);
1395 }
1396 }
1397
1398 /** @brief Indicates that a host or plugin can fetch more than a type of image from a clip*/
setIsMultiPlanar(bool v)1399 void ImageEffectDescriptor::setIsMultiPlanar(bool v)
1400 {
1401 if (gHostDescription.isMultiPlanar) {
1402 _effectProps.propSetInt(kFnOfxImageEffectPropMultiPlanar, int(v), false);
1403 }
1404 }
1405
setPassThroughForNotProcessedPlanes(PassThroughLevelEnum v)1406 void ImageEffectDescriptor::setPassThroughForNotProcessedPlanes(PassThroughLevelEnum v)
1407 {
1408 if (gHostDescription.isMultiPlanar) {
1409 _effectProps.propSetInt(kFnOfxImageEffectPropPassThroughComponents, int(v), false);
1410 }
1411 }
1412
1413 /** @brief Indicates to the host that the plugin is view aware, in which case it will have to use the view calls*/
setIsViewAware(bool v)1414 void ImageEffectDescriptor::setIsViewAware(bool v)
1415 {
1416 if (OFX::Private::gImageEffectPlaneSuiteV2) {
1417 _effectProps.propSetInt(kFnOfxImageEffectPropViewAware, int(v), false);
1418 }
1419 }
1420
1421 /** @brief Indicates to the host that a view aware plugin produces the same image independent of the view being rendered*/
setIsViewInvariant(ViewInvarianceLevelEnum v)1422 void ImageEffectDescriptor::setIsViewInvariant(ViewInvarianceLevelEnum v)
1423 {
1424 if (OFX::Private::gImageEffectPlaneSuiteV2) {
1425 _effectProps.propSetInt(kFnOfxImageEffectPropViewInvariance, int(v), false);
1426 }
1427 }
1428 #endif
1429
1430 /** @brief If the slave param changes the clip preferences need to be re-evaluated */
addClipPreferencesSlaveParam(ParamDescriptor & p)1431 void ImageEffectDescriptor::addClipPreferencesSlaveParam(ParamDescriptor &p)
1432 {
1433 int n = _effectProps.propGetDimension(kOfxImageEffectPropClipPreferencesSlaveParam);
1434 validateXMLString(p.getName(), false);
1435 # ifdef DEBUG
1436 if (p.getPropertySet().propGetInt(kOfxParamPropAnimates)) {
1437 std::cout << "Warning: parameter " << p.getName() << " is a clip preferences slave param but is animated\n";
1438 }
1439 # endif
1440 _effectProps.propSetString(kOfxImageEffectPropClipPreferencesSlaveParam, p.getName(), n);
1441 }
1442
1443 #ifdef OFX_EXTENSIONS_VEGAS
1444 /** @brief Add a guid to tell Vegas that this plug-in can uplift the guid of that older plug-in */
addVegasUpgradePath(const std::string & guidString)1445 void ImageEffectDescriptor::addVegasUpgradePath(const std::string &guidString)
1446 {
1447 int n = _effectProps.propGetDimension(kOfxImageEffectPropVegasUpliftGUID, false);
1448 validateXMLString(guidString, false);
1449 _effectProps.propSetString(kOfxImageEffectPropVegasUpliftGUID, guidString.c_str(), n, false);
1450 }
1451
1452 /** @brief sets the path to a help file, defaults to none, must be called at least once */
setHelpPath(const std::string & helpPathString)1453 void ImageEffectDescriptor::setHelpPath(const std::string &helpPathString)
1454 {
1455 validateXMLString(helpPathString, false);
1456 _effectProps.propSetString(kOfxImageEffectPropHelpFile, helpPathString.c_str(), false);
1457 }
1458
1459 /** @brief sets the context ID to a help file if it's a .chm file, defaults to none, must be called at least once */
setHelpContextID(int helpContextID)1460 void ImageEffectDescriptor::setHelpContextID(int helpContextID)
1461 {
1462 _effectProps.propSetInt(kOfxImageEffectPropHelpContextID, helpContextID, false);
1463 }
1464 #endif
1465
1466 /** @brief Create a clip, only callable from describe in context */
defineClip(const std::string & name)1467 ClipDescriptor *ImageEffectDescriptor::defineClip(const std::string &name)
1468 {
1469 validateXMLString(name, false);
1470 // do we have the clip already
1471 std::map<std::string, ClipDescriptor *>::const_iterator search;
1472 search = _definedClips.find(name);
1473 if(search != _definedClips.end())
1474 return search->second;
1475
1476 // no, so make it
1477 OfxPropertySetHandle propSet;
1478 OfxStatus stat = OFX::Private::gEffectSuite->clipDefine(_effectHandle, name.c_str(), &propSet);
1479 throwSuiteStatusException(stat);
1480
1481 ClipDescriptor *clip = new ClipDescriptor(name, propSet);
1482
1483 std::map<std::string, ClipDescriptor *>::iterator it = _definedClips.find(name);
1484 if (it != _definedClips.end()) {
1485 delete it->second;
1486 it->second = clip;
1487 } else {
1488 _definedClips[name] = clip;
1489 }
1490 _clipComponentsPropNames[name] = std::string("OfxImageClipPropComponents_") + name;
1491 _clipDepthPropNames[name] = std::string("OfxImageClipPropDepth_") + name;
1492 _clipPARPropNames[name] = std::string("OfxImageClipPropPAR_") + name;
1493 _clipROIPropNames[name] = std::string("OfxImageClipPropRoI_") + name;
1494 _clipFrameRangePropNames[name] = std::string("OfxImageClipPropFrameRange_") + name;
1495 #ifdef OFX_EXTENSIONS_NUKE
1496 _clipPlanesPropNames[name] = std::string(kFnOfxImageEffectActionGetClipComponentsPropString) + name;
1497 _clipFrameViewsPropNames[name] = std::string("OfxImageClipPropFrameRangeView_") + name;
1498 #endif
1499 return clip;
1500 }
1501
1502 #ifdef OFX_EXTENSIONS_NUKE
1503 /** @brief Create a camera, only callable from describe in context */
defineCamera(const std::string & name)1504 CameraDescriptor *ImageEffectDescriptor::defineCamera(const std::string &name)
1505 {
1506 validateXMLString(name, false);
1507 if (OFX::Private::gCameraSuite == NULL) {
1508 throwHostMissingSuiteException(kNukeOfxCameraSuite);
1509 }
1510 // do we have the camera already
1511 std::map<std::string, CameraDescriptor *>::const_iterator search;
1512 search = _definedCameras.find(name);
1513 if(search != _definedCameras.end())
1514 return search->second;
1515
1516 // no, so make it
1517 OfxPropertySetHandle propSet;
1518 OfxStatus stat = OFX::Private::gCameraSuite->cameraDefine(_effectHandle, name.c_str(), &propSet);
1519 throwSuiteStatusException(stat);
1520
1521 CameraDescriptor *camera = new CameraDescriptor(name, propSet);
1522
1523 std::map<std::string, CameraDescriptor *>::iterator it = _definedCameras.find(name);
1524 if (it != _definedCameras.end()) {
1525 delete it->second;
1526 it->second = camera;
1527 } else {
1528 _definedCameras[name] = camera;
1529 }
1530
1531 return camera;
1532 }
1533 #endif
1534
1535 #ifdef OFX_EXTENSIONS_NATRON
1536 /** @brief indicate that a plugin or host can handle distortion function effects */
setCanDistort(bool v)1537 void ImageEffectDescriptor::setCanDistort(bool v)
1538 {
1539 // the header says this property is on the effect instance, but on Nuke it only exists on the effect descriptor
1540 if (gHostDescription.canDistort) {
1541 _effectProps.propSetInt(kOfxImageEffectPropCanDistort, int(v), false);
1542 }
1543 }
1544
1545 /** @brief indicate if the host may add a channel selector */
setChannelSelector(PixelComponentEnum v)1546 void ImageEffectDescriptor::setChannelSelector(PixelComponentEnum v)
1547 {
1548 if (gHostDescription.supportsChannelSelector) {
1549 _effectProps.propSetString(kNatronOfxImageEffectPropChannelSelector, mapPixelComponentEnumToStr(v), false);
1550 }
1551 }
1552
1553 /** @brief indicate that this plugin is deprecated */
setIsDeprecated(bool v)1554 void ImageEffectDescriptor::setIsDeprecated(bool v)
1555 {
1556 _effectProps.propSetInt(kNatronOfxImageEffectPropDeprecated, (int)v, false);
1557 }
1558
1559 /** @brief say whether all the planes listed on the output clip in the getClipComponents action should preferably be rendered
1560 at once or not (e.g: optical flow plug-in that could produce bw/fw planes at once)*/
setRenderAllPlanes(bool enabled)1561 void ImageEffectDescriptor::setRenderAllPlanes(bool enabled)
1562 {
1563 _effectProps.propSetInt(kOfxImageEffectPropRenderAllPlanes, (int)enabled, false);
1564 }
1565 #endif
1566
1567 ////////////////////////////////////////////////////////////////////////////////
1568 // wraps up an image
ImageBase(OfxPropertySetHandle props)1569 ImageBase::ImageBase(OfxPropertySetHandle props)
1570 : _imageProps(props)
1571 {
1572 OFX::Validation::validateImageBaseProperties(props);
1573
1574 // and fetch all the properties
1575 _rowBytes = _imageProps.propGetInt(kOfxImagePropRowBytes);
1576 _pixelAspectRatio = _imageProps.propGetDouble(kOfxImagePropPixelAspectRatio);;
1577
1578 std::string str = _imageProps.propGetString(kOfxImageEffectPropComponents);
1579 _pixelComponents = mapStrToPixelComponentEnum(str);
1580
1581 switch (_pixelComponents) {
1582 case ePixelComponentAlpha:
1583 _pixelComponentCount = 1;
1584 break;
1585 case ePixelComponentNone:
1586 _pixelComponentCount = 0;
1587 break;
1588 #ifdef OFX_EXTENSIONS_NUKE
1589 case ePixelComponentMotionVectors:
1590 case ePixelComponentStereoDisparity:
1591 _pixelComponentCount = 2;
1592 break;
1593 #endif
1594 case ePixelComponentRGB:
1595 _pixelComponentCount = 3;
1596 break;
1597 case ePixelComponentRGBA:
1598 _pixelComponentCount = 4;
1599 break;
1600 #ifdef OFX_EXTENSIONS_NATRON
1601 case ePixelComponentXY:
1602 _pixelComponentCount = 2;
1603 break;
1604 #endif
1605 case ePixelComponentCustom: {
1606 #ifdef OFX_EXTENSIONS_NATRON
1607
1608 std::string planeName, planeLabel, channelsLabel;
1609 std::vector<std::string> channels;
1610 extractCustomPlane(str, &planeName, &planeLabel, &channelsLabel, &channels);
1611 _pixelComponentCount = (int)channels.size();
1612 #else
1613 _pixelComponentCount = 0;
1614 #endif
1615 } break;
1616 default:
1617 _pixelComponentCount = 0;
1618 break;
1619 }
1620
1621 str = _imageProps.propGetString(kOfxImageEffectPropPixelDepth);
1622 _pixelDepth = mapStrToBitDepthEnum(str);
1623
1624 // compute bytes per pixel
1625 _pixelBytes = _pixelComponentCount;
1626
1627 switch(_pixelDepth)
1628 {
1629 case eBitDepthNone : _pixelBytes *= 0; break;
1630 case eBitDepthUByte : _pixelBytes *= 1; break;
1631 case eBitDepthUShort : _pixelBytes *= 2; break;
1632 case eBitDepthHalf : _pixelBytes *= 2; break;
1633 case eBitDepthFloat : _pixelBytes *= 4; break;
1634 #ifdef OFX_EXTENSIONS_VEGAS
1635 case eBitDepthUByteBGRA : _pixelBytes *= 1; break;
1636 case eBitDepthUShortBGRA : _pixelBytes *= 2; break;
1637 case eBitDepthFloatBGRA : _pixelBytes *= 4; break;
1638 #endif
1639 case eBitDepthCustom : _pixelBytes *= 0; break;
1640 }
1641
1642 str = _imageProps.propGetString(kOfxImageEffectPropPreMultiplication);
1643 _preMultiplication = mapStrToPreMultiplicationEnum(str);
1644
1645 _regionOfDefinition.x1 = _imageProps.propGetInt(kOfxImagePropRegionOfDefinition, 0);
1646 _regionOfDefinition.y1 = _imageProps.propGetInt(kOfxImagePropRegionOfDefinition, 1);
1647 _regionOfDefinition.x2 = _imageProps.propGetInt(kOfxImagePropRegionOfDefinition, 2);
1648 _regionOfDefinition.y2 = _imageProps.propGetInt(kOfxImagePropRegionOfDefinition, 3);
1649
1650 _bounds.x1 = _imageProps.propGetInt(kOfxImagePropBounds, 0);
1651 _bounds.y1 = _imageProps.propGetInt(kOfxImagePropBounds, 1);
1652 _bounds.x2 = _imageProps.propGetInt(kOfxImagePropBounds, 2);
1653 _bounds.y2 = _imageProps.propGetInt(kOfxImagePropBounds, 3);
1654
1655 str = _imageProps.propGetString(kOfxImagePropField);
1656 if(str == kOfxImageFieldNone) {
1657 _field = eFieldNone;
1658 }
1659 else if(str == kOfxImageFieldBoth) {
1660 _field = eFieldBoth;
1661 }
1662 else if(str == kOfxImageFieldLower) {
1663 _field = eFieldLower;
1664 }
1665 else if(str == kOfxImageFieldUpper) {
1666 _field = eFieldLower;
1667 }
1668 else {
1669 OFX::Log::error(true, "Unknown field state '%s' reported on an image", str.c_str());
1670 _field = eFieldNone;
1671 }
1672
1673 _uniqueID = _imageProps.propGetString(kOfxImagePropUniqueIdentifier);
1674
1675 _renderScale.x = _renderScale.y = 1.;
1676 _imageProps.propGetDoubleN(kOfxImageEffectPropRenderScale, &_renderScale.x, 2, false);
1677
1678 #if defined(OFX_EXTENSIONS_NATRON) || defined(OFX_EXTENSIONS_NUKE)
1679 bool gotDistortion = false;
1680 #endif
1681 #ifdef OFX_EXTENSIONS_NATRON
1682
1683 // Check for distortion function
1684 _inverseDistortionFunction = (OfxInverseDistortionFunctionV1)_imageProps.propGetPointer(kOfxPropInverseDistortionFunction, false);
1685 _inverseDistortionFunctionData = _imageProps.propGetPointer(kOfxPropInverseDistortionFunctionData, false);
1686 if (_inverseDistortionFunction) {
1687 gotDistortion = true;
1688 }
1689
1690 _transformIsIdentity = true;
1691
1692 if (!gotDistortion) {
1693 // Check for canonical transform matrix
1694 if (_imageProps.propGetDimension(kOfxPropMatrix3x3, false) != 0) {
1695 gotDistortion = true;
1696
1697 std::fill(_transform, _transform + 9, 0.);
1698 _imageProps.propGetDoubleN(kOfxPropMatrix3x3, _transform, 9);
1699 // check if the transform is identity (a zero matrix is considered identity)
1700 _transformIsIdentity = (_transform[1] == 0. && _transform[2] == 0. &&
1701 _transform[3] == 0. && _transform[5] == 0. &&
1702 _transform[6] == 0. && _transform[7] == 0. &&
1703 _transform[0] == _transform[2] && _transform[0] == _transform[8]);
1704 }
1705 }
1706 #endif
1707 #ifdef OFX_EXTENSIONS_NUKE
1708 if (!gotDistortion) {
1709 std::fill(_transform, _transform + 9, 0.);
1710 if (_imageProps.propGetDimension(kFnOfxPropMatrix2D, false) != 0) {
1711 // Check for deprecated pixel transform matrix
1712
1713 std::fill(_transform, _transform + 9, 0.);
1714 _imageProps.propGetDoubleN(kFnOfxPropMatrix2D, _transform, 9);
1715 // check if the transform is identity (a zero matrix is considered identity)
1716 _transformIsIdentity = (_transform[1] == 0. && _transform[2] == 0. &&
1717 _transform[3] == 0. && _transform[5] == 0. &&
1718 _transform[6] == 0. && _transform[7] == 0. &&
1719 _transform[0] == _transform[2] && _transform[0] == _transform[8]);
1720 }
1721 }
1722 #endif
1723 }
1724
~ImageBase()1725 ImageBase::~ImageBase()
1726 {
1727 }
1728
1729 ////////////////////////////////////////////////////////////////////////////////
1730 // wraps up an image
Image(OfxPropertySetHandle props)1731 Image::Image(OfxPropertySetHandle props)
1732 : ImageBase(props)
1733 {
1734 OFX::Validation::validateImageProperties(props);
1735
1736 // and fetch all the properties
1737 // should throw if it is not an image
1738 _pixelData = _imageProps.propGetPointer(kOfxImagePropData);
1739 }
1740
~Image()1741 Image::~Image()
1742 {
1743 // error are ignored: don't throw in a destructor
1744 OFX::Private::gEffectSuite->clipReleaseImage(_imageProps.propSetHandle());
1745 }
1746
1747 #ifdef OFX_SUPPORTS_OPENGLRENDER
1748 ////////////////////////////////////////////////////////////////////////////////
1749 // wraps up an OpenGL texture
Texture(OfxPropertySetHandle props)1750 Texture::Texture(OfxPropertySetHandle props)
1751 : ImageBase(props)
1752 {
1753 OFX::Validation::validateTextureProperties(props);
1754
1755 // should throw if it is not a texture
1756 _index = _imageProps.propGetInt(kOfxImageEffectPropOpenGLTextureIndex);
1757 _target = _imageProps.propGetInt(kOfxImageEffectPropOpenGLTextureTarget);
1758 }
1759
~Texture()1760 Texture::~Texture()
1761 {
1762 OfxStatus stat = OFX::Private::gOpenGLRenderSuite->clipFreeTexture(_imageProps.propSetHandle());
1763 // ignore status code for exception purposes
1764 (void)stat;
1765 }
1766 #endif
1767
1768 /** @brief return a pixel pointer
1769
1770 No attempt made to be uber efficient here.
1771 */
getPixelAddress(int x,int y)1772 void *Image::getPixelAddress(int x, int y)
1773 {
1774 // are we in the image bounds
1775 if(x < _bounds.x1 || x >= _bounds.x2 || y < _bounds.y1 || y >= _bounds.y2 || _pixelBytes == 0)
1776 return 0;
1777
1778 char *pix = ((char *) _pixelData) + (size_t)(y - _bounds.y1) * _rowBytes;
1779 pix += (x - _bounds.x1) * _pixelBytes;
1780 return (void *) pix;
1781 }
1782
getPixelAddress(int x,int y) const1783 const void *Image::getPixelAddress(int x, int y) const
1784 {
1785 // are we in the image bounds
1786 if(x < _bounds.x1 || x >= _bounds.x2 || y < _bounds.y1 || y >= _bounds.y2 || _pixelBytes == 0)
1787 return 0;
1788
1789 const char *pix = ((const char *) _pixelData) + (size_t)(y - _bounds.y1) * _rowBytes;
1790 pix += (x - _bounds.x1) * _pixelBytes;
1791 return (const void *) pix;
1792 }
1793
getPixelAddressNearest(int x,int y)1794 void *Image::getPixelAddressNearest(int x, int y)
1795 {
1796 x = std::max(_bounds.x1, std::min(x, _bounds.x2 - 1));
1797 y = std::max(_bounds.y1, std::min(y, _bounds.y2 - 1));
1798
1799 char *pix = ((char *) _pixelData) + (size_t)(y - _bounds.y1) * _rowBytes;
1800 pix += (x - _bounds.x1) * _pixelBytes;
1801 return (void *) pix;
1802 }
1803
getPixelAddressNearest(int x,int y) const1804 const void *Image::getPixelAddressNearest(int x, int y) const
1805 {
1806 x = std::max(_bounds.x1, std::min(x, _bounds.x2 - 1));
1807 y = std::max(_bounds.y1, std::min(y, _bounds.y2 - 1));
1808
1809 const char *pix = ((const char *) _pixelData) + (size_t)(y - _bounds.y1) * _rowBytes;
1810 pix += (x - _bounds.x1) * _pixelBytes;
1811 return (const void *) pix;
1812 }
1813
1814 ////////////////////////////////////////////////////////////////////////////////
1815 // clip instance
1816
1817 /** @brief hidden constructor */
Clip(ImageEffect * effect,const std::string & name,OfxImageClipHandle handle,OfxPropertySetHandle props)1818 Clip::Clip(ImageEffect *effect, const std::string &name, OfxImageClipHandle handle, OfxPropertySetHandle props)
1819 : _clipName(name)
1820 , _clipProps(props)
1821 , _clipHandle(handle)
1822 , _effect(effect)
1823 #ifdef OFX_EXTENSIONS_VEGAS
1824 , _pixelOrder(ePixelOrderRGBA)
1825 #endif
1826 {
1827 OFX::Validation::validateClipInstanceProperties(_clipProps);
1828 }
1829
1830 #ifdef OFX_EXTENSIONS_NATRON
1831 /** @brief set the label property */
1832 void
setLabel(const std::string & label)1833 Clip::setLabel(const std::string &label)
1834 {
1835 _clipProps.propSetString(kOfxPropLabel, label, false);
1836 }
1837
1838 /** @brief set the label properties */
1839 void
setLabels(const std::string & label,const std::string & shortLabel,const std::string & longLabel)1840 Clip::setLabels(const std::string &label, const std::string &shortLabel, const std::string &longLabel)
1841 {
1842 setLabel(label);
1843 _clipProps.propSetString(kOfxPropShortLabel, shortLabel, false);
1844 _clipProps.propSetString(kOfxPropLongLabel, longLabel, false);
1845 }
1846
1847 /** @brief set the secretness of the param, defaults to false */
setIsSecret(bool v)1848 void Clip::setIsSecret(bool v)
1849 {
1850 _clipProps.propSetInt(kOfxParamPropSecret, v, false);
1851 }
1852
1853 /** @brief set the clip hint */
1854 void
setHint(const std::string & v)1855 Clip::setHint(const std::string &v)
1856 {
1857 _clipProps.propSetString(kOfxParamPropHint, v, false);
1858 }
1859
1860 /** @brief set the clip label and hint */
1861 void
setLabelAndHint(const std::string & label,const std::string & hint)1862 Clip::setLabelAndHint(const std::string &label, const std::string &hint)
1863 {
1864 setLabel(label);
1865 setHint(hint);
1866 }
1867
1868 void
getFormat(OfxRectI & format) const1869 Clip::getFormat(OfxRectI &format) const
1870 {
1871 format.x1 = format.y1 = format.x2 = format.y2 = 0; // default value
1872 _clipProps.propGetIntN(kOfxImageClipPropFormat, &format.x1, 4, false);
1873 }
1874 #endif
1875
1876 /** @brief fetch the label */
getLabel(std::string & label) const1877 void Clip::getLabel(std::string &label) const
1878 {
1879 label = _clipProps.propGetString(kOfxPropLabel);
1880 }
1881
1882 /** @brief fetch the labels */
getLabels(std::string & label,std::string & shortLabel,std::string & longLabel) const1883 void Clip::getLabels(std::string &label, std::string &shortLabel, std::string &longLabel) const
1884 {
1885 getLabel(label);
1886 shortLabel = _clipProps.propGetString(kOfxPropShortLabel, false);
1887 longLabel = _clipProps.propGetString(kOfxPropLongLabel, false);
1888 }
1889
1890 /** @brief get the pixel depth */
getPixelDepth(void) const1891 BitDepthEnum Clip::getPixelDepth(void) const
1892 {
1893 std::string str = _clipProps.propGetString(kOfxImageEffectPropPixelDepth);
1894 BitDepthEnum e;
1895 try {
1896 e = mapStrToBitDepthEnum(str);
1897 if(e == eBitDepthNone && isConnected()) {
1898 OFX::Log::error(true, "Clip %s is connected and has no pixel depth.", _clipName.c_str());
1899 }
1900 }
1901 // gone wrong ?
1902 catch(std::invalid_argument) {
1903 OFX::Log::error(true, "Unknown pixel depth property '%s' reported on clip '%s'", str.c_str(), _clipName.c_str());
1904 e = eBitDepthNone;
1905 }
1906 return e;
1907 }
1908
1909 /** @brief get the components in the image */
getPixelComponents(void) const1910 PixelComponentEnum Clip::getPixelComponents(void) const
1911 {
1912 std::string str = _clipProps.propGetString(kOfxImageEffectPropComponents);
1913 PixelComponentEnum e;
1914 try {
1915 e = mapStrToPixelComponentEnum(str);
1916 if(e == ePixelComponentNone && isConnected()) {
1917 OFX::Log::error(true, "Clip %s is connected and has no pixel component type!", _clipName.c_str());
1918 }
1919 }
1920 // gone wrong ?
1921 catch(std::invalid_argument) {
1922 OFX::Log::error(true, "Unknown pixel component type '%s' reported on clip '%s'", str.c_str(), _clipName.c_str());
1923 e = ePixelComponentNone;
1924 }
1925 return e;
1926 }
1927
1928 /** @brief get the number of components in the image */
getPixelComponentCount(void) const1929 int Clip::getPixelComponentCount(void) const
1930 {
1931 std::string str = _clipProps.propGetString(kOfxImageEffectPropComponents);
1932 PixelComponentEnum e;
1933 try {
1934 e = mapStrToPixelComponentEnum(str);
1935 if(e == ePixelComponentNone && isConnected()) {
1936 OFX::Log::error(true, "Clip %s is connected and has no pixel component type!", _clipName.c_str());
1937 }
1938 }
1939 // gone wrong ?
1940 catch(std::invalid_argument) {
1941 OFX::Log::error(true, "Unknown pixel component type '%s' reported on clip '%s'", str.c_str(), _clipName.c_str());
1942 e = ePixelComponentNone;
1943 }
1944
1945 switch (e) {
1946 case ePixelComponentAlpha:
1947 return 1;
1948 case ePixelComponentNone:
1949 return 0;
1950 #ifdef OFX_EXTENSIONS_NUKE
1951 case ePixelComponentMotionVectors:
1952 case ePixelComponentStereoDisparity:
1953 return 2;
1954 #endif
1955 case ePixelComponentRGB:
1956 return 3;
1957 case ePixelComponentRGBA:
1958 return 4;
1959 #ifdef OFX_EXTENSIONS_NATRON
1960 case ePixelComponentXY:
1961 return 2;
1962 #endif
1963 case ePixelComponentCustom: {
1964 #ifdef OFX_EXTENSIONS_NATRON
1965 std::string planeName, planeLabel, channelsLabel;
1966 std::vector<std::string> channels;
1967 extractCustomPlane(str, &planeName, &planeLabel, &channelsLabel, &channels);
1968 return (int)channels.size();
1969 #else
1970 return 0;
1971 #endif
1972 }
1973 default:
1974 return 0;
1975 }
1976 }
1977
1978 /** @brief what is the actual pixel depth of the clip */
getUnmappedPixelDepth(void) const1979 BitDepthEnum Clip::getUnmappedPixelDepth(void) const
1980 {
1981 std::string str = _clipProps.propGetString(kOfxImageClipPropUnmappedPixelDepth);
1982 BitDepthEnum e;
1983 try {
1984 e = mapStrToBitDepthEnum(str);
1985 if(e == eBitDepthNone && !isConnected()) {
1986 OFX::Log::error(true, "Clip %s is connected and has no unmapped pixel depth.", _clipName.c_str());
1987 }
1988 }
1989 // gone wrong ?
1990 catch(std::invalid_argument) {
1991 OFX::Log::error(true, "Unknown unmapped pixel depth property '%s' reported on clip '%s'", str.c_str(), _clipName.c_str());
1992 e = eBitDepthNone;
1993 }
1994 return e;
1995 }
1996
1997 /** @brief what is the component type of the clip */
getUnmappedPixelComponents(void) const1998 PixelComponentEnum Clip::getUnmappedPixelComponents(void) const
1999 {
2000 std::string str = _clipProps.propGetString(kOfxImageClipPropUnmappedComponents);
2001 PixelComponentEnum e;
2002 try {
2003 e = mapStrToPixelComponentEnum(str);
2004 if(e == ePixelComponentNone && !isConnected()) {
2005 OFX::Log::error(true, "Clip %s is connected and has no unmapped pixel component type!", _clipName.c_str());
2006 }
2007 }
2008 // gone wrong ?
2009 catch(std::invalid_argument) {
2010 OFX::Log::error(true, "Unknown unmapped pixel component type '%s' reported on clip '%s'", str.c_str(), _clipName.c_str());
2011 e = ePixelComponentNone;
2012 }
2013 return e;
2014 }
2015
2016 /** @brief get the components in the image */
getPreMultiplication(void) const2017 PreMultiplicationEnum Clip::getPreMultiplication(void) const
2018 {
2019 std::string str = _clipProps.propGetString(kOfxImageEffectPropPreMultiplication);
2020 PreMultiplicationEnum e;
2021 try {
2022 e = mapStrToPreMultiplicationEnum(str);
2023 }
2024 // gone wrong ?
2025 catch(std::invalid_argument) {
2026 OFX::Log::error(true, "Unknown premultiplication type '%s' reported on clip %s!", str.c_str(), _clipName.c_str());
2027 e = eImageOpaque;
2028 }
2029 return e;
2030 }
2031
2032 /** @brief which spatial field comes first temporally */
getFieldOrder(void) const2033 FieldEnum Clip::getFieldOrder(void) const
2034 {
2035 std::string str = _clipProps.propGetString(kOfxImageClipPropFieldOrder);
2036 FieldEnum e;
2037 try {
2038 e = mapStrToFieldEnum(str);
2039 OFX::Log::error(e != eFieldNone && e != eFieldLower && e != eFieldUpper,
2040 "Field order '%s' reported on a clip %s is invalid, it must be none, lower or upper.", str.c_str(), _clipName.c_str());
2041 }
2042 // gone wrong ?
2043 catch(std::invalid_argument) {
2044 OFX::Log::error(true, "Unknown field order '%s' reported on a clip %s.", str.c_str(), _clipName.c_str());
2045 e = eFieldNone;
2046 }
2047 return e;
2048 }
2049
2050 #ifdef OFX_EXTENSIONS_VEGAS
2051 /** @brief get the pixel order of this image */
getPixelOrder(void) const2052 PixelOrderEnum Clip::getPixelOrder(void) const
2053 {
2054 // only vegas supports this so far, so ignore it if it doesn't work
2055 std::string str = _clipProps.propGetString(kOfxImagePropPixelOrder, false);
2056 PixelOrderEnum e;
2057 if(str == kOfxImagePixelOrderRGBA) {
2058 e = ePixelOrderRGBA;
2059 }
2060 else if(str == kOfxImagePixelOrderBGRA) {
2061 e = ePixelOrderBGRA;
2062 }
2063 else {
2064 e = ePixelOrderRGBA;
2065 }
2066 return e;
2067 }
2068 #endif
2069
2070 /** @brief is the clip connected */
isConnected(void) const2071 bool Clip::isConnected(void) const
2072 {
2073 return _clipProps.propGetInt(kOfxImageClipPropConnected) != 0;
2074 }
2075
2076 /** @brief can the clip be continuously sampled */
hasContinuousSamples(void) const2077 bool Clip::hasContinuousSamples(void) const
2078 {
2079 return _clipProps.propGetInt(kOfxImageClipPropContinuousSamples) != 0;
2080 }
2081
2082 /** @brief get the scale factor that has been applied to this clip */
getPixelAspectRatio(void) const2083 double Clip::getPixelAspectRatio(void) const
2084 {
2085 double par = _clipProps.propGetDouble(kOfxImagePropPixelAspectRatio, false);
2086 if (par != 0.) {
2087 return par;
2088 }
2089 return 1.; // This error could happen in Eyeon Fusion.
2090 }
2091
2092 /** @brief get the frame rate, in frames per second on this clip, after any clip preferences have been applied */
getFrameRate(void) const2093 double Clip::getFrameRate(void) const
2094 {
2095 return _clipProps.propGetDouble(kOfxImageEffectPropFrameRate);
2096 }
2097
2098 /** @brief return the range of frames over which this clip has images, after any clip preferences have been applied */
getFrameRange(void) const2099 OfxRangeD Clip::getFrameRange(void) const
2100 {
2101 OfxRangeD v = {0., 0.};
2102 _clipProps.propGetDoubleN(kOfxImageEffectPropFrameRange, &v.min, 2);
2103 return v;
2104 }
2105
2106 /** @brief get the frame rate, in frames per second on this clip, before any clip preferences have been applied */
getUnmappedFrameRate(void) const2107 double Clip::getUnmappedFrameRate(void) const
2108 {
2109 return _clipProps.propGetDouble(kOfxImageEffectPropUnmappedFrameRate);
2110 }
2111
2112 /** @brief return the range of frames over which this clip has images, before any clip preferences have been applied */
getUnmappedFrameRange(void) const2113 OfxRangeD Clip::getUnmappedFrameRange(void) const
2114 {
2115 OfxRangeD v = {0., 0.};
2116 _clipProps.propGetDoubleN(kOfxImageEffectPropUnmappedFrameRange, &v.min, 2);
2117 return v;
2118 }
2119
2120 /** @brief get the RoD for this clip in the cannonical coordinate system */
getRegionOfDefinition(double t)2121 OfxRectD Clip::getRegionOfDefinition(double t)
2122 {
2123 if ( OFX::IsNaN(t) ) {
2124 throwSuiteStatusException(kOfxStatErrValue);
2125 }
2126 OfxRectD bounds;
2127 OfxStatus stat = OFX::Private::gEffectSuite->clipGetRegionOfDefinition(_clipHandle, t, &bounds);
2128 if(stat == kOfxStatFailed) {
2129 bounds.x1 = bounds.x2 = bounds.y1 = bounds.y2 = 0;
2130 }
2131 throwSuiteStatusException(stat);
2132 return bounds;
2133 }
2134
2135 #ifdef OFX_EXTENSIONS_RESOLVE
2136 /** @brief is the clip for thumbnail */
isForThumbnail(void) const2137 bool Clip::isForThumbnail(void) const
2138 {
2139 return (_clipProps.propGetInt(kOfxImageClipPropThumbnail, false) != 0);
2140 }
2141 #endif
2142
2143 /** @brief fetch an image */
fetchImage(double t)2144 Image *Clip::fetchImage(double t)
2145 {
2146 if ( OFX::IsNaN(t) ) {
2147 throwSuiteStatusException(kOfxStatErrValue);
2148 }
2149 OfxPropertySetHandle imageHandle;
2150 OfxStatus stat = OFX::Private::gEffectSuite->clipGetImage(_clipHandle, t, NULL, &imageHandle);
2151 if(stat == kOfxStatFailed) {
2152 return NULL; // not an error, fetched images out of range/region, assume black and transparent
2153 }
2154 else
2155 throwSuiteStatusException(stat);
2156
2157 return new Image(imageHandle);
2158 }
2159
2160 /** @brief fetch an image, with a specific region in cannonical coordinates */
fetchImage(double t,const OfxRectD & bounds)2161 Image *Clip::fetchImage(double t, const OfxRectD &bounds)
2162 {
2163 if ( OFX::IsNaN(t) ) {
2164 throwSuiteStatusException(kOfxStatErrValue);
2165 }
2166 OfxPropertySetHandle imageHandle;
2167 OfxStatus stat = OFX::Private::gEffectSuite->clipGetImage(_clipHandle, t, &bounds, &imageHandle);
2168 if(stat == kOfxStatFailed) {
2169 return NULL; // not an error, fetched images out of range/region, assume black and transparent
2170 }
2171 else
2172 throwSuiteStatusException(stat);
2173
2174 return new Image(imageHandle);
2175 }
2176
2177 #ifdef OFX_EXTENSIONS_NUKE
getRegionOfDefinition(double t,int view)2178 OfxRectD Clip::getRegionOfDefinition(double t, int view)
2179 {
2180 if ( OFX::IsNaN(t) ) {
2181 throwSuiteStatusException(kOfxStatErrValue);
2182 }
2183 if (!OFX::Private::gImageEffectPlaneSuiteV2) {
2184 return getRegionOfDefinition(t);
2185 }
2186 OfxRectD bounds;
2187 OfxStatus stat = OFX::Private::gImageEffectPlaneSuiteV2->clipGetRegionOfDefinition(_clipHandle, t, view, &bounds);
2188 if(stat == kOfxStatFailed) {
2189 bounds.x1 = bounds.x2 = bounds.y1 = bounds.y2 = 0;
2190 }
2191 throwSuiteStatusException(stat);
2192 return bounds;
2193 }
2194
fetchImagePlane(double t,int view,const char * plane)2195 Image* Clip::fetchImagePlane(double t, int view, const char* plane)
2196 {
2197 if ( OFX::IsNaN(t) ) {
2198 throwSuiteStatusException(kOfxStatErrValue);
2199 }
2200 if (!OFX::Private::gImageEffectPlaneSuiteV2 || !OFX::Private::gImageEffectPlaneSuiteV2->clipGetImagePlane) {
2201 throwHostMissingSuiteException(kFnOfxImageEffectPlaneSuite"V2");
2202 }
2203 OfxPropertySetHandle imageHandle;
2204 OfxStatus stat = OFX::Private::gImageEffectPlaneSuiteV2->clipGetImagePlane(_clipHandle, t, view, plane, NULL, &imageHandle);
2205 if(stat == kOfxStatFailed) {
2206 return NULL; // not an error, fetched images out of range/region, assume black and transparent
2207 }
2208 else
2209 throwSuiteStatusException(stat);
2210
2211 return new Image(imageHandle);
2212 }
2213
fetchImagePlane(double t,const char * plane)2214 Image* Clip::fetchImagePlane(double t, const char* plane)
2215 {
2216 if ( OFX::IsNaN(t) ) {
2217 throwSuiteStatusException(kOfxStatErrValue);
2218 }
2219 if (!OFX::Private::gImageEffectPlaneSuiteV1 || !OFX::Private::gImageEffectPlaneSuiteV1->clipGetImagePlane) {
2220 if (std::string(plane) == kFnOfxImagePlaneColour) {
2221 return fetchImage(t);
2222 }
2223 throwHostMissingSuiteException(kFnOfxImageEffectPlaneSuite"V1");
2224 return NULL;
2225 }
2226 OfxPropertySetHandle imageHandle;
2227 OfxStatus stat = OFX::Private::gImageEffectPlaneSuiteV1->clipGetImagePlane(_clipHandle, t, plane, NULL, &imageHandle);
2228 if(stat == kOfxStatFailed) {
2229 return NULL; // not an error, fetched images out of range/region, assume black and transparent
2230 }
2231 else
2232 throwSuiteStatusException(stat);
2233
2234 return new Image(imageHandle);
2235 }
2236
fetchImagePlane(double t,int view,const char * plane,const OfxRectD & bounds)2237 Image* Clip::fetchImagePlane(double t, int view, const char* plane, const OfxRectD& bounds)
2238 {
2239 if ( OFX::IsNaN(t) ) {
2240 throwSuiteStatusException(kOfxStatErrValue);
2241 }
2242 if (!OFX::Private::gImageEffectPlaneSuiteV2 || !OFX::Private::gImageEffectPlaneSuiteV2->clipGetImagePlane) {
2243 throwHostMissingSuiteException(kFnOfxImageEffectPlaneSuite"V2");
2244 }
2245 OfxPropertySetHandle imageHandle;
2246
2247 OfxStatus stat = OFX::Private::gImageEffectPlaneSuiteV2->clipGetImagePlane(_clipHandle, t, view, plane, &bounds, &imageHandle);
2248 if(stat == kOfxStatFailed) {
2249 return NULL; // not an error, fetched images out of range/region, assume black and transparent
2250 }
2251 else
2252 throwSuiteStatusException(stat);
2253
2254 return new Image(imageHandle);
2255 }
2256
fetchImagePlane(double t,const char * plane,const OfxRectD & bounds)2257 Image* Clip::fetchImagePlane(double t, const char* plane, const OfxRectD& bounds)
2258 {
2259 if ( OFX::IsNaN(t) ) {
2260 throwSuiteStatusException(kOfxStatErrValue);
2261 }
2262 if (!OFX::Private::gImageEffectPlaneSuiteV1 || !OFX::Private::gImageEffectPlaneSuiteV1->clipGetImagePlane) {
2263 if (std::string(plane) == kFnOfxImagePlaneColour) {
2264 return fetchImage(t, bounds);
2265 }
2266 throwHostMissingSuiteException(kFnOfxImageEffectPlaneSuite"V1");
2267 return NULL;
2268 }
2269 OfxPropertySetHandle imageHandle;
2270
2271 OfxStatus stat = OFX::Private::gImageEffectPlaneSuiteV1->clipGetImagePlane(_clipHandle, t, plane, &bounds, &imageHandle);
2272 if(stat == kOfxStatFailed) {
2273 return NULL; // not an error, fetched images out of range/region, assume black and transparent
2274 }
2275 else
2276 throwSuiteStatusException(stat);
2277
2278 return new Image(imageHandle);
2279 }
2280
getPlanesPresent(std::vector<std::string> * components) const2281 void Clip::getPlanesPresent(std::vector<std::string>* components) const
2282 {
2283 _clipProps.propGetStringN(kFnOfxImageEffectPropComponentsPresent, components, false);
2284 }
2285 #endif // OFX_EXTENSIONS_NUKE
2286
2287 #if defined(OFX_EXTENSIONS_VEGAS) || defined(OFX_EXTENSIONS_NUKE)
2288 /** @brief fetch an image */
fetchStereoscopicImage(double t,int view)2289 Image *Clip::fetchStereoscopicImage(double t, int view)
2290 {
2291 if ( OFX::IsNaN(t) ) {
2292 throwSuiteStatusException(kOfxStatErrValue);
2293 }
2294 #ifdef OFX_EXTENSIONS_NUKE
2295 if (OFX::Private::gImageEffectPlaneSuiteV2 && OFX::Private::gImageEffectPlaneSuiteV2->clipGetImagePlane) {
2296 return fetchImagePlane(t, view, kFnOfxImagePlaneColour);
2297 }
2298 else
2299 #endif
2300 #ifdef OFX_EXTENSIONS_VEGAS
2301 if (OFX::Private::gVegasStereoscopicImageSuite && OFX::Private::gVegasStereoscopicImageSuite->clipGetStereoscopicImage) {
2302 OfxPropertySetHandle imageHandle;
2303 OfxStatus stat = OFX::Private::gVegasStereoscopicImageSuite->clipGetStereoscopicImage(_clipHandle, t, view, NULL, &imageHandle);
2304 if (stat == kOfxStatFailed) {
2305 return NULL; // not an error, fetched images out of range/region, assume black and transparent
2306 } else {
2307 throwSuiteStatusException(stat);
2308 }
2309 return new Image(imageHandle);
2310 }
2311 else
2312 #endif
2313 {
2314 #if defined(OFX_EXTENSIONS_VEGAS) && defined(OFX_EXTENSIONS_NUKE)
2315 throwHostMissingSuiteException(kFnOfxImageEffectPlaneSuite "V2 & " kOfxVegasStereoscopicImageEffectSuite);
2316 #else
2317 #ifdef OFX_EXTENSIONS_VEGAS
2318 throwHostMissingSuiteException(kOfxVegasStereoscopicImageEffectSuite);
2319 #else
2320 throwHostMissingSuiteException(kFnOfxImageEffectPlaneSuite"V2");
2321 #endif
2322 #endif
2323 }
2324 return NULL;
2325 }
2326 #endif
2327
2328 #ifdef OFX_SUPPORTS_OPENGLRENDER
loadTexture(double t,BitDepthEnum format,const OfxRectD * region)2329 Texture *Clip::loadTexture(double t, BitDepthEnum format, const OfxRectD *region)
2330 {
2331 if ( OFX::IsNaN(t) ) {
2332 throwSuiteStatusException(kOfxStatErrValue);
2333 }
2334 if (!gHostDescription.supportsOpenGLRender) {
2335 throwHostMissingSuiteException("loadTexture");
2336 }
2337 OfxPropertySetHandle hTex;
2338 OfxStatus stat = Private::gOpenGLRenderSuite->clipLoadTexture(_clipHandle, t, format == eBitDepthNone ? NULL : mapBitDepthEnumToStr(format), region, &hTex);
2339 if (stat != kOfxStatOK) {
2340 throwSuiteStatusException(stat);
2341 }
2342 return new Texture(hTex);
2343 }
2344 #endif
2345
2346 #ifdef OFX_EXTENSIONS_NUKE
2347 ////////////////////////////////////////////////////////////////////////////////
2348 // camera instance
2349
2350 /** @brief hidden constructor */
Camera(ImageEffect * effect,const std::string & name,NukeOfxCameraHandle handle,OfxPropertySetHandle props)2351 Camera::Camera(ImageEffect *effect, const std::string &name, NukeOfxCameraHandle handle, OfxPropertySetHandle props)
2352 : _cameraName(name)
2353 , _cameraProps(props)
2354 , _cameraHandle(handle)
2355 , _effect(effect)
2356 {
2357 OFX::Validation::validateCameraInstanceProperties(_cameraProps);
2358 }
2359
2360 #ifdef OFX_EXTENSIONS_NATRON
2361 /** @brief set the label property */
2362 void
setLabel(const std::string & label)2363 Camera::setLabel(const std::string &label)
2364 {
2365 _cameraProps.propSetString(kOfxPropLabel, label, false);
2366 }
2367
2368 /** @brief set the label properties */
2369 void
setLabels(const std::string & label,const std::string & shortLabel,const std::string & longLabel)2370 Camera::setLabels(const std::string &label, const std::string &shortLabel, const std::string &longLabel)
2371 {
2372 setLabel(label);
2373 _cameraProps.propSetString(kOfxPropShortLabel, shortLabel, false);
2374 _cameraProps.propSetString(kOfxPropLongLabel, longLabel, false);
2375 }
2376
2377 /** @brief set the secretness of the param, defaults to false */
setIsSecret(bool v)2378 void Camera::setIsSecret(bool v)
2379 {
2380 _cameraProps.propSetInt(kOfxParamPropSecret, v, false);
2381 }
2382
2383 /** @brief set the camera hint */
2384 void
setHint(const std::string & v)2385 Camera::setHint(const std::string &v)
2386 {
2387 _cameraProps.propSetString(kOfxParamPropHint, v, false);
2388 }
2389
2390 /** @brief set the camera label and hint */
2391 void
setLabelAndHint(const std::string & label,const std::string & hint)2392 Camera::setLabelAndHint(const std::string &label, const std::string &hint)
2393 {
2394 setLabel(label);
2395 setHint(hint);
2396 }
2397 #endif
2398
2399 /** @brief fetch the label */
getLabel(std::string & label) const2400 void Camera::getLabel(std::string &label) const
2401 {
2402 label = _cameraProps.propGetString(kOfxPropLabel);
2403 }
2404
2405 /** @brief fetch the labels */
getLabels(std::string & label,std::string & shortLabel,std::string & longLabel) const2406 void Camera::getLabels(std::string &label, std::string &shortLabel, std::string &longLabel) const
2407 {
2408 getLabel(label);
2409 shortLabel = _cameraProps.propGetString(kOfxPropShortLabel, false);
2410 longLabel = _cameraProps.propGetString(kOfxPropLongLabel, false);
2411 }
2412
2413
2414 /** @brief is the camera connected */
isConnected(void) const2415 bool Camera::isConnected(void) const
2416 {
2417 return _cameraProps.propGetInt(kOfxImageClipPropConnected) != 0;
2418 }
2419
2420 /** @brief Get an arbitrary camera parameter for a given time and view */
getParameter(const char * paramName,double time,int view,double * baseReturnAddress,int returnSize) const2421 void Camera::getParameter(const char* paramName, double time, int view, double* baseReturnAddress, int returnSize) const
2422 {
2423 OfxStatus stat = OFX::Private::gCameraSuite->cameraGetParameter(_cameraHandle, paramName, time, view, baseReturnAddress, returnSize);
2424 throwSuiteStatusException(stat);
2425 }
2426
2427 #endif // OFX_EXTENSIONS_NUKE
2428
2429
2430 ////////////////////////////////////////////////////////////////////////////////
2431 /// image effect
2432
2433 /** @brief ctor */
ImageEffect(OfxImageEffectHandle handle)2434 ImageEffect::ImageEffect(OfxImageEffectHandle handle)
2435 : _effectHandle(handle)
2436 , _effectProps(NULL)
2437 , _context(eContextNone)
2438 , _progressStartSuccess(false)
2439 {
2440 // get the property handle
2441 _effectProps = OFX::Private::fetchEffectProps(handle);
2442
2443 // Set this as the instance data pointer on the effect handle
2444 _effectProps.propSetPointer(kOfxPropInstanceData, this);
2445
2446 // validate the plugin instance
2447 OFX::Validation::validatePluginInstanceProperties(_effectProps);
2448
2449 // fetch the context
2450 std::string ctxt = _effectProps.propGetString(kOfxImageEffectPropContext);
2451 _context = mapToContextEnum(ctxt);
2452
2453 // the param set daddy-oh
2454 OfxParamSetHandle paramSet;
2455 OfxStatus stat = OFX::Private::gEffectSuite->getParamSet(handle, ¶mSet);
2456 throwSuiteStatusException(stat);
2457 setParamSetHandle(paramSet);
2458
2459 }
2460
2461 /** @brief dtor */
~ImageEffect()2462 ImageEffect::~ImageEffect()
2463 {
2464 // clobber the instance data property on the effect handle
2465 _effectProps.propSetPointer(kOfxPropInstanceData, 0, false);
2466
2467 // delete any clip instances we may have constructed
2468 std::map<std::string, Clip *>::iterator iter;
2469 for(iter = _fetchedClips.begin(); iter != _fetchedClips.end(); ++iter) {
2470 if(iter->second) {
2471 delete iter->second;
2472 iter->second = NULL;
2473 }
2474 }
2475 }
2476
2477 /** @brief the context this effect was instantiate in */
getContext(void) const2478 ContextEnum ImageEffect::getContext(void) const
2479 {
2480 return _context;
2481 }
2482
2483 #ifdef OFX_EXTENSIONS_VEGAS
2484 /** @brief the Vegas context this effect exists in */
getVegasContext(void)2485 VegasContextEnum ImageEffect::getVegasContext(void)
2486 {
2487 // fetch the context
2488 std::string ctxt = _effectProps.propGetString(kOfxImageEffectPropVegasContext, false);
2489 return mapToVegasContextEnum(ctxt);
2490 }
2491 #endif
2492
2493 /** @brief size of the project */
getProjectSize(void) const2494 OfxPointD ImageEffect::getProjectSize(void) const
2495 {
2496 OfxPointD v = {0., 0.};
2497 _effectProps.propGetDoubleN(kOfxImageEffectPropProjectSize, &v.x, 2);
2498 return v;
2499 }
2500
2501 /** @brief origin of the project */
getProjectOffset(void) const2502 OfxPointD ImageEffect::getProjectOffset(void) const
2503 {
2504 OfxPointD v = {0., 0.};
2505 _effectProps.propGetDoubleN(kOfxImageEffectPropProjectOffset, &v.x, 2);
2506 return v;
2507 }
2508
2509 /** @brief extent of the project */
getProjectExtent(void) const2510 OfxPointD ImageEffect::getProjectExtent(void) const
2511 {
2512 OfxPointD v = {0., 0.};
2513 _effectProps.propGetDoubleN(kOfxImageEffectPropProjectExtent, &v.x, 2);
2514 return v;
2515 }
2516
2517 /** @brief pixel aspect ratio of the project */
getProjectPixelAspectRatio(void) const2518 double ImageEffect::getProjectPixelAspectRatio(void) const
2519 {
2520 return _effectProps.propGetDouble(kOfxImageEffectPropProjectPixelAspectRatio, 0);
2521 }
2522
2523 /** @brief how long does the effect last */
getEffectDuration(void) const2524 double ImageEffect::getEffectDuration(void) const
2525 {
2526 return _effectProps.propGetDouble(kOfxImageEffectInstancePropEffectDuration, 0);
2527 }
2528
2529 /** @brief the frame rate of the project */
getFrameRate(void) const2530 double ImageEffect::getFrameRate(void) const
2531 {
2532 return _effectProps.propGetDouble(kOfxImageEffectPropFrameRate, 0);
2533 }
2534
2535 /** @brief is the instance currently being interacted with */
isInteractive(void) const2536 bool ImageEffect::isInteractive(void) const
2537 {
2538 return _effectProps.propGetInt(kOfxPropIsInteractive) != 0;
2539 }
2540
2541 /** @brief set the instance to be sequentially renderred, this should have been part of clip preferences! */
setSequentialRender(bool v)2542 void ImageEffect::setSequentialRender(bool v)
2543 {
2544 _effectProps.propSetInt(kOfxImageEffectInstancePropSequentialRender, int(v));
2545 }
2546
2547 /** @brief Have we informed the host we want to be seqentially renderred ? */
getSequentialRender(void) const2548 bool ImageEffect::getSequentialRender(void) const
2549 {
2550 return _effectProps.propGetInt(kOfxImageEffectInstancePropSequentialRender) != 0;
2551 }
2552
2553 /** @brief Does the plugin support image tiling ? Can only be called from changedParam or changedClip. */
setSupportsTiles(bool v)2554 void ImageEffect::setSupportsTiles(bool v)
2555 {
2556 _effectProps.propSetInt(kOfxImageEffectPropSupportsTiles, int(v), false); // read/write from OFX 1.4
2557 }
2558
2559 /** @brief Have we informed the host we support image tiling ? */
getSupportsTiles(void) const2560 bool ImageEffect::getSupportsTiles(void) const
2561 {
2562 return _effectProps.propGetInt(kOfxImageEffectPropSupportsTiles) != 0;
2563 }
2564
2565 #ifdef OFX_EXTENSIONS_NATRON
2566 void
setCanDistort(bool v)2567 ImageEffect::setCanDistort(bool v)
2568 {
2569 _effectProps.propSetInt(kOfxImageEffectPropCanDistort, int(v), false);
2570 }
2571
2572 bool
getCanDistort() const2573 ImageEffect::getCanDistort() const
2574 {
2575 return _effectProps.propGetInt(kOfxImageEffectPropCanDistort, false) != 0;
2576 }
2577
getExtraneousPlanesCreated(std::vector<std::string> * planes) const2578 void ImageEffect::getExtraneousPlanesCreated(std::vector<std::string>* planes) const
2579 {
2580 _effectProps.propGetStringN(kNatronOfxExtraCreatedPlanes, planes, false);
2581 }
2582 #endif
2583
2584 #ifdef OFX_EXTENSIONS_NUKE
2585 void
setCanTransform(bool v)2586 ImageEffect::setCanTransform(bool v)
2587 {
2588 _effectProps.propSetInt(kFnOfxImageEffectCanTransform, int(v), false);
2589 }
2590
2591 bool
getCanTransform() const2592 ImageEffect::getCanTransform() const
2593 {
2594 return _effectProps.propGetInt(kFnOfxImageEffectCanTransform, false) != 0;
2595 }
2596 #endif
2597
2598 #ifdef OFX_SUPPORTS_OPENGLRENDER
2599 /** @brief Does the plugin support OpenGL accelerated rendering (but is also capable of CPU rendering) ? Can only be called from changedParam or changedClip (OFX 1.4). */
setSupportsOpenGLRender(bool v)2600 void ImageEffect::setSupportsOpenGLRender(bool v) {
2601 if (gHostDescription.supportsOpenGLRender) {
2602 _effectProps.propSetString(kOfxImageEffectPropOpenGLRenderSupported, (v ? "true" : "false"), false); // read/write from OFX 1.4
2603 }
2604 }
2605 #endif
2606
2607
2608 /** @brief notify host that the internal data structures need syncing back to parameters for persistence and so on. This is reset by the host after calling SyncPrivateData. */
setParamSetNeedsSyncing()2609 void ImageEffect::setParamSetNeedsSyncing()
2610 {
2611 _effectProps.propSetInt(kOfxPropParamSetNeedsSyncing, 1, false); // introduced in OFX 1.2
2612 }
2613
sendMessage(OFX::Message::MessageTypeEnum type,const std::string & id,const std::string & msg,bool throwIfMissing)2614 OFX::Message::MessageReplyEnum ImageEffect::sendMessage(OFX::Message::MessageTypeEnum type, const std::string& id, const std::string& msg, bool throwIfMissing)
2615 {
2616 if (!OFX::Private::gMessageSuite || !OFX::Private::gMessageSuite->message) {
2617 if (throwIfMissing) {
2618 OFX::Log::error(true, "OfxMessageSuiteV1::message() not available, could not send message \"%s\"/\"%s\"", id.c_str(), msg.c_str());
2619 throwHostMissingSuiteException("message");
2620 } else {
2621 OFX::Log::warning(true, "OfxMessageSuiteV1::message() not available, could not send message \"%s\"/\"%s\"", id.c_str(), msg.c_str());
2622 }
2623 return OFX::Message::eMessageReplyFailed;
2624 }
2625 OfxStatus stat = OFX::Private::gMessageSuite->message(_effectHandle, mapMessageTypeEnumToStr(type), id.c_str(), msg.c_str());
2626 return mapToMessageReplyEnum(stat);
2627 }
2628
setPersistentMessage(OFX::Message::MessageTypeEnum type,const std::string & id,const std::string & msg,bool throwIfMissing)2629 OFX::Message::MessageReplyEnum ImageEffect::setPersistentMessage(OFX::Message::MessageTypeEnum type, const std::string& id, const std::string& msg, bool throwIfMissing)
2630 {
2631 if (!OFX::Private::gMessageSuiteV2 || !OFX::Private::gMessageSuiteV2->setPersistentMessage) {
2632 if (throwIfMissing) {
2633 OFX::Log::error(true, "OfxMessageSuiteV2::setPersistentMessage() not available, could not set message \"%s\"/\"%s\"", id.c_str(), msg.c_str());
2634 throwHostMissingSuiteException("setPersistentMessage");
2635 } else {
2636 OFX::Log::warning(true, "OfxMessageSuiteV2::setPersistentMessage() not available, could not set message \"%s\"/\"%s\"", id.c_str(), msg.c_str());
2637 }
2638 return OFX::Message::eMessageReplyFailed;
2639 }
2640 OfxStatus stat = OFX::Private::gMessageSuiteV2->setPersistentMessage(_effectHandle, mapMessageTypeEnumToStr(type), id.c_str(), msg.c_str());
2641 return mapToMessageReplyEnum(stat);
2642 }
2643
clearPersistentMessage(bool throwIfMissing)2644 OFX::Message::MessageReplyEnum ImageEffect::clearPersistentMessage(bool throwIfMissing)
2645 {
2646 if (!OFX::Private::gMessageSuiteV2 || !OFX::Private::gMessageSuiteV2->clearPersistentMessage) {
2647 if (throwIfMissing) {
2648 OFX::Log::error(true, "OfxMessageSuiteV2::clearPersistentMessage() not available");
2649 throwHostMissingSuiteException("clearPersistentMessage");
2650 } else {
2651 OFX::Log::warning(true, "OfxMessageSuiteV2::clearPersistentMessage() not available");
2652 }
2653 return OFX::Message::eMessageReplyFailed;
2654 }
2655 OfxStatus stat = OFX::Private::gMessageSuiteV2->clearPersistentMessage(_effectHandle);
2656 return mapToMessageReplyEnum(stat);
2657 }
2658
2659 #ifdef OFX_SUPPORTS_DIALOG
requestDialog(OfxPropertySetHandle inArgs,void * instanceData)2660 void ImageEffect::requestDialog(OfxPropertySetHandle inArgs, void *instanceData)
2661 {
2662 if(!(OFX::Private::gDialogSuiteV1 && OFX::Private::gDialogSuiteV1->requestDialog) &&
2663 !(OFX::Private::gDialogSuiteV2 && OFX::Private::gDialogSuiteV2->requestDialog)){ throwHostMissingSuiteException("requestDialog"); }
2664 OfxStatus stat;
2665 if (OFX::Private::gDialogSuiteV2) {
2666 stat = OFX::Private::gDialogSuiteV2->requestDialog(_effectHandle, inArgs, instanceData);
2667 } else {
2668 stat = OFX::Private::gDialogSuiteV1->requestDialog(instanceData);
2669 }
2670 throwSuiteStatusException(stat);
2671 }
2672
notifyRedrawPending(OfxPropertySetHandle inArgs)2673 void ImageEffect::notifyRedrawPending(OfxPropertySetHandle inArgs)
2674 {
2675 if(!(OFX::Private::gDialogSuiteV1 && OFX::Private::gDialogSuiteV1->notifyRedrawPending) &&
2676 !(OFX::Private::gDialogSuiteV2 && OFX::Private::gDialogSuiteV2->notifyRedrawPending))
2677 { throwHostMissingSuiteException("notifyRedrawPending"); }
2678 OfxStatus stat;
2679 if (OFX::Private::gDialogSuiteV2) {
2680 stat = OFX::Private::gDialogSuiteV2->notifyRedrawPending(_effectHandle, inArgs);
2681 } else {
2682 stat = OFX::Private::gDialogSuiteV1->notifyRedrawPending();
2683 }
2684 throwSuiteStatusException(stat);
2685 }
2686 #endif
2687
2688 /** @brief Fetch the named clip from this instance */
fetchClip(const std::string & name)2689 Clip *ImageEffect::fetchClip(const std::string &name)
2690 {
2691 // do we have the clip already
2692 std::map<std::string, Clip *>::const_iterator search;
2693 search = _fetchedClips.find(name);
2694 if(search != _fetchedClips.end())
2695 return search->second;
2696
2697 // fetch the property set handle of the effect
2698 OfxImageClipHandle clipHandle = 0;
2699 OfxPropertySetHandle propHandle = 0;
2700 OfxStatus stat = OFX::Private::gEffectSuite->clipGetHandle(_effectHandle, name.c_str(), &clipHandle, &propHandle);
2701 throwSuiteStatusException(stat);
2702
2703 // and make one
2704 Clip *newClip = new Clip(this, name, clipHandle, propHandle);
2705
2706 // add it in
2707 std::map<std::string, Clip *>::iterator it = _fetchedClips.find(name);
2708 if (it != _fetchedClips.end()) {
2709 delete it->second;
2710 it->second = newClip;
2711 } else {
2712 _fetchedClips[name] = newClip;
2713 }
2714
2715 // return it
2716 return newClip;
2717 }
2718
2719 #ifdef OFX_EXTENSIONS_NUKE
2720 /** @brief Fetch the named camera from this instance */
fetchCamera(const std::string & name)2721 Camera* ImageEffect::fetchCamera(const std::string& name)
2722 {
2723 if (!OFX::Private::gCameraSuite) {
2724 throwHostMissingSuiteException(kNukeOfxCameraSuite);
2725 }
2726 // do we have the camera already
2727 std::map<std::string, Camera *>::const_iterator search;
2728 search = _fetchedCameras.find(name);
2729 if(search != _fetchedCameras.end())
2730 return search->second;
2731
2732 // fetch the property set handle of the effect
2733 NukeOfxCameraHandle cameraHandle = 0;
2734 OfxPropertySetHandle propHandle = 0;
2735 OfxStatus stat = OFX::Private::gCameraSuite->cameraGetHandle(_effectHandle, name.c_str(), &cameraHandle, &propHandle);
2736 throwSuiteStatusException(stat);
2737
2738 // and make one
2739 Camera *newCamera = new Camera(this, name, cameraHandle, propHandle);
2740
2741 // add it in
2742 std::map<std::string, Camera *>::iterator it = _fetchedCameras.find(name);
2743 if (it != _fetchedCameras.end()) {
2744 delete it->second;
2745 it->second = newCamera;
2746 } else {
2747 _fetchedCameras[name] = newCamera;
2748 }
2749
2750 // return it
2751 return newCamera;
2752 }
2753 #endif
2754
2755 /** @brief does the host want us to abort rendering? */
abort(void) const2756 bool ImageEffect::abort(void) const
2757 {
2758 return OFX::Private::gEffectSuite->abort(_effectHandle) != 0;
2759 }
2760
2761 /** @brief adds a new interact to the set of interacts open on this effect */
addOverlayInteract(OverlayInteract * interact)2762 void ImageEffect::addOverlayInteract(OverlayInteract *interact)
2763 {
2764 // do we have it already ?
2765 std::list<OverlayInteract *>::iterator i;
2766 i = std::find(_overlayInteracts.begin(), _overlayInteracts.end(), interact);
2767
2768 // we don't, put it in there
2769 if(i == _overlayInteracts.end()) {
2770 // we have a new one to add in here
2771 _overlayInteracts.push_back(interact);
2772 }
2773 }
2774
2775 /** @brief removes an interact to the set of interacts open on this effect */
removeOverlayInteract(OverlayInteract * interact)2776 void ImageEffect::removeOverlayInteract(OverlayInteract *interact)
2777 {
2778 // find it
2779 std::list<OverlayInteract *>::iterator i;
2780 i = std::find(_overlayInteracts.begin(), _overlayInteracts.end(), interact);
2781
2782 // and remove it
2783 if(i != _overlayInteracts.end()) {
2784 _overlayInteracts.erase(i);
2785 }
2786 }
2787
2788 #ifdef OFX_SUPPORTS_OPENGLRENDER
flushOpenGLResources(void)2789 bool ImageEffect::flushOpenGLResources(void)
2790 {
2791 if (!gHostDescription.supportsOpenGLRender) {
2792 return false;
2793 }
2794 return Private::gOpenGLRenderSuite->flushResources() == kOfxStatOK;
2795 }
2796 #endif
2797
2798 ////////////////////////////////////////////////////////////////////////////////
2799 // below are the default members for the base image effect
2800
2801
2802 /** @brief client is identity function, returns the clip and time for the identity function
2803 */
isIdentity(const IsIdentityArguments &,Clip * &,double &,int &,std::string &)2804 bool ImageEffect::isIdentity(const IsIdentityArguments &/*args*/, Clip * &/*identityClip*/, double &/*identityTime*/
2805 #ifdef OFX_EXTENSIONS_NUKE
2806 , int& /*view*/
2807 , std::string& /*plane*/
2808 #endif
2809 )
2810 {
2811 return false; // by default, we are not an identity operation
2812 }
2813
2814 /** @brief The get RoD action */
getRegionOfDefinition(const RegionOfDefinitionArguments &,OfxRectD &)2815 bool ImageEffect::getRegionOfDefinition(const RegionOfDefinitionArguments &/*args*/, OfxRectD &/*rod*/)
2816 {
2817 return false; // by default, we are not setting the RoD
2818 }
2819
2820 /** @brief the get RoI action */
getRegionsOfInterest(const RegionsOfInterestArguments &,RegionOfInterestSetter &)2821 void ImageEffect::getRegionsOfInterest(const RegionsOfInterestArguments &/*args*/, RegionOfInterestSetter &/*rois*/)
2822 {
2823 // fa niente
2824 }
2825
2826 /** @brief the get frames needed action */
getFramesNeeded(const FramesNeededArguments &,FramesNeededSetter &)2827 void ImageEffect::getFramesNeeded(const FramesNeededArguments &/*args*/, FramesNeededSetter &/*frames*/)
2828 {
2829 // fa niente
2830 }
2831
2832 /** @brief client begin sequence render function */
beginSequenceRender(const BeginSequenceRenderArguments &)2833 void ImageEffect::beginSequenceRender(const BeginSequenceRenderArguments &/*args*/)
2834 {
2835 // fa niente
2836 }
2837
2838 /** @brief client end sequence render function, this is one of the few that must be set */
endSequenceRender(const EndSequenceRenderArguments &)2839 void ImageEffect::endSequenceRender(const EndSequenceRenderArguments &/*args*/)
2840 {
2841 // fa niente
2842 }
2843
2844 /** @brief The purge caches action, a request for an instance to free up as much memory as possible in low memory situations */
purgeCaches(void)2845 void ImageEffect::purgeCaches(void)
2846 {
2847 // fa niente
2848 }
2849
2850 /** @brief The sync private data action, called when the effect needs to sync any private data to persistent parameters */
syncPrivateData(void)2851 void ImageEffect::syncPrivateData(void)
2852 {
2853 // fa niente
2854 }
2855
2856 /** @brief get the clip preferences */
getClipPreferences(ClipPreferencesSetter &)2857 void ImageEffect::getClipPreferences(ClipPreferencesSetter &/*clipPreferences*/)
2858 {
2859 // fa niente
2860 }
2861
isChromaticComponent(const std::string & str)2862 static bool isChromaticComponent(const std::string &str)
2863 {
2864 if(str == kOfxImageComponentRGBA)
2865 return true;
2866 if(str == kOfxImageComponentRGB)
2867 return true;
2868 if(str == kOfxImageComponentAlpha)
2869 return true;
2870 #ifdef OFX_EXTENSIONS_NATRON
2871 if(str == kNatronOfxImageComponentXY)
2872 return true;
2873 #endif
2874 return false;
2875 }
2876
findMostChromaticComponents(const std::string & a,const std::string & b)2877 static const std::string &findMostChromaticComponents(const std::string &a, const std::string &b)
2878 {
2879 if(a == kOfxImageComponentNone)
2880 return b;
2881 if(a == kOfxImageComponentRGBA)
2882 return a;
2883 if(b == kOfxImageComponentRGBA)
2884 return b;
2885 if(a == kOfxImageComponentRGB)
2886 return a;
2887 if(b == kOfxImageComponentRGB)
2888 return b;
2889 return a;
2890 }
2891
getSupportedComponents(const PropertySet & props,std::set<std::string> * supportedComponents)2892 static void getSupportedComponents(const PropertySet& props, std::set<std::string>* supportedComponents)
2893 {
2894 int nDims = props.propGetDimension(kOfxImageEffectPropSupportedComponents);
2895 for (int i = 0; i < nDims; ++i) {
2896 supportedComponents->insert(props.propGetString(kOfxImageEffectPropSupportedComponents, i));
2897 }
2898 }
2899
isSupportedComponent(const std::set<std::string> & supportedComponents,const std::string & p)2900 static bool isSupportedComponent(const std::set<std::string>& supportedComponents, const std::string& p) {
2901 return supportedComponents.find(p) != supportedComponents.end();
2902 }
2903
getSupportedPixelDepths(const PropertySet & props,std::set<std::string> * supportedPixelDepths)2904 static void getSupportedPixelDepths(const PropertySet& props, std::set<std::string>* supportedPixelDepths)
2905 {
2906 int nDims = props.propGetDimension(kOfxImageEffectPropSupportedPixelDepths);
2907 for (int i = 0; i < nDims; ++i) {
2908 supportedPixelDepths->insert(props.propGetString(kOfxImageEffectPropSupportedPixelDepths, i));
2909 }
2910 }
2911
isSupportedPixelDepth(const std::set<std::string> & supportedPixelDepths,const std::string & p)2912 static bool isSupportedPixelDepth(const std::set<std::string>& supportedPixelDepths, const std::string& p) {
2913 return supportedPixelDepths.find(p) != supportedPixelDepths.end();
2914 }
2915
findBestSupportedComponent(const std::set<std::string> & supportedComponents,const std::string & s)2916 static const std::string& findBestSupportedComponent(const std::set<std::string>& supportedComponents, const std::string &s)
2917 {
2918 static const std::string none(kOfxImageComponentNone);
2919 static const std::string rgba(kOfxImageComponentRGBA);
2920 static const std::string rgb(kOfxImageComponentRGB);
2921 static const std::string alpha(kOfxImageComponentAlpha);
2922 #ifdef OFX_EXTENSIONS_NATRON
2923 static const std::string xy(kNatronOfxImageComponentXY);
2924 #endif
2925 /// is it there
2926 if(isSupportedComponent(supportedComponents, s))
2927 return s;
2928
2929 #ifdef OFX_EXTENSIONS_NATRON
2930 if (s == xy) {
2931 if (isSupportedComponent(supportedComponents, rgb)) {
2932 return rgb;
2933 } else if (isSupportedComponent(supportedComponents, rgba)) {
2934 return rgba;
2935 } else if (isSupportedComponent(supportedComponents, alpha)) {
2936 return alpha;
2937 }
2938 }
2939 #endif
2940
2941 /// were we fed some custom non chromatic component by getUnmappedComponents? Return it.
2942 /// we should never be here mind, so a bit weird
2943 if(!isChromaticComponent(s))
2944 return s;
2945
2946 /// Means we have RGBA or Alpha being passed in and the clip
2947 /// only supports the other one, so return that
2948 if(s == rgba) {
2949 if(isSupportedComponent(supportedComponents, rgb))
2950 return rgb;
2951 if(isSupportedComponent(supportedComponents, alpha))
2952 return alpha;
2953 } else if(s == alpha) {
2954 if(isSupportedComponent(supportedComponents, rgba))
2955 return rgba;
2956 if(isSupportedComponent(supportedComponents, rgb))
2957 return rgb;
2958 }
2959
2960 /// wierd, must be some custom bit , if only one, choose that, otherwise no idea
2961 /// how to map, you need to derive to do so.
2962 return none;
2963 }
2964
FindDeepestBitDepth(const std::string & s1,const std::string & s2)2965 static std::string FindDeepestBitDepth(const std::string &s1, const std::string &s2)
2966 {
2967 if(s1 == kOfxBitDepthNone) {
2968 return s2;
2969 }
2970 else if(s1 == kOfxBitDepthByte) {
2971 if(s2 == kOfxBitDepthShort || s2 == kOfxBitDepthFloat)
2972 return s2;
2973 return s1;
2974 }
2975 else if(s1 == kOfxBitDepthShort) {
2976 if(s2 == kOfxBitDepthFloat)
2977 return s2;
2978 return s1;
2979 }
2980 else if(s1 == kOfxBitDepthHalf) {
2981 if(s2 == kOfxBitDepthFloat)
2982 return s2;
2983 return s1;
2984 }
2985 else if(s1 == kOfxBitDepthFloat) {
2986 return s1;
2987 }
2988 else {
2989 return s2; // oooh this might be bad dad.
2990 }
2991 }
2992
findBestSupportedPixelDepth(const std::set<std::string> & supportedPixelDepths,const std::string & depth)2993 static const std::string& findBestSupportedPixelDepth(const std::set<std::string>& supportedPixelDepths, const std::string &depth)
2994 {
2995 static const std::string none(kOfxBitDepthNone);
2996 static const std::string bytes(kOfxBitDepthByte);
2997 static const std::string shorts(kOfxBitDepthShort);
2998 static const std::string halfs(kOfxBitDepthHalf);
2999 static const std::string floats(kOfxBitDepthFloat);
3000
3001 if(depth == none)
3002 return none;
3003
3004 if(isSupportedPixelDepth(supportedPixelDepths, depth))
3005 return depth;
3006
3007 if(depth == floats) {
3008 if(isSupportedPixelDepth(supportedPixelDepths, halfs))
3009 return halfs;
3010 if(isSupportedPixelDepth(supportedPixelDepths, shorts))
3011 return shorts;
3012 if(isSupportedPixelDepth(supportedPixelDepths, bytes))
3013 return bytes;
3014 }
3015
3016 if(depth == halfs) {
3017 if(isSupportedPixelDepth(supportedPixelDepths, floats))
3018 return floats;
3019 if(isSupportedPixelDepth(supportedPixelDepths, shorts))
3020 return shorts;
3021 if(isSupportedPixelDepth(supportedPixelDepths, bytes))
3022 return bytes;
3023 }
3024
3025 if(depth == shorts) {
3026 if(isSupportedPixelDepth(supportedPixelDepths, floats))
3027 return floats;
3028 if(isSupportedPixelDepth(supportedPixelDepths, halfs))
3029 return halfs;
3030 if(isSupportedPixelDepth(supportedPixelDepths, bytes))
3031 return bytes;
3032 }
3033
3034 if(depth == bytes) {
3035 if(isSupportedPixelDepth(supportedPixelDepths, shorts))
3036 return shorts;
3037 if(isSupportedPixelDepth(supportedPixelDepths, halfs))
3038 return halfs;
3039 if(isSupportedPixelDepth(supportedPixelDepths, floats))
3040 return floats;
3041 }
3042
3043 return none;
3044 }
3045
getDefaultOutputClipComponents()3046 PixelComponentEnum ImageEffect::getDefaultOutputClipComponents()
3047 {
3048 bool hasSetComps = false;
3049 std::string mostComponents = kOfxImageComponentNone;
3050
3051 Clip* outputClip = 0;
3052 for (std::map<std::string, Clip *>::const_iterator it = _fetchedClips.begin(); it != _fetchedClips.end(); ++it) {
3053 Clip *clip = it->second;
3054
3055 if(clip->getName() == kOfxImageEffectOutputClipName) {
3056 outputClip = clip;
3057 } else {
3058 bool connected = clip->isConnected();
3059
3060 if(connected) {
3061 std::string rawComp = it->second->getUnmappedPixelComponentsProperty();
3062 std::set<std::string> supportedComponents;
3063 getSupportedComponents(clip->getPropertySet(), &supportedComponents);
3064 rawComp = findBestSupportedComponent(supportedComponents, rawComp); // turn that into a comp the plugin expects on that clip
3065
3066 if(isChromaticComponent(rawComp)) {
3067 //Update deepest bitdepth and most components only if the infos are relevant, i.e: only if the clip is connected
3068 hasSetComps = true;
3069 bool mostIsAlpha = (mostComponents == kOfxImageComponentAlpha);
3070 bool rawIsAlpha = (rawComp == kOfxImageComponentAlpha);
3071 if (mostIsAlpha != rawIsAlpha && mostComponents != kOfxImageComponentNone) {
3072 // one is alpha, the other is anything else than just alpha: the union is RGBA
3073 mostComponents = kOfxImageComponentRGBA;
3074 }
3075 mostComponents = findMostChromaticComponents(mostComponents, rawComp);
3076 }
3077 }
3078 }
3079 }
3080 if (!outputClip) {
3081 return mapStrToPixelComponentEnum(mostComponents);
3082 }
3083 if (!hasSetComps) {
3084 mostComponents = kOfxImageComponentRGBA;
3085 }
3086
3087 // "Optional input clips can always have their component types remapped"
3088 // http://openfx.sourceforge.net/Documentation/1.3/ofxProgrammingReference.html#id482755
3089 std::set<std::string> supportedComponents;
3090 getSupportedComponents(outputClip->getPropertySet(), &supportedComponents);
3091 std::string comp = findBestSupportedComponent(supportedComponents, mostComponents);
3092 return mapStrToPixelComponentEnum(comp);
3093 } // getDefaultOutputClipComponents
3094
getDefaultBitdepth()3095 BitDepthEnum ImageEffect::getDefaultBitdepth()
3096 {
3097 bool hasSetDepth = false;
3098 std::string deepestBitDepth = kOfxBitDepthNone;
3099
3100 Clip* outputClip = 0;
3101 for (std::map<std::string, Clip *>::const_iterator it = _fetchedClips.begin(); it != _fetchedClips.end(); ++it) {
3102 Clip *clip = it->second;
3103 if(clip->getName() == kOfxImageEffectOutputClipName) {
3104 outputClip = clip;
3105 } else {
3106 bool connected = clip->isConnected();
3107 if(connected) {
3108 //Update deepest bitdepth and most components only if the infos are relevant, i.e: only if the clip is connected
3109 hasSetDepth = true;
3110 std::string rawDepth = clip->getPropertySet().propGetString(kOfxImageClipPropUnmappedPixelDepth, 0);
3111
3112 std::set<std::string> supportedPixelDepths;
3113 getSupportedPixelDepths(clip->getPropertySet(), &supportedPixelDepths);
3114 rawDepth = findBestSupportedPixelDepth(supportedPixelDepths, rawDepth);
3115 deepestBitDepth = FindDeepestBitDepth(deepestBitDepth, rawDepth);
3116 }
3117
3118 }
3119 }
3120 if (!outputClip) {
3121 return mapStrToBitDepthEnum(deepestBitDepth);
3122 }
3123 if (!hasSetDepth) {
3124 deepestBitDepth = kOfxBitDepthFloat;
3125 }
3126
3127 std::set<std::string> supportedPixelDepths;
3128 getSupportedComponents(outputClip->getPropertySet(), &supportedPixelDepths);
3129 deepestBitDepth = findBestSupportedPixelDepth(supportedPixelDepths, deepestBitDepth);
3130
3131 return mapStrToBitDepthEnum(deepestBitDepth);
3132 }
3133
3134 /** @brief the effect is about to be actively edited by a user, called when the first user interface is opened on an instance */
beginEdit(void)3135 void ImageEffect::beginEdit(void)
3136 {
3137 // fa niente
3138 }
3139
3140 /** @brief the effect is no longer being edited by a user, called when the last user interface is closed on an instance */
endEdit(void)3141 void ImageEffect::endEdit(void)
3142 {
3143 // fa niente
3144 }
3145
3146 /** @brief the effect is about to have some values changed */
beginChanged(InstanceChangeReason)3147 void ImageEffect::beginChanged(InstanceChangeReason /*reason*/)
3148 {
3149 }
3150
3151 /** @brief called when a param has just had its value changed */
changedParam(const InstanceChangedArgs &,const std::string &)3152 void ImageEffect::changedParam(const InstanceChangedArgs &/*args*/, const std::string &/*paramName*/)
3153 {
3154 }
3155
3156 /** @brief called when a clip has just been changed in some way (a rewire maybe) */
changedClip(const InstanceChangedArgs &,const std::string &)3157 void ImageEffect::changedClip(const InstanceChangedArgs &/*args*/, const std::string &/*clipName*/)
3158 {
3159 }
3160
3161 /** @brief the effect has just had some values changed */
endChanged(InstanceChangeReason)3162 void ImageEffect::endChanged(InstanceChangeReason /*reason*/)
3163 {
3164 }
3165
3166 #ifdef OFX_SUPPORTS_DIALOG
3167 /** @brief called in the host's UI thread after a plugin has requested a dialog @see requestDialog() */
dialog(void *)3168 void ImageEffect::dialog(void */*instanceData*/)
3169 {
3170 }
3171 #endif
3172
3173 /** @brief get the time domain */
getTimeDomain(OfxRangeD &)3174 bool ImageEffect::getTimeDomain(OfxRangeD &/*range*/)
3175 {
3176 // by default, do the default
3177 return false;
3178 }
3179
3180 #ifdef OFX_SUPPORTS_OPENGLRENDER
3181 /** @brief OpenGL context attached (returns context-specific data or NULL if the plugin does not support multiple contexts) */
contextAttached(bool)3182 void* ImageEffect::contextAttached(bool)
3183 {
3184 // fa niente
3185 return NULL;
3186 }
3187
3188 /** @brief OpenGL context detached */
contextDetached(void *)3189 void ImageEffect::contextDetached(void*)
3190 {
3191 // fa niente
3192 }
3193 #endif
3194
3195 #ifdef OFX_EXTENSIONS_VEGAS
3196 /** @brief Vegas requires conversion of keyframe data */
upliftVegasKeyframes(const SonyVegasUpliftArguments &)3197 void ImageEffect::upliftVegasKeyframes(const SonyVegasUpliftArguments &/*upliftInfo*/)
3198 {
3199 // fa niente
3200 }
3201
3202 /** @brief Vegas requests custom about dialog */
invokeAbout()3203 bool ImageEffect::invokeAbout()
3204 {
3205 // by default, do nothing
3206 return false;
3207 }
3208
3209 /** @brief Vegas requests custom help dialog */
invokeHelp()3210 bool ImageEffect::invokeHelp()
3211 {
3212 // by default, do nothing
3213 return false;
3214 }
3215 #endif
3216
3217 #ifdef OFX_EXTENSIONS_NATRON
3218 /** @brief get the distortion function */
getInverseDistortion(const DistortionArguments &,Clip * &,double[9],OfxInverseDistortionFunctionV1 *,void **,int *,OfxInverseDistortionDataFreeFunctionV1 *)3219 bool ImageEffect::getInverseDistortion(const DistortionArguments &/*args*/, Clip * &/*transformClip*/, double /*transformMatrix*/[9],
3220 OfxInverseDistortionFunctionV1* /*distortionFunction*/,
3221 void** /*distortionFunctionData*/,
3222 int* /*distortionFunctionDataSizeHintInBytes*/,
3223 OfxInverseDistortionDataFreeFunctionV1* /*freeDataFunction*/)
3224 {
3225 // by default, do the default
3226 return false;
3227 }
3228 #endif
3229
3230 #ifdef OFX_EXTENSIONS_NUKE
getClipComponents(const ClipComponentsArguments &,ClipComponentsSetter &)3231 OfxStatus ImageEffect::getClipComponents(const ClipComponentsArguments& /*args*/, ClipComponentsSetter& /*clipComponents*/)
3232 {
3233 return kOfxStatReplyDefault;
3234 // pass
3235 }
3236
getFrameViewsNeeded(const FrameViewsNeededArguments &,FrameViewsNeededSetter &)3237 void ImageEffect::getFrameViewsNeeded(const FrameViewsNeededArguments & /*args*/, FrameViewsNeededSetter & /*frameViews*/)
3238 {
3239 // pass
3240 }
3241
3242 /** @brief recover a transform matrix from an effect */
getTransform(const TransformArguments &,Clip * &,double[9])3243 bool ImageEffect::getTransform(const TransformArguments &/*args*/, Clip * &/*transformClip*/, double /*transformMatrix*/[9])
3244 {
3245 // by default, do the default
3246 return false;
3247 }
3248
3249
getViewName(int viewIndex) const3250 std::string ImageEffect::getViewName(int viewIndex) const
3251 {
3252 const char* viewName;
3253 OfxStatus stat = OFX::Private::gImageEffectPlaneSuiteV2->getViewName(_effectHandle, viewIndex, &viewName);
3254 if(stat == kOfxStatFailed || !viewName) {
3255 return std::string();
3256 }
3257 throwSuiteStatusException(stat);
3258 return std::string(viewName);
3259 }
3260
getViewCount() const3261 int ImageEffect::getViewCount() const
3262 {
3263 int viewCount;
3264 OfxStatus stat = OFX::Private::gImageEffectPlaneSuiteV2->getViewCount(_effectHandle, &viewCount);
3265 if(stat == kOfxStatFailed) {
3266 return 0;
3267 }
3268 throwSuiteStatusException(stat);
3269 return viewCount;
3270 }
3271
3272 #endif
3273
3274 /** @brief called when a custom param needs to be interpolated */
interpolateCustomParam(const InterpolateCustomArgs & args,const std::string &)3275 std::string ImageEffect::interpolateCustomParam(const InterpolateCustomArgs &args, const std::string &/*paramName*/)
3276 {
3277 return args.value1;
3278 }
3279
3280 /// Start doing progress.
progressStart(const std::string & message,const std::string & messageid)3281 void ImageEffect::progressStart(const std::string &message, const std::string &messageid)
3282 {
3283 if(OFX::Private::gProgressSuiteV2) {
3284 OfxStatus stat = OFX::Private::gProgressSuiteV2->progressStart((void *) _effectHandle, message.c_str(), messageid.c_str());
3285 _progressStartSuccess = ( stat == kOfxStatOK );
3286 #ifdef OFX_EXTENSIONS_VEGAS
3287 } else if(OFX::Private::gVegasProgressSuite) {
3288 OfxStatus stat = OFX::Private::gVegasProgressSuite->progressStart((void *) _effectHandle, message.c_str(), messageid.c_str());
3289 _progressStartSuccess = ( stat == kOfxStatOK );
3290 #endif
3291 } else if(OFX::Private::gProgressSuiteV1) {
3292 OfxStatus stat = OFX::Private::gProgressSuiteV1->progressStart((void *) _effectHandle, message.c_str());
3293 _progressStartSuccess = ( stat == kOfxStatOK );
3294 }
3295
3296 }
3297
3298 /// finish yer progress
progressEnd()3299 void ImageEffect::progressEnd()
3300 {
3301 if(_progressStartSuccess) {
3302 if(OFX::Private::gProgressSuiteV2) {
3303 OFX::Private::gProgressSuiteV2->progressEnd((void *) _effectHandle);
3304 } else if(OFX::Private::gProgressSuiteV1) {
3305 OFX::Private::gProgressSuiteV1->progressEnd((void *) _effectHandle);
3306 }
3307 }
3308 }
3309
3310 /// set the progress to some level of completion, returns
3311 /// false if you should abandon processing, true to continue
progressUpdate(double t)3312 bool ImageEffect::progressUpdate(double t)
3313 {
3314 if ( OFX::IsNaN(t) ) {
3315 throwSuiteStatusException(kOfxStatErrValue);
3316 }
3317 if(_progressStartSuccess) {
3318 if(OFX::Private::gProgressSuiteV2) {
3319 OfxStatus stat = OFX::Private::gProgressSuiteV2->progressUpdate((void *) _effectHandle, t);
3320 if(stat == kOfxStatReplyNo)
3321 return false;
3322 #ifdef OFX_EXTENSIONS_VEGAS
3323 } else if(OFX::Private::gVegasProgressSuite) {
3324 OfxStatus stat = OFX::Private::gVegasProgressSuite->progressUpdate((void *) _effectHandle, t);
3325 if(stat == kOfxStatReplyNo)
3326 return false;
3327 #endif
3328 } else if(OFX::Private::gProgressSuiteV1) {
3329 OfxStatus stat = OFX::Private::gProgressSuiteV1->progressUpdate((void *) _effectHandle, t);
3330 if(stat == kOfxStatReplyNo)
3331 return false;
3332 }
3333 }
3334 return true;
3335 }
3336
3337 /// get the current time on the timeline. This is not necessarily the same
3338 /// time as being passed to an action (eg render)
timeLineGetTime()3339 double ImageEffect::timeLineGetTime()
3340 {
3341 if(OFX::Private::gTimeLineSuite) {
3342 double time;
3343 if(OFX::Private::gTimeLineSuite->getTime((void *) _effectHandle, &time) == kOfxStatOK)
3344 return time;
3345 }
3346 return 0;
3347 }
3348
3349 /// set the timeline to a specific time
timeLineGotoTime(double t)3350 void ImageEffect::timeLineGotoTime(double t)
3351 {
3352 if ( OFX::IsNaN(t) ) {
3353 throwSuiteStatusException(kOfxStatErrValue);
3354 }
3355 if(OFX::Private::gTimeLineSuite) {
3356 OFX::Private::gTimeLineSuite->gotoTime((void *) _effectHandle, t);
3357 }
3358 }
3359
3360 /// get the first and last times available on the effect's timeline
timeLineGetBounds(double & t1,double & t2)3361 void ImageEffect:: timeLineGetBounds(double &t1, double &t2)
3362 {
3363 if(OFX::Private::gTimeLineSuite) {
3364 OFX::Private::gTimeLineSuite->getTimeBounds((void *) _effectHandle, &t1, &t2);
3365 return;
3366 }
3367 t1 = t2 = 0;
3368 }
3369
3370 #ifdef OFX_EXTENSIONS_VEGAS
3371 ////////////////////////////////////////////////////////////////////////////////
3372 // Class used to uplift previous vegas keyframe data of the effect. */
SonyVegasUpliftArguments(PropertySet args)3373 SonyVegasUpliftArguments::SonyVegasUpliftArguments(PropertySet args)
3374 : guidUplift()
3375 , keyframeCount(0)
3376 , commonData(NULL)
3377 , commonDataSize(0)
3378 {
3379 _argProps = args;
3380 }
3381
getKeyframeData(int keyframeIndex) const3382 void* SonyVegasUpliftArguments::getKeyframeData (int keyframeIndex) const
3383 {
3384 return _argProps.propGetPointer(kOfxPropVegasUpliftKeyframeData, keyframeIndex);
3385 }
3386
getKeyframeDataSize(int keyframeIndex) const3387 int SonyVegasUpliftArguments::getKeyframeDataSize (int keyframeIndex) const
3388 {
3389 return _argProps.propGetInt(kOfxPropVegasUpliftKeyframeDataLength, keyframeIndex);
3390 }
3391
getKeyframeTime(int keyframeIndex) const3392 double SonyVegasUpliftArguments::getKeyframeTime (int keyframeIndex) const
3393 {
3394 return _argProps.propGetDouble(kOfxPropVegasUpliftKeyframeTime, keyframeIndex);
3395 }
3396
getKeyframeInterpolation(int keyframeIndex) const3397 VegasInterpolationEnum SonyVegasUpliftArguments::getKeyframeInterpolation (int keyframeIndex) const
3398 {
3399 return mapToInterpolationEnum(_argProps.propGetString(kOfxPropVegasUpliftKeyframeInterpolation, keyframeIndex));
3400 }
3401 #endif
3402
3403 #ifdef OFX_EXTENSIONS_NUKE
extractValueForName(const StringStringMap & m,const std::string & name)3404 const std::string& ClipComponentsSetter::extractValueForName(const StringStringMap& m, const std::string& name)
3405 {
3406 StringStringMap::const_iterator it = m.find(name);
3407 if(it==m.end())
3408 throw(Exception::PropertyUnknownToHost(name.c_str()));
3409 return it->second;
3410 }
3411
setOutProperties()3412 bool ClipComponentsSetter::setOutProperties()
3413 {
3414 for (std::map<std::string,std::vector<std::string> >::iterator it = _clipPlanes.begin(); it!=_clipPlanes.end(); ++it) {
3415 const std::string& propName = extractValueForName(_clipPlanesPropNames, it->first);
3416 for (std::size_t i = 0; i < it->second.size(); ++i) {
3417 _outArgs.propSetString(propName.c_str(), it->second[i], (int)i, true);
3418 }
3419 }
3420 return _doneSomething;
3421 }
3422
addClipPlane(Clip & clip,const std::string & comps)3423 void ClipComponentsSetter::addClipPlane(Clip& clip, const std::string& comps)
3424 {
3425 _doneSomething = true;
3426 _clipPlanes[clip.name()].push_back(comps);
3427 }
3428
setPassThroughClip(const Clip * clip,double time,int view)3429 void ClipComponentsSetter::setPassThroughClip(const Clip* clip, double time, int view)
3430 {
3431 if ( OFX::IsNaN(time) ) {
3432 throwSuiteStatusException(kOfxStatErrValue);
3433 }
3434 _doneSomething = true;
3435 if (clip) {
3436 _outArgs.propSetString(kFnOfxImageEffectPropPassThroughClip, clip->name(), 0);
3437 } else {
3438 _outArgs.propSetString(kFnOfxImageEffectPropPassThroughClip, "", 0);
3439 }
3440 _outArgs.propSetDouble(kFnOfxImageEffectPropPassThroughTime, time, 0);
3441 _outArgs.propSetInt(kFnOfxImageEffectPropPassThroughView, view, 0);
3442 }
3443
3444
extractValueForName(const StringStringMap & m,const std::string & name)3445 const std::string& FrameViewsNeededSetter::extractValueForName(const StringStringMap& m, const std::string& name)
3446 {
3447 StringStringMap::const_iterator it = m.find(name);
3448 if(it==m.end())
3449 throw(Exception::PropertyUnknownToHost(name.c_str()));
3450 return it->second;
3451 }
3452
setOutProperties()3453 bool FrameViewsNeededSetter::setOutProperties()
3454 {
3455 for (std::map<std::string, std::map<int, std::vector<OfxRangeD> > >::iterator it = _frameViews.begin(); it!=_frameViews.end(); ++it) {
3456 int dimIndex = 0;
3457 const std::string& propName = extractValueForName(_clipFrameViewsPropnames, it->first);
3458 for (std::map<int, std::vector<OfxRangeD> >::iterator it2 = it->second.begin(); it2!=it->second.end(); ++it2) {
3459 for (std::vector<OfxRangeD>::iterator it3 = it2->second.begin(); it3 != it2->second.end(); ++it3, dimIndex += 3) {
3460 _outArgs.propSetDouble(propName.c_str(), it3->min, dimIndex);
3461 _outArgs.propSetDouble(propName.c_str(), it3->max, dimIndex + 1);
3462 _outArgs.propSetDouble(propName.c_str(), it2->first, dimIndex + 2);
3463 }
3464 }
3465 }
3466 return _doneSomething;
3467 }
3468
addFrameViewsNeeded(const Clip & clip,const OfxRangeD & range,int view)3469 void FrameViewsNeededSetter::addFrameViewsNeeded(const Clip& clip,const OfxRangeD &range, int view)
3470 {
3471 _doneSomething = true;
3472 std::map<int, std::vector<OfxRangeD> >& frameViews = _frameViews[clip.name()];
3473 std::vector<OfxRangeD>& ranges = frameViews[view];
3474 ranges.push_back(range);
3475 }
3476 #endif
3477
3478 ////////////////////////////////////////////////////////////////////////////////
3479 // Class used to set the clip preferences of the effect. */
3480
extractValueForName(const StringStringMap & m,const std::string & name)3481 const std::string& ClipPreferencesSetter::extractValueForName(const StringStringMap& m, const std::string& name)
3482 {
3483 StringStringMap::const_iterator it = m.find(name);
3484 if(it==m.end())
3485 throw(Exception::PropertyUnknownToHost(name.c_str()));
3486 return it->second;
3487 }
3488
3489 /** @brief, force the host to set a clip's mapped component type to be \em comps. */
setClipComponents(Clip & clip,PixelComponentEnum comps)3490 void ClipPreferencesSetter::setClipComponents(Clip &clip, PixelComponentEnum comps)
3491 {
3492 doneSomething_ = true;
3493 const std::string& propName = extractValueForName(clipComponentPropNames_, clip.name());
3494
3495 switch(comps)
3496 {
3497 case ePixelComponentNone :
3498 outArgs_.propSetString(propName.c_str(), kOfxImageComponentNone);
3499 break;
3500 case ePixelComponentRGBA :
3501 outArgs_.propSetString(propName.c_str(), kOfxImageComponentRGBA);
3502 break;
3503 case ePixelComponentRGB :
3504 outArgs_.propSetString(propName.c_str(), kOfxImageComponentRGB);
3505 break;
3506 case ePixelComponentAlpha :
3507 outArgs_.propSetString(propName.c_str(), kOfxImageComponentAlpha);
3508 break;
3509 #ifdef OFX_EXTENSIONS_NUKE
3510 case ePixelComponentMotionVectors :
3511 outArgs_.propSetString(propName.c_str(), kFnOfxImageComponentMotionVectors);
3512 break;
3513 case ePixelComponentStereoDisparity :
3514 outArgs_.propSetString(propName.c_str(), kFnOfxImageComponentStereoDisparity);
3515 break;
3516 #endif
3517 #ifdef OFX_EXTENSIONS_NATRON
3518 case ePixelComponentXY:
3519 outArgs_.propSetString(propName.c_str(), kNatronOfxImageComponentXY);
3520 break;
3521 #endif
3522 case ePixelComponentCustom :
3523 break;
3524 }
3525 }
3526
3527 /** @brief, force the host to set a clip's mapped bit depth be \em bitDepth */
setClipBitDepth(Clip & clip,BitDepthEnum bitDepth)3528 void ClipPreferencesSetter::setClipBitDepth(Clip &clip, BitDepthEnum bitDepth)
3529 {
3530 doneSomething_ = true;
3531 const std::string& propName = extractValueForName(clipDepthPropNames_, clip.name());
3532
3533 switch(bitDepth)
3534 {
3535 case eBitDepthNone :
3536 outArgs_.propSetString(propName.c_str(), kOfxBitDepthNone);
3537 break;
3538 case eBitDepthUByte :
3539 outArgs_.propSetString(propName.c_str(), kOfxBitDepthByte);
3540 break;
3541 case eBitDepthUShort :
3542 outArgs_.propSetString(propName.c_str(), kOfxBitDepthShort);
3543 break;
3544 case eBitDepthHalf :
3545 outArgs_.propSetString(propName.c_str(), kOfxBitDepthHalf);
3546 break;
3547 case eBitDepthFloat :
3548 outArgs_.propSetString(propName.c_str(), kOfxBitDepthFloat);
3549 break;
3550 #ifdef OFX_EXTENSIONS_VEGAS
3551 case eBitDepthUByteBGRA :
3552 outArgs_.propSetString(propName.c_str(), kOfxBitDepthByteBGR);
3553 break;
3554 case eBitDepthUShortBGRA :
3555 outArgs_.propSetString(propName.c_str(), kOfxBitDepthShortBGR);
3556 break;
3557 case eBitDepthFloatBGRA :
3558 outArgs_.propSetString(propName.c_str(), kOfxBitDepthFloatBGR);
3559 break;
3560 #endif
3561 case eBitDepthCustom :
3562 break;
3563 }
3564 }
3565
3566 /** @brief, force the host to set a clip's mapped Pixel Aspect Ratio to be \em PAR */
setPixelAspectRatio(Clip & clip,double PAR)3567 void ClipPreferencesSetter::setPixelAspectRatio(Clip &clip, double PAR)
3568 {
3569 doneSomething_ = true;
3570 const std::string& propName = extractValueForName(clipPARPropNames_, clip.name());
3571 outArgs_.propSetDouble(propName.c_str(), PAR);
3572 }
3573
3574 /** @brief Allows an effect to change the output frame rate */
setOutputFrameRate(double v)3575 void ClipPreferencesSetter::setOutputFrameRate(double v)
3576 {
3577 doneSomething_ = true;
3578 outArgs_.propSetDouble(kOfxImageEffectPropFrameRate, v);
3579 }
3580
3581 /** @brief Set the premultiplication state of the output clip. */
setOutputPremultiplication(PreMultiplicationEnum v)3582 void ClipPreferencesSetter::setOutputPremultiplication(PreMultiplicationEnum v)
3583 {
3584 doneSomething_ = true;
3585 switch(v)
3586 {
3587 case eImageOpaque :
3588 outArgs_.propSetString(kOfxImageEffectPropPreMultiplication, kOfxImageOpaque);
3589 break;
3590 case eImagePreMultiplied:
3591 outArgs_.propSetString(kOfxImageEffectPropPreMultiplication, kOfxImagePreMultiplied);
3592 break;
3593 case eImageUnPreMultiplied:
3594 outArgs_.propSetString(kOfxImageEffectPropPreMultiplication, kOfxImageUnPreMultiplied);
3595 break;
3596 }
3597 }
3598
3599 /** @brief Set whether the effect can be continuously sampled. */
setOutputHasContinuousSamples(bool v)3600 void ClipPreferencesSetter::setOutputHasContinuousSamples(bool v)
3601 {
3602 doneSomething_ = true;
3603 outArgs_.propSetInt(kOfxImageClipPropContinuousSamples, int(v));
3604 }
3605
3606 /** @brief Sets whether the effect will produce different images in all frames, even if the no params or input images are varying (eg: a noise generator). */
setOutputFrameVarying(bool v)3607 void ClipPreferencesSetter::setOutputFrameVarying(bool v)
3608 {
3609 doneSomething_ = true;
3610 outArgs_.propSetInt(kOfxImageEffectFrameVarying, int(v));
3611 }
3612
3613
setOutputFielding(FieldEnum v)3614 void ClipPreferencesSetter::setOutputFielding(FieldEnum v)
3615 {
3616 doneSomething_ = true;
3617 switch(v)
3618 {
3619 case eFieldNone : outArgs_.propSetString(kOfxImageClipPropFieldOrder, kOfxImageFieldNone, 0, false); break;
3620 case eFieldLower : outArgs_.propSetString(kOfxImageClipPropFieldOrder, kOfxImageFieldLower, 0, false); break;
3621 case eFieldUpper : outArgs_.propSetString(kOfxImageClipPropFieldOrder, kOfxImageFieldUpper, 0, false); break;
3622 case eFieldBoth : outArgs_.propSetString(kOfxImageClipPropFieldOrder, kOfxImageFieldBoth, 0, false); break;
3623 case eFieldSingle : outArgs_.propSetString(kOfxImageClipPropFieldOrder, kOfxImageFieldSingle, 0, false); break;
3624 case eFieldDoubled : outArgs_.propSetString(kOfxImageClipPropFieldOrder, kOfxImageFieldDoubled, 0, false); break;
3625 }
3626 }
3627
3628 #ifdef OFX_EXTENSIONS_NATRON
3629 /** @brief Sets the output format in pixel coordinates.
3630 Default to first non optional input clip format
3631 */
setOutputFormat(const OfxRectI & format)3632 void ClipPreferencesSetter::setOutputFormat(const OfxRectI& format)
3633 {
3634 doneSomething_ = true;
3635 std::vector<int> v(4);
3636 v[0] = format.x1;
3637 v[1] = format.y1;
3638 v[2] = format.x2;
3639 v[3] = format.y2;
3640 outArgs_.propSetIntN(kOfxImageClipPropFormat, v, false);
3641 }
3642 #endif
3643
3644 ////////////////////////////////////////////////////////////////////////////////
3645 /** @brief Class that skins image memory allocation */
3646
3647 /** @brief ctor */
ImageMemory(size_t nBytes,ImageEffect * associatedEffect)3648 ImageMemory::ImageMemory(size_t nBytes, ImageEffect *associatedEffect)
3649 : _handle(NULL)
3650 {
3651 OfxImageEffectHandle effectHandle = 0;
3652 if(associatedEffect != 0) {
3653 effectHandle = associatedEffect->_effectHandle;
3654 }
3655
3656 OfxStatus stat = OFX::Private::gEffectSuite->imageMemoryAlloc(effectHandle, nBytes, &_handle);
3657 if(stat == kOfxStatErrMemory)
3658 throw std::bad_alloc();
3659 throwSuiteStatusException(stat);
3660 }
3661
3662 /** @brief dtor */
~ImageMemory()3663 ImageMemory::~ImageMemory()
3664 {
3665 OfxStatus stat = OFX::Private::gEffectSuite->imageMemoryFree(_handle);
3666 // ignore status code for exception purposes
3667 (void)stat;
3668 }
3669
3670 /** @brief lock the memory and return a pointer to it */
lock(void)3671 void *ImageMemory::lock(void)
3672 {
3673 void *ptr;
3674 OfxStatus stat = OFX::Private::gEffectSuite->imageMemoryLock(_handle, &ptr);
3675 if(stat == kOfxStatErrMemory)
3676 throw std::bad_alloc();
3677 throwSuiteStatusException(stat);
3678 return ptr;
3679 }
3680
3681 /** @brief unlock the memory */
unlock(void)3682 void ImageMemory::unlock(void)
3683 {
3684 OfxStatus stat = OFX::Private::gEffectSuite->imageMemoryUnlock(_handle);
3685 (void)stat;
3686 }
3687
3688
3689
3690 /** @brief OFX::Private namespace, for things private to the support library code here generally calls image effect class members */
3691 namespace Private {
3692
3693 #ifdef OFX_EXTENSIONS_NATRON
3694 static
3695 bool
decodeNativeOverlayHandle(const std::string & str,ImageEffectHostDescription::NativeOverlayHandle & handle)3696 decodeNativeOverlayHandle(const std::string& str, ImageEffectHostDescription::NativeOverlayHandle& handle)
3697 {
3698 static const std::string idToken(kNatronNativeOverlayType);
3699 static const std::string paramHintToken(kNatronNativeOverlayParameterHint);
3700 static const std::string paramTypeToken(kNatronNativeOverlayParameterHint);
3701 std::size_t foundName = str.find_first_of(idToken);
3702 if (foundName == std::string::npos) {
3703 return false;
3704 }
3705
3706 // Position the cursor to the start of the identifier string. +1 to ignore the '_' character.
3707 std::size_t identifierStart = foundName + idToken.size() + 1;
3708
3709 std::size_t foundParamHint = str.find_first_of(paramHintToken);
3710 if (foundParamHint == std::string::npos) {
3711 return false;
3712 }
3713
3714 std::size_t identifierEnd = foundParamHint - 1;
3715 handle.identifier = str.substr(identifierStart, identifierEnd - identifierStart);
3716
3717 while (foundParamHint != std::string::npos) {
3718 // Position the cursor to the start of the first parameter string. +1 to ignore the '_' character.
3719 std::size_t paramHintStart = foundParamHint + paramHintToken.size() + 1;
3720
3721
3722 // Find the param type string token
3723 std::size_t foundParamType = str.find_first_of(paramTypeToken, paramHintStart);
3724
3725 // huh badly encoded...
3726 if (foundParamType == std::string::npos) {
3727 return false;
3728 }
3729
3730 std::size_t paramHintEnd = foundParamType - 1;
3731 std::string paramHint = str.substr(paramHintStart, paramHintEnd - paramHintStart);
3732
3733
3734 std::size_t paramTypeStart = foundParamType + paramTypeToken.size() + 1;
3735
3736 // Find the next parameter description if any
3737 foundParamHint = str.find_first_of(paramHintToken, paramTypeStart);
3738
3739 std::size_t paramTypeEnd;
3740 if (foundParamHint != std::string::npos) {
3741 // there's a parameter after this one, use it to know where to stop for the type string
3742 paramTypeEnd = foundParamHint - 1;
3743 } else {
3744 // we reached the end!
3745 paramTypeEnd = std::string::npos;
3746 }
3747 std::string paramType = str.substr(paramTypeStart, paramTypeEnd - paramTypeStart);
3748 handle.parameters.push_back(std::make_pair(paramHint, paramType));
3749
3750 }
3751
3752 return true;
3753
3754 }
3755 #endif
3756 /** @brief Creates the global host description and sets its properties */
3757 static
3758 void
fetchHostDescription(OfxHost * host)3759 fetchHostDescription(OfxHost *host)
3760 {
3761 OFX::Log::error(OFX::gHostDescriptionHasInit, "Tried to create host description when we already have one.");
3762 if(!OFX::gHostDescriptionHasInit) {
3763 OFX::gHostDescriptionHasInit = true;
3764 // wrap the property handle up with a property set
3765 PropertySet hostProps(host->host);
3766
3767 // and get some properties
3768 gHostDescription.APIVersionMajor = hostProps.propGetInt(kOfxPropAPIVersion, 0, false); // OFX 1.2
3769 if (gHostDescription.APIVersionMajor == 0) {
3770 // assume OFX 1.0
3771 gHostDescription.APIVersionMajor = 1;
3772 }
3773 gHostDescription.APIVersionMinor = hostProps.propGetInt(kOfxPropAPIVersion, 1, false); // OFX 1.2
3774 gHostDescription.hostName = hostProps.propGetString(kOfxPropName);
3775 gHostDescription.hostLabel = hostProps.propGetString(kOfxPropLabel);
3776 gHostDescription.versionMajor = hostProps.propGetInt(kOfxPropVersion, 0, false); // OFX 1.2
3777 gHostDescription.versionMinor = hostProps.propGetInt(kOfxPropVersion, 1, false); // OFX 1.2
3778 gHostDescription.versionMicro = hostProps.propGetInt(kOfxPropVersion, 2, false); // OFX 1.2
3779 gHostDescription.versionLabel = hostProps.propGetString(kOfxPropVersionLabel, false); // OFX 1.2
3780 gHostDescription.hostIsBackground = hostProps.propGetInt(kOfxImageEffectHostPropIsBackground) != 0;
3781 gHostDescription.supportsOverlays = hostProps.propGetInt(kOfxImageEffectPropSupportsOverlays) != 0;
3782 gHostDescription.supportsMultiResolution = hostProps.propGetInt(kOfxImageEffectPropSupportsMultiResolution) != 0;
3783 gHostDescription.supportsTiles = hostProps.propGetInt(kOfxImageEffectPropSupportsTiles) != 0;
3784 gHostDescription.temporalClipAccess = hostProps.propGetInt(kOfxImageEffectPropTemporalClipAccess) != 0;
3785 gHostDescription.supportsMultipleClipDepths = hostProps.propGetInt(kOfxImageEffectPropSupportsMultipleClipDepths) != 0;
3786 gHostDescription.supportsMultipleClipPARs = hostProps.propGetInt(kOfxImageEffectPropSupportsMultipleClipPARs) != 0;
3787 gHostDescription.supportsSetableFrameRate = hostProps.propGetInt(kOfxImageEffectPropSetableFrameRate) != 0;
3788 gHostDescription.supportsSetableFielding = hostProps.propGetInt(kOfxImageEffectPropSetableFielding) != 0;
3789 gHostDescription.sequentialRender = hostProps.propGetInt(kOfxImageEffectInstancePropSequentialRender, false); // appeared in OFX 1.2
3790 gHostDescription.supportsStringAnimation = hostProps.propGetInt(kOfxParamHostPropSupportsStringAnimation) != 0;
3791 gHostDescription.supportsCustomInteract = hostProps.propGetInt(kOfxParamHostPropSupportsCustomInteract) != 0;
3792 gHostDescription.supportsChoiceAnimation = hostProps.propGetInt(kOfxParamHostPropSupportsChoiceAnimation) != 0;
3793 #ifdef OFX_EXTENSIONS_RESOLVE
3794 gHostDescription.supportsStrChoiceAnimation = hostProps.propGetInt(kOfxParamHostPropSupportsStrChoiceAnimation, false) != 0;
3795 #endif
3796 gHostDescription.supportsBooleanAnimation = hostProps.propGetInt(kOfxParamHostPropSupportsBooleanAnimation) != 0;
3797 gHostDescription.supportsCustomAnimation = hostProps.propGetInt(kOfxParamHostPropSupportsCustomAnimation) != 0;
3798 gHostDescription.osHandle = hostProps.propGetPointer(kOfxPropHostOSHandle, false);
3799 gHostDescription.supportsParametricParameter = gParametricParameterSuite != 0;
3800 gHostDescription.supportsParametricAnimation = hostProps.propGetInt(kOfxParamHostPropSupportsParametricAnimation, false) != 0;
3801 #ifdef OFX_EXTENSIONS_RESOLVE
3802 gHostDescription.supportsOpenCLRender = hostProps.propGetString(kOfxImageEffectPropOpenCLRenderSupported, 0, false) == "true";
3803 gHostDescription.supportsCudaRender = hostProps.propGetString(kOfxImageEffectPropCudaRenderSupported, 0, false) == "true";
3804 #endif
3805 gHostDescription.supportsRenderQualityDraft = hostProps.propGetInt(kOfxImageEffectPropRenderQualityDraft, false) != 0; // appeared in OFX 1.4
3806 {
3807 std::string originStr = hostProps.propGetString(kOfxImageEffectHostPropNativeOrigin, false); // appeared in OFX 1.4
3808 if (originStr.empty()) {
3809 // from http://openeffects.org/standard_changes/host-origin-hints :
3810 // "All this hint does is tell plugin that the host world is different
3811 // than OFX. Historically the first two hosts that exhibited this issue
3812 // could be Fusion (upper left is 0,0 natively) and Toxic (Center is 0,0)."
3813 if (gHostDescription.hostName == "com.eyeonline.Fusion" ||
3814 ends_with(gHostDescription.hostName, "Fusion")) {
3815 // if host is Fusion, set to TopLeft
3816 gHostDescription.nativeOrigin = eNativeOriginTopLeft;
3817 } else if (starts_with(gHostDescription.hostName, "Autodesk Toxik") ||
3818 ends_with(gHostDescription.hostName, "Toxik")) {
3819 // if host is Toxic, set to Center
3820 gHostDescription.nativeOrigin = eNativeOriginCenter;
3821 } else {
3822 gHostDescription.nativeOrigin = eNativeOriginBottomLeft;
3823 }
3824 } else if (originStr == kOfxHostNativeOriginBottomLeft) {
3825 gHostDescription.nativeOrigin = eNativeOriginBottomLeft;
3826 } else if (originStr == kOfxHostNativeOriginTopLeft) {
3827 gHostDescription.nativeOrigin = eNativeOriginTopLeft;
3828 } else if (originStr == kOfxHostNativeOriginCenter) {
3829 gHostDescription.nativeOrigin = eNativeOriginCenter;
3830 }
3831 }
3832 #ifdef OFX_SUPPORTS_OPENGLRENDER
3833 gHostDescription.supportsOpenGLRender = gOpenGLRenderSuite != 0 && hostProps.propGetString(kOfxImageEffectPropOpenGLRenderSupported, 0, false) == "true";
3834 #endif
3835 #ifdef OFX_EXTENSIONS_NUKE
3836 gHostDescription.supportsCamera = gCameraSuite != 0;
3837 gHostDescription.canTransform = hostProps.propGetInt(kFnOfxImageEffectCanTransform, false) != 0;
3838 gHostDescription.isMultiPlanar = hostProps.propGetInt(kFnOfxImageEffectPropMultiPlanar, false) != 0;
3839 #endif
3840 gHostDescription.maxParameters = hostProps.propGetInt(kOfxParamHostPropMaxParameters);
3841 gHostDescription.maxPages = hostProps.propGetInt(kOfxParamHostPropMaxPages);
3842 gHostDescription.pageRowCount = hostProps.propGetInt(kOfxParamHostPropPageRowColumnCount, 0);
3843 gHostDescription.pageColumnCount = hostProps.propGetInt(kOfxParamHostPropPageRowColumnCount, 1);
3844 #ifdef OFX_EXTENSIONS_NATRON
3845 gHostDescription.isNatron = hostProps.propGetInt(kNatronOfxHostIsNatron, false) != 0;
3846 gHostDescription.supportsDynamicChoices = hostProps.propGetInt(kNatronOfxParamHostPropSupportsDynamicChoices, false) != 0;
3847 gHostDescription.supportsCascadingChoices = hostProps.propGetInt(kNatronOfxParamPropChoiceCascading, false) != 0;
3848 gHostDescription.supportsChannelSelector = hostProps.propGetString(kNatronOfxImageEffectPropChannelSelector, false) == kOfxImageComponentRGBA;
3849 gHostDescription.canDistort = hostProps.propGetInt(kOfxImageEffectPropCanDistort, false) != 0;
3850
3851 int nOverlayHandles = hostProps.propGetDimension(kNatronOfxPropNativeOverlays, false);
3852 for (int i = 0; i < nOverlayHandles; ++i) {
3853 std::string overlayHandleEncoded = hostProps.propGetString(kNatronOfxPropNativeOverlays, i, false);
3854 ImageEffectHostDescription::NativeOverlayHandle h;
3855 if (decodeNativeOverlayHandle(overlayHandleEncoded, h)) {
3856 gHostDescription.nativeInteracts.push_back(h);
3857 }
3858
3859 }
3860
3861 #endif
3862
3863 int numComponents = hostProps.propGetDimension(kOfxImageEffectPropSupportedComponents);
3864 for(int i=0; i<numComponents; ++i)
3865 gHostDescription._supportedComponents.push_back(mapStrToPixelComponentEnum(hostProps.propGetString(kOfxImageEffectPropSupportedComponents, i)));
3866
3867 int numContexts = hostProps.propGetDimension(kOfxImageEffectPropSupportedContexts);
3868 for(int i=0; i<numContexts; ++i)
3869 gHostDescription._supportedContexts.push_back(mapToContextEnum(hostProps.propGetString(kOfxImageEffectPropSupportedContexts, i)));
3870
3871 int numPixelDepths = hostProps.propGetDimension(kOfxImageEffectPropSupportedPixelDepths);
3872 for(int i=0; i<numPixelDepths; ++i)
3873 gHostDescription._supportedPixelDepths.push_back(mapStrToBitDepthEnum(hostProps.propGetString(kOfxImageEffectPropSupportedPixelDepths, i)));
3874 }
3875
3876 }
3877
3878 /** @brief fetch the effect property set from the ImageEffectHandle */
3879 OFX::PropertySet
fetchEffectProps(OfxImageEffectHandle handle)3880 fetchEffectProps(OfxImageEffectHandle handle)
3881 {
3882 // get the property handle
3883 OfxPropertySetHandle propHandle;
3884 OfxStatus stat = OFX::Private::gEffectSuite->getPropertySet(handle, &propHandle);
3885 throwSuiteStatusException(stat);
3886 return OFX::PropertySet(propHandle);
3887 }
3888
3889 /** @brief Keeps count of how many times load/unload have been called */
3890 int gLoadCount = 0;
3891
3892 /** @brief Library side load action, this fetches all the suite pointers */
loadAction(void)3893 void loadAction(void)
3894 {
3895 gLoadCount++;
3896
3897 //OfxStatus status = kOfxStatOK;
3898
3899 // fetch the suites
3900 OFX::Log::error(gHost == 0, "Host pointer has not been set.");
3901 if(!gHost) throw OFX::Exception::Suite(kOfxStatErrBadHandle);
3902
3903 if(gLoadCount == 1) {
3904 gEffectSuite = (OfxImageEffectSuiteV1 *) fetchSuite(kOfxImageEffectSuite, 1);
3905 gPropSuite = (OfxPropertySuiteV1 *) fetchSuite(kOfxPropertySuite, 1);
3906 gParamSuite = (OfxParameterSuiteV1 *) fetchSuite(kOfxParameterSuite, 1);
3907 gMemorySuite = (OfxMemorySuiteV1 *) fetchSuite(kOfxMemorySuite, 1);
3908 gThreadSuite = (OfxMultiThreadSuiteV1 *) fetchSuite(kOfxMultiThreadSuite, 1);
3909 gMessageSuite = (OfxMessageSuiteV1 *) fetchSuite(kOfxMessageSuite, 1);
3910 gMessageSuiteV2 = (OfxMessageSuiteV2 *) fetchSuite(kOfxMessageSuite, 2, true);
3911 gProgressSuiteV1 = (OfxProgressSuiteV1 *) fetchSuite(kOfxProgressSuite, 1, true);
3912 gProgressSuiteV2 = (OfxProgressSuiteV2 *) fetchSuite(kOfxProgressSuite, 2, true);
3913 gTimeLineSuite = (OfxTimeLineSuiteV1 *) fetchSuite(kOfxTimeLineSuite, 1, true);
3914 gParametricParameterSuite = (OfxParametricParameterSuiteV1*) fetchSuite(kOfxParametricParameterSuite, 1, true);
3915 #ifdef OFX_SUPPORTS_OPENGLRENDER
3916 gOpenGLRenderSuite = (OfxImageEffectOpenGLRenderSuiteV1*) fetchSuite(kOfxOpenGLRenderSuite, 1, true);
3917 #endif
3918 #ifdef OFX_EXTENSIONS_NUKE
3919 gCameraSuite = (NukeOfxCameraSuiteV1*) fetchSuite(kNukeOfxCameraSuite, 1, true );
3920 gImageEffectPlaneSuiteV1 = (FnOfxImageEffectPlaneSuiteV1*) fetchSuite(kFnOfxImageEffectPlaneSuite, 1, true );
3921 gImageEffectPlaneSuiteV2 = (FnOfxImageEffectPlaneSuiteV2*) fetchSuite(kFnOfxImageEffectPlaneSuite, 2, true );
3922 #endif
3923 #ifdef OFX_EXTENSIONS_VEGAS
3924 gVegasProgressSuite = (OfxVegasProgressSuiteV1 *) fetchSuite(kOfxVegasProgressSuite, 1, true);
3925 gVegasStereoscopicImageSuite = (OfxVegasStereoscopicImageSuiteV1 *) fetchSuite(kOfxVegasStereoscopicImageEffectSuite, 1, true);
3926 gVegasKeyframeSuite = (OfxVegasKeyframeSuiteV1 *) fetchSuite(kOfxVegasKeyframeSuite, 1, true);
3927 #endif
3928
3929 // OK check and fetch host information
3930 fetchHostDescription(gHost);
3931
3932 /// and set some dendent flags
3933 OFX::gHostDescription.supportsMessageSuiteV2 = gMessageSuiteV2 != NULL;
3934 #ifdef OFX_EXTENSIONS_VEGAS
3935 OFX::gHostDescription.supportsProgressSuite = (gProgressSuiteV1 != NULL || gProgressSuiteV2 != NULL || gVegasProgressSuite != NULL);
3936 #else
3937 OFX::gHostDescription.supportsProgressSuite = (gProgressSuiteV1 != NULL || gProgressSuiteV2 != NULL);
3938 #endif
3939 OFX::gHostDescription.supportsTimeLineSuite = gTimeLineSuite != NULL;
3940
3941 // fetch the interact suite if the host supports interaction
3942 if(OFX::gHostDescription.supportsOverlays || OFX::gHostDescription.supportsCustomInteract)
3943 gInteractSuite = (OfxInteractSuiteV1 *) fetchSuite(kOfxInteractSuite, 1);
3944
3945 #ifdef OFX_EXTENSIONS_VEGAS
3946 #if defined(WIN32) || defined(WIN64)
3947 gHWNDInteractSuite = (OfxHWNDInteractSuiteV1 *) fetchSuite(kOfxHWndInteractSuite, 1, true);
3948 #endif // #if defined(WIN32) || defined(WIN64)
3949 #endif
3950 }
3951
3952 // initialise the validation code
3953 OFX::Validation::initialise();
3954
3955 // validate the host
3956 OFX::Validation::validateHostProperties(gHost);
3957
3958 }
3959
3960 /** @brief Library side unload action, this fetches all the suite pointers */
3961 static
unloadAction(const char * id,unsigned int majorVersion,unsigned int minorVersion)3962 void unloadAction(const char* id, unsigned int majorVersion, unsigned int minorVersion)
3963 {
3964 gLoadCount--;
3965 if (gLoadCount<0) {
3966 OFX::Log::warning(true, "OFX Plugin '%s' is already unloaded.", id);
3967 return;
3968 }
3969
3970 if(gLoadCount==0)
3971 {
3972 // force these to null
3973 gEffectSuite = 0;
3974 gPropSuite = 0;
3975 gParamSuite = 0;
3976 gMemorySuite = 0;
3977 gThreadSuite = 0;
3978 gMessageSuite = 0;
3979 gMessageSuiteV2 = 0;
3980 gInteractSuite = 0;
3981 gParametricParameterSuite = 0;
3982 #ifdef OFX_EXTENSIONS_NUKE
3983 gCameraSuite = 0;
3984 gImageEffectPlaneSuiteV1 = 0;
3985 gImageEffectPlaneSuiteV2 = 0;
3986 #endif
3987 #ifdef OFX_EXTENSIONS_VEGAS
3988 #if defined(WIN32) || defined(WIN64)
3989 gHWNDInteractSuite = 0;
3990 #endif // #if defined(WIN32) || defined(WIN64)
3991 gVegasStereoscopicImageSuite = 0;
3992 gVegasKeyframeSuite = 0;
3993 #endif
3994 }
3995
3996 {
3997 OFX::Private::VersionIDKey key;
3998 key.id = id;
3999 key.majorVersion = majorVersion;
4000 key.minorVersion = minorVersion;
4001 EffectDescriptorMap::iterator it = gEffectDescriptors.find(key);
4002 EffectContextMap& toBeDeleted = it->second;
4003 for(EffectContextMap::iterator it2 = toBeDeleted.begin(); it2 != toBeDeleted.end(); ++it2)
4004 {
4005 OFX::ImageEffectDescriptor* desc = it2->second;
4006 delete desc;
4007 }
4008 gEffectDescriptors.erase(it);
4009 }
4010 {
4011 OFX::OfxPlugInfoMap::iterator it = OFX::plugInfoMap.find(id);
4012 OfxPlugin* plug = it->second._plug;
4013 OFX::OfxPluginArray::iterator it2 = std::find(ofxPlugs.begin(), ofxPlugs.end(), plug);
4014 if (it2 != ofxPlugs.end()) {
4015 (*it2) = 0;
4016 }
4017 delete plug;
4018 OFX::plugInfoMap.erase(it);
4019 }
4020 }
4021
4022
4023 /** @brief fetches our pointer out of the props on the handle */
retrieveImageEffectPointer(OfxImageEffectHandle handle)4024 ImageEffect *retrieveImageEffectPointer(OfxImageEffectHandle handle)
4025 {
4026 ImageEffect *instance;
4027
4028 // get the prop set on the handle
4029 OfxPropertySetHandle propHandle;
4030 OfxStatus stat = OFX::Private::gEffectSuite->getPropertySet(handle, &propHandle);
4031 throwSuiteStatusException(stat);
4032
4033 // make our wrapper object
4034 PropertySet props(propHandle);
4035
4036 // fetch the instance data out of the properties
4037 instance = (ImageEffect *) props.propGetPointer(kOfxPropInstanceData);
4038
4039 OFX::Log::error(instance == 0, "Instance data handle in effect instance properties is NULL!");
4040
4041 // need to throw something here
4042 if (!instance) {
4043 throwSuiteStatusException(kOfxStatErrBadHandle);
4044 }
4045 // and dance to the music
4046 return instance;
4047 }
4048
4049 /** @brief Checks the handles passed into the plugin's main entry point */
4050 static
4051 void
checkMainHandles(const std::string & action,const void * handle,OfxPropertySetHandle inArgsHandle,OfxPropertySetHandle outArgsHandle,bool handleCanBeNull,bool inArgsCanBeNull,bool outArgsCanBeNull)4052 checkMainHandles(const std::string &action, const void *handle,
4053 OfxPropertySetHandle inArgsHandle, OfxPropertySetHandle outArgsHandle,
4054 bool handleCanBeNull, bool inArgsCanBeNull, bool outArgsCanBeNull)
4055 {
4056 if(handleCanBeNull)
4057 OFX::Log::warning(handle != 0, "Handle passed to '%s' is not null.", action.c_str());
4058 else
4059 OFX::Log::error(handle == 0, "'Handle passed to '%s' is null.", action.c_str());
4060
4061 if(inArgsCanBeNull)
4062 OFX::Log::warning(inArgsHandle != 0, "'inArgs' Handle passed to '%s' is not null.", action.c_str());
4063 else
4064 OFX::Log::error(inArgsHandle == 0, "'inArgs' handle passed to '%s' is null.", action.c_str());
4065
4066 if(outArgsCanBeNull)
4067 OFX::Log::warning(outArgsHandle != 0, "'outArgs' Handle passed to '%s' is not null.", action.c_str());
4068 else
4069 OFX::Log::error(outArgsHandle == 0, "'outArgs' handle passed to '%s' is null.", action.c_str());
4070
4071 // validate the property sets on the arguments
4072 OFX::Validation::validateActionArgumentsProperties(action, inArgsHandle, outArgsHandle);
4073
4074 // throw exceptions if null when not meant to be null
4075 if(!handleCanBeNull && !handle) throwSuiteStatusException(kOfxStatErrBadHandle);
4076 if(!inArgsCanBeNull && !inArgsHandle) throwSuiteStatusException(kOfxStatErrBadHandle);
4077 if(!outArgsCanBeNull && !outArgsHandle) throwSuiteStatusException(kOfxStatErrBadHandle);
4078 }
4079
4080
4081 /** @brief Fetches the arguments used in a render action 'inargs' property set into a POD struct */
4082 static void
getRenderActionArguments(RenderArguments & args,OFX::PropertySet inArgs)4083 getRenderActionArguments(RenderArguments &args, OFX::PropertySet inArgs)
4084 {
4085 args.time = inArgs.propGetDouble(kOfxPropTime);
4086
4087 args.renderScale.x = args.renderScale.y = 1.;
4088 inArgs.propGetDoubleN(kOfxImageEffectPropRenderScale, &args.renderScale.x, 2);
4089
4090 args.renderWindow.x1 = args.renderWindow.y1 = args.renderWindow.x2 = args.renderWindow.y2 = 0;
4091 inArgs.propGetIntN(kOfxImageEffectPropRenderWindow, &args.renderWindow.x1, 4);
4092
4093 #ifdef OFX_EXTENSIONS_RESOLVE
4094 args.isEnabledOpenCLRender = inArgs.propGetInt(kOfxImageEffectPropOpenCLEnabled, false) != 0;
4095 args.isEnabledCudaRender = inArgs.propGetInt(kOfxImageEffectPropCudaEnabled, false) != 0;
4096 args.pOpenCLCmdQ = inArgs.propGetPointer(kOfxImageEffectPropOpenCLCommandQueue, false);
4097 #endif
4098
4099 #ifdef OFX_SUPPORTS_OPENGLRENDER
4100 // Don't throw an exception if the following inArgs are not present.
4101 // OpenGL rendering appeared in OFX 1.3
4102 args.openGLEnabled = inArgs.propGetInt(kOfxImageEffectPropOpenGLEnabled, false) != 0;
4103 #ifdef OFX_EXTENSIONS_NATRON
4104 args.openGLContextData = args.openGLEnabled ? inArgs.propGetPointer(kNatronOfxImageEffectPropOpenGLContextData, false) : NULL;
4105 #endif
4106 #endif
4107
4108 // Don't throw an exception if the following inArgs are not present:
4109 // They appeared in OFX 1.2.
4110 args.sequentialRenderStatus = inArgs.propGetInt(kOfxImageEffectPropSequentialRenderStatus, false) != 0;
4111 args.interactiveRenderStatus = inArgs.propGetInt(kOfxImageEffectPropInteractiveRenderStatus, false) != 0;
4112
4113 // kOfxImageEffectPropRenderQualityDraft appeared in OFX 1.4
4114 args.renderQualityDraft = inArgs.propGetInt(kOfxImageEffectPropRenderQualityDraft, false) != 0;
4115
4116 #ifdef OFX_EXTENSIONS_NUKE
4117 args.renderView = 0; // to support both Nuke and Vegas
4118 #endif
4119
4120 #ifdef OFX_EXTENSIONS_VEGAS
4121 args.viewsToRender = inArgs.propGetInt(kOfxImageEffectPropViewsToRender, 0, false);
4122 args.renderView = inArgs.propGetInt(kOfxImageEffectPropRenderView, 0, false);
4123 #endif
4124
4125 #ifdef OFX_EXTENSIONS_NUKE
4126 if (args.renderView == 0) {
4127 args.renderView = inArgs.propGetInt(kFnOfxImageEffectPropView, 0, false);
4128 }
4129 int numPlanes = inArgs.propGetDimension(kOfxImageEffectPropRenderPlanes, false);
4130 for (int i = 0; i < numPlanes; ++i) {
4131 args.planes.push_back(inArgs.propGetString(kOfxImageEffectPropRenderPlanes, i, false));
4132 }
4133 #endif
4134
4135 args.fieldToRender = eFieldNone;
4136 std::string str = inArgs.propGetString(kOfxImageEffectPropFieldToRender);
4137 try {
4138 args.fieldToRender = mapStrToFieldEnum(str);
4139 }
4140 catch (std::invalid_argument) {
4141 // dud field?
4142 OFX::Log::error(true, "Unknown field to render '%s'", str.c_str());
4143
4144 // HACK need to throw something to cause a failure
4145 }
4146
4147 #ifdef OFX_EXTENSIONS_VEGAS
4148 if (args.renderQualityDraft) { // OFX 1.4 property wins over Vegas extension
4149 args.renderQuality = eVegasRenderQualityDraft;
4150 } else {
4151 args.renderQuality = eVegasRenderQualityBest;
4152 std::string strQuality = inArgs.propGetString(kOfxImageEffectPropRenderQuality, /*throwOnFailure*/false);
4153 try {
4154 args.renderQuality = mapToVegasRenderQualityEnum(strQuality);
4155 } catch (std::invalid_argument) {
4156 // dud field?
4157 OFX::Log::error(true, "Unknown render quality '%s'", str.c_str());
4158 }
4159 }
4160 #endif
4161 }
4162
4163 /** @brief Library side render action, fetches relevant properties and calls the client code */
4164 static
4165 void
renderAction(OfxImageEffectHandle handle,OFX::PropertySet inArgs)4166 renderAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs)
4167 {
4168 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4169 RenderArguments args;
4170
4171 // get the arguments
4172 getRenderActionArguments(args, inArgs);
4173
4174 // and call the plugin client render code
4175 effectInstance->render(args);
4176 }
4177
4178 /** @brief Library side render begin sequence render action, fetches relevant properties and calls the client code */
4179 static
4180 void
beginSequenceRenderAction(OfxImageEffectHandle handle,OFX::PropertySet inArgs)4181 beginSequenceRenderAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs)
4182 {
4183 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4184
4185 BeginSequenceRenderArguments args;
4186
4187 args.frameRange.min = args.frameRange.max = 0.;
4188 inArgs.propGetDoubleN(kOfxImageEffectPropFrameRange, &args.frameRange.min, 2);
4189
4190 args.frameStep = inArgs.propGetDouble(kOfxImageEffectPropFrameStep, 0);
4191
4192 args.renderScale.x = args.renderScale.y = 1.;
4193 inArgs.propGetDoubleN(kOfxImageEffectPropRenderScale, &args.renderScale.x, 2);
4194
4195 #ifdef OFX_EXTENSIONS_RESOLVE
4196 args.isEnabledOpenCLRender = inArgs.propGetInt(kOfxImageEffectPropOpenCLEnabled, false) != 0;
4197 args.isEnabledCudaRender = inArgs.propGetInt(kOfxImageEffectPropCudaEnabled, false) != 0;
4198 args.pOpenCLCmdQ = inArgs.propGetPointer(kOfxImageEffectPropOpenCLCommandQueue, false);
4199 #endif
4200
4201 #ifdef OFX_SUPPORTS_OPENGLRENDER
4202 // Don't throw an exception if the following inArgs are not present.
4203 // OpenGL rendering appeared in OFX 1.3
4204 args.openGLEnabled = inArgs.propGetInt(kOfxImageEffectPropOpenGLEnabled, false) != 0;
4205 #ifdef OFX_EXTENSIONS_NATRON
4206 args.openGLContextData = args.openGLEnabled ? inArgs.propGetPointer(kNatronOfxImageEffectPropOpenGLContextData, false) : NULL;
4207 #endif
4208 #endif
4209 args.isInteractive = inArgs.propGetInt(kOfxPropIsInteractive) != 0;
4210 // Don't throw an exception if the following inArgs are not present:
4211 // They appeared in OFX 1.2
4212 args.sequentialRenderStatus = inArgs.propGetInt(kOfxImageEffectPropSequentialRenderStatus, false) != 0;
4213 args.interactiveRenderStatus = inArgs.propGetInt(kOfxImageEffectPropInteractiveRenderStatus, false) != 0;
4214
4215 // kOfxImageEffectPropRenderQualityDraft appeared in OFX 1.4
4216 args.renderQualityDraft = inArgs.propGetInt(kOfxImageEffectPropRenderQualityDraft, false) != 0;
4217
4218 #ifdef OFX_EXTENSIONS_NUKE
4219 args.view = inArgs.propGetInt(kFnOfxImageEffectPropView, 0, false);
4220 #endif
4221
4222 // and call the plugin client render code
4223 effectInstance->beginSequenceRender(args);
4224 }
4225
4226 /** @brief Library side render begin sequence render action, fetches relevant properties and calls the client code */
4227 static
4228 void
endSequenceRenderAction(OfxImageEffectHandle handle,OFX::PropertySet inArgs)4229 endSequenceRenderAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs)
4230 {
4231 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4232
4233 EndSequenceRenderArguments args;
4234
4235 args.renderScale.x = args.renderScale.y = 1.;
4236 inArgs.propGetDoubleN(kOfxImageEffectPropRenderScale, &args.renderScale.x, 2);
4237
4238 #ifdef OFX_SUPPORTS_OPENGLRENDER
4239 // Don't throw an exception if the following inArgs are not present.
4240 // OpenGL rendering appeared in OFX 1.3
4241 args.openGLEnabled = inArgs.propGetInt(kOfxImageEffectPropOpenGLEnabled, false) != 0;
4242 #ifdef OFX_EXTENSIONS_NATRON
4243 args.openGLContextData = args.openGLEnabled ? inArgs.propGetPointer(kNatronOfxImageEffectPropOpenGLContextData, false) : NULL;
4244 #endif
4245 #endif
4246 args.isInteractive = inArgs.propGetInt(kOfxPropIsInteractive) != 0;
4247 // Don't throw an exception if the following inArgs are not present:
4248 // They appeared in OFX 1.2
4249 args.sequentialRenderStatus = inArgs.propGetInt(kOfxImageEffectPropSequentialRenderStatus, false) != 0;
4250 args.interactiveRenderStatus = inArgs.propGetInt(kOfxImageEffectPropInteractiveRenderStatus, false) != 0;
4251
4252 // kOfxImageEffectPropRenderQualityDraft appeared in OFX 1.4
4253 args.renderQualityDraft = inArgs.propGetInt(kOfxImageEffectPropRenderQualityDraft, false) != 0;
4254
4255 #ifdef OFX_EXTENSIONS_NUKE
4256 args.view = inArgs.propGetInt(kFnOfxImageEffectPropView, 0, false);
4257 #endif
4258
4259 // and call the plugin client render code
4260 effectInstance->endSequenceRender(args);
4261 }
4262
4263
4264 /** @brief Fetches the arguments used in a isIdentity action 'inargs' property set into a POD struct */
4265 static void
getIsIdentityActionArguments(IsIdentityArguments & args,OFX::PropertySet inArgs)4266 getIsIdentityActionArguments(IsIdentityArguments &args, OFX::PropertySet inArgs)
4267 {
4268 args.time = inArgs.propGetDouble(kOfxPropTime);
4269
4270 args.renderScale.x = args.renderScale.y = 1.;
4271 inArgs.propGetDoubleN(kOfxImageEffectPropRenderScale, &args.renderScale.x, 2);
4272
4273 args.renderWindow.x1 = args.renderWindow.y1 = args.renderWindow.x2 = args.renderWindow.y2 = 0;
4274 inArgs.propGetIntN(kOfxImageEffectPropRenderWindow, &args.renderWindow.x1, 4);
4275
4276 #ifdef OFX_EXTENSIONS_NUKE
4277 args.view = inArgs.propGetInt(kFnOfxImageEffectPropView, 0, false);
4278 args.plane = inArgs.propGetString(kOfxImageEffectPropIdentityPlane, 0, false);
4279 #endif
4280
4281 std::string str = inArgs.propGetString(kOfxImageEffectPropFieldToRender);
4282 try {
4283 args.fieldToRender = mapStrToFieldEnum(str);
4284 }
4285 catch (std::invalid_argument) {
4286 // dud field?
4287 OFX::Log::error(true, "Unknown field to render '%s'", str.c_str());
4288
4289 // HACK need to throw something to cause a failure
4290 }
4291 }
4292
4293 /** @brief Library side render begin sequence render action, fetches relevant properties and calls the client code */
4294 static
4295 bool
isIdentityAction(OfxImageEffectHandle handle,OFX::PropertySet inArgs,OFX::PropertySet & outArgs)4296 isIdentityAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs, OFX::PropertySet &outArgs)
4297 {
4298 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4299 IsIdentityArguments args;
4300
4301 // get the arguments
4302 getIsIdentityActionArguments(args, inArgs);
4303
4304 // and call the plugin client isIdentity code
4305 Clip *identityClip = 0;
4306 double identityTime = args.time;
4307 #ifdef OFX_EXTENSIONS_NUKE
4308 int identityView = args.view;
4309 std::string identityPlane = args.plane;
4310 #endif
4311 bool v = effectInstance->isIdentity(args, identityClip, identityTime
4312 #ifdef OFX_EXTENSIONS_NUKE
4313 , identityView, identityPlane
4314 #endif
4315 );
4316
4317 if(v && identityClip) {
4318 outArgs.propSetString(kOfxPropName, identityClip->name());
4319 outArgs.propSetDouble(kOfxPropTime, identityTime);
4320 #ifdef OFX_EXTENSIONS_NUKE
4321 outArgs.propSetInt(kFnOfxImageEffectPropView, identityView, 0, false);
4322 outArgs.propSetString(kOfxImageEffectPropIdentityPlane, identityPlane, 0, false);
4323 #endif
4324 return true;
4325 }
4326 return false;
4327 }
4328
4329 /** @brief Library side get region of definition function */
4330 static
4331 bool
regionOfDefinitionAction(OfxImageEffectHandle handle,OFX::PropertySet inArgs,OFX::PropertySet & outArgs)4332 regionOfDefinitionAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs, OFX::PropertySet &outArgs)
4333 {
4334 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4335 RegionOfDefinitionArguments args;
4336
4337 args.renderScale.x = args.renderScale.y = 1.;
4338 inArgs.propGetDoubleN(kOfxImageEffectPropRenderScale, &args.renderScale.x, 2);
4339
4340 args.time = inArgs.propGetDouble(kOfxPropTime);
4341
4342 #ifdef OFX_EXTENSIONS_NUKE
4343 args.view = inArgs.propGetInt(kFnOfxImageEffectPropView, 0, false);
4344 #endif
4345
4346 // and call the plugin client code
4347 OfxRectD rod;
4348 bool v = effectInstance->getRegionOfDefinition(args, rod);
4349
4350 if(v) {
4351 outArgs.propSetDoubleN(kOfxImageEffectPropRegionOfDefinition, &rod.x1, 4);
4352 return true;
4353 }
4354 return false;
4355 }
4356
4357 /** @brief Library side get regions of interest function */
4358 static
4359 bool
regionsOfInterestAction(OfxImageEffectHandle handle,OFX::PropertySet inArgs,OFX::PropertySet & outArgs,const char * plugname,unsigned int majorVersion,unsigned int minorVersion)4360 regionsOfInterestAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs, OFX::PropertySet &outArgs, const char* plugname, unsigned int majorVersion, unsigned int minorVersion)
4361 {
4362 /** @brief local class to set the roi of a clip */
4363 class LOCAL ActualROISetter : public OFX::RegionOfInterestSetter {
4364 OFX::PropertySet &outArgs_;
4365 bool doneSomething_;
4366 const std::map<std::string, std::string>& clipROIPropNames_;
4367 public :
4368 /** @brief ctor */
4369 ActualROISetter(OFX::PropertySet &args, const std::map<std::string, std::string>& clipROIPropNames)
4370 : outArgs_(args)
4371 , doneSomething_(false)
4372 , clipROIPropNames_(clipROIPropNames)
4373 { }
4374
4375 /** @brief did we set something ? */
4376 bool didSomething(void) const {return doneSomething_;}
4377
4378 /** @brief set the RoI of the clip */
4379 virtual void setRegionOfInterest(const Clip &clip, const OfxRectD &roi)
4380 {
4381 std::map<std::string, std::string>::const_iterator it = clipROIPropNames_.find(clip.name());
4382 if(it==clipROIPropNames_.end())
4383 throw(Exception::PropertyUnknownToHost(clip.name().c_str()));
4384
4385 // construct the name of the property
4386 const std::string& propName = it->second;
4387
4388 // and set it
4389 outArgs_.propSetDoubleN(propName.c_str(), &roi.x1, 4);
4390
4391 // and record the face we have done something
4392 doneSomething_ = true;
4393 }
4394 }; // end of local class
4395
4396 // fetch our effect pointer
4397 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4398 RegionsOfInterestArguments args;
4399
4400 // fetch in arguments from the prop handle
4401 args.renderScale.x = args.renderScale.y = 1.;
4402 inArgs.propGetDoubleN(kOfxImageEffectPropRenderScale, &args.renderScale.x, 2);
4403
4404 args.regionOfInterest.x1 = args.regionOfInterest.y1 = args.regionOfInterest.x2 = args.regionOfInterest.y2 = 0.;
4405 inArgs.propGetDoubleN(kOfxImageEffectPropRegionOfInterest, &args.regionOfInterest.x1, 4);
4406
4407 args.time = inArgs.propGetDouble(kOfxPropTime);
4408
4409 #ifdef OFX_EXTENSIONS_NUKE
4410 args.view = inArgs.propGetInt(kFnOfxImageEffectPropView, 0, false);
4411 #endif
4412
4413 // make a roi setter object
4414 OFX::Private::VersionIDKey key;
4415 key.id = plugname;
4416 key.majorVersion = majorVersion;
4417 key.minorVersion = minorVersion;
4418 ActualROISetter setRoIs(outArgs, gEffectDescriptors[key][effectInstance->getContext()]->getClipROIPropNames());
4419
4420 // and call the plugin client code
4421 effectInstance->getRegionsOfInterest(args, setRoIs);
4422
4423 // did we do anything ?
4424 if(setRoIs.didSomething())
4425 return true;
4426 return false;
4427 }
4428
4429 /** @brief Library side frames needed action */
4430 static
4431 bool
framesNeededAction(OfxImageEffectHandle handle,OFX::PropertySet inArgs,OFX::PropertySet & outArgs,const char * plugname,unsigned int majorVersion,unsigned int minorVersion)4432 framesNeededAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs, OFX::PropertySet &outArgs, const char* plugname, unsigned int majorVersion, unsigned int minorVersion)
4433 {
4434 /** @brief local class to set the frames needed from a clip */
4435 class LOCAL ActualSetter : public OFX::FramesNeededSetter {
4436 OFX::PropertySet &outArgs_; /**< @brief property set to set values in */
4437 std::map<std::string, std::vector<OfxRangeD> > frameRanges_; /**< @brief map holding a bunch of frame ranges, one for each clip */
4438 const std::map<std::string, std::string>& _clipFrameRangePropNames;
4439 public :
4440 /** @brief ctor */
4441 ActualSetter(OFX::PropertySet &args, const std::map<std::string, std::string>& clipFrameRangePropNames)
4442 : outArgs_(args), _clipFrameRangePropNames(clipFrameRangePropNames)
4443 { }
4444
4445 /** @brief set the RoI of the clip */
4446 virtual void setFramesNeeded(const Clip &clip, const OfxRangeD &range)
4447 {
4448 // insert this into the vector which is in the map
4449 frameRanges_[clip.name()].push_back(range);
4450 }
4451
4452 /** @brief write frameRanges_ back to the property set */
4453 bool setOutProperties(void)
4454 {
4455 bool didSomething = false;
4456
4457 std::map<std::string, std::vector<OfxRangeD> >::iterator i;
4458
4459 for(i = frameRanges_.begin(); i != frameRanges_.end(); ++i) {
4460 if(i->first != kOfxImageEffectOutputClipName) {
4461 didSomething = true;
4462
4463 // Make the property name we are setting
4464 const std::map<std::string, std::string>::const_iterator it = _clipFrameRangePropNames.find(i->first);
4465 if(it==_clipFrameRangePropNames.end())
4466 throw(Exception::PropertyUnknownToHost(i->first.c_str()));
4467
4468 const std::string& propName = it->second;
4469
4470 // fetch the list of frame ranges
4471 std::vector<OfxRangeD> &clipRange = i->second;
4472 std::vector<OfxRangeD>::iterator j;
4473 int n = 0;
4474
4475 // The host may not have the property if the clip is not connected (Resolve).
4476 // Just proceed to the next clip.
4477 if (outArgs_.propExists(propName.c_str())) {
4478 // and set 'em
4479 for(j = clipRange.begin(); j < clipRange.end(); ++j) {
4480 outArgs_.propSetDouble(propName.c_str(), j->min, n++);
4481 outArgs_.propSetDouble(propName.c_str(), j->max, n++);
4482 }
4483 }
4484 }
4485 }
4486
4487 return didSomething;
4488 }
4489
4490 }; // end of local class
4491
4492 // fetch our effect pointer
4493 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4494 FramesNeededArguments args;
4495
4496 // fetch in arguments from the prop handle
4497 args.time = inArgs.propGetDouble(kOfxPropTime);
4498
4499 // make a roi setter object
4500 OFX::Private::VersionIDKey key;
4501 key.id = plugname;
4502 key.majorVersion = majorVersion;
4503 key.minorVersion = minorVersion;
4504 ActualSetter setFrames(outArgs, gEffectDescriptors[key][effectInstance->getContext()]->getClipFrameRangePropNames());
4505
4506 // and call the plugin client code
4507 effectInstance->getFramesNeeded(args, setFrames);
4508
4509 // Write it back to the properties and see if we set anything
4510 if(setFrames.setOutProperties())
4511 return true;
4512 return false;
4513 }
4514
4515 /** @brief Library side get regions of interest function */
4516 static
4517 bool
getTimeDomainAction(OfxImageEffectHandle handle,OFX::PropertySet & outArgs)4518 getTimeDomainAction(OfxImageEffectHandle handle, OFX::PropertySet &outArgs)
4519 {
4520 // fetch our effect pointer
4521 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4522
4523 // we can only be a general context effect, so check that this is true
4524 #ifdef OFX_EXTENSIONS_TUTTLE
4525 OFX::Log::error(effectInstance->getContext() != eContextGeneral &&
4526 effectInstance->getContext() != eContextReader &&
4527 effectInstance->getContext() != eContextGenerator, "Calling kOfxImageEffectActionGetTimeDomain on an effect that is not a 'general', 'reader' or 'generator' context effect.");
4528 #else
4529 OFX::Log::error(effectInstance->getContext() != eContextGeneral, "Calling kOfxImageEffectActionGetTimeDomain on an effect that is not a general context effect.");
4530 #endif
4531
4532 OfxRangeD timeDomain;
4533
4534 // and call the plugin client code
4535 bool v = effectInstance->getTimeDomain(timeDomain);
4536
4537 if(v) {
4538 outArgs.propSetDoubleN(kOfxImageEffectPropFrameRange, &timeDomain.min, 2);
4539 }
4540
4541 return v;
4542 }
4543
4544 #ifdef OFX_SUPPORTS_OPENGLRENDER
4545 /** @brief Library side context attached function */
4546 static
4547 void
contextAttachedAction(OfxImageEffectHandle handle,OFX::PropertySet & outArgs)4548 contextAttachedAction(OfxImageEffectHandle handle, OFX::PropertySet &outArgs)
4549 {
4550 // fetch our effect pointer
4551 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4552
4553 bool createContextData = false;
4554 #ifdef OFX_EXTENSIONS_NATRON
4555 createContextData = outArgs.propGetDimension(kNatronOfxImageEffectPropOpenGLContextData, false) > 0; // don't throw if the host does not support it
4556 #endif
4557
4558 // and call the plugin client code
4559 void* v = effectInstance->contextAttached(createContextData);
4560
4561 #ifdef OFX_EXTENSIONS_NATRON
4562 if(v) {
4563 outArgs.propSetPointer(kNatronOfxImageEffectPropOpenGLContextData, v, false); // don't throw if the host does not support it
4564 }
4565 #endif
4566 }
4567
4568 /** @brief Library side context attached function */
4569 static
4570 void
contextDetachedAction(OfxImageEffectHandle handle,OFX::PropertySet inArgs)4571 contextDetachedAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs)
4572 {
4573 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4574
4575 #ifdef OFX_EXTENSIONS_NATRON
4576 void* contextData = inArgs.propGetPointer(kNatronOfxImageEffectPropOpenGLContextData, false);
4577 #else
4578 void* contextData = NULL;
4579 #endif
4580
4581 // and call the plugin client code
4582 effectInstance->contextDetached(contextData);
4583 }
4584 #endif
4585
4586 /** @brief Library side get regions of interest function */
4587 static
4588 bool
clipPreferencesAction(OfxImageEffectHandle handle,OFX::PropertySet & outArgs,const char * plugname,unsigned int majorVersion,unsigned int minorVersion)4589 clipPreferencesAction(OfxImageEffectHandle handle, OFX::PropertySet &outArgs, const char* plugname, unsigned int majorVersion, unsigned int minorVersion)
4590 {
4591 // fetch our effect pointer
4592 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4593
4594 // set up our clip preferences setter
4595 OFX::Private::VersionIDKey key;
4596 key.id = plugname;
4597 key.majorVersion = majorVersion;
4598 key.minorVersion = minorVersion;
4599 ImageEffectDescriptor* desc = gEffectDescriptors[key][effectInstance->getContext()];
4600 ClipPreferencesSetter prefs(outArgs, desc->getClipDepthPropNames(), desc->getClipComponentPropNames(), desc->getClipPARPropNames());
4601
4602 // and call the plug-in client code
4603 effectInstance->getClipPreferences(prefs);
4604
4605 // did we do anything ?
4606 if(prefs.didSomething())
4607 return true;
4608 return false;
4609 }
4610
4611 /** @brief Library side begin instance changed action */
4612 static
4613 void
beginInstanceChangedAction(OfxImageEffectHandle handle,OFX::PropertySet inArgs)4614 beginInstanceChangedAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs)
4615 {
4616 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4617
4618 std::string reasonStr = inArgs.propGetString(kOfxPropChangeReason);
4619 InstanceChangeReason reason = mapToInstanceChangedReason(reasonStr);
4620
4621 // and call the plugin client code
4622 effectInstance->beginChanged(reason);
4623 }
4624
4625 /** @brief Library side instance changed action */
4626 static
4627 void
instanceChangedAction(OfxImageEffectHandle handle,OFX::PropertySet inArgs)4628 instanceChangedAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs)
4629 {
4630 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4631
4632 InstanceChangedArgs args;
4633
4634 // why did it change
4635 std::string reasonStr = inArgs.propGetString(kOfxPropChangeReason);
4636 args.reason = mapToInstanceChangedReason(reasonStr);
4637 args.time = inArgs.propGetDouble(kOfxPropTime);
4638 args.renderScale.x = args.renderScale.y = 1.;
4639 inArgs.propGetDoubleN(kOfxImageEffectPropRenderScale, &args.renderScale.x, 2);
4640
4641 // what changed
4642 std::string changedType = inArgs.propGetString(kOfxPropType);
4643 std::string changedName = inArgs.propGetString(kOfxPropName);
4644
4645 if(changedType == kOfxTypeParameter) {
4646 // and call the plugin client code
4647 effectInstance->changedParam(args, changedName);
4648 }
4649 else if(changedType == kOfxTypeClip) {
4650 // and call the plugin client code
4651 effectInstance->changedClip(args, changedName);
4652 }
4653 else {
4654 OFX::Log::error(true, "Instance Changed called with unknown type '%s' of object '%s'", changedType.c_str(), changedName.c_str());
4655 }
4656 }
4657
4658 /** @brief Library side end instance changed action */
4659 static
4660 void
endInstanceChangedAction(OfxImageEffectHandle handle,OFX::PropertySet inArgs)4661 endInstanceChangedAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs)
4662 {
4663 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4664
4665 std::string reasonStr = inArgs.propGetString(kOfxPropChangeReason);
4666 InstanceChangeReason reason = mapToInstanceChangedReason(reasonStr);
4667
4668 // and call the plugin client code
4669 effectInstance->endChanged(reason);
4670 }
4671
4672 #ifdef OFX_EXTENSIONS_VEGAS
4673 /** @brief Library side uplift vegas keyframe action */
4674 static
4675 void
upliftVegasKeyframeAction(OfxImageEffectHandle handle,OFX::PropertySet inArgs)4676 upliftVegasKeyframeAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs)
4677 {
4678 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4679
4680 SonyVegasUpliftArguments upliftArgs(inArgs);
4681
4682 upliftArgs.keyframeCount = inArgs.propGetDimension(kOfxPropVegasUpliftKeyframeData);
4683 upliftArgs.guidUplift = inArgs.propGetString(kOfxImageEffectPropVegasUpliftGUID);
4684
4685 upliftArgs.commonData = inArgs.propGetPointer(kOfxPropVegasUpliftData, false);
4686 upliftArgs.commonDataSize = inArgs.propGetInt(kOfxPropVegasUpliftDataLength, false);
4687
4688 // and call the plugin client code
4689 effectInstance->upliftVegasKeyframes(upliftArgs);
4690 }
4691
4692 /** @brief Library side invoke About function */
4693 static
4694 bool
invokeAbout(OfxImageEffectHandle handle,const char *)4695 invokeAbout(OfxImageEffectHandle handle, const char* /*plugname*/)
4696 {
4697 // fetch our effect pointer
4698 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4699
4700 // and call the plug-in client code
4701 return effectInstance->invokeAbout();
4702 }
4703
4704 /** @brief Library side invoke Help function */
4705 static
4706 bool
invokeHelp(OfxImageEffectHandle handle,const char *)4707 invokeHelp(OfxImageEffectHandle handle, const char* /*plugname*/)
4708 {
4709 // fetch our effect pointer
4710 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4711
4712 // and call the plug-in client code
4713 return effectInstance->invokeHelp();
4714 }
4715 #endif
4716 #ifdef OFX_EXTENSIONS_NUKE
4717
4718 static
4719 bool
getFrameViewsNeededAction(OfxImageEffectHandle handle,OFX::PropertySet inArgs,OFX::PropertySet & outArgs,const char * plugname,unsigned int majorVersion,unsigned int minorVersion)4720 getFrameViewsNeededAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs, OFX::PropertySet &outArgs, const char* plugname, unsigned int majorVersion, unsigned int minorVersion)
4721 {
4722 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4723 FrameViewsNeededArguments args;
4724 args.time = inArgs.propGetDouble(kOfxPropTime);
4725 args.view = inArgs.propGetInt(kFnOfxImageEffectPropView, 0, false);
4726
4727
4728 OFX::Private::VersionIDKey key;
4729 key.id = plugname;
4730 key.majorVersion = majorVersion;
4731 key.minorVersion = minorVersion;
4732 ImageEffectDescriptor* desc = gEffectDescriptors[key][effectInstance->getContext()];
4733 FrameViewsNeededSetter setter(outArgs,desc->getClipFrameViewsPropNames());
4734 effectInstance->getFrameViewsNeeded(args,setter);
4735 if (setter.setOutProperties()) {
4736 return true;
4737 }
4738 return false;
4739 }
4740
4741 static
4742 OfxStatus
getClipComponentsAction(OfxImageEffectHandle handle,OFX::PropertySet inArgs,OFX::PropertySet & outArgs,const char * plugname,unsigned int majorVersion,unsigned int minorVersion)4743 getClipComponentsAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs, OFX::PropertySet &outArgs, const char* plugname, unsigned int majorVersion, unsigned int minorVersion)
4744 {
4745 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4746 ClipComponentsArguments args;
4747 args.time = inArgs.propGetDouble(kOfxPropTime);
4748 args.view = inArgs.propGetInt(kFnOfxImageEffectPropView, 0, false);
4749
4750 OFX::Private::VersionIDKey key;
4751 key.id = plugname;
4752 key.majorVersion = majorVersion;
4753 key.minorVersion = minorVersion;
4754 ImageEffectDescriptor* desc = gEffectDescriptors[key][effectInstance->getContext()];
4755 ClipComponentsSetter setter(outArgs,desc->getClipPlanesPropNames());
4756 OfxStatus stat = effectInstance->getClipComponents(args,setter);
4757 if (!setter.setOutProperties()) {
4758 return kOfxStatReplyDefault;
4759 }
4760 return stat;
4761 }
4762
4763 /** @brief Action called in place of a render to recover a transform matrix from an effect. */
4764 static
4765 bool
getTransform(OfxImageEffectHandle handle,OFX::PropertySet inArgs,OFX::PropertySet & outArgs)4766 getTransform(OfxImageEffectHandle handle, OFX::PropertySet inArgs, OFX::PropertySet &outArgs)
4767 {
4768 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4769 TransformArguments args;
4770
4771 // get the arguments
4772 args.time = inArgs.propGetDouble(kOfxPropTime);
4773
4774 args.renderScale.x = args.renderScale.y = 1.;
4775 inArgs.propGetDoubleN(kOfxImageEffectPropRenderScale, &args.renderScale.x, 2);
4776
4777 // kOfxImageEffectPropRenderQualityDraft appeared in OFX 1.4
4778 args.renderQualityDraft = inArgs.propGetInt(kOfxImageEffectPropRenderQualityDraft, false) != 0;
4779
4780 args.renderView = inArgs.propGetInt(kFnOfxImageEffectPropView, 0, false);
4781
4782 std::string str = inArgs.propGetString(kOfxImageEffectPropFieldToRender);
4783 try {
4784 args.fieldToRender = eFieldBoth;
4785 args.fieldToRender = mapStrToFieldEnum(str);
4786 } catch (std::invalid_argument) {
4787 // dud field?
4788 OFX::Log::error(true, "Unknown field to render '%s'", str.c_str());
4789
4790 // HACK need to throw something to cause a failure
4791 }
4792
4793 // and call the plugin client getTransform code
4794 Clip *transformClip = 0;
4795 double transformMatrix[9];
4796 bool v = effectInstance->getTransform(args, transformClip, transformMatrix);
4797
4798 if(v && transformClip) {
4799 outArgs.propSetString(kOfxPropName, transformClip->name());
4800 outArgs.propSetDoubleN(kFnOfxPropMatrix2D, transformMatrix, 9);
4801 return true; // the transfrom and clip name were set and can be used to modify the named image appropriately
4802 }
4803 return false; // don't attempt to use the transform matrix, but render the image as per normal
4804 }
4805 #endif
4806
4807 #ifdef OFX_EXTENSIONS_NATRON
4808 /** @brief Action called in place of a render to recover a distortion function from an effect. */
4809 static
4810 bool
getInverseDistortion(OfxImageEffectHandle handle,OFX::PropertySet inArgs,OFX::PropertySet & outArgs)4811 getInverseDistortion(OfxImageEffectHandle handle, OFX::PropertySet inArgs, OFX::PropertySet &outArgs)
4812 {
4813 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
4814 DistortionArguments args;
4815
4816 // get the arguments
4817 args.time = inArgs.propGetDouble(kOfxPropTime);
4818
4819 args.renderScale.x = args.renderScale.y = 1.;
4820 inArgs.propGetDoubleN(kOfxImageEffectPropRenderScale, &args.renderScale.x, 2);
4821
4822 // kOfxImageEffectPropRenderQualityDraft appeared in OFX 1.4
4823 args.renderQualityDraft = inArgs.propGetInt(kOfxImageEffectPropRenderQualityDraft, false) != 0;
4824
4825 args.renderView = inArgs.propGetInt(kFnOfxImageEffectPropView, 0, false);
4826
4827 std::string str = inArgs.propGetString(kOfxImageEffectPropFieldToRender);
4828 try {
4829 args.fieldToRender = eFieldBoth;
4830 args.fieldToRender = mapStrToFieldEnum(str);
4831 } catch (std::invalid_argument) {
4832 // dud field?
4833 OFX::Log::error(true, "Unknown field to render '%s'", str.c_str());
4834
4835 // HACK need to throw something to cause a failure
4836 }
4837
4838 // and call the plugin client getTransform code
4839 Clip *transformClip = 0;
4840 double transformMatrix[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1};
4841 if ( effectInstance->getCanDistort() ) {
4842 OfxInverseDistortionFunctionV1 distortionFunc = NULL;
4843 void* distortionFunctionData = NULL;
4844 int distortionFunctionDataSize = 0;
4845 OfxInverseDistortionDataFreeFunctionV1 freeDataFunction = NULL;
4846 bool v = effectInstance->getInverseDistortion(args, transformClip, transformMatrix, &distortionFunc, &distortionFunctionData, &distortionFunctionDataSize, &freeDataFunction);
4847
4848 if(v && transformClip) {
4849 outArgs.propSetString(kOfxPropName, transformClip->name());
4850 if (distortionFunc == NULL) {
4851 outArgs.propSetDoubleN(kOfxPropMatrix3x3, transformMatrix, 9);
4852 } else {
4853 outArgs.propSetPointer(kOfxPropInverseDistortionFunction, (void*)distortionFunc);
4854 outArgs.propSetPointer(kOfxPropInverseDistortionFunctionData, distortionFunctionData);
4855 outArgs.propSetInt(kOfxPropInverseDistortionFunctionDataSize, distortionFunctionDataSize);
4856 outArgs.propSetPointer(kOfxPropInverseDistortionDataFreeFunction, (void*)freeDataFunction);
4857 }
4858 return true; // the transfrom and clip name were set and can be used to modify the named image appropriately
4859 }
4860 } else {
4861 // effect can not distort, maybe it can transform?
4862
4863 TransformArguments argsTransform = {
4864 args.time,
4865 args.renderScale,
4866 args.fieldToRender,
4867 args.renderQualityDraft,
4868 args.renderView
4869 };
4870
4871 // get the transform in pixel coords using the legacy getTransform function, then convert it to canonical coords
4872 bool v = effectInstance->getTransform(argsTransform, transformClip, transformMatrix);
4873
4874 if(v && transformClip) {
4875 outArgs.propSetString(kOfxPropName, transformClip->name());
4876 // transform from pixel to canonical
4877 double par = transformClip->getPixelAspectRatio();
4878 const bool fielded = args.fieldToRender == eFieldLower || args.fieldToRender == eFieldUpper;
4879 // FS = fielded ? 0.5 : 1.
4880 // canonical to pixel:
4881 // X' = (X * SX)/PAR -> multiply first column by SX/PAR
4882 // Y' = Y * SY * FS -> multiply second column by SY*FS
4883 // pixel to canonical:
4884 // X' = (X * PAR)/SX -> divide first line by SX/PAR
4885 // Y' = Y/(SY * FS) -> divide second line by SY*FS
4886 double fx = args.renderScale.x / par;
4887 double fy = args.renderScale.y * (fielded ? 0.5 : 1.);
4888 //transformMatrix[0] *= 1.;
4889 transformMatrix[1] *= fy/fx;
4890 transformMatrix[2] *= 1./fx;
4891 transformMatrix[3] *= fx/fy;
4892 //transformMatrix[4] *= 1.;
4893 transformMatrix[5] *= 1./fy;
4894 transformMatrix[6] *= fx;
4895 transformMatrix[7] *= fy;
4896 //transformMatrix[8] *= 1.;
4897
4898 outArgs.propSetDoubleN(kOfxPropMatrix3x3, transformMatrix, 9);
4899 return true; // the transfrom and clip name were set and can be used to modify the named image appropriately
4900 }
4901 }
4902 return false; // don't attempt to use the distortion function, but render the image as per normal
4903 }
4904 #endif
4905
4906 /** @brief The main entry point for the plugin
4907 */
mainEntryStr(const char * actionRaw,const void * handleRaw,OfxPropertySetHandle inArgsRaw,OfxPropertySetHandle outArgsRaw,const char * plugname)4908 OfxStatus mainEntryStr(const char *actionRaw,
4909 const void *handleRaw,
4910 OfxPropertySetHandle inArgsRaw,
4911 OfxPropertySetHandle outArgsRaw,
4912 const char* plugname)
4913 {
4914 OFX::Log::print("********************************************************************************");
4915 OFX::Log::print("START mainEntry (%s)", actionRaw);
4916 OFX::Log::indent();
4917 OfxStatus stat = kOfxStatReplyDefault;
4918 try {
4919
4920 OfxPlugInfoMap::iterator it = plugInfoMap.find(plugname);
4921 if(it==plugInfoMap.end())
4922 throw;
4923
4924 OFX::PluginFactory* factory = it->second._factory;
4925
4926 // Cast the raw handle to be an image effect handle, because that is what it is
4927 OfxImageEffectHandle handle = (OfxImageEffectHandle) handleRaw;
4928
4929 // Turn the arguments into wrapper objects to make our lives easier
4930 OFX::PropertySet inArgs(inArgsRaw);
4931 OFX::PropertySet outArgs(outArgsRaw);
4932
4933 // turn the action into a std::string
4934 std::string action(actionRaw);
4935
4936 // figure the actions
4937 if (action == kOfxActionLoad) {
4938 // call the support load function, param-less
4939 OFX::Private::loadAction();
4940
4941 // call the plugin side load action, param-less
4942 factory->load();
4943
4944 // got here, must be good
4945 stat = kOfxStatOK;
4946 }
4947
4948 // figure the actions
4949 else if (action == kOfxActionUnload) {
4950 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, true, true, true);
4951
4952 // call the plugin side unload action, param-less, should be called, eve if the stat above failed!
4953 factory->unload();
4954
4955 // call the support unload function, param-less
4956 OFX::Private::unloadAction(plugname, it->second._plug->pluginVersionMajor, it->second._plug->pluginVersionMinor);
4957
4958 // got here, must be good
4959 stat = kOfxStatOK;
4960 }
4961
4962 else if(action == kOfxActionDescribe) {
4963 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true);
4964
4965 // make the plugin descriptor
4966 ImageEffectDescriptor *desc = new ImageEffectDescriptor(handle);
4967
4968 // validate the host
4969 OFX::Validation::validatePluginDescriptorProperties(fetchEffectProps(handle));
4970
4971 // and pass it to the plugin to do something with it
4972
4973 factory->describe(*desc);
4974
4975 // add it to our map
4976 OFX::Private::VersionIDKey key;
4977 key.id = it->first;
4978 key.majorVersion = it->second._plug->pluginVersionMajor;
4979 key.minorVersion = it->second._plug->pluginVersionMinor;
4980 EffectDescriptorMap::iterator it = gEffectDescriptors.find(key);
4981 if (it != gEffectDescriptors.end()) {
4982 EffectContextMap& contextMap = it->second;
4983 EffectContextMap::iterator it2 = contextMap.find(eContextNone);
4984 if (it2 != contextMap.end()) {
4985 delete it2->second;
4986 }
4987 }
4988 gEffectDescriptors[key][eContextNone] = desc;
4989
4990 // got here, must be good
4991 stat = kOfxStatOK;
4992 }
4993 else if(action == kOfxImageEffectActionDescribeInContext) {
4994 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true);
4995
4996 // make the plugin descriptor and pass it to the plugin to do something with it
4997 ImageEffectDescriptor *desc = new ImageEffectDescriptor(handle);
4998
4999 // figure the context and map it to an enum
5000 std::string contextStr = inArgs.propGetString(kOfxImageEffectPropContext);
5001 ContextEnum context = mapToContextEnum(contextStr);
5002
5003 // validate the host
5004 OFX::Validation::validatePluginDescriptorProperties(fetchEffectProps(handle));
5005
5006 // call plugin describe in context
5007 factory->describeInContext(*desc, context);
5008
5009 // add it to our map
5010 OFX::Private::VersionIDKey key;
5011 key.id = it->first;
5012 key.majorVersion = it->second._plug->pluginVersionMajor;
5013 key.minorVersion = it->second._plug->pluginVersionMinor;
5014 EffectDescriptorMap::iterator it = gEffectDescriptors.find(key);
5015 if (it != gEffectDescriptors.end()) {
5016 EffectContextMap& contextMap = it->second;
5017 EffectContextMap::iterator it2 = contextMap.find(context);
5018 if (it2 != contextMap.end()) {
5019 delete it2->second;
5020 }
5021 }
5022 gEffectDescriptors[key][context] = desc;
5023
5024 // got here, must be good
5025 stat = kOfxStatOK;
5026 }
5027 else if(action == kOfxActionCreateInstance) {
5028 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true);
5029
5030 // fetch the effect props to figure the context
5031 PropertySet effectProps = fetchEffectProps(handle);
5032
5033 // get the context and turn it into an enum
5034 std::string str = effectProps.propGetString(kOfxImageEffectPropContext);
5035 ContextEnum context = mapToContextEnum(str);
5036
5037 // make the image effect instance for this context
5038 ImageEffect *instance = factory->createInstance(handle, context);
5039 (void)instance;
5040
5041 // validate the plugin handle's properties
5042 OFX::Validation::validatePluginInstanceProperties(fetchEffectProps(handle));
5043
5044 // got here, must be good
5045 stat = kOfxStatOK;
5046 }
5047 else if(action == kOfxActionDestroyInstance) {
5048 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true);
5049
5050 // fetch our pointer out of the props on the handle
5051 ImageEffect *instance = retrieveImageEffectPointer(handle);
5052
5053 // kill it
5054 delete instance;
5055
5056 // got here, must be good
5057 stat = kOfxStatOK;
5058 }
5059 else if(action == kOfxImageEffectActionRender) {
5060 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true);
5061
5062 // call the render action skin
5063 renderAction(handle, inArgs);
5064
5065 // got here, must be good
5066 stat = kOfxStatOK;
5067 }
5068 else if(action == kOfxImageEffectActionBeginSequenceRender) {
5069 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true);
5070
5071 // call the begin render action skin
5072 beginSequenceRenderAction(handle, inArgs);
5073 }
5074 else if(action == kOfxImageEffectActionEndSequenceRender) {
5075 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true);
5076
5077 // call the begin render action skin
5078 endSequenceRenderAction(handle, inArgs);
5079 }
5080 else if(action == kOfxImageEffectActionIsIdentity) {
5081 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, false);
5082
5083 // call the identity action, if it is, return OK
5084 if(isIdentityAction(handle, inArgs, outArgs))
5085 stat = kOfxStatOK;
5086 }
5087 else if(action == kOfxImageEffectActionGetRegionOfDefinition) {
5088 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, false);
5089
5090 // call the rod action, return OK if it does something
5091 if(regionOfDefinitionAction(handle, inArgs, outArgs))
5092 stat = kOfxStatOK;
5093 }
5094 else if(action == kOfxImageEffectActionGetRegionsOfInterest) {
5095 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, false);
5096
5097 // call the RoI action, return OK if it does something
5098 if(regionsOfInterestAction(handle, inArgs, outArgs, plugname, it->second._plug->pluginVersionMajor, it->second._plug->pluginVersionMinor))
5099 stat = kOfxStatOK;
5100 }
5101 else if(action == kOfxImageEffectActionGetFramesNeeded) {
5102 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, false);
5103
5104 // call the frames needed action, return OK if it does something
5105 if(framesNeededAction(handle, inArgs, outArgs, plugname, it->second._plug->pluginVersionMajor, it->second._plug->pluginVersionMinor))
5106 stat = kOfxStatOK;
5107 }
5108 else if(action == kOfxImageEffectActionGetClipPreferences) {
5109 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, false);
5110
5111 // call the frames needed action, return OK if it does something
5112 if(clipPreferencesAction(handle, outArgs, plugname, it->second._plug->pluginVersionMajor, it->second._plug->pluginVersionMinor))
5113 stat = kOfxStatOK;
5114 }
5115 else if(action == kOfxActionPurgeCaches) {
5116 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true);
5117
5118 // fetch our pointer out of the props on the handle
5119 ImageEffect *instance = retrieveImageEffectPointer(handle);
5120
5121 // purge 'em
5122 instance->purgeCaches();
5123 }
5124 else if(action == kOfxActionSyncPrivateData) {
5125 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true);
5126
5127 // fetch our pointer out of the props on the handle
5128 ImageEffect *instance = retrieveImageEffectPointer(handle);
5129
5130 // and sync it
5131 instance->syncPrivateData();
5132 }
5133 else if(action == kOfxImageEffectActionGetTimeDomain) {
5134 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, false);
5135
5136 // call the get time domain action
5137 if(getTimeDomainAction(handle, outArgs))
5138 stat = kOfxStatOK;
5139 }
5140 else if(action == kOfxActionBeginInstanceChanged) {
5141 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true);
5142
5143 // call the begin instance changed action
5144 beginInstanceChangedAction(handle, inArgs);
5145 }
5146 else if(action == kOfxActionInstanceChanged) {
5147 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true);
5148
5149 // call the instance changed action
5150 instanceChangedAction(handle, inArgs);
5151 }
5152 else if(action == kOfxActionEndInstanceChanged) {
5153 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true);
5154
5155 // call the end instance changed action
5156 endInstanceChangedAction(handle, inArgs);
5157 }
5158 else if(action == kOfxActionBeginInstanceEdit) {
5159 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true);
5160
5161 // fetch our pointer out of the props on the handle
5162 ImageEffect *instance = retrieveImageEffectPointer(handle);
5163
5164 // call the begin edit function
5165 instance->beginEdit();
5166 }
5167 else if(action == kOfxActionEndInstanceEdit) {
5168 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true);
5169
5170 // fetch our pointer out of the props on the handle
5171 ImageEffect *instance = retrieveImageEffectPointer(handle);
5172
5173 // call the end edit function
5174 instance->endEdit();
5175 }
5176 #ifdef OFX_SUPPORTS_OPENGLRENDER
5177 else if(action == kOfxActionOpenGLContextAttached) {
5178 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true);
5179
5180 // call the context attached action
5181 contextAttachedAction(handle, outArgs);
5182 }
5183 else if(action == kOfxActionOpenGLContextDetached) {
5184 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true);
5185
5186 // call the context detached action
5187 contextDetachedAction(handle, inArgs);
5188 }
5189 #endif
5190 #ifdef OFX_SUPPORTS_DIALOG
5191 else if(action == kOfxActionDialog) {
5192 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true);
5193
5194 // fetch our pointer out of the props on the handle
5195 ImageEffect *instance = retrieveImageEffectPointer(handle);
5196
5197 void* instanceData = inArgs.propGetPointer(kOfxPropInstanceData);
5198
5199 // need to throw something here
5200 if (!instanceData) {
5201 throwSuiteStatusException(kOfxStatErrBadHandle);
5202 }
5203 // call the dialog action (user_data is in the raw handle)
5204 instance->dialog(instanceData);
5205 }
5206 #endif
5207 #ifdef OFX_EXTENSIONS_VEGAS
5208 else if(action == kOfxImageEffectActionVegasKeyframeUplift) {
5209 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true);
5210
5211 // call the uplift vegas keyframes function
5212 upliftVegasKeyframeAction(handle, inArgs);
5213 }
5214 else if(action == kOfxImageEffectActionInvokeHelp) {
5215 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true);
5216
5217 // call the invoke help function
5218 if(invokeHelp(handle, plugname))
5219 stat = kOfxStatOK;
5220 }
5221 else if(action == kOfxImageEffectActionInvokeAbout) {
5222 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true);
5223
5224 // call the invoke help function
5225 if(invokeAbout(handle, plugname))
5226 stat = kOfxStatOK;
5227 }
5228 #endif
5229 #ifdef OFX_EXTENSIONS_NUKE
5230 else if(action == kFnOfxImageEffectActionGetClipComponents) {
5231 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, false);
5232
5233 // call the clip components function, return OK if it does something
5234 // the spec is not clear as to whether it is allowed to do nothing but
5235 // this action should always be implemented for multi-planes effects.
5236 stat = getClipComponentsAction(handle, inArgs, outArgs, plugname, it->second._plug->pluginVersionMajor, it->second._plug->pluginVersionMinor);
5237 }
5238 else if(action == kFnOfxImageEffectActionGetFrameViewsNeeded) {
5239 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, false);
5240
5241 // call the frames views needed action, return OK if it does something
5242 if (getFrameViewsNeededAction(handle, inArgs, outArgs, plugname, it->second._plug->pluginVersionMajor, it->second._plug->pluginVersionMinor)) {
5243 stat = kOfxStatOK;
5244 }
5245 }
5246 else if(action == kFnOfxImageEffectActionGetTransform) {
5247 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, false);
5248
5249 // call the get transform function
5250 if(getTransform(handle, inArgs, outArgs))
5251 stat = kOfxStatOK;
5252 }
5253 #endif
5254 #ifdef OFX_EXTENSIONS_NATRON
5255 else if(action == kOfxImageEffectActionGetInverseDistortion) {
5256 checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, false);
5257
5258 // call the get transform function
5259 if(getInverseDistortion(handle, inArgs, outArgs))
5260 stat = kOfxStatOK;
5261 }
5262 #endif
5263
5264 else if(actionRaw) {
5265 OFX::Log::error(true, "Unknown action '%s'.", actionRaw);
5266 }
5267 else {
5268 OFX::Log::error(true, "Requested action was a null pointer.");
5269 }
5270 }
5271
5272 // catch suite exceptions
5273 catch (const OFX::Exception::Suite &ex)
5274 {
5275 # ifdef DEBUG
5276 std::cout << "Caught OFX::Exception::Suite: " << ex.what() << std::endl;
5277 # endif
5278 stat = ex.status();
5279 }
5280
5281 // catch host inadequate exceptions
5282 catch (const OFX::Exception::HostInadequate &e)
5283 {
5284 # ifdef DEBUG
5285 std::cout << "Caught OFX::Exception::HostInadequate: " << e.what() << std::endl;
5286 # endif
5287 unused(e);
5288 stat = kOfxStatErrMissingHostFeature;
5289 }
5290
5291 // catch exception due to a property being unknown to the host, implies something wrong with host if not caught further down
5292 catch (const OFX::Exception::PropertyUnknownToHost &e)
5293 {
5294 # ifdef DEBUG
5295 std::cout << "Caught OFX::Exception::PropertyUnknownToHost: " << e.what() << std::endl;
5296 # endif
5297 unused(e);
5298 stat = kOfxStatErrMissingHostFeature;
5299 }
5300
5301 // catch memory
5302 catch (std::bad_alloc)
5303 {
5304 stat = kOfxStatErrMemory;
5305 }
5306
5307 // catch a custom client exception, if defined
5308 #ifdef OFX_CLIENT_EXCEPTION_TYPE
5309 catch (OFX_CLIENT_EXCEPTION_TYPE &ex)
5310 {
5311 stat = OFX_CLIENT_EXCEPTION_HANDLER(ex, plugname);
5312 }
5313 #endif
5314 // Catch anything else, unknown
5315 catch (const std::exception &e)
5316 {
5317 # ifdef DEBUG
5318 std::cout << "Caught exception: " << e.what() << std::endl;
5319 # endif
5320 unused(e);
5321 stat = kOfxStatFailed;
5322 }
5323 catch (...)
5324 {
5325 # ifdef DEBUG
5326 std::cout << "Caught Unknown exception" << std::endl;
5327 # endif
5328 stat = kOfxStatFailed;
5329 }
5330
5331 OFX::Log::outdent();
5332 OFX::Log::print("STOP mainEntry (%s)\n", actionRaw);
5333 return stat;
5334 }
5335
5336
customParamInterpolationV1Entry(const void * handleRaw,OfxPropertySetHandle inArgsRaw,OfxPropertySetHandle outArgsRaw)5337 OfxStatus customParamInterpolationV1Entry(
5338 const void* handleRaw,
5339 OfxPropertySetHandle inArgsRaw,
5340 OfxPropertySetHandle outArgsRaw)
5341 {
5342 OFX::Log::print("********************************************************************************");
5343 OFX::Log::print("START customParamInterpolationV1Entry");
5344 OFX::Log::indent();
5345 OfxStatus stat = kOfxStatReplyDefault;
5346 try {
5347 // Cast the raw handle to be an image effect handle, because that is what it is
5348 OfxImageEffectHandle handle = (OfxImageEffectHandle) handleRaw;
5349
5350 // Turn the arguments into wrapper objects to make our lives easier
5351 OFX::PropertySet inArgs(inArgsRaw);
5352 OFX::PropertySet outArgs(outArgsRaw);
5353
5354 ImageEffect *effectInstance = retrieveImageEffectPointer(handle);
5355
5356 InterpolateCustomArgs interpArgs;
5357
5358 interpArgs.time = inArgs.propGetDouble(kOfxPropTime);
5359 interpArgs.value1 = inArgs.propGetString(kOfxParamPropCustomValue, 0);
5360 interpArgs.value2 = inArgs.propGetString(kOfxParamPropCustomValue, 1);
5361 interpArgs.keytime1 = inArgs.propGetDouble(kOfxParamPropInterpolationTime, 0);
5362 interpArgs.keytime2 = inArgs.propGetDouble(kOfxParamPropInterpolationTime, 1);
5363 interpArgs.amount = inArgs.propGetDouble(kOfxParamPropInterpolationAmount);
5364
5365 std::string paramName = inArgs.propGetString(kOfxPropName);
5366
5367 // and call the plugin client code
5368 std::string output = effectInstance->interpolateCustomParam(interpArgs, paramName);
5369
5370 outArgs.propSetString(kOfxParamPropCustomValue, output);
5371 }
5372
5373 // catch suite exceptions
5374 catch (OFX::Exception::Suite &ex)
5375 {
5376 # ifdef DEBUG
5377 std::cout << "Caught OFX::Exception::Suite" << std::endl;
5378 # endif
5379 stat = ex.status();
5380 }
5381
5382 // catch host inadequate exceptions
5383 catch (OFX::Exception::HostInadequate)
5384 {
5385 # ifdef DEBUG
5386 std::cout << "Caught OFX::Exception::HostInadequate" << std::endl;
5387 # endif
5388 stat = kOfxStatErrMissingHostFeature;
5389 }
5390
5391 // catch exception due to a property being unknown to the host, implies something wrong with host if not caught further down
5392 catch (OFX::Exception::PropertyUnknownToHost)
5393 {
5394 # ifdef DEBUG
5395 std::cout << "Caught OFX::Exception::PropertyUnknownToHost" << std::endl;
5396 # endif
5397 stat = kOfxStatErrMissingHostFeature;
5398 }
5399
5400 // catch memory
5401 catch (std::bad_alloc)
5402 {
5403 stat = kOfxStatErrMemory;
5404 }
5405
5406 // catch a custom client exception, if defined
5407 #ifdef OFX_CLIENT_EXCEPTION_TYPE
5408 catch (OFX_CLIENT_EXCEPTION_TYPE &ex)
5409 {
5410 stat = OFX_CLIENT_EXCEPTION_HANDLER(ex, plugname);
5411 }
5412 #endif
5413 // Catch anything else, unknown
5414 catch (...)
5415 {
5416 # ifdef DEBUG
5417 std::cout << "Caught Unknown exception" << std::endl;
5418 # endif
5419 stat = kOfxStatFailed;
5420 }
5421
5422 OFX::Log::outdent();
5423 OFX::Log::print("STOP customParamInterpolationV1Entry\n");
5424 return stat;
5425 }
5426
5427 /** @brief The plugin function that gets passed the host structure. */
setHost(OfxHost * host)5428 void setHost(OfxHost *host)
5429 {
5430 gHost = host;
5431 }
5432
5433 }; // namespace Private
5434
5435 /** @brief Fetch's a suite from the host and logs errors */
fetchSuite(const char * suiteName,int suiteVersion,bool optional)5436 const void * fetchSuite(const char *suiteName, int suiteVersion, bool optional)
5437 {
5438 const void *suite = Private::gHost->fetchSuite(Private::gHost->host, suiteName, suiteVersion);
5439 if(suite==0)
5440 {
5441 if(optional)
5442 OFX::Log::warning(suite == 0, "Could not fetch the optional suite '%s' version %d.", suiteName, suiteVersion);
5443 else
5444 OFX::Log::error(suite == 0, "Could not fetch the mandatory suite '%s' version %d.", suiteName, suiteVersion);
5445 }
5446 if(!optional && suite == 0) throw OFX::Exception::HostInadequate(suiteName);
5447 return suite;
5448 }
5449
5450 #ifndef OFXS_MANUAL_REGISTRATION
5451 ////////////////////////////////////////////////////////////////////////////////
5452 /** @brief The OFX::Plugin namespace. All the functions in here needs to be defined by each plugin that uses the support libs.
5453 */
5454 namespace Plugin {
5455 /** @brief Plugin side function used to identify the plugin to the support library.
5456
5457 This was obsoleted by automatic plugin registration, using the macro mRegisterPluginFactoryInstance:
5458 static BasicExamplePluginFactory p("net.sf.openfx.basicPlugin", 1, 0);
5459 mRegisterPluginFactoryInstance(p)
5460 */
getPluginIDs(OFX::PluginFactoryArray &)5461 void getPluginIDs(OFX::PluginFactoryArray &/*id*/)
5462 {
5463 // an empty definition is enough to prevent old code from compiling.
5464 }
5465 };
5466 #endif // OFXS_MANUAL_REGISTRATION
5467 }; // namespace OFX
5468
5469 static
generatePlugInfo(OFX::PluginFactory * factory,std::string & newID)5470 OFX::OfxPlugInfo generatePlugInfo(OFX::PluginFactory* factory, std::string& newID)
5471 {
5472 validateXMLString(factory->getID(), true);
5473 newID = factory->getUID();
5474 OFX::auto_ptr<OfxPlugin> ofxPlugin(new OfxPlugin());
5475 ofxPlugin->pluginApi = kOfxImageEffectPluginApi;
5476 ofxPlugin->apiVersion = 1;
5477 ofxPlugin->pluginIdentifier = factory->getID().c_str();
5478 ofxPlugin->pluginVersionMajor = factory->getMajorVersion();
5479 ofxPlugin->pluginVersionMinor = factory->getMinorVersion();
5480 ofxPlugin->setHost = OFX::Private::setHost;
5481 ofxPlugin->mainEntry = factory->getMainEntry();
5482 return OFX::OfxPlugInfo(factory, ofxPlugin.release());
5483 }
5484
5485 bool gHasInit = false;
5486
5487 static
init()5488 void init()
5489 {
5490 if(gHasInit)
5491 return;
5492
5493 #ifdef OFXS_MANUAL_REGISTRATION
5494 // Call OFX::Plugin::getPluginIDs if the plugin uses manual plugin registration.
5495 // Note that manual registration was obsoleted by automatic registratic using mRegisterPluginFactoryInstance().
5496 OFX::Plugin::getPluginIDs(OFX::PluginFactories::plugIDs());
5497 #endif // OFXS_MANUAL_REGISTRATION
5498 const OFX::PluginFactoryArray& plugIDs = OFX::PluginFactories::plugIDs();
5499 if(OFX::ofxPlugs.empty())
5500 OFX::ofxPlugs.resize(plugIDs.size());
5501
5502 int counter = 0;
5503 for (OFX::PluginFactoryArray::const_iterator it = plugIDs.begin(); it != plugIDs.end(); ++it, ++counter)
5504 {
5505 std::string newID;
5506 OFX::OfxPlugInfo info = generatePlugInfo(*it, newID);
5507 OFX::plugInfoMap[newID] = info;
5508 OFX::ofxPlugs[counter] = info._plug;
5509 }
5510 gHasInit = true;
5511 }
5512
5513 /** @brief, mandated function returning the number of plugins, which is always 1 */
OfxGetNumberOfPlugins(void)5514 EXPORT int OfxGetNumberOfPlugins(void)
5515 {
5516 init();
5517 return (int)OFX::PluginFactories::plugIDs().size();
5518 }
5519
5520 /** @brief, mandated function returning the nth plugin
5521
5522 We call the plugin side defined OFX::Plugin::getPluginIDs function to find out what to set.
5523 */
5524
OfxGetPlugin(int nth)5525 EXPORT OfxPlugin* OfxGetPlugin(int nth)
5526 {
5527 init();
5528 int numPlugs = (int)OFX::plugInfoMap.size();
5529 OFX::Log::error(nth >= numPlugs, "Host attempted to get plugin %d, when there is only %d plugin(s), so it should have asked for 0.", nth, numPlugs);
5530 if(OFX::ofxPlugs[nth] == 0)
5531 {
5532 std::string newID;
5533 OFX::OfxPlugInfo info = generatePlugInfo(OFX::PluginFactories::plugIDs()[nth], newID);
5534 OFX::plugInfoMap[newID] = info;
5535 OFX::ofxPlugs[nth] = info._plug;
5536 }
5537 return OFX::ofxPlugs[nth];
5538 }
5539