Beispiel #1
0
bool
GusdUSD_StageProxy::MultiAccessor::ClampTimes(
    UT_Array<UsdTimeCode>& times) const
{
    UT_ASSERT(times.size() == _size);

    for(exint i = 0; i < times.size(); ++i) {
        if(const auto* accessor = (*this)(i))
            times(i) = accessor->ClampTime(times(i));
    }
    return true;
}
Beispiel #2
0
bool
GusdUSD_StageProxy::MultiAccessor::_GetPrims(
    const UT_Array<SdfPath>& primPaths,
    UT_Array<UsdPrim>& prims,
    GusdUT_ErrorContext* err)
{
    if(!_Load(primPaths))
        return false;

    prims.setSize(primPaths.size());

    std::atomic_bool workerInterrupt(false);
    UTparallelFor(UT_BlockedRange<size_t>(0, primPaths.size()),
                  _GetPrimsFn(*this, primPaths, prims, err, workerInterrupt));
    return !UTgetInterrupt()->opInterrupt() && !workerInterrupt;
}
Beispiel #3
0
int64 
GusdBoundsCache::Clear(const UT_Set<std::string>& paths)
{
    int64 freed = 0;

    UT_Array<Key> keys;
    for( auto const& entry : m_map ) {
        if( paths.contains( entry.first.path.GetString() ) ) {
            keys.append( entry.first );
        }
    }

    for( auto const& k : keys ) {
        m_map.erase( k );
    }
    return freed;    
}
Beispiel #4
0
bool
GusdUSD_StageProxy::MultiAccessor::Bind(
    const UT_Array<GusdUSD_StageProxyHandle>& proxies,
    const UT_Array<SdfPath>& paths,
    UT_Array<UsdPrim>& prims,
    UsdStage::InitialLoadSet loadSet,
    GusdUT_ErrorContext* err)
{
    Release();

    UT_ASSERT(paths.isEmpty() || paths.size() == proxies.size());

    if(proxies.size() == 0)
        return true;

    /* We have an input arrays of proxies and paths.
       Many of the paths will be associated with the same proxy,
       but they may also point at different proxies.
       
       To avoid having to lock every individual prim, we want to compute
       a mapping of indices from those input arrays into indices in
       an array containing just the unique set of proxies.*/

    UT_Array<GusdUSD_StageProxyHandle> uniqueProxies;
    if(!_ComputeUniqueProxies(uniqueProxies, _indexMap, proxies))
        return false;

    _numAccessors = uniqueProxies.size();
    _accessors = new Accessor[_numAccessors];
    _size = proxies.size();

    /* Now the unique set of proxies is known, so acquire accessors
       (I.e., lock and load stages) */
    std::atomic_bool workerInterrupt(false);
    UTparallelForHeavyItems(UT_BlockedRange<size_t>(0, _numAccessors),
                            _BindAccessorsFn(_accessors, uniqueProxies,
                                             loadSet, err, workerInterrupt));
    if(UTgetInterrupt()->opInterrupt() || workerInterrupt)
        return false;

    /* Any entries referencing proxies that couldn't be bound 
       should have an invalid index; no point in accessing invalid accessors.*/
    for(exint i = 0; i < _indexMap.size(); ++i) {
        int idx = _indexMap(i);
        if(idx >= 0) {
            if(!_accessors[idx])
                _indexMap(i) = -1;
        }
    }

    return _GetPrims(paths, prims, err);
}
void
SOP_PrimGroupCentroid::buildGroupData(UT_String &pattern,
                                      const GU_Detail *input_geo,
                                      UT_Array<GA_Range> &range_array,
                                      UT_StringArray &string_values)
{
    GA_Range                    pr_range;
    const GA_PrimitiveGroup     *group;
    GA_ElementGroupTable::ordered_iterator group_it;

    UT_String                   group_name;
    UT_WorkArgs                 tokens;

    // Tokenize the pattern.
    pattern.tokenize(tokens);

    // Get all the primitive groups.
    const GA_ElementGroupTable &prim_groups = input_geo->primitiveGroups();

    // For each primitive group in order.
    for (group_it=prim_groups.obegin(); !group_it.atEnd(); ++group_it)
    {
        // Get the group.
        group = static_cast<GA_PrimitiveGroup *>(*group_it);

        // Ensure the group is valid.
        if (!group)
            continue;

        // Skip internal groups.
        if (group->getInternal())
            continue;

        // Check to see if this group name matches the pattern.
        group_name = group->getName();
        if (!group_name.matchPattern(tokens))
            continue;

        // Get a range for the primitives in the group.
        pr_range = input_geo->getPrimitiveRange(group);

        // Add the primitive range and the group name to the arrays.
        range_array.append(pr_range);
        string_values.append(group_name);
    }
}
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);
                }
            }
        }
    }
