HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
knotData.h
Go to the documentation of this file.
1 //
2 // Copyright 2024 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 
8 #ifndef PXR_BASE_TS_KNOT_DATA_H
9 #define PXR_BASE_TS_KNOT_DATA_H
10 
11 #include "pxr/pxr.h"
12 #include "pxr/base/ts/api.h"
13 #include "pxr/base/ts/types.h"
15 #include "pxr/base/vt/value.h"
16 #include "pxr/base/tf/type.h"
17 
18 #include <memory>
19 #include <cstring>
20 
22 
23 
24 // Ts API objects (Spline, Knot) are non-templated, but they can represent
25 // different value types (double, float, half), and internally we handle those
26 // different value types with templates. Some knot members (like time) are
27 // type-independent, while others (like value) are type-dependent. All knots in
28 // a spline have the same value type.
29 //
30 // Splines can have many knots, and we try to take up as little memory as
31 // possible in storing them. We also try to be as fast as possible in accessing
32 // them, but the combination of non-templated API classes and templated data is
33 // a form of type erasure that requires a compromise: we use virtual methods to
34 // retrieve data.
35 //
36 // We manage knot data with two class hierarchies:
37 //
38 // - The data itself is stored as a plain struct. There are two halves: a
39 // non-templated base struct that contains the type-independent members, and a
40 // templated derived struct that contains the type-dependent members. By
41 // making the data a plain struct, we avoid storing a vtable pointer for every
42 // instance, but in return we have no convenient way to get at the templated
43 // data directly.
44 //
45 // - We access the type-dependent members using a proxy class. There is an
46 // abstract base class that declares a virtual interface, and a templated
47 // derived class that implements it. Proxy objects have a vtable pointer, and
48 // contain a pointer to a templated derived data struct.
49 
50 
51 // XXX TODO
52 // review access patterns - do we need all?:
53 // SplineData -> AsDouble -> direct access
54 // SplineData virtuals
55 // Ts_Get[Typed]SplineData
56 // Knot -> proxy
57 // Knot -> _TypedData -> direct access
58 // TsDispatchToValueTypeTemplate
59 
60 
61 // Non-template base class for knot data.
62 //
64 {
65 public:
66  // Typically used by Create(), but can be invoked directly for clients that
67  // don't care about the value dimension, and instantiate this struct without
68  // subclassing.
69  Ts_KnotData();
70 
71  // Creates an appropriately subtyped instance on the heap.
72  static Ts_KnotData* Create(TfType valueType);
73 
74  // Compares two KnotData structs. Ignores subclasses.
75  bool operator==(const Ts_KnotData &other) const;
76 
77 public:
78  // Helpers that switch on flags.
79 
80  TsTime GetPreTanWidth() const
81  {
82  return preTanWidth;
83  }
84 
85  TsTime GetPostTanWidth() const
86  {
87  return postTanWidth;
88  }
89 
90  void SetPreTanWidth(const TsTime width)
91  {
93  }
94 
95  void SetPostTanWidth(const TsTime width)
96  {
98  }
99 
100 public:
101  // Knot time.
102  TsTime time;
103 
104  // Time width of the pre-tangent. Always non-negative. Ignored for Hermite
105  // knots.
106  TsTime preTanWidth;
107 
108  // Time width of the post-tangent. Always non-negative. Ignored for
109  // Hermite knots.
110  TsTime postTanWidth;
111 
112  // BITFIELDS - note: for enum-typed bitfields, we declare one bit more than
113  // is minimally needed to represent all declared enum values. For example,
114  // TsCurveType has only two values, so it should be representable in one
115  // bit. However, compilers are free to choose the underlying representation
116  // of enums, and some platforms choose signed values, meaning that we
117  // actually need one bit more, so that we can hold the sign bit. We could
118  // declare the enums with unsigned underlying types, but that runs into a
119  // gcc 9.2 bug. We can spare the extra bit; alignment means there is no
120  // difference in struct size.
121 
122  // Interpolation mode for the segment following this knot.
124 
125  // The spline type this knot belongs to, or is intended for.
127 
128  // Whether this knot is dual-valued (value discontinuity at the knot).
129  bool dualValued : 1;
130 };
131 
132 
133 // Data for one knot in a spline.
134 //
135 // Tangents are expressed as width and slope.
136 //
137 template <typename T>
139  public Ts_KnotData
140 {
141 public:
143 
144  bool operator==(const Ts_TypedKnotData<T> &other) const;
145 
146 public:
147  // Helpers that switch on flags.
148  T GetPreValue() const;
149  T GetPreTanSlope() const;
150  T GetPreTanHeight() const;
151  T GetPostTanSlope() const;
152  T GetPostTanHeight() const;
153 
154 public:
155  // Value at this knot.
157 
158  // If dual-valued, the pre-value at this knot.
160 
161  // preTanSlope stores the slope of the pre-tangent, rise over run, value
162  // height divided by time width.
164 
165  // postTanSlope stores the slope of the post-tangent, rise over run, value
166  // height divided by time width.
168 };
169 
170 // For double-typed values, on x86-64, this struct should fit in a cache line.
171 // Exceeding this size may impact performance.
172 static_assert(sizeof(Ts_TypedKnotData<double>) <= 64);
173 
174 
175 // Virtual interface to TypedKnotData.
176 //
177 // VtValue parameters are not type-checked. They are blindly cast. Callers
178 // must verify types.
179 //
181 {
182 public:
183  // Creates an appropriately subtyped instance.
184  static std::unique_ptr<Ts_KnotDataProxy>
185  Create(Ts_KnotData *data, TfType valueType);
186 
187  virtual ~Ts_KnotDataProxy();
188 
189  virtual Ts_KnotData* CloneData() const = 0;
190  virtual void DeleteData() = 0;
191 
192  virtual TfType GetValueType() const = 0;
193  virtual bool IsDataEqualTo(const Ts_KnotData &other) const = 0;
194 
195  virtual void SetValue(VtValue value) = 0;
196  virtual void GetValue(VtValue *valueOut) const = 0;
197  virtual void SetPreValue(VtValue value) = 0;
198  virtual void GetPreValue(VtValue *valueOut) const = 0;
199 
200  virtual void SetPreTanSlope(VtValue slope) = 0;
201  virtual void GetPreTanSlope(VtValue *slopeOut) const = 0;
202  virtual void SetPostTanSlope(VtValue slope) = 0;
203  virtual void GetPostTanSlope(VtValue *slopeOut) const = 0;
204 };
205 
206 
207 // A means of accessing TypedKnotData.
208 //
209 template <typename T>
211  public Ts_KnotDataProxy
212 {
213 public:
215 
216  Ts_KnotData* CloneData() const override;
217  void DeleteData() override;
218 
219  TfType GetValueType() const override;
220  bool IsDataEqualTo(const Ts_KnotData &other) const override;
221 
222  void SetValue(VtValue value) override;
223  void GetValue(VtValue *valueOut) const override;
224  void SetPreValue(VtValue value) override;
225  void GetPreValue(VtValue *valueOut) const override;
226 
227  void SetPreTanSlope(VtValue slope) override;
228  void GetPreTanSlope(VtValue *slopeOut) const override;
229  void SetPostTanSlope(VtValue slope) override;
230  void GetPostTanSlope(VtValue *slopeOut) const override;
231 
232 private:
233  Ts_TypedKnotData<T> *_data;
234 };
235 
236 
237 ////////////////////////////////////////////////////////////////////////////////
238 // TEMPLATE IMPLEMENTATIONS
239 
240 template <typename T>
242  : Ts_KnotData(),
243  value(T()),
244  preValue(T()),
245  preTanSlope(T()),
246  postTanSlope(T())
247 {
248 }
249 
250 #define COMP(member) \
251  if (member != other.member) \
252  { \
253  return false; \
254  }
255 
256 template <typename T>
258  const Ts_TypedKnotData<T> &other) const
259 {
260  COMP(time);
261  COMP(preTanWidth);
262  COMP(postTanWidth);
263  COMP(dualValued);
264  COMP(nextInterp);
265  COMP(curveType);
266 
267  COMP(value);
268  COMP(preValue);
269  COMP(preTanSlope);
270  COMP(postTanSlope);
271 
272  return true;
273 }
274 
275 #undef COMP
276 
277 template <typename T>
279 {
280  return (dualValued ? preValue : value);
281 }
282 
283 template <typename T>
285 {
286  return preTanSlope;
287 }
288 
289 template <typename T>
291 {
292  return -preTanWidth * preTanSlope;
293 }
294 
295 template <typename T>
297 {
298  return postTanSlope;
299 }
300 
301 template <typename T>
303 {
304  return postTanWidth * postTanSlope;
305 }
306 
307 ////////////////////////////////////////////////////////////////////////////////
308 // TypedKnotDataProxy
309 
310 template <typename T>
313  : _data(data)
314 {
315 }
316 
317 template <typename T>
319 {
320  return new Ts_TypedKnotData<T>(*_data);
321 }
322 
323 template <typename T>
325 {
326  delete _data;
327 }
328 
329 template <typename T>
331 {
332  return Ts_GetType<T>();
333 }
334 
335 template <typename T>
337 {
338  // Force-downcast to our value type. Callers must verify types match.
339  const Ts_TypedKnotData<T> *typedOther =
340  static_cast<const Ts_TypedKnotData<T>*>(&other);
341 
342  return *_data == *typedOther;
343 }
344 
345 template <typename T>
347  const VtValue value)
348 {
349  _data->value = value.UncheckedGet<T>();
350 }
351 
352 template <typename T>
354  VtValue* const valueOut) const
355 {
356  *valueOut = VtValue(_data->value);
357 }
358 
359 template <typename T>
361  const VtValue value)
362 {
363  _data->preValue = value.UncheckedGet<T>();
364 }
365 
366 template <typename T>
368  VtValue* const valueOut) const
369 {
370  *valueOut = VtValue(_data->preValue);
371 }
372 
373 template <typename T>
375  const VtValue slope)
376 {
377  _data->preTanSlope = slope.UncheckedGet<T>();
378 }
379 
380 template <typename T>
382  VtValue* const slopeOut) const
383 {
384  *slopeOut = VtValue(_data->GetPreTanSlope());
385 }
386 
387 template <typename T>
389  const VtValue slope)
390 {
391  _data->postTanSlope = slope.UncheckedGet<T>();
392 }
393 
394 template <typename T>
396  VtValue* const slopeOut) const
397 {
398  *slopeOut = VtValue(_data->GetPostTanSlope());
399 }
400 
401 
403 
404 #endif
TsCurveType curveType
Definition: knotData.h:126
void SetValue(VtValue value) override
Definition: knotData.h:346
T const & UncheckedGet() const &
Definition: value.h:1104
TsInterpMode nextInterp
Definition: knotData.h:123
static Ts_KnotData * Create(TfType valueType)
#define COMP(member)
Definition: knotData.h:250
GT_API const UT_StringHolder time
T GetPreValue() const
Definition: knotData.h:278
virtual void SetPreTanSlope(VtValue slope)=0
GLsizei const GLfloat * value
Definition: glcorearb.h:824
bool operator==(const Ts_TypedKnotData< T > &other) const
Definition: knotData.h:257
TsTime preTanWidth
Definition: knotData.h:106
virtual void SetValue(VtValue value)=0
void GetPreTanSlope(VtValue *slopeOut) const override
Definition: knotData.h:381
void GetPostTanSlope(VtValue *slopeOut) const override
Definition: knotData.h:395
void SetPreTanSlope(VtValue slope) override
Definition: knotData.h:374
void SetPostTanWidth(const TsTime width)
Definition: knotData.h:95
void SetPreValue(VtValue value) override
Definition: knotData.h:360
TsTime GetPostTanWidth() const
Definition: knotData.h:85
TsCurveType
Definition: types.h:92
Ts_TypedKnotDataProxy(Ts_TypedKnotData< T > *data)
Definition: knotData.h:311
bool operator==(const Ts_KnotData &other) const
void SetPreTanWidth(const TsTime width)
Definition: knotData.h:90
T GetPostTanSlope() const
Definition: knotData.h:296
virtual bool IsDataEqualTo(const Ts_KnotData &other) const =0
Ts_KnotData * CloneData() const override
Definition: knotData.h:318
virtual TfType GetValueType() const =0
virtual ~Ts_KnotDataProxy()
T GetPostTanHeight() const
Definition: knotData.h:302
TfType GetValueType() const override
Definition: knotData.h:330
virtual void GetValue(VtValue *valueOut) const =0
virtual Ts_KnotData * CloneData() const =0
bool dualValued
Definition: knotData.h:129
static std::unique_ptr< Ts_KnotDataProxy > Create(Ts_KnotData *data, TfType valueType)
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
virtual void SetPostTanSlope(VtValue slope)=0
virtual void GetPreTanSlope(VtValue *slopeOut) const =0
TsTime GetPreTanWidth() const
Definition: knotData.h:80
bool IsDataEqualTo(const Ts_KnotData &other) const override
Definition: knotData.h:336
TsTime time
Definition: knotData.h:102
virtual void GetPreValue(VtValue *valueOut) const =0
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
Definition: type.h:47
GLint GLsizei width
Definition: glcorearb.h:103
void SetPostTanSlope(VtValue slope) override
Definition: knotData.h:388
virtual void SetPreValue(VtValue value)=0
virtual void DeleteData()=0
T GetPreTanHeight() const
Definition: knotData.h:290
void DeleteData() override
Definition: knotData.h:324
T GetPreTanSlope() const
Definition: knotData.h:284
TsTime postTanWidth
Definition: knotData.h:110
virtual void GetPostTanSlope(VtValue *slopeOut) const =0
Definition: value.h:146
TsInterpMode
Definition: types.h:82
Definition: format.h:1821
void GetPreValue(VtValue *valueOut) const override
Definition: knotData.h:367
void GetValue(VtValue *valueOut) const override
Definition: knotData.h:353