// general cortex render function, takes a gu_detail and uses the NodePassData attribute // to call the required render method void GR_Cortex::render( GU_Detail *gdp, const IECoreGL::State *displayState ) { // gl scene from a parameterised procedural const GA_ROAttributeRef attrRef = gdp->findAttribute( GA_ATTRIB_DETAIL, GA_SCOPE_PRIVATE, "IECoreHoudiniNodePassData" ); if ( attrRef.isInvalid() ) { return; } const GA_Attribute *attr = attrRef.getAttribute(); const GA_AIFBlindData *blindData = attr->getAIFBlindData(); const NodePassData passData = blindData->getValue<NodePassData>( attr, 0 ); switch( passData.type() ) { case IECoreHoudini::NodePassData::CORTEX_OPHOLDER : { SOP_OpHolder *sop = dynamic_cast<SOP_OpHolder*>( const_cast<OP_Node*>( passData.nodePtr() ) ); if ( !sop ) { return; } IECore::OpPtr op = IECore::runTimeCast<IECore::Op>( sop->getParameterised() ); if ( !op ) { return; } const IECore::Parameter *result_parameter = op->resultParameter(); const IECore::Object *result_object = result_parameter->getValue(); renderObject( result_object, displayState ); break; } case IECoreHoudini::NodePassData::CORTEX_PROCEDURALHOLDER : { SOP_ProceduralHolder *sop = dynamic_cast<SOP_ProceduralHolder*>( const_cast<OP_Node*>( passData.nodePtr() ) ); if ( !sop ) { return; } IECoreGL::ConstScenePtr scene = sop->scene(); if ( !scene ) { return; } scene->render( const_cast<IECoreGL::State *>( displayState ) ); break; } default : { break; } } }
MStatus OpHolder<B>::compute( const MPlug &plug, MDataBlock &block ) { IECore::OpPtr op = getOp(); if (op) { MFnDependencyNode fnDN( B::thisMObject() ); MPlug resultPlug( B::thisMObject(), fnDN.attribute( "result" ) ); if (plug != resultPlug) { return MS::kUnknownParameter; } IECore::ObjectPtr result; try { ParameterisedHolder<B>::setParameterisedValues( true /* lazy */ ); result = op->operate(); if (!result) { return MS::kFailure; } } catch( std::exception &e ) { MGlobal::displayError( e.what() ); return MS::kFailure; } catch( boost::python::error_already_set & ) { IECorePython::ScopedGILLock lock; PyErr_Print(); return MS::kFailure; } catch (...) { return MS::kFailure; } assert( result ); MStatus s = ParameterHandler::setValue( op->resultParameter(), resultPlug ); block.setClean( resultPlug ); return s; } return MS::kFailure; }
MStatus OpHolder<B>::createResultAttribute() { IECore::OpPtr op = IECore::runTimeCast<IECore::Op>( ParameterisedHolder<B>::m_parameterised ); if( !op ) { MString nodeName = ParameterisedHolder<B>::name(); msg( Msg::Error, "OpHolder::createResultAttribute", boost::format( "No Op found on node \"%s\"." ) % nodeName.asChar() ); return MStatus::kFailure; } MStatus s = ParameterisedHolder<B>::createOrUpdateAttribute( const_cast<IECore::Parameter *>( op->resultParameter() ), "result" ); if( !s ) { MString nodeName = ParameterisedHolder<B>::name(); msg( Msg::Error, "OpHolder::createResultAttribute", boost::format( "Unable to update result attribute to represent class \"%s\" on node \"%s\"." ) % op->typeName() % nodeName.asChar() ); return s; } MFnDependencyNode fnDN( B::thisMObject() ); MObject attribute = fnDN.attribute( "result" ); MFnAttribute fnAttr( attribute ); fnAttr.setWritable( false ); fnAttr.setStorable( false ); return MStatus::kSuccess; }
void SOP_ParameterisedHolder::setInputParameterValues( float now ) { for ( unsigned int i=0; i < m_inputParameters.size(); i++ ) { useInputSource( i, m_dirty, false ); IECore::ParameterPtr inputParameter = m_inputParameters[i]; GU_DetailHandle inputHandle = inputGeoHandle( i ); GU_DetailHandleAutoReadLock readHandle( inputHandle ); const GU_Detail *inputGdp = readHandle.getGdp(); if ( !inputGdp ) { continue; } const GA_ROAttributeRef attrRef = inputGdp->findAttribute( GA_ATTRIB_DETAIL, GA_SCOPE_PRIVATE, "IECoreHoudiniNodePassData" ); if ( attrRef.isValid() ) { // looks like data passed from another ParameterisedHolder const GA_Attribute *attr = attrRef.getAttribute(); const GA_AIFBlindData *blindData = attr->getAIFBlindData(); const NodePassData passData = blindData->getValue<NodePassData>( attr, 0 ); SOP_ParameterisedHolder *sop = dynamic_cast<SOP_ParameterisedHolder*>( const_cast<OP_Node*>( passData.nodePtr() ) ); IECore::ConstObjectPtr result = 0; if ( passData.type() == IECoreHoudini::NodePassData::CORTEX_OPHOLDER ) { IECore::OpPtr op = IECore::runTimeCast<IECore::Op>( sop->getParameterised() ); result = op->resultParameter()->getValue(); } else if ( passData.type() == IECoreHoudini::NodePassData::CORTEX_PROCEDURALHOLDER ) { IECore::ParameterisedProcedural *procedural = IECore::runTimeCast<IECore::ParameterisedProcedural>( sop->getParameterised() ); IECore::CapturingRendererPtr renderer = new IECore::CapturingRenderer(); // We are acquiring and releasing the GIL here to ensure that it is released when we render. This has // to be done because a procedural might jump between c++ and python a few times (i.e. if it spawns // subprocedurals that are implemented in python). In a normal call to cookMySop, this wouldn't be an // issue, but if cookMySop was called from HOM, hou.Node.cook appears to be holding onto the GIL. IECorePython::ScopedGILLock gilLock; { IECorePython::ScopedGILRelease gilRelease; { IECore::WorldBlock worldBlock( renderer ); procedural->render( renderer ); } } result = IECore::runTimeCast<const IECore::Object>( renderer->world() ); } else { continue; } try { inputParameter->setValidatedValue( IECore::constPointerCast<IECore::Object>( result ) ); } catch ( const IECore::Exception &e ) { addError( SOP_MESSAGE, e.what() ); } } else { // looks like a regular Houdini detail IECore::ObjectParameterPtr objectParameter = IECore::runTimeCast<IECore::ObjectParameter>( inputParameter ); if ( !objectParameter ) { continue; } FromHoudiniGeometryConverterPtr converter = FromHoudiniGeometryConverter::create( inputHandle, objectParameter->validTypes() ); if ( !converter ) { continue; } // set converter parameters from the node values const CompoundParameter::ParameterVector &converterParameters = converter->parameters()->orderedParameters(); for ( CompoundParameter::ParameterVector::const_iterator it=converterParameters.begin(); it != converterParameters.end(); ++it ) { updateParameter( *it, now, "parm_" + inputParameter->name() + "_" ); } try { IECore::ObjectPtr converted = converter->convert(); if ( converted ) { inputParameter->setValidatedValue( converted ); } } catch ( const IECore::Exception &e ) { addError( SOP_MESSAGE, e.what() ); } catch ( std::runtime_error &e ) { addError( SOP_MESSAGE, e.what() ); } } } }
/// Cook the SOP! This method does all the work OP_ERROR SOP_OpHolder::cookMySop( OP_Context &context ) { IECore::MessageHandler::Scope handlerScope( getMessageHandler() ); // some defaults and useful variables Imath::Box3f bbox( Imath::V3f(-1,-1,-1), Imath::V3f(1,1,1) ); float now = context.getTime(); // force eval of our nodes parameters with our hidden parameter expression evalInt( "__evaluateParameters", 0, now ); // get our op IECore::OpPtr op = IECore::runTimeCast<IECore::Op>( getParameterised() ); // check for a valid parameterised on this SOP if ( !op ) { UT_String msg( "Op Holder has no parameterised class to operate on!" ); addError( SOP_MESSAGE, msg ); return error(); } if( lockInputs(context)>=UT_ERROR_ABORT ) { return error(); } // start our work UT_Interrupt *boss = UTgetInterrupt(); boss->opStart("Building OpHolder Geometry..."); gdp->clearAndDestroy(); setParameterisedValues( now ); try { // make our Cortex op do it's thing... op->operate(); // pass ourselves onto the GR_Cortex render hook IECoreHoudini::NodePassData data( this, IECoreHoudini::NodePassData::CORTEX_OPHOLDER ); GA_RWAttributeRef attrRef = gdp->createAttribute( GA_ATTRIB_DETAIL, GA_SCOPE_PRIVATE, "IECoreHoudiniNodePassData", NULL, NULL, "blinddata" ); GA_Attribute *attr = attrRef.getAttribute(); const GA_AIFBlindData *blindData = attr->getAIFBlindData(); blindData->setDataSize( attr, sizeof(IECoreHoudini::NodePassData), &data ); // if our result is a visible renderable then set our bounds on our output gdp const IECore::Object *result = op->resultParameter()->getValue(); IECore::ConstVisibleRenderablePtr renderable = IECore::runTimeCast<const IECore::VisibleRenderable>( result ); if ( renderable ) { Imath::Box3f bbox = renderable->bound(); gdp->cube( bbox.min.x, bbox.max.x, bbox.min.y, bbox.max.y, bbox.min.z, bbox.max.z, 0, 0, 0, 1, 1 ); } } catch( boost::python::error_already_set ) { addError( SOP_MESSAGE, "Error raised during Python evaluation!" ); IECorePython::ScopedGILLock lock; PyErr_Print(); } catch( const IECore::Exception &e ) { addError( SOP_MESSAGE, e.what() ); } catch( const std::exception &e ) { addError( SOP_MESSAGE, e.what() ); } catch( ... ) { addError( SOP_MESSAGE, "Caught unknown exception!" ); } // tidy up & go home! boss->opEnd(); unlockInputs(); return error(); }