OP_ERROR SOP_SceneCacheSource::cookMySop( OP_Context &context ) { flags().setTimeDep( true ); std::string file; if ( !ensureFile( file ) ) { addError( SOP_ATTRIBUTE_INVALID, ( file + " is not a valid .scc" ).c_str() ); gdp->clearAndDestroy(); return error(); } std::string path = getPath(); Space space = getSpace(); UT_String shapeFilterStr; evalString( shapeFilterStr, pShapeFilter.getToken(), 0, 0 ); UT_StringMMPattern shapeFilter; shapeFilter.compile( shapeFilterStr ); UT_String p( "P" ); UT_String attributeFilter; evalString( attributeFilter, pAttributeFilter.getToken(), 0, 0 ); if ( !p.match( attributeFilter ) ) { attributeFilter += " P"; } ConstSceneInterfacePtr scene = this->scene( file, path ); if ( !scene ) { addError( SOP_ATTRIBUTE_INVALID, ( path + " is not a valid location in " + file ).c_str() ); gdp->clearAndDestroy(); return error(); } MurmurHash hash; hash.append( file ); hash.append( path ); hash.append( space ); hash.append( shapeFilterStr ); hash.append( attributeFilter ); if ( !m_loaded || m_hash != hash ) { gdp->clearAndDestroy(); } Imath::M44d transform = ( space == World ) ? worldTransform( file, path, context.getTime() ) : Imath::M44d(); SceneInterface::Path rootPath; scene->path( rootPath ); loadObjects( scene, transform, context.getTime(), space, shapeFilter, attributeFilter.toStdString(), rootPath.size() ); m_loaded = true; m_hash = hash; return error(); }
OP_ERROR GusdSOP_usdimport::_Cook(OP_Context& ctx) { fpreal t = ctx.getTime(); UT_String traversal; evalString( traversal, "import_traversal", 0, t ); ErrorChoice errorMode = static_cast<ErrorChoice>(evalInt("missingframe", 0, t )); auto lockedMgr = getLockedErrorManager(); GusdUT_ErrorManager errMgr(*lockedMgr); GusdUT_ErrorContext errContext(errMgr, errorMode == MISSINGFRAME_WARN ? UT_ERROR_WARNING : UT_ERROR_ABORT); const GusdUSD_Traverse* trav = NULL; if(traversal != _NOTRAVERSE_NAME) { const auto& table = GusdUSD_TraverseTable::GetInstance(); trav = table.FindTraversal(traversal); if(!trav) { UT_WorkBuffer buf; buf.sprintf("Failed locating traversal '%s'", traversal.c_str()); return errContext.AddError(buf.buffer()); } } return getInput(0) ? _ExpandPrims(ctx, trav, errContext) : _CreateNewPrims(ctx, trav, errContext); }
OP_ERROR SOP_Density::cookMySop(OP_Context &context) { //Lock inputs and cehck everything is ok OP_AutoLockInputs inputs(this); if (inputs.lock(context) >= UT_ERROR_ABORT){ return error(); } // duplicate source from input 0 duplicateSource(0,context); flags().timeDep = 1; //Varaibles fpreal ctime = context.getTime();//ctime is the currrent time e.g frame 1020 in a 24fps project is 1020.0/24 = 42.666666667 float radius = SOP_Density::RADIUS(ctime); int neighbours = SOP_Density::NEIGHBOURS(ctime); UT_String attrstr; SOP_Density::ATTRIBNAME(attrstr,ctime); //create the actual attribute to store the density GA_RWHandleF densityAttr(gdp->addFloatTuple(GA_ATTRIB_POINT,attrstr,1)); //create ppoint tree object GEO_PointTreeGAOffset pointtree; pointtree.build(gdp,NULL); GA_Offset ptoff; GA_FOR_ALL_PTOFF(gdp,ptoff){ GEO_PointTree::IdxArrayType pointlist; //generate array to put points from ptree in GEO_PointTree::IdxArrayType distancelist; // generate array to put distance from ptree UT_Vector3 pos = gdp->getPos3(ptoff); //vector pos for points current position UT_FloatArray distance; //Array to store the calculated distance //ptree.findAllCloseIdx(pos,radius,pointlist) //find all points within the given radius int numclosept = pointtree.findNearestGroupIdx(pos,radius,neighbours,distancelist,distance); float weight = 1.0/numclosept; float sum = 0.0; //total sum of distance for(int i = 0;i<numclosept;++i){ sum += distance(i); } sum *= weight; if(numclosept >= 1){ densityAttr.set(ptoff,sum); }else{ densityAttr.set(ptoff,-1.0); } }
OP_ERROR GusdSOP_usdimport::_ExpandPrims(OP_Context& ctx, const GusdUSD_Traverse* traverse, GusdUT_ErrorContext& err) { if(!traverse) return UT_ERROR_NONE; // Nothing to do! fpreal t = ctx.getTime(); // Construt a range and bind prims. bool packedPrims = !evalInt("import_class", 0, t); GA_AttributeOwner owner = packedPrims ? GA_ATTRIB_PRIMITIVE : GA_ATTRIB_POINT; GA_Range rng(gdp->getIndexMap(owner), UTverify_cast<const GA_ElementGroup*>(_group)); UT_Array<UsdPrim> rootPrims; GusdDefaultArray<UsdTimeCode> times; GusdDefaultArray<GusdPurposeSet> purposes; { GusdStageCacheReader cache; if(!GusdGU_USD::BindPrims(cache, rootPrims, *gdp, rng, /*variants*/ nullptr, &purposes, ×, &err)) { return err(); } } if(!times.IsVarying()) times.SetConstant(evalFloat("import_time", 0, t)); // Traverse to find a new prim selection. UT_Array<GusdUSD_Traverse::PrimIndexPair> expandedPrims; { UT_UniquePtr<GusdUSD_Traverse::Opts> opts(traverse->CreateOpts()); if(opts) { if(!opts->Configure(*this, t)) return err(); } if(!traverse->FindPrims(rootPrims, times, purposes, expandedPrims, /*skip root*/ true, opts.get())) return err(); } GA_AttributeFilter filter(GA_AttributeFilter::selectPublic()); GusdGU_USD::AppendExpandedRefPoints( *gdp, *gdp, rng, expandedPrims, filter, GUSD_PATH_ATTR, GUSD_PRIMPATH_ATTR, &err); if(evalInt("import_delold", 0, t)) { if(packedPrims) gdp->destroyPrimitives(rng, /*and points*/ true); else gdp->destroyPoints(rng); // , GA_DESTROY_DEGENERATE); } return err(); }
std::string getStringParam(OP_Parameters& node, OP_Context &context, const std::string& label, bool trimspace) { UT_String s; node.evalString(s, label.c_str(), 0, context.getTime()); if(trimspace) s.trimSpace(); return s.toStdString(); }
OP_ERROR SOP_Cleave::cookMySop(OP_Context &context) { const GA_PrimitiveGroup *polyGroup; GEO_Primitive *prim; GQ_Detail *gqd; int i,j,k; UT_Vector4 np,p; // Before we do anything, we must lock our inputs. Before returning, // we have to make sure that the inputs get unlocked. if (lockInputs(context) >= UT_ERROR_ABORT) return error(); float now = context.getTime(); duplicateSource(0, context, 0, 1); // Here we determine which groups we have to work on. We only // handle poly groups. UT_String groups; getGroups(groups); if (groups.isstring()) polyGroup = parsePrimitiveGroups(groups); else polyGroup = 0; if (error() >= UT_ERROR_ABORT) { unlockInputs(); return error(); } UT_Interrupt* boss = UTgetInterrupt(); // Start the interrupt server boss->opStart("Cleaving Polys"); // separate out all polys to be cleaved GA_PrimitiveGroup* cleave_group = gdp->newPrimitiveGroup("cleave",1); GA_PrimitiveGroup* not_cleave_group = gdp->newPrimitiveGroup("not_cleave",1); if (polyGroup) { GA_FOR_ALL_PRIMITIVES(gdp,prim) { if ( (prim->getTypeId()==GEO_PRIMPOLY) && (polyGroup->contains(prim)!=0)) cleave_group->add(prim); else not_cleave_group->add(prim); } } else {
OP_ERROR GusdOBJ_usdcamera::_Cook(OP_Context& ctx) { _LoadCamera(ctx.getTime(), ctx.getThread()); /* XXX: There's a potential race condition here, between loading and stealing cached errors. Would be better to keep the camera cache locked until the error stealing is done.*/ UT_AutoReadLock readLock(_lock); stealErrors(_errors, /*borrow*/ true); return error(); }
OP_ERROR SOP_PrimGroupCentroid::cookMySop(OP_Context &context) { fpreal now; int method, mode; now = context.getTime(); if (lockInputs(context) >= UT_ERROR_ABORT) return error(); // The partitioning mode. mode = MODE(now); // Find out which calculation method we are attempting. method = METHOD(now); // Binding geometry. if (nConnectedInputs() == 2) { // Duplicate the source. duplicateSource(0, context); // Bind to the centroids. If the function returns 1, unlock // the inputs and return. if (bindToCentroids(now, mode, method)) { unlockInputs(); return error(); } } // Creating centroids. else { // Clear out any previous data. gdp->clearAndDestroy(); // Build the centroids. If the function returns 1, unlock // the inputs and return. if (buildCentroids(now, mode, method)) { unlockInputs(); return error(); } } unlockInputs(); return error(); }
/* ****************************************************************************** * Function Name : cookMySop() * * Description : Cook this SOP node * * Input Arguments : None * * Return Value : OP_ERROR * ***************************************************************************** */ OP_ERROR SOP_RF_Import::cookMySop(OP_Context & context) { char GUI_str[128]; OP_ERROR myError; float now = context.getTime(); OP_Node::flags().timeDep = 1; myTotalPoints = 0; // Set the NPT local variable value myCurrPoint = 0; // Initialize the PT local variable FNAME(myFileName, now); myFileType = FTYPE(now); disableParms(); sprintf(GUI_str, "%s", ""); setString((UT_String)GUI_str, CH_STRING_LITERAL, ARG_RF_IMPORT_VER, 0, now); setString((UT_String)GUI_str, CH_STRING_LITERAL, ARG_RF_IMPORT_INFO1, 0, now); setString((UT_String)GUI_str, CH_STRING_LITERAL, ARG_RF_IMPORT_INFO2, 0, now); sprintf(GUI_str, "Version: %s", SOP_Version.c_str()); setString((UT_String)GUI_str, CH_STRING_LITERAL, ARG_RF_IMPORT_INFO3, 0, now); #ifdef DEBUG std::cout << "cookMySop() - myFileType = " << myFileType << endl; #endif switch(myFileType) { case 0: myError = ReadRFParticleFile(context); break; case 1: myError = ReadRFMeshFile(context); break; case 2: myError = ReadRFSDFile(context); break; case 3: myError = ReadRFRWCFile(context); break; default: return error(); } myCurrPoint = -1; return myError; }
OP_ERROR GusdSOP_usdimport::cookInputGroups(OP_Context& ctx, int alone) { if(!getInput(0)) return UT_ERROR_NONE; int groupIdx = getParmList()->getParmIndex("import_group"); int classIdx = getParmList()->getParmIndex("import_class"); bool packedPrims = !evalInt(classIdx, 0, ctx.getTime()); GA_GroupType groupType = packedPrims ? GA_GROUP_PRIMITIVE : GA_GROUP_POINT; return cookInputAllGroups(ctx, _group, alone, /* do selection*/ true, groupIdx, classIdx, groupType); }
int GusdOBJ_usdcamera::applyInputIndependentTransform(OP_Context& ctx, UT_DMatrix4& mx) { mx.identity(); fpreal t = ctx.getTime(); if(UsdGeomCamera cam = _LoadCamera(t, ctx.getThread())) { float frame = evalFloat(_frameIdx, 0, t); GfMatrix4d ctm(1.); bool stat = true; bool resetsXformStack = false; switch(evalInt("xformmode", 0, t)) { case _POSTMULTCTM_TRANSFORM: stat = true; ctm = cam.ComputeLocalToWorldTransform(frame); break; case _CTM_TRANSFORM: stat = true; ctm = cam.ComputeParentToWorldTransform(frame); break; case _OBJ_TRANSFORM: // XXX: how do we reset xformStack here? // Is that (or should that // be) handled by the Compute calls above? stat = cam.GetLocalTransformation(&ctm, &resetsXformStack, frame); break; default: // _IGNORE_TRANSFORM: stat = true; ctm.SetIdentity(); break; } if(!stat) { stealErrors(_errors, /*borrow*/ true); return 0; } mx = GusdUT_Gf::Cast(ctm); } return OBJ_Camera::applyInputIndependentTransform(ctx, mx); }
/// Cook the SOP! This method does all the work OP_ERROR SOP_ProceduralHolder::cookMySop( OP_Context &context ) { IECore::MessageHandler::Scope handlerScope( getMessageHandler() ); // some defaults and useful variables float now = context.getTime(); // force eval of our nodes parameters with our hidden parameter expression evalInt( "__evaluateParameters", 0, now ); // update parameters on procedural from our Houdini parameters IECore::ParameterisedProceduralPtr procedural = IECore::runTimeCast<IECore::ParameterisedProcedural>( getParameterised() ); // check for a valid parameterised on this SOP if ( !procedural ) { UT_String msg( "Procedural 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 ProceduralHolder Geometry..."); gdp->clearAndDestroy(); setParameterisedValues( now ); ToHoudiniCortexObjectConverterPtr converter = new ToHoudiniCortexObjectConverter( procedural ); if ( !converter->convert( myGdpHandle ) ) { addError( SOP_MESSAGE, "Unable to store procedural on gdp" ); } // tidy up & go home! boss->opEnd(); unlockInputs(); return error(); }
OP_ERROR SOP_InterpolatedCacheReader::cookMySop( OP_Context &context ) { flags().setTimeDep( true ); if ( lockInputs( context ) >= UT_ERROR_ABORT ) { return error(); } gdp->stashAll(); float time = context.getTime(); float frame = context.getFloatFrame(); UT_String paramVal; evalString( paramVal, "cacheSequence", 0, time ); std::string cacheFileName = paramVal.toStdString(); evalString( paramVal, "objectFixes", 0, time ); std::string objectPrefix = paramVal.toStdString(); evalString( paramVal, "objectFixes", 1, time ); std::string objectSuffix = paramVal.toStdString(); evalString( paramVal, "attributeFixes", 0, time ); std::string attributePrefix = paramVal.toStdString(); evalString( paramVal, "attributeFixes", 1, time ); std::string attributeSuffix = paramVal.toStdString(); evalString( paramVal, "transformAttribute", 0, time ); std::string transformAttribute = paramVal.toStdString(); int samplesPerFrame = evalInt( "samplesPerFrame", 0, time ); InterpolatedCache::Interpolation interpolation = (InterpolatedCache::Interpolation)evalInt( "interpolation", 0, time ); GroupingMode groupingMode = (GroupingMode)evalInt( "groupingMode", 0, time ); // create the InterpolatedCache if ( cacheFileName.compare( m_cacheFileName ) != 0 || samplesPerFrame != m_samplesPerFrame || interpolation != m_interpolation ) { try { float fps = OPgetDirector()->getChannelManager()->getSamplesPerSec(); OversamplesCalculator calc( fps, samplesPerFrame ); m_cache = new InterpolatedCache( cacheFileName, interpolation, calc ); } catch ( IECore::InvalidArgumentException e ) { addWarning( SOP_ATTRIBUTE_INVALID, e.what() ); unlockInputs(); return error(); } m_cacheFileName = cacheFileName; m_samplesPerFrame = samplesPerFrame; m_interpolation = interpolation; } if ( !m_cache ) { addWarning( SOP_MESSAGE, "SOP_InterpolatedCacheReader: Cache Sequence not found" ); unlockInputs(); return error(); } std::vector<InterpolatedCache::ObjectHandle> objects; std::vector<InterpolatedCache::AttributeHandle> attrs; try { m_cache->objects( frame, objects ); } catch ( IECore::Exception e ) { addWarning( SOP_ATTRIBUTE_INVALID, e.what() ); unlockInputs(); return error(); } duplicatePointSource( 0, context ); GA_ElementGroupTable *groups = 0; if ( groupingMode == PointGroup ) { groups = &gdp->pointGroups(); } else if ( groupingMode == PrimitiveGroup ) { groups = &gdp->primitiveGroups(); } for ( GA_GroupTable::iterator<GA_ElementGroup> it=groups->beginTraverse(); !it.atEnd(); ++it ) { GA_ElementGroup *group = it.group(); if ( group->getInternal() || group->isEmpty() ) { continue; } // match GA_ElementGroup name to InterpolatedCache::ObjectHandle std::string searchName = objectPrefix + group->getName().toStdString() + objectSuffix; std::vector<InterpolatedCache::ObjectHandle>::iterator oIt = find( objects.begin(), objects.end(), searchName ); if ( oIt == objects.end() ) { continue; } CompoundObjectPtr attributes = 0; try { m_cache->attributes( frame, *oIt, attrs ); attributes = m_cache->read( frame, *oIt ); } catch ( IECore::Exception e ) { addError( SOP_ATTRIBUTE_INVALID, e.what() ); unlockInputs(); return error(); } const CompoundObject::ObjectMap &attributeMap = attributes->members(); GA_Range pointRange; GA_Range primRange; GA_Range vertexRange; if ( groupingMode == PointGroup ) { pointRange = gdp->getPointRange( (GA_PointGroup*)it.group() ); } else if ( groupingMode == PrimitiveGroup ) { primRange = gdp->getPrimitiveRange( (GA_PrimitiveGroup*)it.group() ); const GA_PrimitiveList &primitives = gdp->getPrimitiveList(); GA_OffsetList pointOffsets; GA_OffsetList vertOffsets; for ( GA_Iterator it=primRange.begin(); !it.atEnd(); ++it ) { const GA_Primitive *prim = primitives.get( it.getOffset() ); GA_Range primPointRange = prim->getPointRange(); for ( GA_Iterator pIt=primPointRange.begin(); !pIt.atEnd(); ++pIt ) { pointOffsets.append( pIt.getOffset() ); } size_t numPrimVerts = prim->getVertexCount(); for ( size_t v=0; v < numPrimVerts; v++ ) { if ( prim->getTypeId() == GEO_PRIMPOLY ) { vertOffsets.append( prim->getVertexOffset( numPrimVerts - 1 - v ) ); } else { vertOffsets.append( prim->getVertexOffset( v ) ); } } } pointOffsets.sortAndRemoveDuplicates(); pointRange = GA_Range( gdp->getPointMap(), pointOffsets ); vertexRange = GA_Range( gdp->getVertexMap(), vertOffsets ); } // transfer the InterpolatedCache::Attributes onto the GA_ElementGroup for ( CompoundObject::ObjectMap::const_iterator aIt=attributeMap.begin(); aIt != attributeMap.end(); aIt++ ) { Data *data = IECore::runTimeCast<Data>( aIt->second ); if ( !data ) { continue; } ToHoudiniAttribConverterPtr converter = ToHoudiniAttribConverter::create( data ); if ( !converter ) { continue; } // strip the prefix/suffix from the GA_Attribute name std::string attrName = aIt->first.value(); size_t prefixLength = attributePrefix.length(); if ( prefixLength && ( search( attrName.begin(), attrName.begin()+prefixLength, attributePrefix.begin(), attributePrefix.end() ) == attrName.begin() ) ) { attrName.erase( attrName.begin(), attrName.begin() + prefixLength ); } size_t suffixLength = attributeSuffix.length(); if ( suffixLength && ( search( attrName.end() - suffixLength, attrName.end(), attributeSuffix.begin(), attributeSuffix.end() ) == ( attrName.end() - suffixLength ) ) ) { attrName.erase( attrName.end() - suffixLength, attrName.end() ); } if ( attrName == "P" ) { const V3fVectorData *positions = IECore::runTimeCast<const V3fVectorData>( data ); if ( !positions ) { continue; } size_t index = 0; size_t entries = pointRange.getEntries(); const std::vector<Imath::V3f> &pos = positions->readable(); // Attempting to account for the vertex difference between an IECore::CurvesPrimitive and Houdini curves. // As Houdini implicitly triples the endpoints of a curve, a cache generated from a single CurvesPrimitive // will have exactly four extra vertices. In this case, we adjust the cache by ignoring the first two and // last two V3fs. In all other cases, we report a warning and don't apply the cache to these points. if ( pos.size() - 4 == entries ) { index = 2; } else if ( pos.size() != entries ) { addWarning( SOP_ATTRIBUTE_INVALID, ( boost::format( "Geometry/Cache mismatch: %s contains %d points, while cache expects %d values for P." ) % group->getName().toStdString() % entries % pos.size() ).str().c_str() ); continue; } /// \todo: try multi-threading this with a GA_SplittableRange for ( GA_Iterator it=pointRange.begin(); !it.atEnd(); ++it, ++index ) { gdp->setPos3( it.getOffset(), IECore::convert<UT_Vector3>( pos[index] ) ); } } else if ( groupingMode == PrimitiveGroup ) { GA_Range currentRange; unsigned size = despatchTypedData<TypedDataSize, TypeTraits::IsVectorTypedData, DespatchTypedDataIgnoreError>( data ); // check for existing attributes if ( gdp->findPrimitiveAttribute( attrName.c_str() ).isValid() && size == primRange.getEntries() ) { currentRange = primRange; } else if ( gdp->findPointAttribute( attrName.c_str() ).isValid() && size == pointRange.getEntries() ) { currentRange = pointRange; } else if ( gdp->findVertexAttribute( attrName.c_str() ).isValid() && size == vertexRange.getEntries() ) { currentRange = vertexRange; } // fall back to Cortex standard inferred order else if ( size == primRange.getEntries() ) { currentRange = primRange; } else if ( size == pointRange.getEntries() ) { currentRange = pointRange; } else if ( size == vertexRange.getEntries() ) { currentRange = vertexRange; } else { addWarning( SOP_ATTRIBUTE_INVALID, ( boost::format( "Geometry/Cache mismatch: %s: cache expects %d values for %s." ) % group->getName().toStdString() % size % attrName ).str().c_str() ); continue; } converter->convert( attrName, gdp, currentRange ); } else { converter->convert( attrName, gdp, pointRange ); } } // if transformAttribute is specified, use to to transform the points if ( transformAttribute != "" ) { const TransformationMatrixdData *transform = attributes->member<TransformationMatrixdData>( transformAttribute ); if ( transform ) { UT_Matrix4 matrix( IECore::convert<UT_Matrix4T<double> >( transform->readable().transform() ) ); gdp->transformGroup( matrix, *group ); } else { const TransformationMatrixfData *transform = attributes->member<TransformationMatrixfData>( transformAttribute ); if ( transform ) { UT_Matrix4 matrix = IECore::convert<UT_Matrix4>( transform->readable().transform() ); gdp->transformGroup( matrix, *group ); } } } } unlockInputs(); return error(); }
OP_ERROR SOP_SceneCacheSource::cookMySop( OP_Context &context ) { // make sure the state is valid if ( boost::indeterminate( m_static ) ) { sceneChanged(); } flags().setTimeDep( bool( !m_static ) ); std::string file; if ( !ensureFile( file ) ) { addError( SOP_ATTRIBUTE_INVALID, ( file + " is not a valid .scc" ).c_str() ); gdp->clearAndDestroy(); return error(); } std::string path = getPath(); Space space = getSpace(); GeometryType geometryType = (GeometryType)this->evalInt( pGeometryType.getToken(), 0, 0 ); UT_String shapeFilterStr; evalString( shapeFilterStr, pShapeFilter.getToken(), 0, 0 ); UT_StringMMPattern shapeFilter; shapeFilter.compile( shapeFilterStr ); UT_String p( "P" ); UT_String attributeFilter; evalString( attributeFilter, pAttributeFilter.getToken(), 0, 0 ); if ( !p.match( attributeFilter ) ) { attributeFilter += " P"; } ConstSceneInterfacePtr scene = this->scene( file, path ); if ( !scene ) { addError( SOP_ATTRIBUTE_INVALID, ( path + " is not a valid location in " + file ).c_str() ); gdp->clearAndDestroy(); return error(); } MurmurHash hash; hash.append( file ); hash.append( path ); hash.append( space ); hash.append( shapeFilterStr ); hash.append( attributeFilter ); hash.append( geometryType ); hash.append( getObjectOnly() ); if ( !m_loaded || m_hash != hash ) { gdp->clearAndDestroy(); } Imath::M44d transform = ( space == World ) ? worldTransform( file, path, context.getTime() ) : Imath::M44d(); SceneInterface::Path rootPath; scene->path( rootPath ); UT_Interrupt *progress = UTgetInterrupt(); if ( !progress->opStart( ( "Cooking objects for " + getPath() ).c_str() ) ) { addError( SOP_ATTRIBUTE_INVALID, "Cooking interrupted before it started" ); gdp->clearAndDestroy(); return error(); } loadObjects( scene, transform, context.getTime(), space, shapeFilter, attributeFilter.toStdString(), geometryType, rootPath.size() ); if ( progress->opInterrupt( 100 ) ) { addError( SOP_ATTRIBUTE_INVALID, "Cooking interrupted" ); gdp->clearAndDestroy(); m_loaded = false; m_hash = MurmurHash(); } else { m_loaded = true; m_hash = hash; } progress->opEnd(); return error(); }
OP_ERROR SOP_AddEdges::cookMySop(OP_Context &context) { typedef dgal::simple_mesh<Imath::V3f> simple_mesh; typedef dgal::EdgeIntersection<unsigned int, float> edge_intersection; typedef std::pair<unsigned int, unsigned int> edge_type; hdk_utils::ScopedCook scc(*this, context, "Performing edges add"); if(!scc.good()) return error(); double now = context.getTime(); // inputs const GU_Detail* gdp0 = inputGeo(0); if (!gdp0 ) { SOP_ADD_FATAL(SOP_MESSAGE, "Not enough sources specified."); } unsigned int npoints0 = gdp0->points().entries(); UT_String edgesAttrib; evalString(edgesAttrib, "edges_string", 0, now); std::string edgesAttribStr = edgesAttrib.toStdString(); std::vector<std::string> toks; pystring::split(edgesAttribStr, toks); if(toks.empty()) { duplicateSource(0, context); return error(); } simple_mesh m, m2; simple_mesh* pm = NULL; std::vector<int> points_remap; std::vector<int> polys_remap; dgal::MeshRemapSettings<int> remap_settings(true, true, true, 0, 0, &points_remap, &polys_remap); std::map<std::string, unsigned int> new_points; // create new points { std::vector<edge_intersection> edgeints; std::string s = pystring::replace(edgesAttribStr, ",", " "); std::vector<std::string> toks; pystring::split(s, toks); for(unsigned int i=0; i<toks.size(); ++i) { // new point will be in form 'X-Y:f' if(toks[i].find('-') != std::string::npos) { s = pystring::replace(toks[i], "-", " "); s = pystring::replace(s, ":", " "); std::istringstream strm(s); edge_intersection ei; try { strm >> ei.m_point1 >> ei.m_point2 >> ei.m_u; } catch(const std::exception&) { continue; } new_points[toks[i]] = npoints0 + edgeints.size(); edgeints.push_back(ei); } } if(new_points.empty()) { // no new points means no point remapping remap_settings.m_genPointRemapping = false; remap_settings.m_identity_point_mapping = true; } else { dgal::addMeshPoints<GEO_Detail, std::vector<edge_intersection>::const_iterator>( *gdp0, m, edgeints.begin(), edgeints.end(), &points_remap, &polys_remap); pm = &m; } }
OP_ERROR SOP_PointsFromVoxels::cookMySop(OP_Context &context) { bool cull, store; fpreal now, value; int rx, ry, rz; unsigned primnum; GA_Offset ptOff; GA_ROAttributeRef input_attr_gah; GA_RWAttributeRef attr_gah; GA_ROHandleS input_attr_h; GA_RWHandleF attr_h; const GU_Detail *input_geo; const GEO_Primitive *prim; const GEO_PrimVolume *vol; UT_String attr_name; UT_Vector3 pos; UT_VoxelArrayIteratorF vit; now = context.getTime(); if (lockInputs(context) >= UT_ERROR_ABORT) { return error(); } // Get the primitive number. primnum = PRIM(now); // Check for culling. cull = CULL(now); store = STORE(now); // Clear out the detail since we only want our new points. gdp->clearAndDestroy(); // Get the input geometry as read only. GU_DetailHandleAutoReadLock gdl(inputGeoHandle(0)); input_geo = gdl.getGdp(); // Primitive number is valid. if (primnum < input_geo->getNumPrimitives()) { // Get the primitive we need. prim = input_geo->primitives()(primnum); // The primitive is a volume primitive. if (prim->getTypeId().get() == GEO_PRIMVOLUME) { // Get the actual PrimVolume. vol = (const GEO_PrimVolume *)prim; // Get a voxel read handle from the primitive. UT_VoxelArrayReadHandleF vox(vol->getVoxelHandle()); // Attach the voxel iterator to the handle. vit.setHandle(vox); if (store) { // Try to find a 'name' attribute. input_attr_gah = input_geo->findPrimitiveAttribute("name"); if (input_attr_gah.isValid()) { // Get this primitive's name. input_attr_h.bind(input_attr_gah.getAttribute()); attr_name = input_attr_h.get(primnum); } // No name, so just use 'value'. else { attr_name = "value"; } // Add a float point attribute to store the values. attr_gah = gdp->addFloatTuple(GA_ATTRIB_POINT, attr_name, 1); // Attach an attribute handle. attr_h.bind(attr_gah.getAttribute()); } // Culling empty voxels. if (cull) { // Iterate over all the voxels. for (vit.rewind(); !vit.atEnd(); vit.advance()) { // The voxel value. value = vit.getValue(); // Skip voxels with a value of 0. if (value == 0) { continue; } // Convert the voxel index to a position. vol->indexToPos(vit.x(), vit.y(), vit.z(), pos); // Create a point and set it to the position of the // voxel. ptOff = gdp->appendPointOffset(); gdp->setPos3(ptOff, pos); // Store the value if necessary. if (store) { attr_h.set(ptOff, value); } } } else { // Get the resolution of the volume. vol->getRes(rx, ry, rz); // Add points for each voxel. ptOff = gdp->appendPointBlock(rx * ry * rz); // Iterate over all the voxels. for (vit.rewind(); !vit.atEnd(); vit.advance()) { // Convert the voxel index to a position. vol->indexToPos(vit.x(), vit.y(), vit.z(), pos); // Set the position for the current offset. gdp->setPos3(ptOff, pos); // Get and store the value if necessary. if (store) { value = vit.getValue(); attr_h.set(ptOff, value); } // Increment the offset since the block of points we // created is guaranteed to be contiguous. ptOff++; } } } // Primitive isn't a volume primitive. else { addError(SOP_MESSAGE, "Not a volume primitive."); } } // Picked a primitive number that is out of range. else { addWarning(SOP_MESSAGE, "Invalid source index. Index out of range."); } unlockInputs(); return error(); }
OP_ERROR SOP_Smoke_Source::cookMySop(OP_Context &context) { // We must lock our inputs before we try to access their geometry. // OP_AutoLockInputs will automatically unlock our inputs when we return. // NOTE: Don't call unlockInputs yourself when using this! OP_AutoLockInputs inputs(this); if (inputs.lock(context) >= UT_ERROR_ABORT) return error(); fpreal now = context.getTime(); duplicateSource(0, context); // These three lines enable the local variable support. This allows // $CR to get the red colour, for example, as well as supporting // any varmap created by the Attribute Create SOP. // Note that if you override evalVariableValue for your own // local variables (like SOP_Star does) it is essential you // still call the SOP_Node::evalVariableValue or you'll not // get any of the benefit of the built in local variables. // The variable order controls precedence for which attribute will be // be bound first if the same named variable shows up in multiple // places. This ordering ensures point attributes get precedence. setVariableOrder(3, 2, 0, 1); // The setCur* functions track which part of the gdp is currently // being processed - it is what is used in the evalVariableValue // callback as the current point. The 0 is for the first input, // you can have two inputs so $CR2 would get the second input's // value. setCurGdh(0, myGdpHandle); // Builds the lookup table matching attributes to the local variables. setupLocalVars(); // Here we determine which groups we have to work on. We only // handle point groups. if (error() < UT_ERROR_ABORT && cookInputGroups(context) < UT_ERROR_ABORT && (!myGroup || !myGroup->isEmpty())) { UT_AutoInterrupt progress("Flattening Points"); // Handle all position, normal, and vector attributes. // It's not entirely clear what to do for quaternion or transform attributes. // We bump the data IDs of the attributes to modify in advance, // since we're already looping over them, and we want to avoid // bumping them all for each point, in case that's slow. UT_Array<GA_RWHandleV3> positionattribs(1); UT_Array<GA_RWHandleV3> normalattribs; UT_Array<GA_RWHandleV3> vectorattribs; GA_Attribute *attrib; GA_FOR_ALL_POINT_ATTRIBUTES(gdp, attrib) { // Skip non-transforming attributes if (!attrib->needsTransform()) continue; GA_TypeInfo typeinfo = attrib->getTypeInfo(); if (typeinfo == GA_TYPE_POINT || typeinfo == GA_TYPE_HPOINT) { GA_RWHandleV3 handle(attrib); if (handle.isValid()) { positionattribs.append(handle); attrib->bumpDataId(); } } else if (typeinfo == GA_TYPE_NORMAL) { GA_RWHandleV3 handle(attrib); if (handle.isValid()) { normalattribs.append(handle); attrib->bumpDataId(); } } else if (typeinfo == GA_TYPE_VECTOR) { GA_RWHandleV3 handle(attrib); if (handle.isValid()) { vectorattribs.append(handle); attrib->bumpDataId(); } } } // Iterate over points up to GA_PAGE_SIZE at a time using blockAdvance. GA_Offset start; GA_Offset end; for (GA_Iterator it(gdp->getPointRange(myGroup)); it.blockAdvance(start, end);) { // Check if user requested abort if (progress.wasInterrupted()) break; for (GA_Offset ptoff = start; ptoff < end; ++ptoff) { // This sets the current point that is beint processed to // ptoff. This means that ptoff will be used for any // local variable for any parameter evaluation that occurs // after this point. // NOTE: Local variables and repeated parameter evaluation // is significantly slower and sometimes more complicated // than having a string parameter that specifies the name // of an attribute whose values should be used instead. // That parameter would only need to be evaluated once, // the attribute could be looked up once, and quickly // accessed; however, a separate point attribute would // be needed for each property that varies per point. // Local variable evaluation isn't threadsafe either, // whereas attributes can be read safely from multiple // threads. // // Long story short: *Local variables are terrible.* myCurPtOff[0] = ptoff; float dist = DIST(now); UT_Vector3 normal; if (!DIRPOP()) { switch (ORIENT()) { case 0 : // XY Plane normal.assign(0, 0, 1); break; case 1 : // YZ Plane normal.assign(1, 0, 0); break; case 2 : // XZ Plane normal.assign(0, 1, 0); break; } } else { normal.assign(NX(now), NY(now), NZ(now)); normal.normalize(); } // Project positions onto the plane by subtracting // off the normal component. for (exint i = 0; i < positionattribs.size(); ++i) { UT_Vector3 p = positionattribs(i).get(ptoff); p -= normal * (dot(normal, p) - dist); positionattribs(i).set(ptoff, p); } // Normals will now all either be normal or -normal. for (exint i = 0; i < normalattribs.size(); ++i) { UT_Vector3 n = normalattribs(i).get(ptoff); if (dot(normal, n) < 0) n = -normal; else n = normal; normalattribs(i).set(ptoff, n); } // Project vectors onto the plane through the origin by // subtracting off the normal component. for (exint i = 0; i < vectorattribs.size(); ++i) { UT_Vector3 v = vectorattribs(i).get(ptoff); v -= normal * dot(normal, v); vectorattribs(i).set(ptoff, v); } } } }
OP_ERROR SOP_PrimCentroid::cookMySop(OP_Context &context) { fpreal now; int method; const GA_Attribute *source_attr; const GA_AttributeDict *dict; GA_AttributeDict::iterator a_it; GA_Offset ptOff; GA_RWAttributeRef n_gah; GA_RWHandleV3 n_h; const GEO_Primitive *prim; const GU_Detail *input_geo; UT_BoundingBox bbox; UT_String pattern, attr_name; UT_WorkArgs tokens; now = context.getTime(); if (lockInputs(context) >= UT_ERROR_ABORT) return error(); // Clear out any previous data. gdp->clearAndDestroy(); // Get the input geometry as read only. GU_DetailHandleAutoReadLock gdl(inputGeoHandle(0)); input_geo = gdl.getGdp(); // Find out which calculation method we are attempting. method = METHOD(now); // Create the standard point normal (N) attribute. n_gah = gdp->addNormalAttribute(GA_ATTRIB_POINT); // Bind a read/write attribute handle to the normal attribute. n_h.bind(n_gah.getAttribute()); // Construct an attribute reference map to map attributes. GA_AttributeRefMap hmap(*gdp, input_geo); // Get the attribute selection string. ATTRIBUTES(pattern, now); // Make sure we entered something. if (pattern.length() > 0) { // Tokenize the pattern. pattern.tokenize(tokens, " "); // The primitive attributes on the incoming geometry. dict = &input_geo->primitiveAttribs(); // Iterate over all the primitive attributes. for (a_it=dict->begin(GA_SCOPE_PUBLIC); !a_it.atEnd(); ++a_it) { // The current attribute. source_attr = a_it.attrib(); // Get the attribute name. attr_name = source_attr->getName(); // If the name doesn't match our pattern, skip it. if (!attr_name.matchPattern(tokens)) continue; // Create a new point attribute on the current geometry // that is the same as the source attribute. Append it and // the source to the map. hmap.append(gdp->addPointAttrib(source_attr).getAttribute(), source_attr); } // Copy local variables. if (COPY(now)) { // Traverse the variable names on the input geometry and attempt to // copy any that match to our new geometry. input_geo->traverseVariableNames( SOP_PrimCentroid::copyLocalVariables, gdp ); } } // Get the list of input primitives. const GA_PrimitiveList &prim_list = input_geo->getPrimitiveList(); // Add points for each primitive. ptOff = gdp->appendPointBlock(input_geo->getNumPrimitives()); // Iterate over primitives using pages. for (GA_Iterator it(input_geo->getPrimitiveRange()); !it.atEnd(); ++it) { // Get the primitive from the list. prim = (const GEO_Primitive *) prim_list.get(*it); if (method) { // Get the bounding box for the primitive and set the point's // position to be the center of the box. prim->getBBox(&bbox); gdp->setPos3(ptOff, bbox.center()); } else // Set the point's position to be the bary center of the primitive gdp->setPos3(ptOff, prim->baryCenter()); // Set the point's normal to be the normal of the primitive. n_h.set(ptOff, prim->computeNormal()); // If we are copying attributes, copy the primitive attributes from // the current primitive to the new point. if (hmap.entries() > 0) hmap.copyValue(GA_ATTRIB_POINT, ptOff, GA_ATTRIB_PRIMITIVE, *it); // Increment the point offset. ptOff++; } unlockInputs(); return error(); }
OP_ERROR SOP_CudaParticles::cookMySop(OP_Context &context) { oldf = f; f = context.getFrame(); GEO_ParticleVertex* pvtx; double t = context.getTime(); particlesSystem->dt = 1/(OPgetDirector()->getChannelManager()->getSamplesPerSec() * SUBSTEPS(t)); particlesSystem->preview = PREVIEW(t); particlesSystem->partsLife = LIFE(t); particlesSystem->partsLifeVar = LIFEVAR(t); particlesSystem->velDamp = VELDAMP(t); particlesSystem->gravityStrength = GRAVITYSTR(t); particlesSystem->gravityDir = cu::make_float3(GRAVITYX(t),GRAVITYY(t),GRAVITYZ(t)); particlesSystem->fluidStrength = FLUIDSTR(t); particlesSystem->noiseAmp = cu::make_float3(NOISEAMP(t),NOISEAMP(t),NOISEAMP(t)); particlesSystem->noiseOct = NOISEOCT(t); particlesSystem->noiseFreq = NOISEFREQ(t); particlesSystem->noiseLac = NOISELACUN(t); particlesSystem->noiseOffset = cu::make_float3(NOISEOFFSETX(t),NOISEOFFSETY(t),NOISEOFFSETZ(t)); particlesSystem->pointSize = POINTSIZE(t); particlesSystem->opacity = OPACITY(t); particlesSystem->startColor = cu::make_float3(STARTCOLORX(t),STARTCOLORY(t),STARTCOLORZ(t)); particlesSystem->endColor = cu::make_float3(ENDCOLORX(t),ENDCOLORY(t),ENDCOLORZ(t)); UT_Interrupt *boss; OP_Node::flags().timeDep = 1; if (error() < UT_ERROR_ABORT) { boss = UTgetInterrupt(); // Start the interrupt server if (boss->opStart("Building Particles")){ //gdp->clearAndDestroy(); static float zero = 0.0; GB_AttributeRef partsAtt = gdp->addAttrib("cudaParticlesPreview", sizeof(int), GB_ATTRIB_INT, &zero); gdp->attribs().getElement().setValue<int>(partsAtt, particlesSystem->preview); GB_AttributeRef systemIdAtt = gdp->addAttrib("systemId", sizeof(int), GB_ATTRIB_INT, &zero); gdp->attribs().getElement().setValue<int>(systemIdAtt, particlesSystem->id); if (f < STARTFRAME(t)) { gdp->clearAndDestroy(); particlesSystem->resetParticles(); } else if (f == STARTFRAME(t)) { gdp->clearAndDestroy(); particlesSystem->resetParticles(); int maxParts = MAXPARTS(t); if (particlesSystem->nParts!=maxParts) particlesSystem->changeMaxParts(maxParts); //hSystem = (GEO_PrimParticle *)gdp->appendPrimitive(GEOPRIMPART); //hSystem->clearAndDestroy(); GB_AttributeRef hVelocity = gdp->addPointAttrib("v", sizeof(UT_Vector3),GB_ATTRIB_VECTOR, 0); GB_AttributeRef hLife = gdp->addPointAttrib("life", sizeof(float)*2,GB_ATTRIB_FLOAT, 0); if(particlesSystem->preview!=1) { UT_Vector4 orig = UT_Vector4(0,0,0,1); for (int i = 0; i<particlesSystem->nParts; i++) { GEO_Point* newPoint = gdp->appendPoint(); newPoint->setPos(orig); /*pvtx = hSystem->giveBirth(); GEO_Point* ppt = pvtx->getPt(); //ppt->getPos().assign(0,0,0,1);*/ hSystemInit = 1; } } } else { if(particlesSystem->nParts != -1) { if(lockInputs(context) >= UT_ERROR_ABORT) return error(); if(getInput(0)){ GU_Detail* emittersInput = (GU_Detail*)inputGeo(0, context); GEO_PointList emittersList = emittersInput->points(); int numEmitters = emittersList.entries(); if (numEmitters != particlesSystem->nEmit) { delete particlesSystem->emitters; particlesSystem->nEmit = numEmitters; particlesSystem->emitters = new ParticlesEmitter[numEmitters]; } GEO_AttributeHandle radAh, amountAh; GEO_AttributeHandle initVelAh, radVelAmpAh, noiseVelAmpAh, noiseVelOffsetAh, noiseVelOctAh, noiseVelLacAh, noiseVelFreqAh; radAh = emittersInput->getPointAttribute("radius"); amountAh = emittersInput->getPointAttribute("amount"); initVelAh = emittersInput->getPointAttribute("initVel"); radVelAmpAh = emittersInput->getPointAttribute("radVelAmp"); noiseVelAmpAh = emittersInput->getPointAttribute("noiseVelAmp"); noiseVelOffsetAh = emittersInput->getPointAttribute("noiseVelOffset"); noiseVelOctAh = emittersInput->getPointAttribute("noiseVelOct"); noiseVelLacAh = emittersInput->getPointAttribute("noiseVelLac"); noiseVelFreqAh = emittersInput->getPointAttribute("noiseVelFreq"); for (int i = 0; i < numEmitters; i++) { UT_Vector4 emitPos = emittersList[i]->getPos(); UT_Vector3 emitPos3(emitPos); particlesSystem->emitters[i].posX = emitPos.x(); particlesSystem->emitters[i].posY = emitPos.y(); particlesSystem->emitters[i].posZ = emitPos.z(); radAh.setElement(emittersList[i]); amountAh.setElement(emittersList[i]); initVelAh.setElement(emittersList[i]); radVelAmpAh.setElement(emittersList[i]); noiseVelAmpAh.setElement(emittersList[i]); noiseVelOffsetAh.setElement(emittersList[i]); noiseVelOctAh.setElement(emittersList[i]); noiseVelLacAh.setElement(emittersList[i]); noiseVelFreqAh.setElement(emittersList[i]); particlesSystem->emitters[i].radius = radAh.getF(0); particlesSystem->emitters[i].amount = amountAh.getF(0); particlesSystem->emitters[i].velX = initVelAh.getF(0); particlesSystem->emitters[i].velY = initVelAh.getF(1); particlesSystem->emitters[i].velZ = initVelAh.getF(2); particlesSystem->emitters[i].radVelAmp = radVelAmpAh.getF(0); particlesSystem->emitters[i].noiseVelAmpX = noiseVelAmpAh.getF(0); particlesSystem->emitters[i].noiseVelAmpY = noiseVelAmpAh.getF(1); particlesSystem->emitters[i].noiseVelAmpZ = noiseVelAmpAh.getF(2); particlesSystem->emitters[i].noiseVelOffsetX = noiseVelOffsetAh.getF(0); particlesSystem->emitters[i].noiseVelOffsetY = noiseVelOffsetAh.getF(1); particlesSystem->emitters[i].noiseVelOffsetZ = noiseVelOffsetAh.getF(2); particlesSystem->emitters[i].noiseVelOct = noiseVelOctAh.getF(0); particlesSystem->emitters[i].noiseVelLac = noiseVelLacAh.getF(0); particlesSystem->emitters[i].noiseVelFreq = noiseVelFreqAh.getF(0); } } else { particlesSystem->nEmit = 0; } if(getInput(1)){ GU_Detail* fluidInput = (GU_Detail*)inputGeo(1, context); GEO_AttributeHandle fluidIdAh= fluidInput->getDetailAttribute("solverId"); fluidIdAh.setElement(fluidInput); int sId = fluidIdAh.getI(); VHFluidSolver3D* curr3DSolver = VHFluidSolver3D::solverList[sId]; particlesSystem->fluidSolver = curr3DSolver; } unlockInputs(); if (f!=oldf) { particlesSystem->emitParticles(); particlesSystem->updateParticles(); } if(particlesSystem->preview!=1 && hSystemInit == 1) { cu::cudaMemcpy( particlesSystem->host_pos, particlesSystem->dev_pos, particlesSystem->nParts*sizeof(cu::float3), cu::cudaMemcpyDeviceToHost ); GEO_Point* ppt; int i = 0; UT_Vector4 p; FOR_ALL_GPOINTS(gdp, ppt) { ppt->getPos() = UT_Vector4(particlesSystem->host_pos[i*3], particlesSystem->host_pos[i*3+1], particlesSystem->host_pos[i*3+2], 1); i++; } /*pvtx = hSystem->iterateInit(); for (int i =0; i<particlesSystem->nParts; i++){ pvtx->getPos().assign(particlesSystem->host_pos[i*3], particlesSystem->host_pos[i*3+1], particlesSystem->host_pos[i*3+2], 1); pvtx = hSystem->iterateFastNext(pvtx); }*/ } } }
OP_ERROR SOP_IntersectRay::cookMySop(OP_Context &context) { double t; float edgelength, primarea, generatepoints; int verbose; // We optionally add points in self-penetration places: GB_PointGroup *hitPointsGroup; UT_RefArray<UT_Vector3> hitPoints; if (lockInputs(context) >= UT_ERROR_ABORT) return error(); t = context.getTime(); duplicatePointSource(0, context); edgelength = EDGELENGTH(t); primarea = PRIMAREA(t); verbose = VERBOSE(t); generatepoints = GENERATEPOINTS(t); // Normals: GEO_AttributeHandle nH; GEO_AttributeHandle cdH; nH = gdp->getAttribute(GEO_POINT_DICT, "N"); cdH = gdp->getAttribute(GEO_POINT_DICT, "Cd"); // RayInfo parms: //float max = 1E18f; // Max specified by edge length... float min = 0.0f; float tol = 1e-1F; // Rayhit objects: GU_RayFindType itype = GU_FIND_ALL; GU_RayIntersect intersect = GU_RayIntersect(gdp); // Profile: //Timer timer = Timer(); //float rayhit_time = 0; //float vertex_time = 0; // Here we determine which groups we have to work on. if (error() < UT_ERROR_ABORT && cookInputGroups(context) < UT_ERROR_ABORT) { UT_AutoInterrupt progress("Checking for self-intersections..."); const GEO_Primitive *ppr; FOR_ALL_GROUP_PRIMITIVES(gdp, myGroup, ppr) { // Check if user requested abort if (progress.wasInterrupted()) break; // Get rid of primitives smaller than primarea: if ( ppr->calcArea() < primarea ) continue; for (int j = 0; j < ppr->getVertexCount() - 1; j++) { // Get data; // TODO: This is extremally inefficent. // TODO: Why do we crash with uv vetrex attributes!? const GEO_Vertex ppv1 = ppr->getVertex(j); const GEO_Vertex ppv2 = ppr->getVertex(j+1); const GEO_Point *ppt1 = ppv1.getPt(); const GEO_Point *ppt2 = ppv2.getPt(); // Vertices positions: UT_Vector3 p1 = ppt1->getPos(); UT_Vector3 p2 = ppt2->getPos(); // Ray direction: p2 = p2 - p1; // Get rid of edges shorter than edgelength: if (p2.length() < edgelength) continue; // hit info with max distance equal edge length: GU_RayInfo hitinfo = GU_RayInfo(p2.length(), min, itype, tol); p2.normalize(); // Send ray: if (intersect.sendRay(p1, p2, hitinfo)) { UT_RefArray<GU_RayInfoHit> hits = *(hitinfo.myHitList); for(int j = 0; j < hits.entries(); j++) { const GEO_Primitive *prim = hits[j].prim; const GEO_PrimPoly *poly = (const GEO_PrimPoly *) prim; //TODO: Prims only? // We are interested only ff points are not part of prims...: if (poly->find(*ppt1) == -1 && poly->find(*ppt2)== -1) { if (verbose) printf("Edge: %i-%i intersects with prim:%d \n",ppt1->getNum(), ppt2->getNum(), prim->getNum()); // Save hit position as points: if (generatepoints) { UT_Vector4 pos; float u = hits[j].u; float v = hits[j].v; if (!prim->evaluateInteriorPoint(pos, u, v)) hitPoints.append(pos); } // TODO: Should I indicate penetration with red color on both ends of edge?: cdH.setElement(ppt1); cdH.setV3(UT_Vector3(1.0, 0.0, 0.0)); cdH.setElement(ppt2); cdH.setV3(UT_Vector3(1.0, 0.0, 0.0)); } } } } } if (generatepoints) { hitPointsGroup = gdp->newPointGroup("__self_penetrate", false); for (int i = 0; i < hitPoints.entries(); i++) { GEO_Point *point; point = gdp->appendPoint(); hitPointsGroup->add(point); point->setPos(hitPoints(i)); } } }
OP_ERROR SOP_groupAsAttr::cookMySop(OP_Context &context) { // We must lock our inputs before we try to access their geometry. // OP_AutoLockInputs will automatically unlock our inputs when we return. // NOTE: Don't call unlockInputs yourself when using this! OP_AutoLockInputs inputs(this); if (inputs.lock(context) >= UT_ERROR_ABORT) return error(); // Duplicate our incoming geometry with the hint that we only // altered points. Thus, if our input was unchanged, we can // easily roll back our changes by copying point values. duplicatePointSource(0, context); fpreal t = context.getTime(); // We evaluate our parameters outside the loop for speed. If we // wanted local variable support, we'd have to do more setup // (see SOP_Flatten) and also move these inside the loop. int get_PointGrp, get_PrimGrp; get_PointGrp = getPointToggle(t); get_PrimGrp = getPrimToggle(t); debug = debugMe(t); cout << "debug :" << debug << endl; cout << "get ptGrp :" << get_PointGrp << endl; cout << "get ptimGrp:" << get_PrimGrp << endl; if (error() >= UT_ERROR_ABORT) return error(); // Here we determine which groups we have to work on. We only // handle point groups. if (cookInputGroups(context) >= UT_ERROR_ABORT) { return error(); } //if we have chosen a point group if(get_PointGrp) { cout << "we are in points now!!" << endl; if(debug) { cout << "-------------------------------" <<endl; cout << "--*>YOU HAVE CHOSEN A POINT GROUP" << endl; } groupToAttrPoints("ptGroupName", debug); } //IF WE HAVE CHOSEN TO DEAL WITH PRIMITIVES if(get_PrimGrp) { //set our flag to signal that we have chosen to use the prim attr if(debug) { cout << "-------------------------------" <<endl; cout << "--*>YOU HAVE CHOSEN A PRIM GROUP" << endl; } //if we have never checked this option before if(!primChanged) { //deal with the prim groups if any as attrs groupToAttrPrims("primGroupName", debug); //change our flag to on primChanged = true; } } else { //otherwise if we have just unchecked the prim attrs if(primChanged) { //destroy the attr and flag our check gdp->destroyAttribute(GA_ATTRIB_PRIMITIVE, "primGroupName"); primChanged = false; } } // If we've modified P, and we're managing our own data IDs, // we must bump the data ID for P. if (!myGroup || !myGroup->isEmpty()) gdp->bumpAllDataIds(); // gdp->getP()->bumpDataId(); return error(); }
OP_ERROR GusdSOP_usdimport::_CreateNewPrims(OP_Context& ctx, const GusdUSD_Traverse* traverse, GusdUT_ErrorContext& err) { fpreal t = ctx.getTime(); UT_String file, primPath; evalString(file, "import_file", 0, t); evalString(primPath, "import_primpath", 0, t); if(!file.isstring() || !primPath.isstring()) { // Nothing to do. return UT_ERROR_NONE; } /* The prim path may be a list of prims. Additionally, those prim paths may include variants (eg., /some/model{variant=sel}/subscope ). Including multiple variants may mean that we need to access multiple stages. Resolve the actual set of prims and variants first.*/ UT_Array<SdfPath> primPaths, variants; if(!GusdUSD_Utils::GetPrimAndVariantPathsFromPathList( primPath, primPaths, variants, &err)) return err(); GusdDefaultArray<UT_StringHolder> filePaths; filePaths.SetConstant(file); // Get stage edits applying any of our variants. GusdDefaultArray<GusdStageEditPtr> edits; edits.GetArray().setSize(variants.size()); for(exint i = 0; i < variants.size(); ++i) { if(!variants(i).IsEmpty()) { GusdStageBasicEdit* edit = new GusdStageBasicEdit; edit->GetVariants().append(variants(i)); edits.GetArray()(i).reset(edit); } } // Load the root prims. UT_Array<UsdPrim> rootPrims; { rootPrims.setSize(primPaths.size()); GusdStageCacheReader cache; if(!cache.GetPrims(filePaths, primPaths, edits, rootPrims.data(), GusdStageOpts::LoadAll(), &err)) return err(); } GusdDefaultArray<UsdTimeCode> times; times.SetConstant(evalFloat("import_time", 0, t)); UT_String purpose; evalString(purpose, "purpose", 0, t); GusdDefaultArray<GusdPurposeSet> purposes; purposes.SetConstant(GusdPurposeSet( GusdPurposeSetFromMask(purpose)| GUSD_PURPOSE_DEFAULT)); UT_Array<UsdPrim> prims; if(traverse) { // Before traversal, make a copy of the variants list. const UT_Array<SdfPath> variantsPreTraverse(variants); UT_Array<GusdUSD_Traverse::PrimIndexPair> primIndexPairs; UT_UniquePtr<GusdUSD_Traverse::Opts> opts(traverse->CreateOpts()); if(opts) { if(!opts->Configure(*this, t)) return err(); } if(!traverse->FindPrims(rootPrims, times, purposes, primIndexPairs, /*skip root*/ false, opts.get())) { return err(); } // Resize the prims and variants lists to match the size of // primIndexPairs. exint size = primIndexPairs.size(); prims.setSize(size); variants.setSize(size); // Now iterate through primIndexPairs to populate the prims // and variants lists. for (exint i = 0; i < size; i++) { prims(i) = primIndexPairs(i).first; exint index = primIndexPairs(i).second; variants(i) = index < variantsPreTraverse.size() ? variantsPreTraverse(index) : SdfPath(); } } else { std::swap(prims, rootPrims); } /* Have the resolved set of USD prims. Now create prims or points on the detail.*/ bool packedPrims = !evalInt("import_class", 0, t); if(packedPrims) { UT_String vpLOD; evalString(vpLOD, "viewportlod", 0, t); GusdDefaultArray<UT_StringHolder> lods; lods.SetConstant(vpLOD); GusdGU_USD::AppendPackedPrims(*gdp, prims, variants, times, lods, purposes, &err); } else { GusdGU_USD::AppendRefPoints(*gdp, prims, GUSD_PATH_ATTR, GUSD_PRIMPATH_ATTR, &err); } return err(); }
OP_ERROR SOP_FlexSolver::cookMySop(OP_Context &context) { // We must lock our inputs before we try to access their geometry. // OP_AutoLockInputs will automatically unlock our inputs when we return. // NOTE: Don't call unlockInputs yourself when using this! OP_AutoLockInputs inputs(this); if (inputs.lock(context) >= UT_ERROR_ABORT) return error(); // Now, indicate that we are time dependent (i.e. have to cook every // time the current frame changes). OP_Node::flags().timeDep = 1; // Channel manager has time info for us CH_Manager *chman = OPgetDirector()->getChannelManager(); // This is the frame that we're cooking at... fpreal current_time = context.getTime(); fpreal currframe = chman->getSample(context.getTime()); fpreal reset = RESET(); // Find our reset frame... maxParticles = MAXPARTICLES(); // Set up our source information... mySource = inputGeo(0, context); if (mySource) { mySourceVel = GA_ROHandleV3(mySource->findFloatTuple(GA_ATTRIB_POINT, "v", 3)); // If there's no velocity, pick up the velocity from the normal if (mySourceVel.isInvalid()) mySourceVel = GA_ROHandleV3(mySource->findFloatTuple(GA_ATTRIB_POINT, "N", 3)); } if (currframe <= reset || !mySolver) { myLastCookTime = reset; initSystem(current_time); } else { // // Set up the collision detection object // const GU_Detail *collision = inputGeo(1, context); // if (collision) // { // myCollision = new GU_RayIntersect; // myCollision->init(collision); // } // else myCollision = 0; // This is where we notify our handles (if any) if the inputs have // changed. This is normally done in cookInputGroups, but since there // is no input group, NULL is passed as the fourth argument. notifyGroupParmListeners(0, -1, mySource, NULL); // Now cook the geometry up to our current time // Here, we could actually re-cook the source input to get a moving // source... But this is just an example ;-) currframe += 0.05; // Add a bit to avoid floating point error while (myLastCookTime < currframe) { // Here we have to convert our frame number to the actual time. timeStep(chman->getTime(myLastCookTime)); myLastCookTime += 1; } // if (myCollision) delete myCollision; // Set the node selection for the generated particles. This will // highlight all the points generated by this node, but only if the // highlight flag is on and the node is selected. select(GA_GROUP_POINT); } return error(); }
double SceneCacheNode<BaseType>::time( OP_Context context ) const { return context.getTime() + CHgetManager()->getSecsPerSample(); }
/* ****************************************************************************** * Function Name : cookMySop() * * Description : * * Input Arguments : None * * Return Value : * ***************************************************************************** */ OP_ERROR SOP_RF_Export::cookMySop(OP_Context & context) { UT_Vector3 trans, rot, scale, up, shear; char GUI_str[128]; OP_ERROR myError; OP_Node::flags().timeDep = 1; float * myBeginEnd_ptr = myBeginEnd; float now = context.getTime(); disableParms(); // Evaluate the GUI parameters myFileFormat = (int)FILE_FORMAT(now); myStaticAnim = (bool)ANIM(now); myMode = (bool)MODE(now); BEGIN_END(myBeginEnd_ptr, now); FNAME(myFileName, now); myEchoData = ECHO_CONSOLE(now); disableParms(); sprintf(GUI_str, "%s", ""); setString((UT_String)GUI_str, CH_STRING_LITERAL, ARG_RF_EXPORT_INFO1, 0, now); setString((UT_String)GUI_str, CH_STRING_LITERAL, ARG_RF_EXPORT_INFO2, 0, now); sprintf(GUI_str, "Version: %s", SOP_Version.c_str()); setString((UT_String)GUI_str, CH_STRING_LITERAL, ARG_RF_EXPORT_INFO3, 0, now); // If there has been a error from the previous callback, report it if(myCallBackFlags) { return(reportCallBackErrors(myCallBackFlags)); } #ifdef DEBUG std::cout << "myFileFormat " << myFileFormat << endl; #endif switch(myFileFormat) { case SD_FILE: myError = writeSDFile(context); break; case BIN_FILE: myError = writeBINFile(context); break; case RWC_FILE: myError = writeRWCFile(context); break; case MESH_FILE: myError = writeMeshFile(context); break; default: return error(); } return myError; }
OP_ERROR SOP_Rain::cookMySop(OP_Context &context) { //UT_Interrupt *boss; if (error() < UT_ERROR_ABORT) { //boss = UTgetInterrupt(); //boss->opStart("Start generating rain"); fpreal now = TIME(context.getTime()); long nPoints = NPOINTS( now ); UT_Vector3 rainDirection = RAINDIRECTION(now); //rainDirection.normalize(); //TODO: check for (0,0,0) vector RainData rain( now, nPoints, BOUNDMIN (now), BOUNDMAX (now), rainDirection, DICEMIN(now), DICEMAX(now), SEED(now), SPEED (now), SPEEDVARIENCE (now)); if(rain.getAllocationState() == false || isPointsNumberChanged_ == true) { rain.allocate(nPoints); } if( rain.getAllocationState() == true && ( rain.getCachedState() == false || isParameterChanged_ == true ) ) { rain.computeInitialPositions(); rain.setCachedState(true); } if (isPointsGenerated_ == false) { printf("Generate Points procedure\n"); gdp->clearAndDestroy(); generatePoints(gdp, nPoints); isPointsGenerated_ = true; } for ( GA_Iterator pr_it(gdp->getPrimitiveRange()); !pr_it.atEnd(); ++pr_it) { GEO_Primitive* prim = gdp->getGEOPrimitive(*pr_it); GA_Range range = prim->getPointRange(); rain.shiftPositions( gdp, range); } //boss->opEnd(); } isParameterChanged_ = false; isPointsNumberChanged_ = false; //unlockInputs(); return error(); }
OP_ERROR SOP_UniPdist::cookMySop(OP_Context &context) { // Before we do anything, we must lock our inputs. Before returning, // we have to make sure that the inputs get unlocked. if (lockInputs(context) >= UT_ERROR_ABORT) return error(); // Duplicate input geometry duplicateSource(0, context); float time = context.getTime(); float dist = evalFloat(distanceName.getToken(), 0, time); GA_PointGroup *removeGroup = gdp->newPointGroup(REMOVE_GROUP_NAME); GA_PointGroup *keepGroup = gdp->newPointGroup(KEEP_GROUP_NAME); // Flag the SOP as being time dependent (i.e. cook on time changes) flags().timeDep = 1; //Create a removeAttrib GA_RWHandleI removeAttrib(gdp->addIntTuple(GA_ATTRIB_POINT, "__remove__", 1)); //Creating PointTree GEO_PointTreeGAOffset pttree; //Build PointTree with all the points pttree.build(gdp,NULL); //Create the Array wich holds the distance for the current point in the for loop UT_FloatArray ptdist; // Index offset const GA_IndexMap points = gdp->getPointMap(); GA_Size ptoffsetindex; ptoffsetindex = points.offsetSize()-points.indexSize(); //set all for (GA_Iterator ptoff(gdp->getPointRange()); !ptoff.atEnd(); ++ptoff) { removeAttrib.set(*ptoff,0); } // loop over all points, find second closest point for (GA_Iterator ptoff(gdp->getPointRange()); !ptoff.atEnd(); ++ptoff) { int removeMe; removeMe = int(removeAttrib.get(*ptoff)); if(removeMe) { removeGroup->addIndex(*ptoff-ptoffsetindex); continue; } // Create the Array which holds a list sorted on distance to current point in the for loop GEO_PointTree::IdxArrayType plist; //plist UT_Vector3 pos = gdp->getPos3(*ptoff); // create pos pttree.findAllCloseIdx(pos,dist,plist); // find all points within the search radius unsigned int tempListP = plist.entries(); //create a int for entries in the array for(int i=0;i < tempListP; ++i) { removeAttrib.set(plist[i],1); //set the tempList points to be removed } removeAttrib.set(*ptoff,0); keepGroup->addIndex(*ptoff-ptoffsetindex); } pttree.clear(); //clear the pointtree unlockInputs(); return error(); }
/// 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(); }
OP_ERROR SOP_Scallop::cookMySop(OP_Context &context) { //OP_Node::flags().timeDep = 1; bool clip = (lockInputs(context) < UT_ERROR_ABORT); UT_BoundingBox bbox; if(clip) { const GU_Detail* input = inputGeo(0,context); if(input != NULL) { //UT_Matrix4 bm; int res = input->getBBox(&bbox); if(res == 0) clip = false; } else clip = false; unlockInputs(); }; float now = context.getTime(); Daemon::now=now; Daemon::caller=this; Daemon::bias = evalFloat("bias",0,now); UT_Ramp ramp; float rampout[4]; bool useRamp = (evalInt("parmcolor",0,now)!=0); if(useRamp) { //PRM_Template *rampTemplate = PRMgetRampTemplate ("ramp", PRM_MULTITYPE_RAMP_RGB, NULL, NULL); if (ramp.getNodeCount () < 2) { ramp.addNode (0, UT_FRGBA (0, 0, 0, 1)); ramp.addNode (1, UT_FRGBA (1, 1, 1, 1)); }; updateRampFromMultiParm(now, getParm("ramp"), ramp); }; gdp->clearAndDestroy(); bool showPts = (evalInt("showpts",0,now)!=0); /* if(showPts) { float sz = evalInt("ptssz",0,now); if(sz > 0) { float one = 1.0f; gdp->addAttribute("showpoints",4,GA_ATTRIB_FLOAT_&one); gdp->addAttribute("revealsize",4,GB_ATTRIB_FLOAT,&sz); }; }; */ int cnt = evalInt("daemons", 0, now); Daemon* daemons=new Daemon[cnt]; float weights = 0; int totd=0; for(int i=1;i<=cnt;i++) { bool skip = (evalIntInst("enabled#",&i,0,now)==0); if(skip) continue; Daemon& d = daemons[totd]; UT_String path = ""; evalStringInst("obj#", &i, path, 0, now); if(path == "") continue; SOP_Node* node = getSOPNode(path); OBJ_Node* obj = dynamic_cast<OBJ_Node*>(node->getParent()); if(obj == NULL) continue; addExtraInput(obj, OP_INTEREST_DATA); //d.xform = obj->getWorldTransform(context); // 10.0 obj->getWorldTransform(d.xform, context); d.weight = evalFloatInst("weight#",&i,0,now); if(!useRamp) { d.c[0] = evalFloatInst("color#",&i,0,now); d.c[1] = evalFloatInst("color#",&i,1,now); d.c[2] = evalFloatInst("color#",&i,2,now); }; int mth = evalIntInst("model#",&i,0,now); switch(mth) { case 1: d.method = Methods::Spherical; break; case 2: d.method = Methods::Polar; break; case 3: d.method = Methods::Swirl; break; case 4: d.method = Methods::Trigonometric; break; case 5: { UT_String script; evalStringInst("vexcode#", &i, script, 0, now); d.SetupCVEX(script); if(d.useVex) { OP_Node* shop = (OP_Node*)findSHOPNode(script); addExtraInput(shop, OP_INTEREST_DATA); } break; } case 0: default: d.method = Methods::Linear; }; d.power = evalFloatInst("power#",&i,0,now); d.radius = evalFloatInst("radius#",&i,0,now); d.parameter = evalFloatInst("parameter#",&i,0,now); weights+=d.weight; totd++; }; if(totd == 0) { delete [] daemons; return error(); } float base = 0.0; for(int i=0;i<totd;i++) { Daemon& d = daemons[i]; d.range[0]=base; d.range[1] = base+d.weight/weights; base=d.range[1]; }; int total = evalInt("count",0,now); int degr = evalInt("degr",0,now); total >>= degr; GA_RWHandleI cntt(gdp->addIntTuple(GA_ATTRIB_POINT, "count", 4, GA_Defaults(1.0))); GB_AttributeRef dt(gdp->addDiffuseAttribute(GEO_POINT_DICT)); gdp->addVariableName("Cd","Cd"); UT_Vector3 current(0,0,0); float C[3] = { 0,0,0 }; float R=1.0f; bool trackRadii = (evalInt("trackradii",0,now)!=0); float rScale = evalFloat("radiiscale",0,now); GB_AttributeRef rt; if(trackRadii) { float one=1.0f; rt = gdp->addPointAttrib("width",4,GB_ATTRIB_FLOAT,&one); if(!GBisAttributeRefValid(rt)) trackRadii=false; else gdp->addVariableName("width","WIDTH"); }; float zero=0.0f; GB_AttributeRef pt = gdp->addPointAttrib("parameter",4,GB_ATTRIB_FLOAT,&zero); if(GBisAttributeRefValid(pt)) gdp->addVariableName("parameter","PARAMETER"); float param=0.0f; srand(0); UT_Interrupt* boss = UTgetInterrupt(); boss->opStart("Computing..."); for(int i=-50;i<total;i++) { bool ok = false; if (boss->opInterrupt()) break; float w = double(rand())/double(RAND_MAX); for(int j=0;j<totd;j++) { ok = daemons[j].Transform(w,current,C,R,param); if(ok) break; }; if(i<0) continue; if(clip) { if(!bbox.isInside(current)) continue; }; if(ok) { GEO_Point* p = gdp->appendPoint(); p->setPos(current); float* Cd=p->castAttribData<float>(dt); if(useRamp) { ramp.rampLookup(param,C); } memcpy(Cd,C,12); if(trackRadii) { float* _R = p->castAttribData<float>(rt); *_R=rScale*R; }; if(GBisAttributeRefValid(pt)) { float* _p = p->castAttribData<float>(pt); *_p=param; } }; }; boss->opEnd(); delete [] daemons; return error(); };
OP_ERROR SOP_IdBlast::cookMySop(OP_Context &context) { fpreal now; exint id; GA_Offset start, end; GA_PointGroup *group; GA_ROAttributeRef id_gah; GA_ROPageHandleI id_ph; UT_String pattern; UT_WorkArgs tokens; IdOffsetMap id_map, srcid_map; GroupIdMapPair pair; now = context.getTime(); if (lockInputs(context) >= UT_ERROR_ABORT) return error(); // Duplicate the incoming geometry. duplicateSource(0, context); // Get the id pattern. IDS(pattern, now); // If it's emptry, don't do anything. if (pattern.length() == 0) { unlockInputs(); return error(); } // Tokenize the range so we can handle multiple blocks. pattern.tokenize(tokens, " "); // Try to find the 'id' point attribute on the 1st input geometry. id_gah = gdp->findPointAttribute(GA_SCOPE_PUBLIC, "id"); // If it doesn't exist, display a node error message and exit. if (id_gah.isInvalid()) { addError(SOP_MESSAGE, "Input geometry has no 'id' attribute."); unlockInputs(); return error(); } // Bind the page handles to the attributes. id_ph.bind(id_gah.getAttribute()); // Iterate over all the points we selected. for (GA_Iterator it(gdp->getPointRange()); it.blockAdvance(start, end); ) { // Set the page handle to the start of this block. id_ph.setPage(start); // Iterate over all the points in the block. for (GA_Offset pt = start; pt < end; ++pt) { // Get the 'id' value for the point. id = id_ph.get(pt); id_map[id] = pt; } } // Create the group. group = createAdhocPointGroup(*gdp); // Add the group and the id map to the pair. pair.first = group; pair.second = &id_map; // Iterate over each block in the tokens and add any ids to the group. for (int i=0; i < tokens.getArgc(); ++i) { UT_String id_range(tokens[i]); id_range.traversePattern(-1, &pair, addOffsetToGroup); } // Destroy the points. gdp->destroyPointOffsets(GA_Range(*group)); unlockInputs(); return error(); }