public UsdTypeBinding(ToVtConverter toVtConverter,
                       ToCsConverter toCsConverter,
                       pxr.SdfValueTypeName sdfName)
 {
     toVtValue   = toVtConverter;
     toCsObject  = toCsConverter;
     sdfTypeName = sdfName;
 }
 public bool GetReverseBinding(pxr.SdfValueTypeName key, out UsdTypeBinding binding)
 {
     // TODO: we could keep a reverse mapping, but waiting for deeper performance analysis first.
     foreach (var kvp in bindings)
     {
         if (kvp.Value.sdfTypeName == key)
         {
             binding = kvp.Value;
             return(true);
         }
     }
     binding = new UsdTypeBinding();
     return(false);
 }
        public void BindNativeType(Type csType, pxr.SdfValueTypeName sdfName)
        {
            string name;

            if (!typeNameMapping.TryGetValue(csType.Name, out name))
            {
                name = csType.Name;
            }
            var converter = typeof(pxr.UsdCs).GetMethod("VtValueTo" + name,
                                                        new Type[] { typeof(pxr.VtValue) });

            if (converter == null)
            {
                throw new ArgumentException(string.Format("No VtValueTo... converter found for type {0}, VtValueTo{1}",
                                                          csType.ToString(), name));
            }
            bindings[csType] = new UsdTypeBinding(DefaultConversions.ToVtValue,
                                                  (x) => converter.Invoke(null, new object[] { x }),
                                                  sdfName);
        }
