TuttleOFX  1
ofxsInteract.cpp
Go to the documentation of this file.
00001 /*
00002  * OFX Support Library, a library that skins the OFX plug-in API with C++ classes.
00003  * Copyright (C) 2004-2005 The Open Effects Association Ltd
00004  * Author Bruno Nicoletti bruno@thefoundry.co.uk
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are met:
00008  *
00009  * Redistributions of source code must retain the above copyright notice,
00010  * this list of conditions and the following disclaimer.
00011  * Redistributions in binary form must reproduce the above copyright notice,
00012  * this list of conditions and the following disclaimer in the documentation
00013  * and/or other materials provided with the distribution.
00014  * Neither the name The Open Effects Association Ltd, nor the names of its
00015  * contributors may be used to endorse or promote products derived from this
00016  * software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00019  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00020  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00021  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
00022  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00023  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00024  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00025  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00026  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00027  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028  *
00029  * The Open Effects Association Ltd
00030  * 1 Wardour St
00031  * London W1D 6PA
00032  * England
00033  *
00034  *
00035  */
00036 
00037 /** @brief This file contains code that skins the ofx interact suite (for image effects) */
00038 
00039 #include "ofxsSupportPrivate.h"
00040 
00041 #include <tuttle/plugin/global.hpp>
00042 #include <tuttle/plugin/exceptions.hpp>
00043 
00044 #include <algorithm> // for find
00045 
00046 /** @brief The core 'OFX Support' namespace, used by plugin implementations. All code for these are defined in the common support libraries.
00047  */
00048 namespace OFX {
00049 
00050 InteractDescriptor::~InteractDescriptor() {}
00051 EffectInteractWrap::~EffectInteractWrap() {}
00052 ParamInteractWrap::~ParamInteractWrap() {}
00053 
00054 /** @brief fetch a pixel scale out of the property set */
00055 static OfxPointD getPixelScale( const PropertySet& props )
00056 {
00057         OfxPointD pixelScale;
00058 
00059         pixelScale.x = props.propGetDouble( kOfxInteractPropPixelScale, 0 );
00060         pixelScale.y = props.propGetDouble( kOfxInteractPropPixelScale, 1 );
00061         return pixelScale;
00062 }
00063 
00064 /** @brief fetch a render scale out of the property set */
00065 static OfxPointD getRenderScale( const PropertySet& props )
00066 {
00067         OfxPointD v;
00068 
00069         v.x = props.propGetDouble( kOfxImageEffectPropRenderScale, 0 );
00070         v.y = props.propGetDouble( kOfxImageEffectPropRenderScale, 1 );
00071         return v;
00072 }
00073 
00074 /** @brief fetch a background colour out of the property set */
00075 static OfxRGBColourD getBackgroundColour( const PropertySet& props )
00076 {
00077         OfxRGBColourD backGroundColour;
00078 
00079         backGroundColour.r = props.propGetDouble( kOfxInteractPropBackgroundColour, 0 );
00080         backGroundColour.g = props.propGetDouble( kOfxInteractPropBackgroundColour, 1 );
00081         backGroundColour.b = props.propGetDouble( kOfxInteractPropBackgroundColour, 2 );
00082         return backGroundColour;
00083 }
00084 
00085 /** @brief retrieves the image effect pointer from the interact handle */
00086 static ImageEffect* retrieveEffectFromInteractHandle( OfxInteractHandle handle )
00087 {
00088         // get the properties set on this handle
00089         OfxPropertySetHandle propHandle;
00090         OfxStatus stat = OFX::Private::gInteractSuite->interactGetPropertySet( handle, &propHandle );
00091 
00092         throwSuiteStatusException( stat );
00093         PropertySet interactProperties( propHandle );
00094 
00095         // get the effect handle from this handle
00096         OfxImageEffectHandle effectHandle = (OfxImageEffectHandle) interactProperties.propGetPointer( kOfxPropEffectInstance );
00097 
00098         // get the effect properties
00099         return OFX::Private::retrieveImageEffectPointer( effectHandle );
00100 }
00101 
00102 
00103 InteractI::~InteractI()
00104 {}
00105 
00106 /** @brief the function called to draw in the interact */
00107 bool InteractI::draw( const DrawArgs& args )
00108 {
00109         return false;
00110 }
00111 
00112 /** @brief the function called to handle pen motion in the interact
00113  *
00114  * returns true if the interact trapped the action in some sense. This will block the action being passed to
00115  * any other interact that may share the viewer.
00116  */
00117 bool InteractI::penMotion( const PenArgs& args )
00118 {
00119         return false;
00120 }
00121 
00122 /** @brief the function called to handle pen down events in the interact
00123  *
00124  * returns true if the interact trapped the action in some sense. This will block the action being passed to
00125  * any other interact that may share the viewer.
00126  */
00127 bool InteractI::penDown( const PenArgs& args )
00128 {
00129         return false;
00130 }
00131 
00132 /** @brief the function called to handle pen up events in the interact
00133  *
00134  * returns true if the interact trapped the action in some sense. This will block the action being passed to
00135  * any other interact that may share the viewer.
00136  */
00137 bool InteractI::penUp( const PenArgs& args )
00138 {
00139         return false;
00140 }
00141 
00142 /** @brief the function called to handle key down events in the interact
00143  *
00144  * returns true if the interact trapped the action in some sense. This will block the action being passed to
00145  * any other interact that may share the viewer.
00146  */
00147 bool InteractI::keyDown( const KeyArgs& args )
00148 {
00149         return false;
00150 }
00151 
00152 /** @brief the function called to handle key up events in the interact
00153  *
00154  * returns true if the interact trapped the action in some sense. This will block the action being passed to
00155  * any other interact that may share the viewer.
00156  */
00157 bool InteractI::keyUp( const KeyArgs& args )
00158 {
00159         return false;
00160 }
00161 
00162 /** @brief the function called to handle key down repeat events in the interact
00163  *
00164  * returns true if the interact trapped the action in some sense. This will block the action being passed to
00165  * any other interact that may share the viewer.
00166  */
00167 bool InteractI::keyRepeat( const KeyArgs& args )
00168 {
00169         return false;
00170 }
00171 
00172 /** @brief Called when the interact is given input focus */
00173 void InteractI::gainFocus( const FocusArgs& args )
00174 {}
00175 
00176 /** @brief Called when the interact is loses input focus */
00177 void InteractI::loseFocus( const FocusArgs& args )
00178 {}
00179 
00180 
00181 Interact::Interact( OfxInteractHandle handle )
00182         : _interactHandle( handle )
00183         , _effect( 0 )
00184         , _magic( kMagic )
00185 {
00186         // get the properties set on this handle
00187         OfxPropertySetHandle propHandle;
00188         OfxStatus stat = OFX::Private::gInteractSuite->interactGetPropertySet( handle, &propHandle );
00189 
00190         throwSuiteStatusException( stat );
00191         _interactProperties.propSetHandle( propHandle );
00192 
00193         // set othe instance data on the property handle to point to this interact
00194         _interactProperties.propSetPointer( kOfxPropInstanceData, (void*)this );
00195 
00196         // get the effect handle from this handle
00197         _effect = retrieveEffectFromInteractHandle( handle );
00198 }
00199 
00200 Interact::~Interact()
00201 {}
00202 
00203 /** @brief The bitdepth of each component in the openGL frame buffer */
00204 int Interact::getBitDepth( void ) const
00205 {
00206         return _interactProperties.propGetInt( kOfxInteractPropBitDepth );
00207 }
00208 
00209 /** @brief Does the openGL frame buffer have an alpha */
00210 bool Interact::hasAlpha( void ) const
00211 {
00212         return _interactProperties.propGetInt( kOfxInteractPropHasAlpha ) != 0;
00213 }
00214 
00215 /** @brief Returns the size of a real screen pixel under the interact's cannonical projection */
00216 OfxPointD Interact::getPixelScale( void ) const
00217 {
00218         OfxPointD v;
00219 
00220         v.x = _interactProperties.propGetDouble( kOfxInteractPropPixelScale, 0 );
00221         v.y = _interactProperties.propGetDouble( kOfxInteractPropPixelScale, 1 );
00222         return v;
00223 }
00224 
00225 /** @brief Request a redraw */
00226 void Interact::requestRedraw( void ) const
00227 {
00228         OfxStatus stat = OFX::Private::gInteractSuite->interactRedraw( _interactHandle );
00229 
00230         throwSuiteStatusException( stat );
00231 }
00232 
00233 /** @brief Swap a buffer in the case of a double bufferred interact, this is possibly a silly one */
00234 void Interact::swapBuffers( void ) const
00235 {
00236         OfxStatus stat = OFX::Private::gInteractSuite->interactSwapBuffers( _interactHandle );
00237 
00238         throwSuiteStatusException( stat );
00239 }
00240 
00241 /** @brief Set a param that the interact should be redrawn on if its value changes */
00242 void Interact::addParamToSlaveTo( Param* p )
00243 {
00244         // do we have it already ?
00245         std::list<Param*>::iterator i;
00246         i = std::find( _slaveParams.begin(), _slaveParams.end(), p );
00247         if( i == _slaveParams.end() )
00248         {
00249                 // we have a new one to add in here
00250                 _slaveParams.push_back( p );
00251 
00252                 // and set the property
00253                 int n = _interactProperties.propGetDimension( kOfxInteractPropSlaveToParam );
00254                 _interactProperties.propSetString( kOfxInteractPropSlaveToParam, p->getName(), n );
00255         }
00256 
00257 }
00258 
00259 /** @brief Remova a param that the interact should be redrawn on if its value changes */
00260 void Interact::removeParamToSlaveTo( Param* p )
00261 {
00262         // do we have it already ?
00263         std::list<Param*>::iterator i;
00264         i = std::find( _slaveParams.begin(), _slaveParams.end(), p );
00265         if( i != _slaveParams.end() )
00266         {
00267                 // clobber it from the list
00268                 _slaveParams.erase( i );
00269 
00270                 // reset the property to remove our dead one
00271                 _interactProperties.propReset( kOfxInteractPropSlaveToParam );
00272 
00273                 // and add them all in again
00274                 int n = 0;
00275                 for( i = _slaveParams.begin(); i != _slaveParams.end(); ++i, ++n )
00276                 {
00277                         _interactProperties.propSetString( kOfxInteractPropSlaveToParam, ( *i )->getName(), n );
00278                 }
00279         }
00280 }
00281 
00282 /** @brief the background colour */
00283 OfxRGBColourD Interact::getBackgroundColour( void ) const
00284 {
00285         return OFX::getBackgroundColour( _interactProperties );
00286 }
00287 
00288 ////////////////////////////////////////////////////////////////////////////////
00289 // overlay interact guff
00290 
00291 /** @brief ctor */
00292 OverlayInteract::OverlayInteract( OfxInteractHandle handle )
00293         : Interact( handle )
00294 {
00295         // add this interact into the list of overlays that the effect knows about
00296         if( _effect )
00297                 _effect->addOverlayInteract( this );
00298 }
00299 
00300 /** @brief ctor */
00301 OverlayInteract::~OverlayInteract()
00302 {
00303         // add this interact into the list of overlays that the effect knows about
00304         if( _effect )
00305                 _effect->removeOverlayInteract( this );
00306 }
00307 
00308 ////////////////////////////////////////////////////////////////////////////////
00309 /** @brief ctor */
00310 InteractArgs::InteractArgs( const PropertySet& props )
00311 {
00312         time        = props.propGetDouble( kOfxPropTime );
00313         renderScale = getRenderScale( props );
00314 }
00315 
00316 /** @brief ctor */
00317 DrawArgs::DrawArgs( const PropertySet& props )
00318         : InteractArgs( props )
00319 {
00320         backGroundColour = getBackgroundColour( props );
00321         pixelScale       = getPixelScale( props );
00322 }
00323 
00324 /** @brief ctor */
00325 PenArgs::PenArgs( const PropertySet& props )
00326         : InteractArgs( props )
00327 {
00328         pixelScale    = getPixelScale( props );
00329         penPosition.x = props.propGetDouble( kOfxInteractPropPenPosition, 0 );
00330         penPosition.y = props.propGetDouble( kOfxInteractPropPenPosition, 1 );
00331         penPressure   = props.propGetDouble( kOfxInteractPropPenPressure );
00332 }
00333 
00334 /** @brief ctor */
00335 KeyArgs::KeyArgs( const PropertySet& props )
00336         : InteractArgs( props )
00337 {
00338         time        = props.propGetDouble( kOfxPropTime );
00339         renderScale = getRenderScale( props );
00340         keyString   = props.propGetString( kOfxPropKeyString );
00341         keySymbol   = props.propGetInt( kOfxPropKeySym );
00342 }
00343 
00344 /** @brief ctor */
00345 FocusArgs::FocusArgs( const PropertySet& props )
00346         : InteractArgs( props )
00347 {
00348         pixelScale       = getPixelScale( props );
00349         backGroundColour = getBackgroundColour( props );
00350 }
00351 
00352 void ParamInteractDescriptor::setInteractSizeAspect( double asp )
00353 {
00354         _props->propSetDouble( kOfxParamPropInteractSizeAspect, asp );
00355 }
00356 
00357 void ParamInteractDescriptor::setInteractMinimumSize( int x, int y )
00358 {
00359         _props->propSetInt( kOfxParamPropInteractMinimumSize, x, 0 );
00360         _props->propSetInt( kOfxParamPropInteractMinimumSize, y, 1 );
00361 }
00362 
00363 void ParamInteractDescriptor::setInteractPreferredSize( int x, int y )
00364 {
00365         _props->propSetInt( kOfxParamPropInteractPreferedSize, x, 0 );
00366         _props->propSetInt( kOfxParamPropInteractPreferedSize, y, 1 );
00367 }
00368 
00369 ParamInteract::ParamInteract( OfxInteractHandle handle, ImageEffect* effect ) : Interact( handle ),
00370         _effect( effect )
00371 {}
00372 
00373 OfxPointI ParamInteract::getInteractSize() const
00374 {
00375         OfxPointI ret;
00376 
00377         ret.x =  _interactProperties.propGetInt( kOfxParamPropInteractSize, 0 );
00378         ret.y =  _interactProperties.propGetInt( kOfxParamPropInteractSize, 1 );
00379         return ret;
00380 }
00381 
00382 namespace Private {
00383 /** @brief fetches our pointer out of the props on the handle */
00384 Interact* retrieveInteractPointer( OfxInteractHandle handle )
00385 {
00386         Interact* instance;
00387 
00388         // get the prop set on the handle
00389         OfxPropertySetHandle propHandle;
00390         OfxStatus stat = OFX::Private::gInteractSuite->interactGetPropertySet( handle, &propHandle );
00391 
00392         throwSuiteStatusException( stat );
00393 
00394         // make our wrapper object
00395         PropertySet props( propHandle );
00396 
00397         // fetch the instance data out of the properties
00398         instance = (Interact*) props.propGetPointer( kOfxPropInstanceData );
00399 
00400         OFX::Log::error( instance == 0, "Instance data handle in effect instance properties is NULL!" );
00401 
00402         // need to throw something here
00403 
00404         // and dance to the music
00405         return instance;
00406 }
00407 
00408 /** @brief The common entry point used by all interacts */
00409 OfxStatus interactMainEntry( const std::string& action,
00410                              OfxInteractHandle  handle,
00411                              PropertySet        inArgs,
00412                              PropertySet        outArgs )
00413 {
00414         OfxStatus stat = kOfxStatReplyDefault;
00415 
00416         // get the interact pointer
00417         Interact* interact = retrieveInteractPointer( handle );
00418 
00419         // if one was not made, return and do nothing
00420         if( interact == NULL )
00421         {
00422                 return kOfxStatErrBadHandle;
00423         }
00424         if( ! interact->verifyMagic() )
00425         {
00426                 return kOfxStatErrBadHandle;
00427         }
00428         
00429         if( action == kOfxActionDestroyInstance )
00430         {
00431                 delete interact;
00432                 stat = kOfxStatOK;
00433         }
00434         else if( action == kOfxInteractActionDraw )
00435         {
00436                 // make the draw args
00437                 DrawArgs drawArgs( inArgs );
00438                 if( interact->draw( drawArgs ) )
00439                         stat = kOfxStatOK;
00440         }
00441         else if( action ==   kOfxInteractActionPenMotion )
00442         {
00443 
00444                 // make the draw args
00445                 PenArgs args( inArgs );
00446                 if( interact->penMotion( args ) )
00447                         stat = kOfxStatOK;
00448         }
00449         else if( action ==   kOfxInteractActionPenDown )
00450         {
00451                 // make the draw args
00452                 PenArgs args( inArgs );
00453                 if( interact->penDown( args ) )
00454                         stat = kOfxStatOK;
00455         }
00456         else if( action ==   kOfxInteractActionPenUp )
00457         {
00458                 // make the draw args
00459                 PenArgs args( inArgs );
00460                 if( interact->penUp( args ) )
00461                         stat = kOfxStatOK;
00462         }
00463         else if( action ==   kOfxInteractActionKeyDown )
00464         {
00465                 // make the draw args
00466                 KeyArgs args( inArgs );
00467                 if( interact->keyDown( args ) )
00468                         stat = kOfxStatOK;
00469         }
00470         else if( action ==   kOfxInteractActionKeyUp )
00471         {
00472                 // make the draw args
00473                 KeyArgs args( inArgs );
00474                 if( interact->keyUp( args ) )
00475                         stat = kOfxStatOK;
00476         }
00477         else if( action ==   kOfxInteractActionKeyRepeat )
00478         {
00479                 // make the draw args
00480                 KeyArgs args( inArgs );
00481                 if( interact->keyRepeat( args ) )
00482                         stat = kOfxStatOK;
00483         }
00484         else if( action ==   kOfxInteractActionGainFocus )
00485         {
00486                 // make the draw args
00487                 FocusArgs args( inArgs );
00488                 interact->gainFocus( args );
00489         }
00490         else if( action ==   kOfxInteractActionGainFocus )
00491         {
00492                 // make the draw args
00493                 FocusArgs args( inArgs );
00494                 interact->loseFocus( args );
00495         }
00496 
00497         return stat;
00498 }
00499 
00500 /** @brief The main entry for image effect overlays */
00501 OfxStatus interactMainEntry( const char*          actionRaw,
00502                              const void*          handleRaw,
00503                              OfxPropertySetHandle inArgsRaw,
00504                              OfxPropertySetHandle outArgsRaw,
00505                              InteractDescriptor&  desc )
00506 {
00507         OFX::Log::print( "********************************************************************************" );
00508         OFX::Log::print( "START overlayInteractMainEntry (%s)", actionRaw );
00509         OFX::Log::indent();
00510         OfxStatus stat = kOfxStatReplyDefault;
00511 
00512         try
00513         {
00514                 // Cast the raw handle to be an image effect handle, because that is what it is
00515                 OfxInteractHandle handle = (OfxInteractHandle) handleRaw;
00516 
00517                 // Turn the arguments into wrapper objects to make our lives easier
00518                 OFX::PropertySet inArgs( inArgsRaw );
00519                 OFX::PropertySet outArgs( outArgsRaw );
00520 
00521                 // turn the action into a std::string
00522                 std::string action( actionRaw );
00523 
00524                 // figure the actions
00525                 if( action == kOfxActionDescribe )
00526                 {
00527                         OfxPropertySetHandle propHandle;
00528                         OfxStatus stat = OFX::Private::gInteractSuite->interactGetPropertySet( handle, &propHandle );
00529                         throwSuiteStatusException( stat );
00530                         PropertySet interactProperties( propHandle );
00531                         desc.setPropertySet( &interactProperties );
00532                         desc.describe();
00533                 }
00534                 else if( action == kOfxActionCreateInstance )
00535                 {
00536                         // fetch the image effect we are being made for out of the interact's property handle
00537                         ImageEffect* effect = retrieveEffectFromInteractHandle( handle );
00538                         /*OFX::Interact* interact = */ desc.createInstance( handle, effect );
00539                         // and all was well
00540                         stat = kOfxStatOK;
00541                 }
00542                 else
00543                 {
00544                         stat = interactMainEntry( action, handle, inArgs, outArgs );
00545                 }
00546 
00547         }
00548         
00549         catch( boost::exception& e )
00550         {
00551                 std::cerr << tuttle::common::Color::get()->_error;
00552                 std::cerr << "__________" << std::endl;
00553                 if( const boost::error_info_sstream* const messageException = boost::get_error_info< tuttle::exception::user >(e) )
00554                 {
00555                         std::cerr << "Error: " << *messageException << std::endl;
00556                 }
00557                 else
00558                 {
00559                         std::cerr << "Error: " "No message." << std::endl;
00560                 }
00561                 if( const std::string* const filenameException = boost::get_error_info< ::boost::errinfo_file_name >(e) )
00562                 {
00563                         std::cerr << "filename: \"" << *filenameException << "\"" << std::endl;
00564                 }
00565 
00566         #ifndef TUTTLE_PRODUCTION
00567                 std::cerr << "__________" << std::endl;
00568                 std::cerr << "* Caught boost::exception on action " << actionRaw << std::endl;
00569         #ifndef BOOST_EXCEPTION_DISABLE
00570                 std::cerr << boost::diagnostic_information(e);
00571         #endif
00572                 std::cerr << "----------" << std::endl;
00573                 std::cerr << "* Backtrace" << std::endl;
00574                 std::cerr << boost::trace(e);
00575         #endif
00576                 std::cerr << "__________" << std::endl;
00577                 std::cerr << tuttle::common::Color::get()->_std;
00578                 
00579                 if( const ::OfxStatus* status = boost::get_error_info< ::OFX::ofxStatus >( e ) )
00580                 {
00581                         stat = *status;
00582                 }
00583                 else
00584                 {
00585                         stat = kOfxStatFailed;
00586                 }
00587         }
00588         
00589         // catch suite exceptions
00590         catch( OFX::Exception::Suite& e )
00591         {
00592                 std::cerr << "Caught OFX::Exception::Suite (" << e.what() << ")" << std::endl;
00593                 stat = e.status();
00594         }
00595         // catch all exceptions
00596         catch( std::exception& e )
00597         {
00598                 std::cerr << "Caught std::exception on action " << actionRaw << " (" << e.what() << ")" << std::endl;
00599                 stat = kOfxStatFailed;
00600         }
00601         catch(... )
00602         {
00603                 std::cerr << "Caught Unknown exception (file:" << __FILE__ << " line:" << __LINE__ << ")" << std::endl;
00604                 stat = kOfxStatFailed;
00605         }
00606 
00607         OFX::Log::outdent();
00608         OFX::Log::print( "STOP overlayInteractMainEntry (%s)", actionRaw );
00609         return stat;
00610 }
00611 
00612 }; // end namespace private
00613 
00614 }; // end of namespace