TuttleOFX
1
|
00001 #include "PushPixelPlugin.hpp" 00002 #include "PushPixelProcess.hpp" 00003 #include "PushPixelDefinitions.hpp" 00004 00005 #include <terry/filter/gaussianKernel.hpp> 00006 00007 #include <tuttle/common/utils/global.hpp> 00008 00009 #include <ofxsImageEffect.h> 00010 #include <ofxsMultiThread.h> 00011 00012 #include <boost/gil/gil_all.hpp> 00013 00014 #include <boost/math/constants/constants.hpp> 00015 00016 namespace tuttle { 00017 namespace plugin { 00018 namespace pushPixel { 00019 00020 00021 PushPixelPlugin::PushPixelPlugin( OfxImageEffectHandle handle ) 00022 : ImageEffect( handle ) 00023 { 00024 _clipSrc = fetchClip( kOfxImageEffectSimpleSourceClipName ); 00025 _clipMask = fetchClip( kClipMask ); 00026 _clipDst = fetchClip( kOfxImageEffectOutputClipName ); 00027 00028 _paramOutput = fetchChoiceParam( kParamOutput ); 00029 _paramSize = fetchDoubleParam( kParamSize ); 00030 _paramNormalizedKernel = fetchBooleanParam( kParamNormalizedKernel ); 00031 _paramIntensity = fetchDoubleParam( kParamIntensity ); 00032 _paramAngle = fetchDoubleParam( kParamAngle ); 00033 _paramInterpolation = fetchChoiceParam( kParamInterpolation ); 00034 _paramBorder = fetchChoiceParam( kParamBorder ); 00035 } 00036 00037 PushPixelProcessParams<PushPixelPlugin::Scalar> PushPixelPlugin::getProcessParams( const OfxPointD& renderScale ) const 00038 { 00039 using namespace boost::gil; 00040 using namespace terry; 00041 using namespace terry::filter; 00042 00043 PushPixelProcessParams<Scalar> params; 00044 params._output = static_cast<EParamOutput>( _paramOutput->getValue() ); 00045 params._size = _paramSize->getValue(); 00046 params._intensity = _paramIntensity->getValue() * params._size; 00047 params._size *= renderScale.x; 00048 params._intensity *= renderScale.x; 00049 00050 static const double degreeToRadian = boost::math::constants::pi<double>() / 180.0; 00051 params._angle = _paramAngle->getValue() * degreeToRadian; 00052 00053 params._interpolation = static_cast<EParamInterpolation>( _paramInterpolation->getValue() ); 00054 00055 params._border = static_cast<EParamBorder>( _paramBorder->getValue() ); 00056 params._boundary_option = convolve_option_extend_mirror; 00057 switch( params._border ) 00058 { 00059 case eParamBorderMirror: 00060 params._boundary_option = convolve_option_extend_mirror; 00061 break; 00062 case eParamBorderConstant: 00063 params._boundary_option = convolve_option_extend_constant; 00064 break; 00065 case eParamBorderBlack: 00066 params._boundary_option = convolve_option_extend_zero; 00067 break; 00068 case eParamBorderPadded: 00069 params._boundary_option = convolve_option_extend_padded; 00070 break; 00071 } 00072 00073 bool normalizedKernel = _paramNormalizedKernel->getValue(); 00074 params._kernelGaussianDerivative = buildGaussianDerivative1DKernel<Scalar>( params._size, normalizedKernel ); 00075 params._kernelGaussian = buildGaussian1DKernel<Scalar>( params._size, normalizedKernel ); 00076 00077 return params; 00078 } 00079 00080 bool PushPixelPlugin::isIdentity( const OFX::RenderArguments &args, OFX::Clip * &identityClip, double &identityTime ) 00081 { 00082 PushPixelProcessParams<Scalar> params = getProcessParams(); 00083 if( params._size != 0 && params._intensity != 0 ) 00084 return false; 00085 00086 identityClip = _clipSrc; 00087 identityTime = args.time; 00088 return true; 00089 } 00090 00091 void PushPixelPlugin::getRegionsOfInterest( const OFX::RegionsOfInterestArguments& args, OFX::RegionOfInterestSetter& rois ) 00092 { 00093 00094 OfxRectD srcRod = _clipSrc->getCanonicalRod( args.time ); 00095 //OfxRectD dstRod = _clipDst->getCanonicalRod( args.time ); 00096 00097 if( _clipMask->isConnected() ) 00098 { 00099 PushPixelProcessParams<Scalar> params( getProcessParams() ); 00100 //OfxRectD maskRod = _clipMask->getCanonicalRod( args.time ); 00101 double maxKernelTL = std::max( params._kernelGaussian.left_size(), params._kernelGaussianDerivative.left_size() ); 00102 double maxKernelBR = std::max( params._kernelGaussian.right_size(), params._kernelGaussianDerivative.right_size() ); 00103 OfxRectD maskRoi; 00104 maskRoi.x1 = args.regionOfInterest.x1 - ( maxKernelTL * _clipMask->getPixelAspectRatio() ); 00105 maskRoi.y1 = args.regionOfInterest.y1 - maxKernelTL; 00106 maskRoi.x2 = args.regionOfInterest.x2 + ( maxKernelBR * _clipMask->getPixelAspectRatio() ); 00107 maskRoi.y2 = args.regionOfInterest.y2 + maxKernelBR; 00108 rois.setRegionOfInterest( *_clipMask, maskRoi ); 00109 } 00110 00111 // no tiles on src clip, because it depends on the mask content so we can't 00112 // define the maximal bounding box needed... 00113 rois.setRegionOfInterest( *_clipSrc, srcRod ); 00114 } 00115 00116 /** 00117 * @brief The overridden render function 00118 * @param[in] args Rendering parameters 00119 */ 00120 void PushPixelPlugin::render( const OFX::RenderArguments &args ) 00121 { 00122 using namespace boost::gil; 00123 BOOST_ASSERT( _clipDst->getPixelDepth() == _clipSrc->getPixelDepth() ); 00124 BOOST_ASSERT( _clipDst->getPixelComponents() == _clipSrc->getPixelComponents() ); 00125 00126 // instantiate the render code based on the pixel depth of the dst clip 00127 OFX::EBitDepth dstBitDepth = _clipDst->getPixelDepth( ); 00128 OFX::EPixelComponent dstComponents = _clipDst->getPixelComponents( ); 00129 00130 // do the rendering 00131 if( dstComponents == OFX::ePixelComponentRGBA ) 00132 { 00133 switch( dstBitDepth ) 00134 { 00135 case OFX::eBitDepthUByte : 00136 { 00137 PushPixelProcess<rgba8_view_t> p( *this ); 00138 p.setupAndProcess( args ); 00139 break; 00140 } 00141 case OFX::eBitDepthUShort : 00142 { 00143 PushPixelProcess<rgba16_view_t> p( *this ); 00144 p.setupAndProcess( args ); 00145 break; 00146 } 00147 case OFX::eBitDepthFloat : 00148 { 00149 PushPixelProcess<rgba32f_view_t> p( *this ); 00150 p.setupAndProcess( args ); 00151 break; 00152 } 00153 case OFX::eBitDepthNone : 00154 TUTTLE_LOG_FATAL( "BitDepthNone not recognize." ); 00155 return; 00156 case OFX::eBitDepthCustom : 00157 TUTTLE_LOG_FATAL( "BitDepthCustom not recognize." ); 00158 return; 00159 } 00160 }/* 00161 else if( dstComponents == OFX::ePixelComponentAlpha ) 00162 { 00163 switch( dstBitDepth ) 00164 { 00165 case OFX::eBitDepthUByte : 00166 { 00167 PushPixelProcess<gray8_view_t> p( *this ); 00168 p.setupAndProcess( args ); 00169 break; 00170 } 00171 case OFX::eBitDepthUShort : 00172 { 00173 PushPixelProcess<gray16_view_t> p( *this ); 00174 p.setupAndProcess( args ); 00175 break; 00176 } 00177 case OFX::eBitDepthFloat : 00178 { 00179 PushPixelProcess<gray32f_view_t> p( *this ); 00180 p.setupAndProcess( args ); 00181 break; 00182 } 00183 case OFX::eBitDepthNone : 00184 TUTTLE_LOG_FATAL( "BitDepthNone not recognize." ); 00185 return; 00186 case OFX::eBitDepthCustom : 00187 TUTTLE_LOG_FATAL( "BitDepthCustom not recognize." ); 00188 return; 00189 } 00190 }*/ 00191 else 00192 { 00193 TUTTLE_LOG_FATAL( "Components not recognize." ); 00194 } 00195 } 00196 00197 } 00198 } 00199 }