TuttleOFX
1
|
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