Пример #4
0
        /// <summary>
        /// Binds the specified C# type to the given USD array and scene description (Sdf) types,
        /// looking for ConverterT.ToVtArray(csType) and ConverterT.FromVtArray(vtArrayType).
        /// </summary>
        ///
        /// <typeparam name="ConverterT">
        /// The C# class type providing type conversion rules ToVtArray and FromVtArray.
        /// </typeparam>
        ///
        /// <param name="csType">The C# type to be mapped to USD</param>
        /// <param name="vtArrayType">The USD C++ value type (Vt)</param>
        /// <param name="sdfName">The USD scene description (Sdf) type</param>
        ///
        /// TODO: The C++ type can be inferred from the Sdf type, so vtArrayType is not needed.
        ///
        public void BindArrayType <ConverterT>(Type csType,
                                               Type vtArrayType,
                                               pxr.SdfValueTypeName sdfName,
                                               string methodNamePrefix = "")
        {
            var csToVtArray = typeof(ConverterT)
                              .GetMethod(methodNamePrefix + "ToVtArray", new Type[] { csType });

            if (csToVtArray == null)
            {
                throw new ArgumentException(string.Format("No ToVtArray overload found for type {0}",
                                                          csType.ToString()));
            }

            var vtToCsArray = typeof(ConverterT)
                              .GetMethod(methodNamePrefix + "FromVtArray", new Type[] { vtArrayType });

            if (vtToCsArray == null)
            {
                throw new ArgumentException(string.Format("No FromVtArray overload found for type {0}",
                                                          vtArrayType.ToString()));
            }

            var valToVtArray = typeof(pxr.UsdCs).GetMethod("VtValueTo" + vtArrayType.Name,
                                                           new Type[] { typeof(pxr.VtValue), vtArrayType });

            if (valToVtArray == null)
            {
                throw new ArgumentException(string.Format("No VtValueTo{...} converter found for type {0}",
                                                          vtArrayType.ToString()));
            }

            var           copyConverter = (ToCsCopyConverter)CodeGen.EmitToCs <ToCsCopyConverter>(valToVtArray, vtToCsArray);
            ToCsConverter toCs          = (vtValue) => ToCsConvertHelper(vtValue, vtArrayType, copyConverter);
            ToVtConverter toVt          =
                (ToVtConverter)CodeGen.EmitToVt <ToVtConverter>(csToVtArray, csType, vtArrayType);

            bindings[csType] = new UsdTypeBinding(toVt, toCs, sdfName);
        }
        /// <summary>
        /// Binds the specified C# type to the given USD array and scene description (Sdf) types,
        /// looking for ConverterT.ToVtArray(csType) and ConverterT.FromVtArray(vtArrayType).
        /// </summary>
        ///
        /// <typeparam name="ConverterT">
        /// The C# class type providing type conversion rules ToVtArray and FromVtArray.
        /// </typeparam>
        ///
        /// <param name="csType">The C# type to be mapped to USD</param>
        /// <param name="vtArrayType">The USD C++ value type (Vt)</param>
        /// <param name="sdfName">The USD scene description (Sdf) type</param>
        ///
        /// TODO: The C++ type can be inferred from the Sdf type, so vtArrayType is not needed.
        ///
        public void BindArrayType <ConverterT>(Type csType,
                                               Type vtArrayType,
                                               pxr.SdfValueTypeName sdfName,
                                               string methodNamePrefix = "")
        {
            // ConverterT and the function being found will be something like:
            //   class IntrinsicTypeConverter {
            //     static public VtTokenArray ToVtArray(string[] input);
            //
            var csToVtArray = typeof(ConverterT)
                              .GetMethod(methodNamePrefix + "ToVtArray", new Type[] { csType });

            if (csToVtArray == null)
            {
                throw new ArgumentException(string.Format("No ToVtArray overload found for type {0}",
                                                          csType.ToString()));
            }

            // ConverterT and the function being found will be something like:
            //   class IntrinsicTypeConverter {
            //     static public string[] FromVtArray(VtTokenArray input);
            //
            var vtToCsArray = typeof(ConverterT)
                              .GetMethod(methodNamePrefix + "FromVtArray", new Type[] { vtArrayType });

            if (vtToCsArray == null)
            {
                throw new ArgumentException(string.Format("No FromVtArray overload found for type {0}",
                                                          vtArrayType.ToString()));
            }

            // The specific UsdCs method being located here will be somthing like:
            //   class UsdCs {
            //     public static void VtValueToVtTokenArray(VtValue value, VtTokenArray output);
            //
            var valToVtArray = typeof(pxr.UsdCs).GetMethod("VtValueTo" + vtArrayType.Name,
                                                           new Type[] { typeof(pxr.VtValue), vtArrayType });

            if (valToVtArray == null)
            {
                throw new ArgumentException(string.Format("No VtValueTo{...} converter found for type {0}",
                                                          vtArrayType.ToString()));
            }

            // The following code constructs functions to:
            //
            //   1) Convert the VtValue (type-erased container) to a specific VtArray<T> type and then
            //      convert the VtArray<T> to a native C# type.
            //
            //   2) Convert a strongly typed C# array to a strongly typed VtArray<T> and then
            //      convert the VtArray<T> to a type-erased VtValue.
            //
            // For example, to will convert:
            //
            //   1) VtValue -> VtArray<TfToken> -> string[]
            //   2) string[] -> VtArray<TfToken> -> VtValue
            //

            ToCsConverter toCs = null;
            ToVtConverter toVt = null;


            if (IsCodeGenEnabled())
            {
                // EmitToCs and EmitToVt are not defined when not using NET_4_6
#if NET_4_6
                var copyConverter = (ToCsCopyConverter)CodeGen.EmitToCs <ToCsCopyConverter>(valToVtArray, vtToCsArray);
                toCs = (vtValue) => ToCsConvertHelper(vtValue, vtArrayType, copyConverter);
                toVt = (ToVtConverter)CodeGen.EmitToVt <ToVtConverter>(csToVtArray, csType, vtArrayType);
#endif
            }
            else
            {
                // In .NET2 or when IL2CPP is enabled , we cannot dynamically emit code.
                // Instead, we use late binding, which is slower, but also doesn't crash.
                // In the future, we should generate code to do these conversions, rather than using late binding.
                toCs = (vtValue) => ToCsDynamicConvertHelper(vtValue, vtArrayType, valToVtArray, vtToCsArray);
                toVt = CsArrayToVtValue(csToVtArray, csType, vtArrayType);
            }

            bindings[csType] = new UsdTypeBinding(toVt, toCs, sdfName);
        }
