1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; -*- */ 2 /* ***** BEGIN LICENSE BLOCK ***** 3 * This file is part of openfx-supportext <https://github.com/devernay/openfx-supportext>, 4 * Copyright (C) 2013-2018 INRIA 5 * 6 * openfx-supportext is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * openfx-supportext is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with openfx-supportext. If not, see <http://www.gnu.org/licenses/gpl-2.0.html> 18 * ***** END LICENSE BLOCK ***** */ 19 20 /* 21 * Helper functions to implement plug-ins that support kFnOfxImageEffectPlaneSuite v2 22 * In order to use these functions the following condition must be met: 23 *#if defined(OFX_EXTENSIONS_NUKE) && defined(OFX_EXTENSIONS_NATRON) 24 25 if (OFX::fetchSuite(kFnOfxImageEffectPlaneSuite, 2) && // for clipGetImagePlane 26 OFX::getImageEffectHostDescription()->supportsDynamicChoices && // for dynamic layer choices 27 OFX::getImageEffectHostDescription()->isMultiPlanar) // for clipGetImagePlane 28 ... this is ok... 29 *#endif 30 */ 31 32 #ifndef openfx_supportext_ofxsMultiPlane_h 33 #define openfx_supportext_ofxsMultiPlane_h 34 35 #include <cmath> 36 #include <map> 37 #include <string> 38 #include <list> 39 #include <vector> 40 41 #include "ofxsImageEffect.h" 42 #include "ofxsMacros.h" 43 #ifdef OFX_EXTENSIONS_NATRON 44 #include "ofxNatron.h" 45 #endif 46 47 48 #define kOfxMultiplaneColorPlaneID kFnOfxImagePlaneColour 49 #define kOfxMultiplaneColorPlaneLabel "Color" 50 51 #define kOfxMultiplaneBackwardMotionVectorsPlaneID kFnOfxImagePlaneBackwardMotionVector 52 #define kOfxMultiplaneBackwardMotionVectorsPlaneLabel "Backward" 53 54 #define kOfxMultiplaneForwardMotionVectorsPlaneID kFnOfxImagePlaneForwardMotionVector 55 #define kOfxMultiplaneForwardMotionVectorsPlaneLabel "Forward" 56 57 #define kOfxMultiplaneDisparityLeftPlaneID kFnOfxImagePlaneStereoDisparityLeft 58 #define kOfxMultiplaneDisparityLeftPlaneLabel "DisparityLeft" 59 60 #define kOfxMultiplaneDisparityRightPlaneID kFnOfxImagePlaneStereoDisparityRight 61 #define kOfxMultiplaneDisparityRightPlaneLabel "DisparityRight" 62 63 #define kOfxMultiplaneDisparityComponentsLabel "Disparity" 64 #define kOfxMultiplaneMotionComponentsLabel "Motion" 65 66 67 #define kMultiPlaneChannelParamOption0 "0" 68 #define kMultiPlaneChannelParamOption0Hint "0 constant channel" 69 #define kMultiPlaneChannelParamOption1 "1" 70 #define kMultiPlaneChannelParamOption1Hint "1 constant channel" 71 72 #define kMultiPlanePlaneParamOptionNone "none" 73 #define kMultiPlanePlaneParamOptionNoneLabel "None" 74 75 #define kMultiPlaneProcessAllPlanesParam "processAllPlanes" 76 #define kMultiPlaneProcessAllPlanesParamLabel "All Planes" 77 #define kMultiPlaneProcessAllPlanesParamHint "When checked all planes in input will be processed and output to the same plane as in input. It is useful for example to apply a Transform effect on all planes." 78 79 80 81 /* 82 A Multi-planar effect is a plane that can process arbitrary (other than color) image planes. 83 The planes described further can be seen as a layer in the OpenEXR specification. 84 85 A plane consists of an arbitrary number of channels, ranging from 1 to 4 (included) and is 86 labeled with a unique name and a label 87 For example... 88 The Color.RGBA plane, corresponds to the Color plane with 4 channels: RGBA 89 90 This extension also allow to alias the channel names in a more meaningful way, 91 For example... 92 93 The DisparityLeft.Disparity plane corresponds to the DisparityLeft plane with 94 channels of type "Disparity", being 2 channels: XY. 95 96 The generic way of describing a layer is done as such: 97 98 99 kNatronOfxImageComponentsPlaneName + 100 planeName + 101 <optional> kNatronOfxImageComponentsPlaneLabel + planeLabel + 102 <optional> kNatronOfxImageComponentsPlaneChannelsLabel + channelsLabel + 103 kNatronOfxImageComponentsPlaneChannel + channel1Name + 104 kNatronOfxImageComponentsPlaneChannel + channel2Name + 105 kNatronOfxImageComponentsPlaneChannel + channel3Name 106 107 Examples: 108 109 kNatronOfxImageComponentsPlaneName + "fr.unique.id.position" + kNatronOfxImageComponentsPlaneLabel + "Position" + kNatronOfxImageComponentsPlaneChannel + "X" + kNatronOfxImageComponentsPlaneChannel + "Y" + kNatronOfxImageComponentsPlaneChannel + "Z" 110 111 112 kNatronOfxImageComponentsPlaneName + "DisparityLeft" + kNatronOfxImageComponentsPlaneChannelsLabel + "Disparity" + kNatronOfxImageComponentsPlaneChannel + "X" + kNatronOfxImageComponentsPlaneChannel + "Y" 113 114 115 A multi-planar effect is expected to set the kFnOfxImageEffectPropMultiPlanar property to 1 on the image effect descritpor. 116 117 A multi-planar effect is expected to support images of any number of channels: 118 119 - The planes fetched from clipGetImagePlane are returned "as is" and will not be remapped by the host to another components type 120 121 - The exception is for the kFnOfxImagePlaneColour plane: the components of the plane will be remapped to those specified in the getClipPreferences action 122 123 A multi-planar effect is expected to specify the planes it produces in output and the planes it needs in input via the getClipComponents action. 124 125 OpenFX only defines kOfxImageComponentRGBA, kOfxImageComponentRGB, kOfxImageComponentAlpha for default components type. 126 However, an effect may still be able to process 2-channel image and be non multi-planar aware. 127 To enable this, we also define kNatronOfxImageComponentXY as a components type that can be used in the getClipPreferences action and can be indicated 128 on a 2-channel image. 129 130 Support for Nuke: 131 ---------------- 132 133 Nuke only supports the MultiPlane suite V1 and does not uses the getClipComponents action and does not support abitrary planes as defined above. 134 135 Nuke only supports the following hard-coded planes: 136 137 kFnOfxImagePlaneColour --> This plane can only have the following components types: kOfxImageComponentRGBA, kOfxImageComponentRGB, kOfxImageComponentAlpha 138 139 kFnOfxImagePlaneBackwardMotionVector --> This plane has the following components type: kFnOfxImageComponentMotionVectors 140 kFnOfxImagePlaneForwardMotionVector --> This plane has the following components type: kFnOfxImageComponentMotionVectors 141 142 kFnOfxImagePlaneStereoDisparityLeft --> This plane has the following components type: kFnOfxImageComponentStereoDisparity 143 kFnOfxImagePlaneStereoDisparityRight --> This plane has the following components type: kFnOfxImageComponentStereoDisparity 144 145 Flagging kFnOfxImageEffectPropMultiPlanar=1 in Nuke only means that besides the regular clipGetImage call to get the color plane, 146 you can fetch the motion vectors (BW/FW) and disparity planes (Left, Right) with the clipGetImagePlane call. 147 148 To indicate which plane you want on a clip, you do so from the getClipPreferences action by indicating the components TYPE, 149 that is kFnOfxImageComponentMotionVectors, kFnOfxImageComponentStereoDisparity or kOfxImageComponentRGBA, kOfxImageComponentRGB, kOfxImageComponentAlpha 150 151 If a clip is set to the kFnOfxImageComponentMotionVectors components type, the host expects the plug-in to call clipGetImagePlane on both the 152 kFnOfxImagePlaneBackwardMotionVector plane and the kFnOfxImagePlaneForwardMotionVector plane. 153 These planes are "paired": a plug-in that renders kFnOfxImageComponentMotionVectors is expected to render both planes at once. 154 155 Similarly, if the clip components are set to kFnOfxImageComponentStereoDisparity, the host expects that the plug-in calls clipGetImagePlane on both 156 the kFnOfxImagePlaneStereoDisparityLeft and kFnOfxImagePlaneStereoDisparityRight planes. 157 158 159 Planes vs. components: 160 ---------------------- 161 162 Planes and components are different things. A plane is a unique image label of a certain components type. 163 The components define how many channels are present in an image plane. 164 165 With the Natron extension, planes encoded directly their components type along them. This is not the case with the 166 Nuke multi-plane suite V1 where components types and planes are hard-coded. 167 168 To sum-up: 169 170 - Planes defined in the Natron extension form indicate directly their components type, in the form 171 172 kNatronOfxImageComponentsPlaneName + planeName + 173 <optional> kNatronOfxImageComponentsPlaneLabel + planeLabel + 174 <optional> kNatronOfxImageComponentsPlaneChannelsLabel + channelsLabel + 175 kNatronOfxImageComponentsPlaneChannel + channel1Name + 176 kNatronOfxImageComponentsPlaneChannel + channel2Name + 177 kNatronOfxImageComponentsPlaneChannel + channel3Name 178 179 - Planes defined in the Nuke multi-plane suite have hard-coded components type (see Support for Nuke above) 180 181 - The getClipComponents action must return a list of string corresponding to planes and not components type. 182 183 MultiPlaneEffect: 184 ---------------- 185 186 To support abitrary planes, this suite needs to deal with dynamic choice parameter menus. This is known not to be supported in Nuke. 187 188 The MultiPlaneEffect class below is mainly a helper class inheriting ImageEffect to conveniently create and manage choice parameters 189 that allow the user to select planes or a specific channel in a plane. 190 191 The host notifies that the planes have changed for a plug-in by calling the instanceChanged action on the output clip. 192 193 This is where the buildChannelMenus() function should be called to refresh choice parameters menus. 194 195 Note that this class also supports multi-planar effects in the sense of the the Nuke multi-plane suite (i.e: only motion vectors and disparity planes) 196 197 Note that the derived plug-in still needs to set the kFnOfxImageEffectPropMultiPlanar property to 1, otherwise this class will not do much. 198 199 */ 200 namespace OFX { 201 namespace MultiPlane { 202 203 204 /** 205 * @brief An ImagePlaneDesc represents an image plane and its components type. 206 * The plane is uniquely identified by its planeID, it is used internally to compare planes. 207 * The plane label is used for any UI related display: this is what the user sees. 208 * If empty, the plane label is the same as the planeID. 209 * The channels label is an optional string indicating in a more convenient way the types 210 * of components expressed by the channels e.g: Instead of having "XY" for motion vectors, 211 * they could be labeled with "Motion". 212 * If empty, the channels label is set to the concatenation of all channels. 213 * The channels are the unique identifier for each channel composing the plane. 214 * The plane can only be composed from 1 to 4 (included) channels. 215 **/ 216 class ImagePlaneDesc 217 { 218 public: 219 220 221 ImagePlaneDesc(); 222 223 ImagePlaneDesc(const std::string& planeID, 224 const std::string& planeLabel, 225 const std::string& channelsLabel, 226 const std::vector<std::string>& channels); 227 228 ImagePlaneDesc(const std::string& planeID, 229 const std::string& planeLabel, 230 const std::string& channelsLabel, 231 const char** channels, 232 int count); 233 234 235 ImagePlaneDesc(const ImagePlaneDesc& other); 236 237 ImagePlaneDesc& operator=(const ImagePlaneDesc& other); 238 239 ~ImagePlaneDesc(); 240 241 // Is it Alpha, RGB or RGBA 242 bool isColorPlane() const; 243 244 static bool isColorPlane(const std::string& layerID); 245 246 /** 247 * @brief Returns the number of channels in this plane. 248 **/ 249 int getNumComponents() const; 250 251 /** 252 * @brief Returns the plane unique identifier. This should be used to compare ImagePlaneDesc together. 253 * This is not supposed to be used for display purpose, use getPlaneLabel() instead. 254 **/ 255 const std::string& getPlaneID() const; 256 257 /** 258 * @brief Returns the plane label. 259 * This is what is used to display to the user. 260 **/ 261 const std::string& getPlaneLabel() const; 262 263 /** 264 * @brief Returns the channels composing this plane. 265 **/ 266 const std::vector<std::string>& getChannels() const; 267 268 /** 269 * @brief Returns a label used to better represent the type of components used by this plane. 270 * e.g: "Motion" can be used to better label "XY" component types. 271 **/ 272 const std::string& getChannelsLabel() const; 273 274 275 bool operator==(const ImagePlaneDesc& other) const; 276 277 bool operator!=(const ImagePlaneDesc& other) const 278 { 279 return !(*this == other); 280 } 281 282 // For std::map 283 bool operator<(const ImagePlaneDesc& other) const; 284 285 operator bool() const 286 { 287 return getNumComponents() > 0; 288 } 289 290 bool operator!() const 291 { 292 return getNumComponents() == 0; 293 } 294 295 296 void getPlaneOption(std::string* optionID, std::string* optionLabel) const; 297 void getChannelOption(int channelIndex, std::string* optionID, std::string* optionLabel) const; 298 299 /** 300 * @brief Maps the given nComps to the color plane 301 **/ 302 static const ImagePlaneDesc& mapNCompsToColorPlane(int nComps); 303 304 /** 305 * @brief Maps the given OpenFX plane to a ImagePlaneDesc. 306 * @param ofxPlane Can be 307 308 * kFnOfxImagePlaneBackwardMotionVector 309 * kFnOfxImagePlaneForwardMotionVector 310 * kFnOfxImagePlaneStereoDisparityLeft 311 * kFnOfxImagePlaneStereoDisparityRight 312 * Or any plane encoded in the format specified by the Natron multi-plane extension. 313 * This function CANNOT be used to map the color plane, instead use mapNCompsToColorPlane. 314 * 315 * This function returns an empty plane desc upon failure. 316 **/ 317 static ImagePlaneDesc mapOFXPlaneStringToPlane(const std::string& ofxPlane); 318 319 /** 320 * @brief Maps OpenFX components string to a plane, optionnally also to a paired plane in the case of disparity/motion vectors. 321 * @param ofxComponents Must be a string between 322 * kOfxImageComponentRGBA, kOfxImageComponentRGB, kOfxImageComponentAlpha, kNatronOfxImageComponentXY, kOfxImageComponentNone 323 * or kFnOfxImageComponentStereoDisparity or kFnOfxImageComponentMotionVectors 324 * Or any plane encoded in the format specified by the Natron multi-plane extension. 325 **/ 326 static void mapOFXComponentsTypeStringToPlanes(const std::string& ofxComponents, ImagePlaneDesc* plane, ImagePlaneDesc* pairedPlane); 327 328 /** 329 * @brief Does the inverse of mapOFXPlaneStringToPlane, except that it can also be used for 330 * the color plane. 331 **/ 332 static std::string mapPlaneToOFXPlaneString(const ImagePlaneDesc& plane); 333 334 /** 335 * @brief Returns an OpenFX encoded string representing the components type of the plane. 336 * @returns One of the following strings: 337 * kOfxImageComponentRGBA, kOfxImageComponentRGB, kOfxImageComponentAlpha, kNatronOfxImageComponentXY, kOfxImageComponentNone 338 * or kFnOfxImageComponentStereoDisparity or kFnOfxImageComponentMotionVectors 339 * Or any plane encoded in the format specified by the Natron multi-plane extension. 340 **/ 341 static std::string mapPlaneToOFXComponentsTypeString(const ImagePlaneDesc& plane); 342 343 /** 344 * @brief Find a layer equivalent to this layer in the other layers container. 345 * ITERATOR must be either a std::vector<ImagePlaneDesc>::iterator or std::list<ImagePlaneDesc>::iterator 346 **/ 347 template <typename ITERATOR> findEquivalentLayer(const ImagePlaneDesc & layer,ITERATOR begin,ITERATOR end)348 static ITERATOR findEquivalentLayer(const ImagePlaneDesc& layer, ITERATOR begin, ITERATOR end) 349 { 350 bool isColor = layer.isColorPlane(); 351 352 ITERATOR foundExistingColorMatch = end; 353 ITERATOR foundExistingComponents = end; 354 355 for (ITERATOR it = begin; it != end; ++it) { 356 if (it->isColorPlane() && isColor) { 357 foundExistingColorMatch = it; 358 } else { 359 if (*it == layer) { 360 foundExistingComponents = it; 361 break; 362 } 363 } 364 } // for each output components 365 366 if (foundExistingComponents != end) { 367 return foundExistingComponents; 368 } else if (foundExistingColorMatch != end) { 369 return foundExistingColorMatch; 370 } else { 371 return end; 372 } 373 } // findEquivalentLayer 374 375 /* 376 * These are default presets image components 377 */ 378 static const ImagePlaneDesc& getNoneComponents(); 379 static const ImagePlaneDesc& getRGBAComponents(); 380 static const ImagePlaneDesc& getRGBComponents(); 381 static const ImagePlaneDesc& getAlphaComponents(); 382 static const ImagePlaneDesc& getBackwardMotionComponents(); 383 static const ImagePlaneDesc& getForwardMotionComponents(); 384 static const ImagePlaneDesc& getDisparityLeftComponents(); 385 static const ImagePlaneDesc& getDisparityRightComponents(); 386 static const ImagePlaneDesc& getXYComponents(); 387 388 389 private: 390 std::string _planeID, _planeLabel; 391 std::vector<std::string> _channels; 392 std::string _channelsLabel; 393 }; 394 395 396 struct MultiPlaneEffectPrivate; 397 class MultiPlaneEffect 398 : public OFX::ImageEffect 399 { 400 auto_ptr<MultiPlaneEffectPrivate> _imp; 401 402 public: 403 404 405 MultiPlaneEffect(OfxImageEffectHandle handle); 406 407 virtual ~MultiPlaneEffect(); 408 409 struct FetchChoiceParamOptions 410 { 411 bool splitPlanesIntoChannelOptions; 412 bool addNoneOption; 413 bool addConstantOptions; 414 bool isOutputPlaneChoice; 415 bool hideIfClipDisconnected; 416 std::vector<OFX::Clip*> dependsClips; 417 createFetchChoiceParamOptionsForInputChannelFetchChoiceParamOptions418 static FetchChoiceParamOptions createFetchChoiceParamOptionsForInputChannel() 419 { 420 FetchChoiceParamOptions ret; 421 ret.splitPlanesIntoChannelOptions = true; 422 ret.addNoneOption = false; 423 ret.addConstantOptions = true; 424 ret.isOutputPlaneChoice = false; 425 ret.hideIfClipDisconnected = false; 426 return ret; 427 } 428 createFetchChoiceParamOptionsForOutputPlaneFetchChoiceParamOptions429 static FetchChoiceParamOptions createFetchChoiceParamOptionsForOutputPlane() 430 { 431 FetchChoiceParamOptions ret; 432 ret.splitPlanesIntoChannelOptions = false; 433 ret.addNoneOption = false; 434 ret.addConstantOptions = false; 435 ret.isOutputPlaneChoice = true; 436 ret.hideIfClipDisconnected = false; 437 return ret; 438 } 439 }; 440 441 /** 442 * @brief Fetch a dynamic choice parameter that was declared to the factory with 443 * describeInContextAddOutputLayerChoice() or describeInContextAddChannelChoice(). 444 * @param splitPlanesIntoChannelOptions If true, each option will be a channel of a plane 445 * @param dependsClips The planes available from the given clips will be used to populate the choice options. 446 * @param isOutputPlaneChoice If this 447 **/ 448 void fetchDynamicMultiplaneChoiceParameter(const std::string& paramName, 449 const FetchChoiceParamOptions& args); 450 451 /** 452 * @brief Should be called by the implementation to refresh the visibility of parameters once they have all been fetched. 453 **/ 454 void onAllParametersFetched(); 455 456 enum GetPlaneNeededRetCodeEnum 457 { 458 eGetPlaneNeededRetCodeFailed, 459 eGetPlaneNeededRetCodeReturnedPlane, 460 eGetPlaneNeededRetCodeReturnedChannelInPlane, 461 eGetPlaneNeededRetCodeReturnedConstant0, 462 eGetPlaneNeededRetCodeReturnedConstant1, 463 eGetPlaneNeededRetCodeReturnedAllPlanes 464 }; 465 466 /** 467 * @brief Returns the plane and channel index selected by the user in the given dynamic choice parameter "paramName". 468 * @param plane Contains in output the plane selected by the user 469 * If ofxPlane is empty but the function returned true that is because the choice is either kMultiPlaneParamOutputOption0 or kMultiPlaneParamOutputOption1 470 * ofxComponents will have been set correctly to one of these values. 471 * 472 * @param channelIndexInPlane Contains in output the selected channel index in the plane set to ofxPlane 473 * 474 * @returns eGetPlaneNeededRetCodeFailed if this function failed. 475 * If the result is eGetPlaneNeededRetCodeReturnedConstant0 or eGetPlaneNeededRetCodeReturnedConstant1 is returned, the plug-in should use 476 * a corresponding constant (0 or 1) instead of a channel from the clip. 477 * If the result is eGetPlaneNeededRetCodeReturnedPlane, the plane in output will be set to the user selected plane. 478 * If the result is eGetPlaneNeededRetCodeReturnedChannelInPlane, the plane and the channelIndexInPlane in output will be set to the user 479 * selected channel. 480 * If the result is eGetPlaneNeededRetCodeReturnedAllPlanes, the plug-in is expected to render what is requested and should act as 481 * plane agnostic. 482 **/ 483 GetPlaneNeededRetCodeEnum getPlaneNeeded(const std::string& paramName, 484 OFX::Clip** clip, 485 ImagePlaneDesc* plane, 486 int* channelIndexInPlane); 487 488 489 /** 490 * @brief Must be called by derived class before anything else: it refreshes the channel menus. 491 * By default it also set the dst clip pixel components according to the output plane selector if there is any 492 **/ 493 virtual void getClipPreferences(ClipPreferencesSetter &clipPreferences) OVERRIDE; 494 495 /** 496 * @brief Set the requested planes according to the selectors that were registered for each clip. 497 * By default the pass-through clip is set to the first source clip encountered in the registered plane selectors 498 **/ 499 virtual OfxStatus getClipComponents(const ClipComponentsArguments& args, ClipComponentsSetter& clipComponents) OVERRIDE; 500 501 /** 502 * @brief Force a refresh of the channel selectors. This should in general not be called as this is done for you in changedClip() in Natron > 3 503 * or getClipPreferences for any other host. 504 **/ 505 void refreshPlaneChoiceMenus(); 506 507 /** 508 * @brief Overriden to handle parameter changes. Derived class must call this class implementation. 509 **/ 510 virtual void changedParam(const InstanceChangedArgs &args, const std::string ¶mName) OVERRIDE; 511 512 /** 513 * @brief Overriden to handle clip changes. Derived class must call this class implementation. 514 **/ 515 virtual void changedClip(const InstanceChangedArgs &args, const std::string &clipName) OVERRIDE; 516 517 518 }; 519 520 namespace Factory { 521 522 /** 523 * @brief Add a dynamic choice parameter to select a plane. 524 * This should only be called for effects that flag kFnOfxImageEffectPropMultiPlanar=1 and 525 * if the host supports multi-plane suite v2 and dynamic choice parameters. 526 **/ 527 OFX::ChoiceParamDescriptor* describeInContextAddPlaneChoice(OFX::ImageEffectDescriptor &desc, 528 OFX::PageParamDescriptor* page, 529 const std::string& name, 530 const std::string& label, 531 const std::string& hint); 532 533 534 /** 535 * @brief Add a boolean parameter indicating if true that the plug-in is plane agnostic and will fetch in input the plane requested to render 536 * in output. Note that in this case any other plane choice parameter will be made secret. 537 **/ 538 OFX::BooleanParamDescriptor* describeInContextAddAllPlanesOutputCheckbox(OFX::ImageEffectDescriptor &desc, OFX::PageParamDescriptor* page); 539 540 /** 541 * @brief Add a dynamic choice parameter to select a channel among planes available in one or multiple source clips. 542 **/ 543 OFX::ChoiceParamDescriptor* describeInContextAddPlaneChannelChoice(OFX::ImageEffectDescriptor &desc, 544 OFX::PageParamDescriptor* page, 545 const std::vector<std::string>& clips, 546 const std::string& name, 547 const std::string& label, 548 const std::string& hint, 549 bool addConstants = true); 550 551 /** 552 * @brief Add the standard R,G,B,A choices for the given clips. 553 * @param addConstants If true, it will also add the "0" and "1" choice to the list 554 **/ 555 void addInputChannelOptionsRGBA(OFX::ChoiceParamDescriptor* param, 556 const std::vector<std::string>& clips, 557 bool addConstants, 558 bool onlyColorPlane); 559 560 561 /** 562 * @brief Same as above, but for a choice param instance 563 **/ 564 void addInputChannelOptionsRGBA(const std::vector<std::string>& clips, 565 bool addConstants, 566 bool onlyColorPlane); 567 } // Factory 568 } // namespace MultiPlane 569 } // namespace OFX 570 571 572 #endif /* defined(openfx_supportext_ofxsMultiPlane_h) */ 573