TuttleOFX  1
WarpPlugin.cpp
Go to the documentation of this file.
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 &paramName )
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