Пример #6
0
        /// <summary>
        /// Internal helper for serializing data to USD.
        /// </summary>
        /// <param name="attrName">The USD attribute name.</param>
        /// <param name="csType">The C# type.</param>
        /// <param name="csValue">The C# value.</param>
        /// <param name="usdTime">The time at which to sample key frames.</param>
        /// <param name="prim">The USD prim at which to write values.</param>
        /// <param name="imgble">The UsdGeomImagable attrbiute, used when writing PrimVars.</param>
        /// <param name="memberInfo">The field/property providing serialization metadata.</param>
        /// <param name="usdNamespace">The optional USD namespace at which values live.</param>
        /// <param name="srcObject">The source object name, used when remapping names.</param>
        /// <returns>True on success.</returns>
        /// <remarks>
        /// Note that "success" in the return value does not indicate data was written, rather it
        /// indicates that no unexpected states were encountered. E.g. calling WriteAttr on a field
        /// marked as [NotSerialized] does not cause this method to return false, since non-serialized
        /// fields are an expected state this function may encounter.
        /// </remarks>
        bool WriteAttr(string attrName, Type csType, object csValue, pxr.UsdTimeCode usdTime,
                       pxr.UsdPrim prim, pxr.UsdGeomImageable imgble, MemberInfo memberInfo,
                       string usdNamespace, string srcObject = null)
        {
            if (Reflect.IsNonSerialized(memberInfo))
            {
                Console.WriteLine("Non serialized");
                return(true);
            }

            // If serializing a Primvar<T>, extract the held value and save it in csValue, allowing the
            // all downstream logic to act as if it's operating on the held value itself.
            PrimvarBase pvBase = null;

            if (csType.IsGenericType && csType.GetGenericTypeDefinition() == typeof(Primvar <>))
            {
                if (csValue == null)
                {
                    // Object not written, still considered success.
                    return(true);
                }

                pvBase  = (PrimvarBase)csValue;
                csValue = (csValue as ValueAccessor).GetValue();
                if (csValue == null)
                {
                    // Object not written, still considered success.
                    return(true);
                }

                csType = csValue.GetType();
            }

            bool isCustomData       = Reflect.IsCustomData(memberInfo);
            bool isMetaData         = Reflect.IsMetadata(memberInfo);
            bool isPrimvar          = Reflect.IsPrimvar(memberInfo);
            bool isNewPrimvar       = pvBase != null;
            int  primvarElementSize = Reflect.GetPrimvarElementSize(memberInfo);

            string ns = IntrinsicTypeConverter.JoinNamespace(usdNamespace,
                                                             Reflect.GetNamespace(memberInfo));

            // If holding a dictionary, immediately recurse and write keys as attributes.
            if (csValue != null &&
                csType.IsGenericType &&
                csType.GetGenericTypeDefinition() == typeof(Dictionary <,>) &&
                csType.GetGenericArguments()[0] == typeof(string))
            {
                isNewPrimvar = csType.GetGenericArguments()[1].IsGenericType &&
                               csType.GetGenericArguments()[1].GetGenericTypeDefinition() == typeof(Primvar <>);

                // Ensure the immediate dictionary member is always namespaced.
                if (string.IsNullOrEmpty(Reflect.GetNamespace(memberInfo)))
                {
                    usdNamespace = IntrinsicTypeConverter.JoinNamespace(usdNamespace, attrName);
                }

                var dict = csValue as System.Collections.IDictionary;
                foreach (System.Collections.DictionaryEntry kvp in dict)
                {
                    object value = kvp.Value;
                    WriteAttr((string)kvp.Key, value.GetType(), value,
                              usdTime, prim, imgble, memberInfo, usdNamespace, srcObject: attrName);
                }
                return(true);
            }

            pxr.TfToken sdfAttrName = sm_tokenCache[attrName];

            if (csType == typeof(Relationship) && csValue != null)
            {
                string[] targetStrings = ((Relationship)csValue).targetPaths;
                if (targetStrings != null)
                {
                    //
                    // Write Relationship
                    //
                    string[]            arr  = IntrinsicTypeConverter.JoinNamespace(ns, sdfAttrName).Split(':');
                    pxr.StdStringVector elts = new pxr.StdStringVector(arr.Length);
                    foreach (var s in arr)
                    {
                        elts.Add(s);
                    }

                    pxr.UsdRelationship rel = null;
                    lock (m_stageLock) {
                        rel = prim.CreateRelationship(elts, custom: false);
                    }

                    if (!rel.IsValid())
                    {
                        throw new ApplicationException("Failed to create relationship <"
                                                       + prim.GetPath().AppendProperty(
                                                           new pxr.TfToken(
                                                               IntrinsicTypeConverter.JoinNamespace(ns, sdfAttrName))).ToString() + ">");
                    }

                    var targets = new pxr.SdfPathVector();
                    foreach (var path in ((Relationship)csValue).targetPaths)
                    {
                        targets.Add(new pxr.SdfPath(path));
                    }
                    lock (m_stageLock) {
                        rel.SetTargets(targets);
                    }
                }
                return(true);
            }

            //
            // Write Attribute
            //

            // FUTURE: When writing sparse overrides, if the csValue is null exit here and avoid
            // defining the target attribute. However, sparse authoring is not yet supported.

            UsdTypeBinding binding;

            // Extract the value and type from the connectable.
            var conn = csValue as Connectable;

            if (conn != null)
            {
                csType  = conn.GetValueType();
                csValue = conn.GetValue();
            }

            // Get the binding for the value about to be serialized.
            if (!sm_bindings.GetBinding(csType, out binding) && !csType.IsEnum)
            {
                if (csValue == null)
                {
                    return(true);
                }

                if (string.IsNullOrEmpty(ns))
                {
                    return(false);
                }

                var sample = csValue as SampleBase;
                if (sample == null && csValue != null)
                {
                    throw new ArgumentException("Type does not inherit from SampleBase: " + attrName);
                }

                Serialize(csValue, prim, usdTime, usdNamespace: ns);
                return(true);
            }

            // Determine metadata for the attribtue, note that in the case of connections and primvars
            // these will be the attributes on the outter object, e.g. declared on the Connection<T> or
            // Primvar<T>.
            pxr.SdfVariability   variability = Reflect.GetVariability(memberInfo);
            pxr.SdfValueTypeName sdfTypeName = binding.sdfTypeName;
            pxr.UsdTimeCode      time        = variability == pxr.SdfVariability.SdfVariabilityUniform
                                          ? pxr.UsdTimeCode.Default()
                                          : usdTime;

            bool custom = false;

            pxr.UsdAttribute attr;
            if (isCustomData || isMetaData)
            {
                // no-op
                attr = null;
            }
            else if (!isPrimvar && !isNewPrimvar)
            {
                if (string.IsNullOrEmpty(ns))
                {
                    //
                    // Create non-namespaced attribute.
                    //
                    lock (m_stageLock) {
                        attr = prim.CreateAttribute(sdfAttrName, csType.IsEnum ? SdfValueTypeNames.Token : sdfTypeName, custom, variability);
                    }
                }
                else
                {
                    //
                    // Create namespaced attribute.
                    //
                    string[]            arr  = IntrinsicTypeConverter.JoinNamespace(ns, sdfAttrName).Split(':');
                    pxr.StdStringVector elts = new pxr.StdStringVector(arr.Length);
                    foreach (var s in arr)
                    {
                        elts.Add(s);
                    }
                    lock (m_stageLock) {
                        attr = prim.CreateAttribute(elts, sdfTypeName, custom, variability);
                    }
                }
            }
            else
            {
                //
                // Create Primvar attribute.
                //
                lock (m_stageLock) {
                    var fullAttrName = IntrinsicTypeConverter.JoinNamespace(ns, sdfAttrName);
                    var primvar      = imgble.CreatePrimvar(new pxr.TfToken(fullAttrName), sdfTypeName,
                                                            VertexDataAttribute.Interpolation);
                    if (isNewPrimvar)
                    {
                        primvar.SetElementSize(pvBase.elementSize);
                        if (pvBase.indices != null)
                        {
                            var vtIndices = IntrinsicTypeConverter.ToVtArray(pvBase.indices);
                            primvar.SetIndices(vtIndices, time);
                        }
                        primvar.SetInterpolation(pvBase.GetInterpolationToken());
                    }
                    else
                    {
                        primvar.SetElementSize(primvarElementSize);
                    }
                    attr = primvar.GetAttr();
                }
            }

            if (attr != null && conn != null && conn.GetConnectedPath() != null)
            {
                // TODO: Pool temp vector, possibly add a single item overload for SetConnections.
                var paths    = new pxr.SdfPathVector();
                var connPath = conn.GetConnectedPath();
                if (connPath != string.Empty)
                {
                    paths.Add(new pxr.SdfPath(conn.GetConnectedPath()));
                }
                attr.SetConnections(paths);
            }

            // This may happen when a connection is present, but has a null default value.
            // Because the connection is applied just before this point, this is the earliest possible
            // exit point.
            if (csValue == null)
            {
                return(true);
            }

            pxr.VtValue vtValue = binding.toVtValue(csValue);
            lock (m_stageLock) {
                if (isMetaData)
                {
                    prim.SetMetadata(sdfAttrName, vtValue);
                }
                else if (isCustomData)
                {
                    prim.SetCustomDataByKey(sdfAttrName, vtValue);
                }
                else if (Reflect.IsFusedDisplayColor(memberInfo))
                {
                    pxr.UsdCs.SetFusedDisplayColor(prim, vtValue, time);
                }
                else
                {
                    attr.Set(vtValue, time);
                }
            }

            if (!isCustomData && srcObject != null)
            {
                lock (m_stageLock) {
                    attr.SetCustomDataByKey(sm_tokenCache["sourceMember"], srcObject);
                }
            }
            return(true);
        }
