1 /* ***** BEGIN LICENSE BLOCK *****
2 * This file is part of openfx-misc <https://github.com/devernay/openfx-misc>,
3 * Copyright (C) 2013-2018 INRIA
4 *
5 * openfx-misc is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * openfx-misc is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with openfx-misc. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>
17 * ***** END LICENSE BLOCK ***** */
18
19 /*
20 * OFX TestGroups plugin.
21 */
22
23 #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
24 #include <windows.h>
25 #endif
26
27 #include <sstream> // stringstream
28
29 #include "ofxsImageEffect.h"
30 #include "ofxsThreadSuite.h"
31 #include "ofxsMultiThread.h"
32
33 #include "ofxsProcessing.H"
34 #include "ofxsMaskMix.h"
35 #include "ofxsCoords.h"
36 #include "ofxsCopier.h"
37 #include "ofxsMacros.h"
38
39 using namespace OFX;
40
41 OFXS_NAMESPACE_ANONYMOUS_ENTER
42
43 #define kPluginName "TestGroupsOFX"
44 #define kPluginGrouping "Other/Test"
45 #define kPluginDescription \
46 "Test parameter groups. See https://github.com/MrKepzie/Natron/issues/521"
47
48 #define kPluginIdentifier "net.sf.openfx.TestGroups"
49 #define kPluginVersionMajor 1 // Incrementing this number means that you have broken backwards compatibility of the plug-in.
50 #define kPluginVersionMinor 0 // Increment this when you have fixed a bug or made it faster.
51
52 #define kSupportsMultipleClipPARs false
53 #define kSupportsMultipleClipDepths false
54
55 #define kParamColor0 "color0"
56 #define kParamColor0Label "Color 0"
57
58 #define kParamTestButton "testButton"
59 #define kParamTestButtonLabel "Click me!"
60
61 #define kParamLabelString "labelString"
62 #define kParamDouble2 "double2"
63
64 #define kParamClipInfo "clipInfo"
65 #define kParamClipInfoLabel "Clip Info..."
66 #define kParamClipInfoHint "Display information about the inputs"
67
68 #define kParamForceCopy "forceCopy"
69 #define kParamForceCopyLabel "Force Copy"
70 #define kParamForceCopyHint "Force copy from input to output"
71
72 // test setting double param properties on the instance
73 #define kParamDoubleTest "doubleTest"
74 #define kParamDoubleTestLabel "doubleTestLabel"
75 #define kParamDoubleTestHint "doubleTestHint"
76 #define kParamDoubleTestDefault "doubleTestDefault"
77 #define kParamDoubleTestMin "doubleTestMin"
78 #define kParamDoubleTestMax "doubleTestMax"
79 #define kParamDoubleTestDisplayMin "doubleTestDisplayMin"
80 #define kParamDoubleTestDisplayMax "doubleTestDisplayMax"
81 #define kParamOptionalClipLabel "optionalClipLabel"
82 #define kParamOptionalClipHint "optionalClipHint"
83
84 #define kClipOptional "optional"
85 #define kClipOptionalLabel "Optional Clip"
86
87 ////////////////////////////////////////////////////////////////////////////////
88 /** @brief The plugin that does our work */
89 class TestGroupsPlugin
90 : public ImageEffect
91 {
92 public:
93 /** @brief ctor */
TestGroupsPlugin(OfxImageEffectHandle handle)94 TestGroupsPlugin(OfxImageEffectHandle handle)
95 : ImageEffect(handle)
96 , _dstClip(NULL)
97 , _srcClip(NULL)
98 , _optionalClip(NULL)
99 , _maskClip(NULL)
100 , _testButton(NULL)
101 , _labelString(NULL)
102 , _double2(NULL)
103 {
104 _dstClip = fetchClip(kOfxImageEffectOutputClipName);
105 assert( _dstClip && (!_dstClip->isConnected() || _dstClip->getPixelComponents() == ePixelComponentRGB ||
106 _dstClip->getPixelComponents() == ePixelComponentRGBA ||
107 _dstClip->getPixelComponents() == ePixelComponentAlpha) );
108 _srcClip = getContext() == eContextGenerator ? NULL : fetchClip(kOfxImageEffectSimpleSourceClipName);
109 assert( (!_srcClip && getContext() == eContextGenerator) ||
110 ( _srcClip && (!_srcClip->isConnected() || _srcClip->getPixelComponents() == ePixelComponentRGB ||
111 _srcClip->getPixelComponents() == ePixelComponentRGBA ||
112 _srcClip->getPixelComponents() == ePixelComponentAlpha) ) );
113 _optionalClip = fetchClip(kClipOptional);
114 _maskClip = fetchClip(getContext() == eContextPaint ? "Brush" : "Mask");
115 assert(!_maskClip || !_maskClip->isConnected() || _maskClip->getPixelComponents() == ePixelComponentAlpha);
116
117 _color = fetchRGBAParam(kParamColor0);
118 assert(_color);
119
120 _forceCopy = fetchBooleanParam(kParamForceCopy);
121 assert(_forceCopy);
122
123 _mix = fetchDoubleParam(kParamMix);
124 _maskApply = ( ofxsMaskIsAlwaysConnected( OFX::getImageEffectHostDescription() ) && paramExists(kParamMaskApply) ) ? fetchBooleanParam(kParamMaskApply) : 0;
125 _maskInvert = fetchBooleanParam(kParamMaskInvert);
126 assert(_mix && _maskInvert);
127
128 _testButton = fetchPushButtonParam(kParamTestButton);
129 _labelString = fetchStringParam(kParamLabelString);
130 _double2 = fetchDoubleParam(kParamDouble2);
131 _doubleTest = fetchDoubleParam(kParamDoubleTest);
132 _doubleTestLabel = fetchStringParam(kParamDoubleTestLabel);
133 _doubleTestHint = fetchStringParam(kParamDoubleTestHint);
134 _doubleTestDefault = fetchDoubleParam(kParamDoubleTestDefault);
135 _doubleTestMin = fetchDoubleParam(kParamDoubleTestMin);
136 _doubleTestMax = fetchDoubleParam(kParamDoubleTestMax);
137 _doubleTestDisplayMin = fetchDoubleParam(kParamDoubleTestDisplayMin);
138 _doubleTestDisplayMax = fetchDoubleParam(kParamDoubleTestDisplayMax);
139 _optionalClipLabel = fetchStringParam(kParamOptionalClipLabel);
140 _optionalClipHint = fetchStringParam(kParamOptionalClipHint);
141 }
142
143 private:
144 virtual void render(const RenderArguments &args) OVERRIDE FINAL;
145 virtual bool isIdentity(const IsIdentityArguments &args, Clip * &identityClip, double &identityTime, int& view, std::string& plane) OVERRIDE FINAL;
146 virtual void changedParam(const InstanceChangedArgs &args, const std::string ¶mName) OVERRIDE FINAL;
147
148 private:
149 // do not need to delete these, the ImageEffect is managing them for us
150 Clip *_dstClip;
151 Clip *_srcClip;
152 Clip *_optionalClip;
153 Clip *_maskClip;
154 RGBAParam* _color;
155 BooleanParam *_forceCopy;
156 DoubleParam* _mix;
157 BooleanParam* _maskApply;
158 BooleanParam* _maskInvert;
159 PushButtonParam* _testButton;
160 StringParam* _labelString;
161 DoubleParam* _double2;
162 DoubleParam* _doubleTest;
163 StringParam* _doubleTestLabel;
164 StringParam* _doubleTestHint;
165 DoubleParam* _doubleTestDefault;
166 DoubleParam* _doubleTestMin;
167 DoubleParam* _doubleTestMax;
168 DoubleParam* _doubleTestDisplayMin;
169 DoubleParam* _doubleTestDisplayMax;
170 StringParam* _optionalClipLabel;
171 StringParam* _optionalClipHint;
172 };
173
174
175 // the overridden render function
176 void
render(const RenderArguments & args)177 TestGroupsPlugin::render(const RenderArguments &args)
178 {
179 const double time = args.time;
180 bool forceCopy;
181
182 _forceCopy->getValueAtTime(time, forceCopy);
183
184 #ifdef DEBUG
185 if (!forceCopy) {
186 setPersistentMessage(Message::eMessageError, "", "OFX Host should not render");
187 throwSuiteStatusException(kOfxStatFailed);
188 }
189 #endif
190
191 assert( kSupportsMultipleClipPARs || !_srcClip || _srcClip->getPixelAspectRatio() == _dstClip->getPixelAspectRatio() );
192 assert( kSupportsMultipleClipDepths || !_srcClip || _srcClip->getPixelDepth() == _dstClip->getPixelDepth() );
193 // do the rendering
194 auto_ptr<Image> dst( _dstClip->fetchImage(args.time) );
195 if ( !dst.get() ) {
196 throwSuiteStatusException(kOfxStatFailed);
197 }
198 if ( (dst->getRenderScale().x != args.renderScale.x) ||
199 ( dst->getRenderScale().y != args.renderScale.y) ||
200 ( ( dst->getField() != eFieldNone) /* for DaVinci Resolve */ && ( dst->getField() != args.fieldToRender) ) ) {
201 setPersistentMessage(Message::eMessageError, "", "OFX Host gave image with wrong scale or field properties");
202 throwSuiteStatusException(kOfxStatFailed);
203 }
204 BitDepthEnum dstBitDepth = dst->getPixelDepth();
205 PixelComponentEnum dstComponents = dst->getPixelComponents();
206 auto_ptr<const Image> src( ( _srcClip && _srcClip->isConnected() ) ?
207 _srcClip->fetchImage(args.time) : 0 );
208 if ( src.get() ) {
209 if ( (src->getRenderScale().x != args.renderScale.x) ||
210 ( src->getRenderScale().y != args.renderScale.y) ||
211 ( ( src->getField() != eFieldNone) /* for DaVinci Resolve */ && ( src->getField() != args.fieldToRender) ) ) {
212 setPersistentMessage(Message::eMessageError, "", "OFX Host gave image with wrong scale or field properties");
213 throwSuiteStatusException(kOfxStatFailed);
214 }
215 BitDepthEnum srcBitDepth = src->getPixelDepth();
216 PixelComponentEnum srcComponents = src->getPixelComponents();
217 if ( (srcBitDepth != dstBitDepth) || (srcComponents != dstComponents) ) {
218 throwSuiteStatusException(kOfxStatErrImageFormat);
219 }
220 }
221 copyPixels( *this, args.renderWindow, src.get(), dst.get() );
222 }
223
224 bool
isIdentity(const IsIdentityArguments & args,Clip * & identityClip,double &,int &,std::string &)225 TestGroupsPlugin::isIdentity(const IsIdentityArguments &args,
226 Clip * &identityClip,
227 double & /*identityTime*/
228 , int& /*view*/, std::string& /*plane*/)
229 {
230 if (!_srcClip || !_srcClip->isConnected()) {
231 return false;
232 }
233 const double time = args.time;
234 bool forceCopy;
235 _forceCopy->getValueAtTime(time, forceCopy);
236
237 if (!forceCopy) {
238 identityClip = _srcClip;
239
240 return true;
241 }
242
243 double mix;
244 _mix->getValueAtTime(args.time, mix);
245
246 if (mix == 0.) {
247 identityClip = _srcClip;
248
249 return true;
250 }
251
252 bool doMasking = ( ( !_maskApply || _maskApply->getValueAtTime(args.time) ) && _maskClip && _maskClip->isConnected() );
253 if (doMasking) {
254 bool maskInvert;
255 _maskInvert->getValueAtTime(args.time, maskInvert);
256 if (!maskInvert) {
257 OfxRectI maskRoD;
258 if (getImageEffectHostDescription()->supportsMultiResolution) {
259 // In Sony Catalyst Edit, clipGetRegionOfDefinition returns the RoD in pixels instead of canonical coordinates.
260 // In hosts that do not support multiResolution (e.g. Sony Catalyst Edit), all inputs have the same RoD anyway.
261 Coords::toPixelEnclosing(_maskClip->getRegionOfDefinition(args.time), args.renderScale, _maskClip->getPixelAspectRatio(), &maskRoD);
262 // effect is identity if the renderWindow doesn't intersect the mask RoD
263 if ( !Coords::rectIntersection<OfxRectI>(args.renderWindow, maskRoD, 0) ) {
264 identityClip = _srcClip;
265
266 return true;
267 }
268 }
269 }
270 }
271
272 return false;
273 }
274
275 static const char*
bitDepthString(BitDepthEnum bitDepth)276 bitDepthString(BitDepthEnum bitDepth)
277 {
278 switch (bitDepth) {
279 case eBitDepthUByte:
280
281 return "8u";
282 case eBitDepthUShort:
283
284 return "16u";
285 case eBitDepthHalf:
286
287 return "16f";
288 case eBitDepthFloat:
289
290 return "32f";
291 case eBitDepthCustom:
292
293 return "x";
294 case eBitDepthNone:
295
296 return "0";
297 #ifdef OFX_EXTENSIONS_VEGAS
298 case eBitDepthUByteBGRA:
299
300 return "8uBGRA";
301 case eBitDepthUShortBGRA:
302
303 return "16uBGRA";
304 case eBitDepthFloatBGRA:
305
306 return "32fBGRA";
307 #endif
308 default:
309
310 return "[unknown bit depth]";
311 }
312 }
313
314 static std::string
pixelComponentString(const std::string & p)315 pixelComponentString(const std::string& p)
316 {
317 const std::string prefix = "OfxImageComponent";
318
319 std::string s = p;
320
321 return s.replace(s.find(prefix), prefix.length(), "");
322 }
323
324 static const char*
premultString(PreMultiplicationEnum e)325 premultString(PreMultiplicationEnum e)
326 {
327 switch (e) {
328 case eImageOpaque:
329
330 return "Opaque";
331 case eImagePreMultiplied:
332
333 return "PreMultiplied";
334 case eImageUnPreMultiplied:
335
336 return "UnPreMultiplied";
337 default:
338
339 return "[unknown premult]";
340 }
341 }
342
343 #ifdef OFX_EXTENSIONS_VEGAS
344 static const char*
pixelOrderString(PixelOrderEnum e)345 pixelOrderString(PixelOrderEnum e)
346 {
347 switch (e) {
348 case ePixelOrderRGBA:
349
350 return "RGBA";
351 case ePixelOrderBGRA:
352
353 return "BGRA";
354 default:
355
356 return "[unknown pixel order]";
357 }
358 }
359
360 #endif
361
362 static const char*
fieldOrderString(FieldEnum e)363 fieldOrderString(FieldEnum e)
364 {
365 switch (e) {
366 case eFieldNone:
367
368 return "None";
369 case eFieldBoth:
370
371 return "Both";
372 case eFieldLower:
373
374 return "Lower";
375 case eFieldUpper:
376
377 return "Upper";
378 case eFieldSingle:
379
380 return "Single";
381 case eFieldDoubled:
382
383 return "Doubled";
384 default:
385
386 return "[unknown field order]";
387 }
388 }
389
390 void
changedParam(const InstanceChangedArgs & args,const std::string & paramName)391 TestGroupsPlugin::changedParam(const InstanceChangedArgs &args,
392 const std::string ¶mName)
393 {
394 const double time = args.time;
395
396 if (paramName == kParamTestButton) {
397 _testButton->setLabel("Clicked!");
398 _testButton->setHint("You clicked me!");
399 _labelString->setValue("New Label");
400 _labelString->setLabel("New labellabel");
401 _double2->setLabel("Double param got a new name");
402 } else if (paramName == kParamClipInfo) {
403 std::ostringstream oss;
404 oss << "Clip Info:\n\n";
405 oss << "Input: ";
406 if (!_srcClip) {
407 oss << "N/A";
408 } else {
409 Clip &c = *_srcClip;
410 oss << pixelComponentString( c.getPixelComponentsProperty() );
411 oss << bitDepthString( c.getPixelDepth() );
412 oss << " (unmapped: ";
413 oss << pixelComponentString( c.getUnmappedPixelComponentsProperty() );
414 oss << bitDepthString( c.getUnmappedPixelDepth() );
415 oss << ")\npremultiplication: ";
416 oss << premultString( c.getPreMultiplication() );
417 #ifdef OFX_EXTENSIONS_VEGAS
418 oss << "\npixel order: ";
419 oss << pixelOrderString( c.getPixelOrder() );
420 #endif
421 oss << "\nfield order: ";
422 oss << fieldOrderString( c.getFieldOrder() );
423 oss << "\n";
424 oss << (c.isConnected() ? "connected" : "not connected");
425 oss << "\n";
426 oss << (c.hasContinuousSamples() ? "continuous samples" : "discontinuous samples");
427 #ifdef OFX_EXTENSIONS_NATRON
428 oss << "\nformat: ";
429 OfxRectI format;
430 c.getFormat(format);
431 oss << format.x2 - format.x1 << 'x' << format.y2 - format.y1;
432 if ( (format.x1 != 0) && (format.y1 != 0) ) {
433 if (format.x1 < 0) {
434 oss << format.x1;
435 } else {
436 oss << '+' << format.x1;
437 }
438 if (format.y1 < 0) {
439 oss << format.y1;
440 } else {
441 oss << '+' << format.y1;
442 }
443 }
444 #endif
445 oss << "\npixel aspect ratio: ";
446 oss << c.getPixelAspectRatio();
447 oss << "\nframe rate: ";
448 oss << c.getFrameRate();
449 oss << " (unmapped: ";
450 oss << c.getUnmappedFrameRate();
451 oss << ")";
452 OfxRangeD range = c.getFrameRange();
453 oss << "\nframe range: ";
454 oss << range.min << "..." << range.max;
455 oss << " (unmapped: ";
456 range = c.getUnmappedFrameRange();
457 oss << range.min << "..." << range.max;
458 oss << ")";
459 oss << "\nregion of definition: ";
460 OfxRectD rod = c.getRegionOfDefinition(args.time);
461 oss << rod.x1 << ' ' << rod.y1 << ' ' << rod.x2 << ' ' << rod.y2;
462 }
463 oss << "\n\n";
464 oss << "Output: ";
465 if (!_dstClip) {
466 oss << "N/A";
467 } else {
468 Clip &c = *_dstClip;
469 oss << pixelComponentString( c.getPixelComponentsProperty() );
470 oss << bitDepthString( c.getPixelDepth() );
471 oss << " (unmapped: ";
472 oss << pixelComponentString( c.getUnmappedPixelComponentsProperty() );
473 oss << bitDepthString( c.getUnmappedPixelDepth() );
474 oss << ")\npremultiplication: ";
475 oss << premultString( c.getPreMultiplication() );
476 #ifdef OFX_EXTENSIONS_VEGAS
477 oss << "\npixel order: ";
478 oss << pixelOrderString( c.getPixelOrder() );
479 #endif
480 oss << "\nfield order: ";
481 oss << fieldOrderString( c.getFieldOrder() );
482 oss << "\n";
483 oss << (c.isConnected() ? "connected" : "not connected");
484 oss << "\n";
485 oss << (c.hasContinuousSamples() ? "continuous samples" : "discontinuous samples");
486 #ifdef OFX_EXTENSIONS_NATRON
487 oss << "\nformat: ";
488 OfxRectI format;
489 c.getFormat(format);
490 oss << format.x2 - format.x1 << 'x' << format.y2 - format.y1;
491 if ( (format.x1 != 0) && (format.y1 != 0) ) {
492 if (format.x1 < 0) {
493 oss << format.x1;
494 } else {
495 oss << '+' << format.x1;
496 }
497 if (format.y1 < 0) {
498 oss << format.y1;
499 } else {
500 oss << '+' << format.y1;
501 }
502 }
503 #endif
504 oss << "\npixel aspect ratio: ";
505 oss << c.getPixelAspectRatio();
506 oss << "\nframe rate: ";
507 oss << c.getFrameRate();
508 oss << " (unmapped: ";
509 oss << c.getUnmappedFrameRate();
510 oss << ")";
511 OfxRangeD range = c.getFrameRange();
512 oss << "\nframe range: ";
513 oss << range.min << "..." << range.max;
514 oss << " (unmapped: ";
515 range = c.getUnmappedFrameRange();
516 oss << range.min << "..." << range.max;
517 oss << ")";
518 oss << "\nregion of definition: ";
519 OfxRectD rod = c.getRegionOfDefinition(args.time);
520 oss << rod.x1 << ' ' << rod.y1 << ' ' << rod.x2 << ' ' << rod.y2;
521 }
522 oss << "\n\n";
523 oss << "time: " << args.time << ", renderscale: " << args.renderScale.x << 'x' << args.renderScale.y << '\n';
524
525 sendMessage( Message::eMessageMessage, "", oss.str() );
526 } else if (paramName == kParamDoubleTestLabel) {
527 std::string s;
528 _doubleTestLabel->getValueAtTime(time, s);
529 _doubleTest->setLabel(s);
530 } else if (paramName == kParamDoubleTestHint) {
531 std::string s;
532 _doubleTestHint->getValueAtTime(time, s);
533 _doubleTest->setHint(s);
534 } else if (paramName == kParamDoubleTestDefault) {
535 _doubleTest->setDefault( _doubleTestDefault->getValueAtTime(time) );
536 } else if ( (paramName == kParamDoubleTestMin) || (paramName == kParamDoubleTestMax) ) {
537 _doubleTest->setRange( _doubleTestMin->getValueAtTime(time), _doubleTestMax->getValueAtTime(time) );
538 } else if ( (paramName == kParamDoubleTestDisplayMin) || (paramName == kParamDoubleTestMax) ) {
539 _doubleTest->setDisplayRange( _doubleTestDisplayMin->getValueAtTime(time), _doubleTestDisplayMax->getValueAtTime(time) );
540 } else if (paramName == kParamOptionalClipLabel) {
541 std::string s;
542 _optionalClipLabel->getValueAtTime(time, s);
543 _optionalClip->setLabel(s);
544 } else if (paramName == kParamOptionalClipHint) {
545 std::string s;
546 _optionalClipHint->getValueAtTime(time, s);
547 _optionalClip->setHint(s);
548 }
549 } // TestGroupsPlugin::changedParam
550
551 mDeclarePluginFactory(TestGroupsPluginFactory, {ofxsThreadSuiteCheck();}, {});
552 void
describe(ImageEffectDescriptor & desc)553 TestGroupsPluginFactory::describe(ImageEffectDescriptor &desc)
554 {
555 // basic labels
556 desc.setLabel(kPluginName);
557 desc.setPluginGrouping(kPluginGrouping);
558 desc.setPluginDescription(kPluginDescription);
559
560 // add the supported contexts
561 desc.addSupportedContext(eContextFilter);
562 desc.addSupportedContext(eContextGeneral);
563 desc.addSupportedContext(eContextPaint);
564 desc.addSupportedContext(eContextGenerator);
565
566 // add supported pixel depths
567 desc.addSupportedBitDepth(eBitDepthUByte);
568 desc.addSupportedBitDepth(eBitDepthUShort);
569 desc.addSupportedBitDepth(eBitDepthFloat);
570
571 // set a few flags
572 desc.setSupportsMultipleClipPARs(kSupportsMultipleClipPARs);
573 desc.setSupportsMultipleClipDepths(kSupportsMultipleClipDepths);
574
575 desc.setRenderThreadSafety(eRenderFullySafe);
576 }
577
578 void
describeInContext(ImageEffectDescriptor & desc,ContextEnum context)579 TestGroupsPluginFactory::describeInContext(ImageEffectDescriptor &desc,
580 ContextEnum context)
581 {
582 // Source clip only in the filter context
583 // create the mandated source clip
584 ClipDescriptor *srcClip = desc.defineClip(kOfxImageEffectSimpleSourceClipName);
585
586 srcClip->addSupportedComponent(ePixelComponentRGBA);
587 srcClip->addSupportedComponent(ePixelComponentRGB);
588 srcClip->addSupportedComponent(ePixelComponentAlpha);
589 srcClip->setTemporalClipAccess(false);
590 srcClip->setIsMask(false);
591
592 {
593 ClipDescriptor *clip = desc.defineClip(kClipOptional);
594 clip->setLabel(kClipOptionalLabel);
595 clip->addSupportedComponent(ePixelComponentRGBA);
596 clip->setOptional(true);
597 }
598
599 // create the mandated output clip
600 ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName);
601 dstClip->addSupportedComponent(ePixelComponentRGBA);
602 dstClip->addSupportedComponent(ePixelComponentRGB);
603 dstClip->addSupportedComponent(ePixelComponentAlpha);
604
605 if (context != eContextGenerator) {
606 ClipDescriptor *maskClip = (context == eContextPaint) ? desc.defineClip("Brush") : desc.defineClip("Mask");
607 maskClip->addSupportedComponent(ePixelComponentAlpha);
608 maskClip->setTemporalClipAccess(false);
609 if (context != eContextPaint) {
610 maskClip->setOptional(true);
611 }
612 maskClip->setIsMask(true);
613 }
614
615 // make some pages and to things in
616 //PageParamDescriptor *page = NULL;
617 PageParamDescriptor *page = desc.definePageParam("Controls");
618
619 // color0
620 {
621 RGBAParamDescriptor *param = desc.defineRGBAParam(kParamColor0);
622 param->setLabel(kParamColor0Label);
623 param->setDefault(0.0, 1.0, 1.0, 1.0);
624 param->setAnimates(true); // can animate
625 if (page) {
626 page->addChild(*param);
627 }
628 }
629
630 // forceCopy
631 {
632 BooleanParamDescriptor *param = desc.defineBooleanParam(kParamForceCopy);
633 param->setLabel(kParamForceCopyLabel);
634 param->setHint(kParamForceCopyHint);
635 param->setDefault(false);
636 param->setAnimates(false);
637 if (page) {
638 page->addChild(*param);
639 }
640 }
641
642 // clipInfo
643 {
644 PushButtonParamDescriptor *param = desc.definePushButtonParam(kParamClipInfo);
645 param->setLabel(kParamClipInfoLabel);
646 param->setHint(kParamClipInfoHint);
647 if (page) {
648 page->addChild(*param);
649 }
650 }
651
652 // testButton
653 {
654 PushButtonParamDescriptor *param = desc.definePushButtonParam(kParamTestButton);
655 param->setLabel(kParamTestButtonLabel);
656 param->setHint("Please click me and see what happens.");
657 if (page) {
658 page->addChild(*param);
659 }
660 }
661
662 // a string param of type label, followed by a double param with no label... does it work?
663 {
664 StringParamDescriptor *param = desc.defineStringParam(kParamLabelString);
665 param->setLabel("");
666 param->setDefault("The label");
667 param->setStringType(eStringTypeLabel);
668 param->setLayoutHint(eLayoutHintNoNewLine, 1);
669 if (page) {
670 page->addChild(*param);
671 }
672 }
673 {
674 DoubleParamDescriptor *param = desc.defineDoubleParam("doubleParam");
675 param->setLabel("");
676 param->setDefault(0.5);
677 param->setRange(0., 1.);
678 param->setDisplayRange(0., 1.);
679 if (page) {
680 page->addChild(*param);
681 }
682 }
683 {
684 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamDouble2);
685 param->setLabel("A Double Param");
686 param->setDefault(0.5);
687 param->setRange(0., 1.);
688 param->setDisplayRange(0., 1.);
689 if (page) {
690 page->addChild(*param);
691 }
692 }
693
694 {
695 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamDoubleTest);
696 if (page) {
697 page->addChild(*param);
698 }
699 }
700 {
701 StringParamDescriptor *param = desc.defineStringParam(kParamDoubleTestLabel);
702 param->setAnimates(false);
703 param->setEvaluateOnChange(false);
704 if (page) {
705 page->addChild(*param);
706 }
707 }
708 {
709 StringParamDescriptor *param = desc.defineStringParam(kParamDoubleTestHint);
710 param->setAnimates(false);
711 param->setEvaluateOnChange(false);
712 if (page) {
713 page->addChild(*param);
714 }
715 }
716 {
717 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamDoubleTestDefault);
718 param->setAnimates(false);
719 param->setEvaluateOnChange(false);
720 if (page) {
721 page->addChild(*param);
722 }
723 }
724 {
725 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamDoubleTestMin);
726 param->setAnimates(false);
727 param->setEvaluateOnChange(false);
728 if (page) {
729 page->addChild(*param);
730 }
731 }
732 {
733 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamDoubleTestMax);
734 param->setAnimates(false);
735 param->setEvaluateOnChange(false);
736 if (page) {
737 page->addChild(*param);
738 }
739 }
740 {
741 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamDoubleTestDisplayMin);
742 param->setAnimates(false);
743 param->setEvaluateOnChange(false);
744 if (page) {
745 page->addChild(*param);
746 }
747 }
748 {
749 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamDoubleTestDisplayMax);
750 param->setAnimates(false);
751 param->setEvaluateOnChange(false);
752 if (page) {
753 page->addChild(*param);
754 }
755 }
756 {
757 StringParamDescriptor *param = desc.defineStringParam(kParamOptionalClipLabel);
758 param->setAnimates(false);
759 param->setEvaluateOnChange(false);
760 if (page) {
761 page->addChild(*param);
762 }
763 }
764 {
765 StringParamDescriptor *param = desc.defineStringParam(kParamOptionalClipHint);
766 param->setAnimates(false);
767 param->setEvaluateOnChange(false);
768 if (page) {
769 page->addChild(*param);
770 }
771 }
772
773 // Groups
774 {
775 GroupParamDescriptor* group = desc.defineGroupParam("group");
776 //group->setAsTab();
777 {
778 GroupParamDescriptor* subgroup = desc.defineGroupParam("subGroup1");
779 if (subgroup) {
780 if (group) {
781 subgroup->setParent(*group);
782 }
783 if (page) {
784 page->addChild(*subgroup);
785 }
786 }
787 {
788 DoubleParamDescriptor* param = desc.defineDoubleParam("valueInsideSubGroup1");
789 if (page) {
790 page->addChild(*param);
791 }
792 if (subgroup) {
793 param->setParent(*subgroup);
794 }
795 }
796 }
797 {
798 GroupParamDescriptor* subgroup = desc.defineGroupParam("subGroup2AsTab");
799 if (subgroup) {
800 subgroup->setAsTab();
801 if (group) {
802 subgroup->setParent(*group);
803 }
804 if (page) {
805 page->addChild(*subgroup);
806 }
807 }
808 {
809 DoubleParamDescriptor* param = desc.defineDoubleParam("valueInsideSubGroup2AsTab");
810 if (page) {
811 page->addChild(*param);
812 }
813 if (subgroup) {
814 param->setParent(*subgroup);
815 }
816 }
817 }
818 {
819 GroupParamDescriptor* subgroup = desc.defineGroupParam("subGroup3AsTab");
820 if (subgroup) {
821 subgroup->setAsTab();
822 if (group) {
823 subgroup->setParent(*group);
824 }
825 if (page) {
826 page->addChild(*subgroup);
827 }
828 }
829 {
830 DoubleParamDescriptor* param = desc.defineDoubleParam("valueInsideSubGroup3AsTab");
831 if (page) {
832 page->addChild(*param);
833 }
834 if (subgroup) {
835 param->setParent(*subgroup);
836 }
837 }
838 }
839 }
840 GroupParamDescriptor* formatGroup = desc.defineGroupParam( "kParamFormatGroup" );
841 GroupParamDescriptor* videoGroup = desc.defineGroupParam( "kParamVideoGroup" );
842 formatGroup->setLabel( "Format" );
843 videoGroup->setLabel( "Video" );
844
845 formatGroup->setAsTab( );
846 videoGroup->setAsTab( );
847
848 /// FORMAT PARAMETERS
849 //avtranscoder::FormatContext formatContext( AV_OPT_FLAG_DECODING_PARAM );
850 //avtranscoder::OptionArray formatOptions = formatContext.getOptions();
851 //common::addOptionsToGroup( desc, formatGroup, formatOptions, common::kPrefixFormat );
852 {
853 ParamDescriptor* param = NULL;
854 BooleanParamDescriptor* boolParam = desc.defineBooleanParam( "opt1" );
855 boolParam->setDefault( true );
856 param = boolParam;
857 param->setLabel( "Opt1" );
858 param->setHint( "Opt1 help" );
859 param->setParent( *formatGroup );
860 }
861
862 {
863 ParamDescriptor* param = NULL;
864 IntParamDescriptor* intParam = desc.defineIntParam( "int" );
865 param = intParam;
866 param->setLabel( "Int1" );
867 param->setHint( "Int1 help" );
868 param->setParent( *formatGroup );
869 }
870
871 GroupParamDescriptor* formatDetailledGroup = desc.defineGroupParam( "kParamFormatDetailledGroup" );
872 formatDetailledGroup->setLabel( "Detailled" );
873 formatDetailledGroup->setAsTab( );
874 formatDetailledGroup->setParent( *formatGroup );
875
876 //avtranscoder::OptionArrayMap formatDetailledGroupOptions = avtranscoder::getOutputFormatOptions();
877 //common::addOptionsToGroup( desc, formatDetailledGroup, formatDetailledGroupOptions, common::kPrefixFormat );
878 {
879 ParamDescriptor* param = NULL;
880 BooleanParamDescriptor* boolParam = desc.defineBooleanParam( "opt2" );
881 boolParam->setDefault( true );
882 param = boolParam;
883 param->setLabel( "Opt2" );
884 param->setHint( "Opt2 help" );
885 param->setParent( *formatDetailledGroup );
886 }
887
888 /// VIDEO PARAMETERS
889 BooleanParamDescriptor* useCustomSAR = desc.defineBooleanParam( "kParamUseCustomSAR" );
890 useCustomSAR->setLabel( "Override SAR" );
891 useCustomSAR->setDefault( false );
892 useCustomSAR->setHint( "Override the file SAR (Storage Aspect Ratio) with a custom SAR value." );
893 useCustomSAR->setParent( *videoGroup );
894
895 DoubleParamDescriptor* customSAR = desc.defineDoubleParam( "kParamCustomSAR" );
896 customSAR->setLabel( "Custom SAR" );
897 customSAR->setDefault( 1.0 );
898 customSAR->setRange( 0., 10. );
899 customSAR->setDisplayRange( 0., 3. );
900 customSAR->setHint( "Choose a custom value to override the file SAR (Storage Aspect Ratio). Maximum value: 10." );
901 customSAR->setParent( *videoGroup );
902
903 IntParamDescriptor* streamIndex = desc.defineIntParam( "kParamVideoStreamIndex" );
904 streamIndex->setLabel( "kParamVideoStreamIndexLabel" );
905 streamIndex->setDefault( 0 );
906 streamIndex->setRange( 0., 100. );
907 streamIndex->setDisplayRange( 0., 16. );
908 streamIndex->setHint( "Choose a custom value to decode the video stream you want. Maximum value: 100." );
909 streamIndex->setParent( *videoGroup );
910
911 GroupParamDescriptor* videoDetailledGroup = desc.defineGroupParam( "kParamVideoDetailledGroup" );
912 videoDetailledGroup->setLabel( "Detailled" );
913 videoDetailledGroup->setAsTab( );
914 videoDetailledGroup->setParent( *videoGroup );
915
916 //avtranscoder::OptionArrayMap videoDetailledGroupOptions = avtranscoder::getVideoCodecOptions();
917 //common::addOptionsToGroup( desc, videoDetailledGroup, videoDetailledGroupOptions, common::kPrefixVideo );
918 {
919 ParamDescriptor* param = NULL;
920 BooleanParamDescriptor* boolParam = desc.defineBooleanParam( "opt3" );
921 boolParam->setDefault( true );
922 param = boolParam;
923 param->setLabel( "Op3" );
924 param->setHint( "Opt3 help" );
925 param->setParent( *videoDetailledGroup );
926 }
927
928 /// VERBOSE
929 BooleanParamDescriptor* useVerbose = desc.defineBooleanParam( "kParamVerbose" );
930 useVerbose->setLabel( "Set to verbose" );
931 useVerbose->setDefault( false );
932 useVerbose->setHint( "Set plugin to verbose to get debug informations." );
933
934 ofxsMaskMixDescribeParams(desc, page);
935 } // TestGroupsPluginFactory::describeInContext
936
937 ImageEffect*
createInstance(OfxImageEffectHandle handle,ContextEnum)938 TestGroupsPluginFactory::createInstance(OfxImageEffectHandle handle,
939 ContextEnum /*context*/)
940 {
941 return new TestGroupsPlugin(handle);
942 }
943
944 static TestGroupsPluginFactory p(kPluginIdentifier, kPluginVersionMajor, kPluginVersionMinor);
945 mRegisterPluginFactoryInstance(p)
946
947 OFXS_NAMESPACE_ANONYMOUS_EXIT
948