TuttleOFX
1
|
00001 #include "WarpPlugin.hpp" 00002 #include "WarpProcess.hpp" 00003 #include "WarpDefinitions.hpp" 00004 #include "Bezier/bezier.hpp" 00005 00006 #include <tuttle/plugin/ofxToGil/image.hpp> 00007 #include <tuttle/plugin/global.hpp> 00008 00009 #include <ofxsImageEffect.h> 00010 #include <ofxsMultiThread.h> 00011 00012 #include <boost/gil/gil_all.hpp> 00013 #include <boost/numeric/conversion/cast.hpp> 00014 #include <boost/numeric/ublas/io.hpp> 00015 #include <boost/numeric/ublas/lu.hpp> 00016 #include <boost/numeric/ublas/matrix.hpp> 00017 #include <boost/numeric/ublas/vector.hpp> 00018 #include <boost/algorithm/string/predicate.hpp> 00019 #include <boost/lexical_cast.hpp> 00020 00021 #include <boost/assign/list_of.hpp> 00022 00023 #include <cstddef> 00024 00025 namespace tuttle { 00026 namespace plugin { 00027 namespace warp { 00028 00029 WarpPlugin::WarpPlugin( OfxImageEffectHandle handle ) : 00030 ImageEffect( handle ) 00031 { 00032 _clipSrc = fetchClip( kOfxImageEffectSimpleSourceClipName ); 00033 _clipSrcB = fetchClip( kClipSourceB ); 00034 _clipDst = fetchClip( kOfxImageEffectOutputClipName ); 00035 00036 _paramOverlay = fetchBooleanParam( kParamOverlay ); 00037 _paramInverse = fetchBooleanParam( kParamInverse ); 00038 _paramReset = fetchPushButtonParam( kParamReset ); 00039 _paramNextCurve = fetchPushButtonParam( kParamNextCurve ); 00040 _paramSetKey = fetchPushButtonParam( kParamSetKey ); 00041 00042 _paramMethod = fetchChoiceParam( kParamMethod ); 00043 _paramNbPoints = fetchIntParam( kParamNbPoints ); 00044 _transition = fetchDoubleParam( kParamTransition ); 00045 00046 _paramRigiditeTPS = fetchDoubleParam( kParamRigiditeTPS ); 00047 _paramNbPointsBezier = fetchIntParam( kParamNbPointsBezier ); 00048 00049 //Multi curve 00050 for( std::size_t cptCBegin = 0; cptCBegin < kMaxNbPoints; ++cptCBegin ) 00051 { 00052 _paramCurveBegin[cptCBegin] = fetchBooleanParam( kParamCurveBegin + boost::lexical_cast<std::string > ( cptCBegin ) ); 00053 _paramCurveBegin[cptCBegin]->setDefault(false); 00054 } 00055 00056 //Param IN 00057 _paramGroupIn = fetchGroupParam( kParamGroupIn ); 00058 for( std::size_t cptIn = 0; cptIn < kMaxNbPoints; ++cptIn ) 00059 { 00060 _paramPointIn[cptIn] = fetchDouble2DParam( kParamPointIn + boost::lexical_cast<std::string > ( cptIn ) ); 00061 } 00062 _paramOverlayIn = fetchBooleanParam( kParamOverlayIn ); 00063 _paramOverlayInColor = fetchRGBParam( kParamOverlayInColor ); 00064 00065 //Param OUT 00066 _paramGroupOut = fetchGroupParam( kParamGroupIn ); 00067 for( std::size_t cptOut = 0; cptOut < kMaxNbPoints; ++cptOut ) 00068 { 00069 _paramPointOut[cptOut] = fetchDouble2DParam( kParamPointOut + boost::lexical_cast<std::string > ( cptOut ) ); 00070 } 00071 _paramOverlayOut = fetchBooleanParam( kParamOverlayOut ); 00072 _paramOverlayOutColor = fetchRGBParam( kParamOverlayOutColor ); 00073 00074 //Param TGT IN 00075 _paramGroupTgtIn = fetchGroupParam( kParamGroupTgtIn ); 00076 for( std::size_t cptTgtIn = 0; cptTgtIn < kMaxNbPoints; ++cptTgtIn ) 00077 { 00078 _paramPointTgtIn[2 * cptTgtIn] = fetchDouble2DParam( kParamPointTgtIn + boost::lexical_cast<std::string > ( 2 * cptTgtIn ) ); 00079 _paramPointTgtIn[2 * cptTgtIn + 1] = fetchDouble2DParam( kParamPointTgtIn + boost::lexical_cast<std::string > ( 2 * cptTgtIn + 1 ) ); 00080 } 00081 _paramOverlayTgtIn = fetchBooleanParam( kParamOverlayTgtIn ); 00082 _paramOverlayTgtInColor = fetchRGBParam( kParamOverlayTgtInColor ); 00083 00084 //Param TGT Out 00085 _paramGroupTgtOut = fetchGroupParam( kParamGroupTgtOut ); 00086 for( std::size_t cptTgtOut = 0; cptTgtOut < kMaxNbPoints; ++cptTgtOut ) 00087 { 00088 _paramPointTgtOut[2 * cptTgtOut] = fetchDouble2DParam( kParamPointTgtOut + boost::lexical_cast<std::string > ( 2 * cptTgtOut ) ); 00089 _paramPointTgtOut[2 * cptTgtOut + 1] = fetchDouble2DParam( kParamPointTgtOut + boost::lexical_cast<std::string > ( 2 * cptTgtOut + 1 ) ); 00090 } 00091 _paramOverlayTgtOut = fetchBooleanParam( kParamOverlayTgtOut ); 00092 _paramOverlayTgtOutColor = fetchRGBParam( kParamOverlayTgtOutColor ); 00093 00094 //Param speciaux 00095 _instanceChangedArgs.time = 0; 00096 _instanceChangedArgs.renderScale.x = 1; 00097 _instanceChangedArgs.renderScale.y = 1; 00098 _instanceChangedArgs.reason = OFX::eChangePluginEdit; 00099 changedParam( _instanceChangedArgs, kParamNbPoints ); // init IsSecret property for each pair of points parameter 00100 } 00101 00102 WarpProcessParams<WarpPlugin::Scalar> WarpPlugin::getProcessParams( const OfxPointD& renderScale ) const 00103 { 00104 using namespace boost::assign; 00105 WarpProcessParams<Scalar> params; 00106 const std::size_t nbPoints = _paramNbPoints->getValue( ); 00107 params._nbPoints = nbPoints; 00108 00109 params._rigiditeTPS = _paramRigiditeTPS->getValue( ); 00110 params._transition = _transition->getValue( ); 00111 params._method = static_cast<EParamMethod> ( _paramMethod->getValue( ) ); 00112 00113 if( nbPoints <= 1 ) 00114 { 00115 /// @todo: in this case it's just a translation... 00116 //TUTTLE_TCOUT_WITHINFOS( "TODO !" ); 00117 } 00118 const std::size_t nbBezierPoints = _paramNbPointsBezier->getValue( ); 00119 //TUTTLE_TCOUT_VAR( nbBezierPoints ); 00120 if( nbPoints == 0 ) 00121 { 00122 return params; 00123 } 00124 for( std::size_t c = 0; c < nbPoints - 1; ++c ) 00125 { 00126 00127 if( _paramCurveBegin[c+1]->getValue() ) 00128 continue; 00129 // Creation des points et des ptTangente et recuperation des valeurs 00130 //points a relier 00131 Point2 pIn1 = ofxToGil( _paramPointIn[c]->getValue( ) ); 00132 params._inPoints.push_back( pIn1 ); 00133 Point2 pIn2 = ofxToGil( _paramPointIn[c + 1]->getValue( ) ); 00134 00135 Point2 pOut1 = ofxToGil( _paramPointOut[c]->getValue( ) ); 00136 params._outPoints.push_back( pOut1 ); 00137 Point2 pOut2 = ofxToGil( _paramPointOut[c + 1]->getValue( ) ); 00138 00139 //Points de la tangente 00140 Point2 tIn1 = ofxToGil( _paramPointTgtIn[( 2 * c ) + 1]->getValue( ) ); 00141 Point2 tIn2 = ofxToGil( _paramPointTgtIn[( 2 * c ) + 2]->getValue( ) ); 00142 params._tgtPointsIn.push_back( tIn1 ); 00143 params._tgtPointsIn.push_back( tIn2 ); 00144 00145 Point2 tOut1 = ofxToGil( _paramPointTgtOut[( 2 * c ) + 1]->getValue( ) ); 00146 Point2 tOut2 = ofxToGil( _paramPointTgtOut[( 2 * c ) + 2]->getValue( ) ); 00147 00148 params._tgtPointsOut.push_back( tOut1 ); 00149 params._tgtPointsOut.push_back( tOut2 ); 00150 00151 // Creation et remplissage du tableau necessaire a Bezier 00152 //TUTTLE_TCOUT_INFOS; 00153 //TUTTLE_TCOUT_VAR( c ); 00154 { 00155 std::vector< Point2 > tabPtsIn; 00156 tabPtsIn.push_back( pIn1 ); 00157 tabPtsIn.push_back( tIn1 ); 00158 tabPtsIn.push_back( tIn2 ); 00159 tabPtsIn.push_back( pIn2 ); 00160 00161 params._bezierIn.push_back( pIn1 ); 00162 bezier::bezierSubdivide( tabPtsIn, nbBezierPoints, params._bezierIn ); 00163 00164 } 00165 { 00166 std::vector< Point2 > tabPtsOut; 00167 tabPtsOut.push_back( pOut1 ); 00168 tabPtsOut.push_back( tOut1 ); 00169 tabPtsOut.push_back( tOut2 ); 00170 tabPtsOut.push_back( pOut2 ); 00171 00172 params._bezierOut.push_back( pOut1 ); 00173 bezier::bezierSubdivide( tabPtsOut, nbBezierPoints, params._bezierOut ); 00174 00175 } 00176 //TUTTLE_TCOUT_INFOS; 00177 } 00178 const std::size_t c = nbPoints - 1; 00179 Point2 pIn = ofxToGil( _paramPointIn[c]->getValue( ) ); 00180 params._inPoints.push_back( pIn ); 00181 params._bezierIn.push_back( pIn ); 00182 Point2 pOut = ofxToGil( _paramPointOut[c]->getValue( ) ); 00183 params._outPoints.push_back( pOut ); 00184 params._bezierOut.push_back( pOut ); 00185 00186 if( _paramInverse->getValue( ) ) 00187 { 00188 std::swap( params._bezierIn, params._bezierOut ); 00189 } 00190 return params; 00191 } 00192 00193 void WarpPlugin::changedParam( const OFX::InstanceChangedArgs &args, const std::string ¶mName ) 00194 { 00195 if( boost::starts_with( paramName, kParamPointIn ) || 00196 boost::starts_with( paramName, kParamPointOut ) || 00197 boost::starts_with( paramName, kParamPointTgtIn ) || 00198 boost::starts_with( paramName, kParamPointTgtOut ) || 00199 paramName == kParamNbPoints ) 00200 { 00201 switch( static_cast<EParamMethod> ( _paramMethod->getValue( ) ) ) 00202 { 00203 case eParamMethodCreation: 00204 { 00205 std::size_t size = _paramNbPoints->getValue( ); 00206 std::size_t i = 0; 00207 for(; i < size; ++i ) 00208 { 00209 _paramPointIn[i]->setIsSecretAndDisabled( false ); 00210 _paramPointOut[i]->setIsSecretAndDisabled( false ); 00211 _paramPointTgtIn[2 * i]->setIsSecretAndDisabled( false ); 00212 _paramPointTgtIn[2 * i + 1]->setIsSecretAndDisabled( false ); 00213 _paramPointTgtOut[2 * i]->setIsSecretAndDisabled( false ); 00214 _paramPointTgtOut[2 * i + 1]->setIsSecretAndDisabled( false ); 00215 } 00216 for(; i < kMaxNbPoints; ++i ) 00217 { 00218 _paramPointIn[i]->setIsSecretAndDisabled( true ); 00219 _paramPointOut[i]->setIsSecretAndDisabled( true ); 00220 _paramPointTgtIn[2 * i]->setIsSecretAndDisabled( true ); 00221 _paramPointTgtIn[2 * i + 1]->setIsSecretAndDisabled( true ); 00222 _paramPointTgtOut[2 * i]->setIsSecretAndDisabled( true ); 00223 _paramPointTgtOut[2 * i + 1]->setIsSecretAndDisabled( true ); 00224 } 00225 break; 00226 } 00227 case eParamMethodDelete: 00228 { 00229 break; 00230 } 00231 case eParamMethodMove: 00232 { 00233 break; 00234 } 00235 } 00236 } 00237 //Si le mode est Reset 00238 else if( paramName == kParamReset ) 00239 { 00240 for( std::size_t i = 0; i < kMaxNbPoints; ++i ) 00241 { 00242 _paramPointIn[i]->setIsSecretAndDisabled( true ); 00243 _paramPointIn[i]->setValue( positionOrigine, positionOrigine ); 00244 _paramPointOut[i]->setIsSecretAndDisabled( true ); 00245 _paramPointOut[i]->setValue( positionOrigine, positionOrigine ); 00246 00247 _paramPointTgtIn[2 * i]->setIsSecretAndDisabled( true ); 00248 _paramPointTgtIn[2 * i]->setValue( positionOrigine, positionOrigine ); 00249 _paramPointTgtIn[( 2 * i ) + 1]->setIsSecretAndDisabled( true ); 00250 _paramPointTgtIn[( 2 * i ) + 1]->setValue( positionOrigine, positionOrigine ); 00251 00252 _paramPointTgtOut[2 * i]->setIsSecretAndDisabled( true ); 00253 _paramPointTgtOut[( 2 * i ) + 1]->setIsSecretAndDisabled( true ); 00254 00255 _paramNbPoints->setValue( 0 ); 00256 } 00257 } 00258 //Si le mode est MultiCurve 00259 else if( paramName == kParamNextCurve ) 00260 { 00261 TUTTLE_LOG_DEBUG(TUTTLE_INFO, _paramNbPoints->getValue()); 00262 _paramCurveBegin[(_paramNbPoints->getValue())]->setValue(true); 00263 TUTTLE_LOG_DEBUG(TUTTLE_INFO, _paramCurveBegin[(_paramNbPoints->getValue())]->getValue()); 00264 } 00265 else if( paramName == kParamSetKey ) 00266 { 00267 // @todo adrien: c'est peut-etre mieux de le faire uniquement sur les points cree ? _paramNbPoints->getValue() 00268 for( std::size_t i = 0; i < kMaxNbPoints; ++i ) 00269 { 00270 _paramPointIn[i]->setValueAtTime( args.time, _paramPointIn[i]->getValue( ) ); 00271 _paramPointOut[i]->setValueAtTime( args.time, _paramPointOut[i]->getValue( ) ); 00272 00273 _paramPointTgtIn[2 * i]->setValueAtTime( args.time, _paramPointTgtIn[2 * i]->getValue( ) ); 00274 _paramPointTgtIn[( 2 * i ) + 1]->setValueAtTime( args.time, _paramPointTgtIn[( 2 * i ) + 1]->getValue( ) ); 00275 00276 _paramPointTgtOut[2 * i]->setValueAtTime( args.time, _paramPointTgtOut[2 * i]->getValue( ) ); 00277 _paramPointTgtOut[( 2 * i ) + 1]->setValueAtTime( args.time, _paramPointTgtOut[( 2 * i ) + 1]->getValue( ) ); 00278 } 00279 } 00280 } 00281 00282 bool WarpPlugin::isIdentity( const OFX::RenderArguments& args, OFX::Clip*& identityClip, double& identityTime ) 00283 { 00284 WarpProcessParams<Scalar> params = getProcessParams( ); 00285 if( params._nbPoints == 0 ) 00286 { 00287 identityClip = _clipSrc; 00288 identityTime = args.time; 00289 return true; 00290 } 00291 // if( params._in == params._out ) 00292 // { 00293 // identityClip = _clipSrc; 00294 // identityTime = args.time; 00295 // return true; 00296 // } 00297 return false; 00298 } 00299 00300 /** 00301 * @brief The overridden render function 00302 * @param[in] args Rendering parameters 00303 */ 00304 void WarpPlugin::render( const OFX::RenderArguments &args ) 00305 { 00306 using namespace boost::gil; 00307 // instantiate the render code based on the pixel depth of the dst clip 00308 OFX::EBitDepth dstBitDepth = _clipDst->getPixelDepth( ); 00309 OFX::EPixelComponent dstComponents = _clipDst->getPixelComponents( ); 00310 00311 // do the rendering 00312 if( dstComponents == OFX::ePixelComponentRGBA ) 00313 { 00314 switch( dstBitDepth ) 00315 { 00316 case OFX::eBitDepthUByte: 00317 { 00318 WarpProcess<rgba8_view_t> p( *this ); 00319 p.setupAndProcess( args ); 00320 break; 00321 } 00322 case OFX::eBitDepthUShort: 00323 { 00324 WarpProcess<rgba16_view_t> p( *this ); 00325 p.setupAndProcess( args ); 00326 break; 00327 } 00328 case OFX::eBitDepthFloat: 00329 { 00330 WarpProcess<rgba32f_view_t> p( *this ); 00331 p.setupAndProcess( args ); 00332 break; 00333 } 00334 default: 00335 { 00336 TUTTLE_LOG_ERROR( "Bit depth (" << mapBitDepthEnumToString( dstBitDepth ) << ") not recognized by the plugin." ); 00337 00338 break; 00339 } 00340 } 00341 } 00342 else if( dstComponents == OFX::ePixelComponentAlpha ) 00343 { 00344 switch( dstBitDepth ) 00345 { 00346 case OFX::eBitDepthUByte: 00347 { 00348 WarpProcess<gray8_view_t> p( *this ); 00349 p.setupAndProcess( args ); 00350 break; 00351 } 00352 case OFX::eBitDepthUShort: 00353 { 00354 WarpProcess<gray16_view_t> p( *this ); 00355 p.setupAndProcess( args ); 00356 break; 00357 } 00358 case OFX::eBitDepthFloat: 00359 { 00360 WarpProcess<gray32f_view_t> p( *this ); 00361 p.setupAndProcess( args ); 00362 break; 00363 } 00364 default: 00365 { 00366 00367 TUTTLE_LOG_ERROR( "Bit depth (" << mapBitDepthEnumToString( dstBitDepth ) << ") not recognized by the plugin." ); 00368 00369 break; 00370 } 00371 } 00372 } 00373 else 00374 { 00375 TUTTLE_LOG_ERROR( "Pixel components (" << mapPixelComponentEnumToString( dstComponents ) << ") not supported by the plugin." ); 00376 00377 } 00378 } 00379 00380 00381 } 00382 } 00383 } 00384 00385