bool
GusdGU_PackedUSD::unpackPrim( 
    GU_Detail&              destgdp,
    UsdGeomImageable        prim, 
    const SdfPath&          primPath,
    const UT_Matrix4D&      xform,
    const GT_RefineParms&   rparms,
    bool                    addPathAttributes ) const
{
    GT_PrimitiveHandle gtPrim = 
        GusdPrimWrapper::defineForRead( 
                    prim,
                    m_frame,
                    m_purposes );

    if( !gtPrim ) {
        const TfToken &type = prim.GetPrim().GetTypeName();
        if( type != "PxHairman" && type != "PxProcArgs" )
            TF_WARN( "Can't convert prim for unpack. %s. Type = %s.", 
                      prim.GetPrim().GetPath().GetText(),
                      type.GetText() );
        return false;
    }
    GusdPrimWrapper* wrapper = UTverify_cast<GusdPrimWrapper*>(gtPrim.get());

    if( !wrapper->unpack( 
            destgdp,
            fileName(),
            primPath,
            xform,
            intrinsicFrame(),
#if SYS_VERSION_FULL_INT < 0x10050000
	    intrinsicViewportLOD(),
#else
	    intrinsicViewportLOD( getPrim() ),
#endif
            m_purposes )) {

        // If the wrapper prim does not do the unpack, do it here.
        UT_Array<GU_Detail *>   details;

        if( prim.GetPrim().IsInMaster() ) {

            gtPrim->setPrimitiveTransform( new GT_Transform( &xform, 1 ) );
        }    


        GA_Size startIndex = destgdp.getNumPrimitives();

        GT_Util::makeGEO(details, gtPrim, &rparms);

        for (exint i = 0; i < details.entries(); ++i)
        {
            copyPrimitiveGroups(*details(i), false);
#if SYS_VERSION_FULL_INT < 0x11000000
            unpackToDetail(destgdp, details(i), true);
#else
            unpackToDetail(destgdp, details(i), &xform);
#endif
            delete details(i);
        }

        if( addPathAttributes ) { 
            // Add usdpath and usdprimpath attributes to unpacked geometry.
            GA_Size endIndex = destgdp.getNumPrimitives();

            const char *path = prim.GetPrim().GetPath().GetString().c_str();

            if( endIndex > startIndex )
            {
                GA_RWHandleS primPathAttr( 
                    destgdp.addStringTuple( GA_ATTRIB_PRIMITIVE, GUSD_PRIMPATH_ATTR, 1 ));
                GA_RWHandleS pathAttr( 
                    destgdp.addStringTuple( GA_ATTRIB_PRIMITIVE, GUSD_PATH_ATTR, 1 ));

                for( GA_Size i = startIndex; i < endIndex; ++i )
                {
                    primPathAttr.set( destgdp.primitiveOffset( i ), 0, path );
                    pathAttr.set( destgdp.primitiveOffset( i ), 0, fileName().c_str() );
                }
            }
        }
    }
    return true;
}
Beispiel #8
0
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();
}
int
SOP_PrimGroupCentroid::buildAttribData(int mode,
                                       const GU_Detail *input_geo,
                                       UT_Array<GA_Range> &range_array,
                                       UT_StringArray &string_values,
                                       UT_IntArray &int_values)
{
    int                         unique_count;
    exint                       int_value;

    GA_Range                    pr_range;

    GA_ROAttributeRef           source_gah;

    UT_String                   attr_name, str_value;

    // Determine the attribute name to use.
    attr_name = (mode == 1) ? "name": "class";

    // Find the attribute.
    source_gah = input_geo->findPrimitiveAttribute(attr_name);

    // If there is no attribute, add an error message and quit.
    if (source_gah.isInvalid())
    {
        addError(SOP_ATTRIBUTE_INVALID, attr_name);
        return 1;
    }

    // If the 'name' attribute isn't a string, add an error and quit.
    if (mode == 1 && !source_gah.isString())
    {
        addError(SOP_ATTRIBUTE_INVALID, "'name' must be a string.");
        return 1;
    }
    // If the 'class' attribute isn't an int, add an error and quit.
    else if (mode == 2 && !source_gah.isInt())
    {
        addError(SOP_ATTRIBUTE_INVALID, "'class' must be an integer.");
        return 1;
    }

    // The number of unique values for the attribute.
    unique_count = input_geo->getUniqueValueCount(source_gah);

    // Add all the ranges and unique values to the appropriate arrays.
    if (mode == 1)
    {
        for (int idx=0; idx<unique_count; ++idx)
        {
            // Get the unique string value.
            str_value = input_geo->getUniqueStringValue(source_gah, idx);
            // Get the primitive range corresponding to that value.
            pr_range = input_geo->getRangeByValue(source_gah, str_value);

            // Add the range to the array.
            range_array.append(pr_range);
            // Add the string value to the string value list.
            string_values.append(str_value);
        }
    }
    else
    {
        for (int idx=0; idx<unique_count; ++idx)
        {
            // Get the unique integer value.
            int_value = input_geo->getUniqueIntegerValue(source_gah, idx);
            // Get the primitive range corresponding to that value.
            pr_range = input_geo->getRangeByValue(source_gah, int_value);

            // Add the range to the array.
            range_array.append(pr_range);
            // Add the integer value to the integer value list.
            int_values.append(int_value);
        }
    }

    // Return 0 for success.
    return 0;
}
Beispiel #10
0
bool
GusdUSD_StageProxy::MultiAccessor::_Load(const UT_Array<SdfPath>& paths)
{
    if(paths.isEmpty())
        return true;

    UT_ASSERT_P(paths.size() == _size);

    typedef tbb::concurrent_unordered_set<
        SdfPath,SdfPath::Hash> ConcurrentPathSet;

    struct _ComputeUnloadedPrimsFn
    {
        _ComputeUnloadedPrimsFn(const UT_Array<SdfPath>& paths,
                                const UT_Array<exint>& indexMap,
                                const UT_Array<_PrimLoader*>& loaders,
                                UT_Array<ConcurrentPathSet*>& pathSets)
            : _paths(paths), _indexMap(indexMap),
              _loaders(loaders), _pathSets(pathSets) {}

        void    operator()(const UT_BlockedRange<size_t>& r) const
                {
                    auto* boss = UTgetInterrupt();
                    char bcnt = 0;

                    for(size_t i = r.begin(); i < r.end(); ++i) {
                        if(BOOST_UNLIKELY(!++bcnt && boss->opInterrupt()))
                            return;
                        
                        exint idx = _indexMap(i);
                        if(idx >= 0) {
                            if(auto* loader = _loaders(idx)) {
                                const SdfPath& path = _paths(i);
                                if(!path.IsEmpty() && !loader->IsLoaded(path))
                                    _pathSets(idx)->insert(path);
                            }
                        }
                    }
                }

    private:
        const UT_Array<SdfPath>&        _paths;
        const UT_Array<exint>&          _indexMap;
        const UT_Array<_PrimLoader*>&   _loaders;
        UT_Array<ConcurrentPathSet*>    _pathSets;
    };

    /* Compute sets of unloaded prims.
       This constitutes the bulk of binding time, so do this parallel.*/
    UT_Array<_PrimLoader*> loaders(_numAccessors, _numAccessors);
    UT_Array<ConcurrentPathSet*> pathSets(_numAccessors, _numAccessors);
    for(exint i = 0; i < _numAccessors; ++i) {
        if ( _accessors[i] ) {
            auto* loader = _accessors[i].GetProxy()->_primLoader;
            if(loader) {
                loaders(i) = loader;
                pathSets(i) = new ConcurrentPathSet;
            }
        }
    }

    UTparallelFor(UT_BlockedRange<size_t>(0, _size),
                  _ComputeUnloadedPrimsFn(paths, _indexMap, loaders, pathSets));

    if(UTgetInterrupt()->opInterrupt())
        return false;

    /* Load the actual prims.
       This could be done in parallel, but is probably not worth it since
       there's only work to perform the first time a prim load is requested.*/
    for(exint i = 0; i < _numAccessors; ++i) {
        if(auto* pathSet = pathSets(i)) {
            SdfPathSet pathsToLoad(pathSet->begin(), pathSet->end());
            _accessors[i]._Load(pathsToLoad);
            
            delete pathSet;
        }
    }

    return true;
}