Пример #7
0
        /// <summary>
        /// Internal helper for serializing data to USD.
        /// </summary>
        /// <param name="attrName">The USD attribute name.</param>
        /// <param name="csType">The C# type.</param>
        /// <param name="csValue">The C# value.</param>
        /// <param name="usdTime">The time at which to sample key frames.</param>
        /// <param name="prim">The USD prim at which to write values.</param>
        /// <param name="imgble">The UsdGeomImagable attrbiute, used when writing PrimVars.</param>
        /// <param name="memberInfo">The field/property providing serialization metadata.</param>
        /// <param name="usdNamespace">The optional USD namespace at which values live.</param>
        /// <param name="srcObject">The source object name, used when remapping names.</param>
        /// <returns>True on success.</returns>
        /// <remarks>
        /// Note that "success" in the return value does not indicate data was written, rather it
        /// indicates that no unexpected states were encountered. E.g. calling WriteAttr on a field
        /// marked as [NotSerialized] does not cause this method to return false, since non-serialized
        /// fields are an expected state this function may encounter.
        /// </remarks>
        bool WriteAttr(string attrName, Type csType, object csValue, pxr.UsdTimeCode usdTime,
                       pxr.UsdPrim prim, pxr.UsdGeomImageable imgble, MemberInfo memberInfo,
                       string usdNamespace, string srcObject = null)
        {
            if (Reflect.IsNonSerialized(memberInfo))
            {
                return(true);
            }

            // If holding a dictionary, immediately recurse and write keys as attributes.
            if (csType == typeof(Dictionary <string, object>))
            {
                Dictionary <string, object> dict = csValue as Dictionary <string, object>;
                foreach (var kvp in dict)
                {
                    object value = kvp.Value;
                    WriteAttr(kvp.Key, value.GetType(), value,
                              usdTime, prim, imgble, memberInfo, usdNamespace, srcObject: attrName);
                }
                return(true);
            }

            string ns = IntrinsicTypeConverter.JoinNamespace(usdNamespace,
                                                             Reflect.GetNamespace(memberInfo));

            pxr.TfToken sdfAttrName = sm_tokenCache[attrName];

            if (csType == typeof(Relationship) && csValue != null)
            {
                string[] targetStrings = ((Relationship)csValue).targetPaths;
                if (targetStrings != null)
                {
                    //
                    // Write Relationship
                    //
                    string[]            arr  = IntrinsicTypeConverter.JoinNamespace(ns, sdfAttrName).Split(':');
                    pxr.StdStringVector elts = new pxr.StdStringVector(arr.Length);
                    foreach (var s in arr)
                    {
                        elts.Add(s);
                    }

                    pxr.UsdRelationship rel = null;
                    lock (m_stageLock) {
                        rel = prim.CreateRelationship(elts, custom: false);
                    }

                    if (!rel.IsValid())
                    {
                        throw new ApplicationException("Failed to create relationship <"
                                                       + prim.GetPath().AppendProperty(
                                                           new pxr.TfToken(
                                                               IntrinsicTypeConverter.JoinNamespace(ns, sdfAttrName))).ToString() + ">");
                    }

                    var targets = new pxr.SdfPathVector();
                    foreach (var path in ((Relationship)csValue).targetPaths)
                    {
                        targets.Add(new pxr.SdfPath(path));
                    }
                    lock (m_stageLock) {
                        rel.SetTargets(targets);
                    }
                }
                return(true);
            }

            //
            // Write Attribute
            //

            // Object not written, still considered success.
            if (csValue == null)
            {
                return(true);
            }

            bool isCustomData = Reflect.IsCustomData(memberInfo);
            bool isPrimvar    = Reflect.IsPrimvar(memberInfo);

            UsdTypeBinding binding;

            var conn = csValue as Connectable;

            if (conn != null)
            {
                csType  = conn.GetValue().GetType();
                csValue = conn.GetValue();
            }

            if (!sm_bindings.GetBinding(csType, out binding) && !csType.IsEnum)
            {
                if (string.IsNullOrEmpty(ns))
                {
                    return(false);
                }

                Serialize(csValue, prim, usdTime, usdNamespace: ns);
                return(true);
            }

            pxr.SdfVariability   variability = Reflect.GetVariability(memberInfo);
            pxr.SdfValueTypeName sdfTypeName = binding.sdfTypeName;
            pxr.UsdTimeCode      time        = variability == pxr.SdfVariability.SdfVariabilityUniform
                                          ? pxr.UsdTimeCode.Default()
                                          : usdTime;

            bool custom = false;

            pxr.UsdAttribute attr;
            if (isCustomData)
            {
                // no-op
                attr = null;
            }
            else if (!isPrimvar)
            {
                if (string.IsNullOrEmpty(ns))
                {
                    lock (m_stageLock) {
                        attr = prim.CreateAttribute(sdfAttrName, csType.IsEnum ? SdfValueTypeNames.Token : sdfTypeName, custom, variability);
                    }
                }
                else
                {
                    string[]            arr  = IntrinsicTypeConverter.JoinNamespace(ns, sdfAttrName).Split(':');
                    pxr.StdStringVector elts = new pxr.StdStringVector(arr.Length);
                    foreach (var s in arr)
                    {
                        elts.Add(s);
                    }
                    lock (m_stageLock) {
                        attr = prim.CreateAttribute(elts, sdfTypeName, custom, variability);
                    }
                }
            }
            else
            {
                // Primvars do not support additional namespaces.
                lock (m_stageLock) {
                    attr = imgble.CreatePrimvar(sdfAttrName, sdfTypeName,
                                                VertexDataAttribute.Interpolation).GetAttr();
                }
            }

            if (attr != null && conn != null && conn.GetConnectedPath() != null)
            {
                // TODO: Pool temp vector, possibly add a single item overload for SetConnections.
                var paths    = new pxr.SdfPathVector();
                var connPath = conn.GetConnectedPath();
                if (connPath != string.Empty)
                {
                    paths.Add(new pxr.SdfPath(conn.GetConnectedPath()));
                }
                attr.SetConnections(paths);
            }

            pxr.VtValue vtValue = binding.toVtValue(csValue);
            lock (m_stageLock) {
                if (isCustomData)
                {
                    prim.SetCustomDataByKey(sdfAttrName, vtValue);
                }
                else if (Reflect.IsFusedDisplayColor(memberInfo))
                {
                    pxr.UsdCs.SetFusedDisplayColor(prim, vtValue, time);
                }
                else
                {
                    attr.Set(vtValue, time);
                }
            }

            if (!isCustomData && srcObject != null)
            {
                lock (m_stageLock) {
                    attr.SetCustomDataByKey(sm_tokenCache["sourceMember"], srcObject);
                }
            }
            return(true);
        }