TuttleOFX
1
|
00001 #include "MergePlugin.hpp" 00002 #include "MergeProcess.hpp" 00003 #include "MergeDefinitions.hpp" 00004 00005 #include <terry/merge/MergeFunctors.hpp> 00006 00007 #include <tuttle/plugin/numeric/rectOp.hpp> 00008 00009 #include <boost/gil/gil_all.hpp> 00010 00011 #include <boost/mpl/bool.hpp> 00012 #include <boost/mpl/if.hpp> 00013 #include <boost/type_traits/is_same.hpp> 00014 00015 namespace tuttle { 00016 namespace plugin { 00017 namespace merge { 00018 00019 MergePlugin::MergePlugin( OfxImageEffectHandle handle ) 00020 : OFX::ImageEffect( handle ) 00021 { 00022 _clipSrcA = fetchClip( kParamSourceA ); 00023 _clipSrcB = fetchClip( kParamSourceB ); 00024 _clipDst = fetchClip( kOfxImageEffectOutputClipName ); 00025 00026 _paramMerge = fetchChoiceParam( kParamFunction ); 00027 _paramOffsetA = fetchInt2DParam( kParamOffsetA ); 00028 _paramOffsetB = fetchInt2DParam( kParamOffsetB ); 00029 _paramRod = fetchChoiceParam( kParamRod ); 00030 } 00031 00032 MergeProcessParams<MergePlugin::Scalar> MergePlugin::getProcessParams( const OfxPointD& renderScale ) const 00033 { 00034 MergeProcessParams<Scalar> params; 00035 00036 params._rod = static_cast<EParamRod>( _paramRod->getValue() ); 00037 00038 OfxPointI offsetA = _paramOffsetA->getValue(); 00039 params._offsetA.x = offsetA.x * renderScale.x; 00040 params._offsetA.y = offsetA.y * renderScale.y; 00041 00042 OfxPointI offsetB = _paramOffsetB->getValue(); 00043 params._offsetB.x = offsetB.x * renderScale.x; 00044 params._offsetB.y = offsetB.y * renderScale.y; 00045 00046 return params; 00047 } 00048 00049 //void MergePlugin::changedParam( const OFX::InstanceChangedArgs& args, const std::string& paramName ) 00050 //{ 00051 //} 00052 00053 bool MergePlugin::getRegionOfDefinition( const OFX::RegionOfDefinitionArguments& args, OfxRectD& rod ) 00054 { 00055 MergeProcessParams<Scalar> params = getProcessParams(); 00056 00057 OfxRectD srcRodA = translateRegion( _clipSrcA->getCanonicalRod( args.time ), params._offsetA ); 00058 OfxRectD srcRodB = translateRegion( _clipSrcB->getCanonicalRod( args.time ), params._offsetB ); 00059 00060 switch( params._rod ) 00061 { 00062 case eParamRodIntersect: 00063 { 00064 rod = rectanglesIntersection( srcRodA, srcRodB ); 00065 return true; 00066 } 00067 case eParamRodUnion: 00068 { 00069 rod = rectanglesBoundingBox( srcRodA, srcRodB ); 00070 return true; 00071 } 00072 case eParamRodA: 00073 { 00074 rod = srcRodA; 00075 return true; 00076 } 00077 case eParamRodB: 00078 { 00079 rod = srcRodB; 00080 return true; 00081 } 00082 } 00083 return false; 00084 } 00085 00086 /** 00087 * @brief The overridden render function 00088 * @param[in] args Rendering parameters 00089 */ 00090 void MergePlugin::render( const OFX::RenderArguments &args ) 00091 { 00092 using namespace boost::gil; 00093 // instantiate the render code based on the pixel depth of the dst clip 00094 OFX::EBitDepth bitDepth = _clipDst->getPixelDepth( ); 00095 OFX::EPixelComponent components = _clipDst->getPixelComponents( ); 00096 00097 switch( components ) 00098 { 00099 case OFX::ePixelComponentRGBA: 00100 { 00101 switch( bitDepth ) 00102 { 00103 case OFX::eBitDepthUByte: 00104 { 00105 render<rgba8_view_t>(args); 00106 return; 00107 } 00108 case OFX::eBitDepthUShort: 00109 { 00110 render<rgba16_view_t>(args); 00111 return; 00112 } 00113 case OFX::eBitDepthFloat: 00114 { 00115 render<rgba32f_view_t>(args); 00116 return; 00117 } 00118 case OFX::eBitDepthCustom: 00119 case OFX::eBitDepthNone: 00120 { 00121 BOOST_THROW_EXCEPTION( exception::Unsupported() 00122 << exception::user() + "Bit depth (" + mapBitDepthEnumToString(bitDepth) + ") not recognized by the plugin." ); 00123 } 00124 } 00125 } 00126 case OFX::ePixelComponentRGB: 00127 { 00128 switch( bitDepth ) 00129 { 00130 case OFX::eBitDepthUByte: 00131 { 00132 render<rgb8_view_t>(args); 00133 return; 00134 } 00135 case OFX::eBitDepthUShort: 00136 { 00137 render<rgb16_view_t>(args); 00138 return; 00139 } 00140 case OFX::eBitDepthFloat: 00141 { 00142 render<rgb32f_view_t>(args); 00143 return; 00144 } 00145 case OFX::eBitDepthCustom: 00146 case OFX::eBitDepthNone: 00147 { 00148 BOOST_THROW_EXCEPTION( exception::Unsupported() 00149 << exception::user() + "Bit depth (" + mapBitDepthEnumToString(bitDepth) + ") not recognized by the plugin." ); 00150 } 00151 } 00152 } 00153 case OFX::ePixelComponentAlpha: 00154 { 00155 switch( bitDepth ) 00156 { 00157 case OFX::eBitDepthUByte : 00158 { 00159 render<gray8_view_t>(args); 00160 return; 00161 } 00162 case OFX::eBitDepthUShort : 00163 { 00164 render<gray16_view_t>(args); 00165 return; 00166 } 00167 case OFX::eBitDepthFloat : 00168 { 00169 render<gray32f_view_t>(args); 00170 return; 00171 } 00172 case OFX::eBitDepthCustom: 00173 case OFX::eBitDepthNone: 00174 { 00175 BOOST_THROW_EXCEPTION( exception::Unsupported() 00176 << exception::user() + "Bit depth (" + mapBitDepthEnumToString(bitDepth) + ") not recognized by the plugin." ); 00177 } 00178 } 00179 } 00180 case OFX::ePixelComponentCustom: 00181 case OFX::ePixelComponentNone: 00182 { 00183 BOOST_THROW_EXCEPTION( exception::Unsupported() 00184 << exception::user() + "Pixel components (" + mapPixelComponentEnumToString(components) + ") not supported by the plugin." ); 00185 } 00186 } 00187 BOOST_THROW_EXCEPTION( exception::Unknown() ); 00188 } 00189 00190 template< class View > 00191 void MergePlugin::render( const OFX::RenderArguments& args ) 00192 { 00193 using namespace boost::gil; 00194 using namespace terry; 00195 typedef typename View::value_type Pixel; 00196 EParamMerge merge = static_cast<EParamMerge>(_paramMerge->getValue()); 00197 00198 // if( ! boost::gil::contains_color<Pixel, boost::gil::alpha_t>::value ) 00199 // { 00200 // // Functions that need alpha 00201 // switch( merge ) 00202 // { 00203 // case eParamMergeATop: 00204 // case eParamMergeColor: 00205 // case eParamMergeConjointOver: 00206 // case eParamMergeColorBurn: 00207 // case eParamMergeColorDodge: 00208 // case eParamMergeDisjointOver: 00209 // case eParamMergeIn: 00210 // case eParamMergeMask: 00211 // case eParamMergeMatte: 00212 // case eParamMergeOut: 00213 // case eParamMergeOver: 00214 // case eParamMergeStencil: 00215 // case eParamMergeUnder: 00216 // case eParamMergeXOR: 00217 // TUTTLE_LOG_FATAL( "Need an alpha channel for this Merge operation." ); 00218 // return; 00219 // default: 00220 // break; 00221 // } 00222 // } 00223 switch( merge ) 00224 { 00225 // Functions that need alpha 00226 case eParamMergeATop: 00227 { 00228 render< View, FunctorATop >( args ); 00229 break; 00230 } 00231 case eParamMergeColor: 00232 { 00233 render< View, FunctorColor >( args ); 00234 break; 00235 } 00236 case eParamMergeConjointOver: 00237 { 00238 render< View, FunctorConjointOver >( args ); 00239 break; 00240 } 00241 case eParamMergeColorBurn: 00242 { 00243 render< View, FunctorColorBurn >( args ); 00244 break; 00245 } 00246 case eParamMergeColorDodge: 00247 { 00248 render< View, FunctorColorDodge >( args ); 00249 break; 00250 } 00251 case eParamMergeDisjointOver: 00252 { 00253 render< View, FunctorDisjointOver >( args ); 00254 break; 00255 } 00256 case eParamMergeIn: 00257 { 00258 render< View, FunctorIn >( args ); 00259 break; 00260 } 00261 case eParamMergeMask: 00262 { 00263 render< View, FunctorMask >( args ); 00264 break; 00265 } 00266 case eParamMergeMatte: 00267 { 00268 render< View, FunctorMatte >( args ); 00269 break; 00270 } 00271 case eParamMergeOut: 00272 { 00273 render< View, FunctorOut >( args ); 00274 break; 00275 } 00276 case eParamMergeOver: 00277 { 00278 render< View, FunctorOver >( args ); 00279 break; 00280 } 00281 case eParamMergeStencil: 00282 { 00283 render< View, FunctorStencil >( args ); 00284 break; 00285 } 00286 case eParamMergeUnder: 00287 { 00288 render< View, FunctorUnder >( args ); 00289 break; 00290 } 00291 case eParamMergeXOR: 00292 { 00293 render< View, FunctorXOR >( args ); 00294 break; 00295 } 00296 // Functions that doesn't need alpha 00297 case eParamMergeAverage: 00298 { 00299 render< View, FunctorAverage >( args ); 00300 break; 00301 } 00302 case eParamMergeCopy: 00303 { 00304 render< View, FunctorCopy >( args ); 00305 break; 00306 } 00307 case eParamMergeDifference: 00308 { 00309 render< View, FunctorDifference >( args ); 00310 break; 00311 } 00312 case eParamMergeDivide: 00313 { 00314 render< View, FunctorDivide >( args ); 00315 break; 00316 } 00317 case eParamMergeExclusion: 00318 { 00319 render< View, FunctorExclusion >( args ); 00320 break; 00321 } 00322 case eParamMergeFrom: 00323 { 00324 render< View, FunctorFrom >( args ); 00325 break; 00326 } 00327 case eParamMergeGeometric: 00328 { 00329 render< View, FunctorGeometric >( args ); 00330 break; 00331 } 00332 case eParamMergeHardLight: 00333 { 00334 render< View, FunctorHardLight >( args ); 00335 break; 00336 } 00337 case eParamMergeHypot: 00338 { 00339 render< View, FunctorHypot >( args ); 00340 break; 00341 } 00342 case eParamMergeLighten: 00343 { 00344 render< View, FunctorLighten >( args ); 00345 break; 00346 } 00347 case eParamMergeDarken: 00348 { 00349 render< View, FunctorDarken >( args ); 00350 break; 00351 } 00352 case eParamMergeMinus: 00353 { 00354 render< View, FunctorMinus >( args ); 00355 break; 00356 } 00357 case eParamMergeMultiply: 00358 { 00359 render< View, FunctorMultiply >( args ); 00360 break; 00361 } 00362 case eParamMergeOverlay: 00363 { 00364 render< View, FunctorOverlay >( args ); 00365 break; 00366 } 00367 case eParamMergePlus: 00368 { 00369 render< View, FunctorPlus >( args ); 00370 break; 00371 } 00372 case eParamMergeScreen: 00373 { 00374 render< View, FunctorScreen >( args ); 00375 break; 00376 } 00377 case eParamMergePinLight: 00378 { 00379 render< View, FunctorPinLight >( args ); 00380 break; 00381 } 00382 case eParamMergeReflect: 00383 { 00384 // Quadratic mode: reflect 00385 render< View, FunctorReflect >( args ); 00386 break; 00387 } 00388 case eParamMergeFreeze: 00389 { 00390 // Quadratic mode: freeze 00391 render< View, FunctorFreeze >( args ); 00392 break; 00393 } 00394 case eParamMergeInterpolated: 00395 { 00396 // Similar to average, but smoother (and a lot slower)... 00397 render< View, FunctorInterpolated >( args ); 00398 break; 00399 } 00400 } 00401 } 00402 00403 template< class View, template <typename> class Functor > 00404 void MergePlugin::render_if( const OFX::RenderArguments& args, boost::mpl::true_ ) 00405 { 00406 typedef typename View::value_type Pixel; 00407 MergeProcess<View, Functor<Pixel> > p( *this ); 00408 p.setupAndProcess( args ); 00409 } 00410 00411 template< class View, template <typename> class Functor > 00412 void MergePlugin::render_if( const OFX::RenderArguments& args, boost::mpl::false_ ) 00413 { 00414 BOOST_THROW_EXCEPTION( exception::Unsupported() 00415 << exception::user() + "Need an alpha channel for this Merge operation." ); 00416 } 00417 00418 template< class View, template <typename> class Functor > 00419 void MergePlugin::render( const OFX::RenderArguments& args ) 00420 { 00421 typedef typename View::value_type Pixel; 00422 typedef typename boost::gil::contains_color< typename View::value_type, boost::gil::alpha_t>::type has_alpha_t; 00423 typedef typename boost::is_same<typename Functor<Pixel>::operating_mode_t, terry::merge_per_channel_with_alpha>::type merge_need_alpha_t; 00424 typedef typename boost::mpl::if_<merge_need_alpha_t, has_alpha_t, boost::mpl::true_>::type render_condition_t; 00425 00426 render_if<View, Functor>( args, render_condition_t() ); 00427 } 00428 00429 } 00430 } 00431 }