HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sparseValueWriter.h
Go to the documentation of this file.
1 //
2 // Copyright 2018 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_USD_USD_UTILS_SPARSE_VALUE_WRITER_H
8 #define PXR_USD_USD_UTILS_SPARSE_VALUE_WRITER_H
9 
10 /// \file usdUtils/sparseValueWriter.h
11 ///
12 /// A collection of utilities for authoring time-varying attribute values with
13 /// basic run-length encoding.
14 
15 #include "pxr/pxr.h"
16 
17 #include "pxr/base/vt/value.h"
18 
19 #include "pxr/usd/usdUtils/api.h"
20 #include "pxr/usd/usd/attribute.h"
21 #include "pxr/usd/usd/timeCode.h"
22 
24 
25 /// \class UsdUtilsSparseAttrValueWriter
26 ///
27 /// A utility class for authoring time-varying attribute values with
28 /// simple run-length encoding, by skipping any redundant time-samples.
29 /// Time-samples that are close enough to each other, with relative difference
30 /// smaller than a fixed epsilon value are considered to be equivalent. This is
31 /// to avoid unnecessary authoring of time-samples caused by numerical fuzz in
32 /// certain computations.
33 ///
34 /// For vectors, matrices, and other composite types (like quaternions and
35 /// arrays), each component is compared with the corresponding component for
36 /// closeness. The chosen epsilon value for double precision floating point
37 /// numbers is 1e-12. For single-precision, it is 1e-6 and for half-precision,
38 /// it is 1e-2.
39 ///
40 /// Example c++ usage:
41 /// \code
42 /// UsdGeomSphere sphere = UsdGeomSphere::Define(stage, SdfPath("/Sphere"));
43 /// UsdAttribute radius = sphere.CreateRadiusAttr();
44 /// UsdUtilsSparseAttrValueWriter attrValueWriter(radius,
45 /// /*defaultValue*/ VtValue(1.0));
46 /// attrValueWriter.SetTimeSample(VtValue(10.0), UsdTimeCode(1.0));
47 /// attrValueWriter.SetTimeSample(VtValue(10.0), UsdTimeCode(2.0));
48 /// attrValueWriter.SetTimeSample(VtValue(10.0), UsdTimeCode(3.0));
49 /// attrValueWriter.SetTimeSample(VtValue(20.0), UsdTimeCode(4.0));
50 /// \endcode
51 ///
52 /// Equivalent python example:
53 /// \code
54 /// sphere = UsdGeom.Sphere.Define(stage, Sdf.Path("/Sphere"))
55 /// radius = sphere.CreateRadiusAttr()
56 /// attrValueWriter = UsdUtils.SparseAttrValueWriter(radius, defaultValue=1.0)
57 /// attrValueWriter.SetTimeSample(10.0, 1.0)
58 /// attrValueWriter.SetTimeSample(10.0, 2.0)
59 /// attrValueWriter.SetTimeSample(10.0, 3.0)
60 /// attrValueWriter.SetTimeSample(20.0, 4.0)
61 /// \endcode
62 ///
63 /// In the above examples, the specified default value of radius (1.0) will not
64 /// be authored into scene description since it matches the fallback value.
65 /// Additionally, the time-sample authored at time=2.0 will be skipped since
66 /// it is redundant. Also note that for correct behavior, the calls to
67 /// SetTimeSample() must be made with sequentially increasing time
68 /// values. If not, a coding error is issued and the authored animation may be
69 /// incorrect.
70 ///
72 public:
73  /// The constructor initializes the data required for run-length encoding of
74  /// time-samples. It also sets the default value of \p attr to
75  /// \p defaultValue, if \p defaultValue is non-empty and different from the
76  /// existing default value of \p attr.
77  ///
78  /// \p defaultValue can be unspecified (or left empty) if you don't
79  /// care about authoring a default value. In this case, the sparse authoring
80  /// logic is initialized with the existing authored default value or
81  /// the fallback value, if \p attr has one.
84  const VtValue &defaultValue=VtValue());
85 
86  /// The constructor initializes the data required for run-length encoding of
87  /// time-samples. It also sets the default value of \p attr to
88  /// \p defaultValue, if \p defaultValue is non-empty and different from
89  /// the existing default value of \p attr.
90  ///
91  /// It \p defaultValue is null or points to an empty VtValue, the sparse
92  /// authoring logic is initialized with the existing authored default value
93  /// or the fallback value, if \p attr has one.
94  ///
95  /// For efficiency, this function swaps out the given \p defaultValue,
96  /// leaving it empty.
98  UsdUtilsSparseAttrValueWriter(const UsdAttribute &attr, VtValue *defaultValue);
99 
100  /// Sets a new time-sample on the attribute with given \p value at the
101  /// given \p time. The time-sample is only authored if it's different
102  /// from the previously set time-sample, in which case the previous
103  /// time-sample is also authored, in order to to end the previous run
104  /// of contiguous identical values and start a new run.
105  ///
106  /// This incurs a copy of \p value. Also, the value will be held in
107  /// memory at least until the next time-sample is written or until the
108  /// SparseAttrValueWriter instance is destroyed.
110  bool SetTimeSample(const VtValue &value, const UsdTimeCode time);
111 
112  /// \overload
113  ///
114  /// For efficiency, this function swaps out the given \p value, leaving
115  /// it empty. The value will be held in memory at least until the next
116  /// time-sample is written or until the SparseAttrValueWriter instance is
117  /// destroyed.
119  bool SetTimeSample(VtValue *value, const UsdTimeCode time);
120 
121  /// Returns the attribute that's held in the sparse value writer.
122  const UsdAttribute & GetAttr() const {
123  return _attr;
124  }
125 
126 private:
127  // Helper method to initialize the sparse authoring scheme.
128  void _InitializeSparseAuthoring(VtValue *defaultValue);
129 
130  // The attribute whose time-samples will be authored via public API.
131  const UsdAttribute _attr;
132 
133  // The time at which previous time-sample was authored.
134  UsdTimeCode _prevTime = UsdTimeCode::Default();
135 
136  // The value at previously authored time-sample.
137  VtValue _prevValue;
138 
139  // Whether a time-sample was written at _prevTime (with value=_prevValue).
140  bool _didWritePrevValue=true;
141 };
142 
143 /// \class UsdUtilsSparseValueWriter
144 ///
145 /// Utility class that manages sparse authoring of a set of UsdAttributes.
146 /// It does this by maintaining a map of UsdAttributes to their corresponding
147 /// UsdUtilsSparseAttrValueWriter objects.
148 ///
149 /// To use this class, simply instantiate an instance of it and invoke
150 /// the SetAttribute() method with various attributes and their associated
151 /// time-samples.
152 ///
153 /// \note If the attribute has a default value, SetAttribute() must be
154 /// called with time=Default first (multiple times, if necessary), followed by
155 /// calls to author time-samples in sequentially increasing time order.
156 ///
157 /// \note This class is not threadsafe.
158 /// In general, authoring to a single USD layer from multiple threads isn't
159 /// threadsafe. Hence, there is little value in making this class threadsafe.
160 ///
161 ///
162 /// Example c++ usage:
163 /// \code
164 /// UsdGeomCylinder cylinder = UsdGeomCylinder::Define(stage, SdfPath("/Cylinder"));
165 /// UsdAttribute radius = cylinder.CreateRadiusAttr();
166 /// UsdAttribute height = cylinder.CreateHeightAttr();
167 /// UsdUtilsSparseValueWriter valueWriter;
168 /// valueWriter.SetAttribute(radius, 2.0, UsdTimeCode::Default());
169 /// valueWriter.SetAttribute(height, 2.0, UsdTimeCode::Default());
170 ///
171 /// valueWriter.SetAttribute(radius, 10.0, UsdTimeCode(1.0));
172 /// valueWriter.SetAttribute(radius, 20.0, UsdTimeCode(2.0));
173 /// valueWriter.SetAttribute(radius, 20.0, UsdTimeCode(3.0));
174 /// valueWriter.SetAttribute(radius, 20.0, UsdTimeCode(4.0));
175 ///
176 /// valueWriter.SetAttribute(height, 2.0, UsdTimeCode(1.0));
177 /// valueWriter.SetAttribute(height, 2.0, UsdTimeCode(2.0));
178 /// valueWriter.SetAttribute(height, 3.0, UsdTimeCode(3.0));
179 /// valueWriter.SetAttribute(height, 3.0, UsdTimeCode(4.0));
180 /// \endcode
181 ///
182 /// Equivalent python code:
183 /// \code{.py}
184 /// cylinder = UsdGeom.Cylinder.Define(stage, Sdf.Path("/Cylinder"))
185 /// radius = cylinder.CreateRadiusAttr()
186 /// height = cylinder.CreateHeightAttr()
187 /// valueWriter = UsdUtils.SparseValueWriter()
188 /// valueWriter.SetAttribute(radius, 2.0, Usd.TimeCode.Default())
189 /// valueWriter.SetAttribute(height, 2.0, Usd.TimeCode.Default())
190 ///
191 /// valueWriter.SetAttribute(radius, 10.0, 1.0)
192 /// valueWriter.SetAttribute(radius, 20.0, 2.0)
193 /// valueWriter.SetAttribute(radius, 20.0, 3.0)
194 /// valueWriter.SetAttribute(radius, 20.0, 4.0)
195 ///
196 /// valueWriter.SetAttribute(height, 2.0, 1.0)
197 /// valueWriter.SetAttribute(height, 2.0, 2.0)
198 /// valueWriter.SetAttribute(height, 3.0, 3.0)
199 /// valueWriter.SetAttribute(height, 3.0, 4.0)
200 /// \endcode
201 ///
202 /// In the above example,
203 /// <ul><li>The default value of the "height" attribute is not authored into scene
204 /// description since it matches the fallback value.</li>
205 /// <li>Time-samples at time=3.0 and time=4.0 will be skipped for the radius
206 /// attribute.</li>
207 /// <li>For the "height" attribute, the first timesample at time=1.0 will be
208 /// skipped since it matches the default value.</li>
209 /// <li>The last time-sample at time=4.0 will also be skipped for "height"
210 /// since it matches the previously written value at time=3.0.</li>
211 /// </ul>
213 public:
214  /// Sets the value of \p attr to \p value at time \p time. The value
215  /// is written sparsely, i.e., the default value is authored only if
216  /// it is different from the fallback value or the existing default value,
217  /// and any redundant time-samples are skipped when the attribute value does
218  /// not change significantly between consecutive time-samples.
220  bool SetAttribute(const UsdAttribute &attr,
221  const VtValue &value,
223 
224  /// \overload
225  /// For efficiency, this function swaps out the given \p value, leaving
226  /// it empty. The value will be held in memory at least until the next
227  /// time-sample is written or until the SparseAttrValueWriter instance is
228  /// destroyed.
230  bool SetAttribute(const UsdAttribute &attr,
231  VtValue *value,
233 
234  /// \overload
235  template<typename T>
236  bool SetAttribute(const UsdAttribute &attr,
237  T &value,
239  {
240  VtValue val = VtValue::Take(value);
241  return SetAttribute(attr, &val, time);
242  }
243 
244  /// Clears the internal map, thereby releasing all the memory used by
245  /// the sparse value-writers.
247  void Clear() {
248  _attrValueWriterMap.clear();
249  }
250 
251  /// Returns a new vector of UsdUtilsSparseAttrValueWriter populated
252  /// from the attrValueWriter map.
254  std::vector<UsdUtilsSparseAttrValueWriter>
256 
257 private:
258  // Templated helper method used by the two public SetAttribute() methods.
259  template <typename T>
260  bool _SetAttributeImpl(const UsdAttribute &attr,
261  T &value,
262  const UsdTimeCode time);
263 
264  struct _AttrHash {
265  inline size_t operator() (const UsdAttribute &attr) const {
266  return hash_value(attr);
267  }
268  };
269 
270  using _AttrValueWriterMap = std::unordered_map<UsdAttribute,
272  _AttrHash>;
273  _AttrValueWriterMap _attrValueWriterMap;
274 };
275 
277 
278 #endif
static constexpr UsdTimeCode Default()
Definition: timeCode.h:113
const UsdAttribute & GetAttr() const
Returns the attribute that's held in the sparse value writer.
static VtValue Take(T &obj)
Definition: value.h:886
GT_API const UT_StringHolder time
GLsizei const GLfloat * value
Definition: glcorearb.h:824
USDUTILS_API UsdUtilsSparseAttrValueWriter(const UsdAttribute &attr, const VtValue &defaultValue=VtValue())
USDUTILS_API bool SetTimeSample(const VtValue &value, const UsdTimeCode time)
USDUTILS_API bool SetAttribute(const UsdAttribute &attr, const VtValue &value, const UsdTimeCode time=UsdTimeCode::Default())
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
GLuint GLfloat * val
Definition: glcorearb.h:1608
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
USDUTILS_API void Clear()
USDUTILS_API std::vector< UsdUtilsSparseAttrValueWriter > GetSparseAttrValueWriters() const
#define USDUTILS_API
Definition: api.h:23
size_t hash_value(const CH_ChannelRef &ref)
bool SetAttribute(const UsdAttribute &attr, T &value, const UsdTimeCode time=UsdTimeCode::Default())
Definition: value.h:146