HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GA_AttributeRefMap.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: GA_AttributeRefMap.h ( GA Library, C++)
7  *
8  * COMMENTS: A mapping between destination and source attributes for
9  * various operations manipulating multiple attributes.
10  */
11 
12 #ifndef __GA_AttributeRefMap__
13 #define __GA_AttributeRefMap__
14 
15 #include "GA_API.h"
16 #include "GA_Types.h"
17 #include "GA_VertexPool.h"
18 #include "GA_ATIGroupBool.h"
19 #include "GA_Attribute.h"
20 #include "GA_AttributeFilter.h"
21 #include "GA_Handle.h"
22 
23 #include <UT/UT_ArraySet.h>
24 #include <UT/UT_COW.h>
25 #include <UT/UT_NonCopyable.h>
26 #include <UT/UT_SharedPtr.h>
27 #include <UT/UT_VectorTypes.h>
28 
29 #include <SYS/SYS_Types.h>
30 
31 #include <stdarg.h>
32 
34 class GA_AttributeSet;
35 class GA_Detail;
36 class GA_WeightedSum;
37 
38 class ga_AttributeHandleList;
39 class ga_VertexPoolProxy;
40 
41 
42 /// @brief A handle to simplify manipulation of multiple attributes.
43 ///
44 /// The GA_AttributeRefMap class maintains a list of attributes.
45 /// Operations can be done on all attributes at one time. The handle keeps a
46 /// mapping between @b destination and @source (const) attributes. All
47 /// destination attributes need to be in one GA_Detail. All source attributes
48 /// must be from one GA_Detail. Often, the source and destination details are
49 /// the same.
50 ///
51 /// When performing operations on object elements, all attribute classes which
52 /// are uniquely identified by the owner of the object will be operated on.
53 /// For example, when operating on a vertex, it is possible to uniquely
54 /// identify a point object. Thus, when @c addValue() is called with a vertex
55 /// source offset, vertex @b and point attributes on the source detail will be
56 /// processed. When @c addValue() is called with a point source offset, there
57 /// may be multiple vertices which share the point. So, only point attributes
58 /// will be processed.
59 ///
60 /// This can be summarized by:
61 /// - @c addValue() with source point offset: @n
62 /// Process GA_ATTRIB_POINT, GA_ATTRIB_GLOBAL
63 /// - @c addValue() with source vertex offset: @n
64 /// Process GA_ATTRIB_VERTEX, GA_ATTRIB_POINT, GA_ATTRIB_PRIMITIVE and
65 /// GA_ATTRIB_DETAIL
66 /// - @c addValue() with source primitive offset: @n
67 /// Process GA_ATTRIB_PRIMITIVE and GA_ATTRIB_DETAIL
68 /// - @c addValue() with source detail offset: @n
69 /// Process GA_ATTRIB_DETAIL
70 ///
71 /// The same semantics are used for the destination offset. For example, if a
72 /// primitive offset is supplied, destination primitive and global attributes
73 /// will be modified.
74 ///
75 /// By default, operations on "P" are performed as with any other attribute.
76 /// However, it's possible to turn on the homogeneous flag which will ensure
77 /// that operations are done using homogeneous coordinates.
79 {
80 public:
81  /// Default constructor
83  /// Copy constructor
85  /// Construct and bind details
86  GA_AttributeRefMap(GA_Detail &dest, const GA_Detail *src=0);
87  /// Construct a handle from a const detail. This will create a temporary
88  /// detail. All temporary vertices will be allocated from the temporary
89  /// detail (rather than the source).
90  GA_AttributeRefMap(const GA_Detail &src);
91  /// Destructor
93 
95 
96  /// @brief Automatically expand attribute data pages for threading
97  ///
98  /// Normally, threading is allowed only if each thread is guaranteed to
99  /// write to an individual page of data. Not all algorithms are amenable
100  /// to this constraint. Using the ThreadHarden class will force the
101  /// attribute map to harden all write attributes so their data pages can be
102  /// written to by multiple threads across page boundaries. Multiple
103  /// threads are still prohibited from writing to the same offset. In its
104  /// destructor, the class will automatically call the compress method to
105  /// regain memory efficiency.
106  /// For example: @code
107  /// void process(GA_RWAttributeRef &write, GA_ROAttributeRef &read)
108  /// {
109  /// GA_AttributeRefMap::ThreadHarden harden(map);
110  /// // There's no need to harden the read-only attribute, but now that
111  /// // we've hardened the write attribute, our threaded algorithm is able
112  /// // to write data across page boundaries.
113  /// UTparallelFor(range, functor(map));
114  /// }
115  ///
116  /// WARNING: It is *NOT* *SAFE* to do random-access writes to a group
117  /// in parallel, even if it is hardened, unordered, and has its
118  /// cached entries count invalidated, because the access to the
119  /// individual bits isn't atomic.
120  class GA_API ThreadHarden
121  {
122  public:
123  ThreadHarden(const GA_AttributeRefMap &map,
124  GA_Offset start_offset = GA_Offset(0),
125  GA_Offset end_offset = GA_INVALID_OFFSET)
126  : myMap(map)
127  , myStart(start_offset)
128  , myEnd(end_offset)
129  {
130  for (int i = 0; i < myMap.entries(); ++i)
131  {
132  GA_Attribute *attrib = myMap.getDestAttribute(i);
133  attrib->hardenAllPages(myStart, myEnd);
134  if (attrib->getScope() == GA_SCOPE_GROUP)
135  {
136  GA_ATIGroupBool *group = static_cast<GA_ATIGroupBool *>(attrib);
137  // We can't write to ordered groups in parallel, and
138  // it's not clear what the desired result would be,
139  // so make all ordered groups unordered.
140  group->clearOrdered();
141  // Invalidate the cached group entries before writing,
142  // because there's no need to update the value at all
143  // while writing.
144  group->invalidateGroupEntries();
145  }
146  }
147  }
148  ~ThreadHarden()
149  {
150  for (int i = 0, n = myMap.entries(); i < n; ++i)
151  {
152  GA_Attribute *attrib = myMap.getDestAttribute(i);
153  attrib->tryCompressAllPages(myStart, myEnd);
154  attrib->bumpDataId();
155  if (attrib->getScope() == GA_SCOPE_GROUP)
156  {
157  GA_ATIGroupBool *group = static_cast<GA_ATIGroupBool *>(attrib);
158  // Invalidate the cached group entries afterward, just
159  // in case someone called entries() on the group after
160  // constructing this ThreadHarden and before writing
161  // multi-threaded.
162  // NOTE: Maybe we should just disallow that and avoid this.
163  group->invalidateGroupEntries();
164  }
165  }
166  }
167  private:
168  const GA_AttributeRefMap &myMap;
169  GA_Offset myStart;
170  GA_Offset myEnd;
171  };
172 
173 
174  /// A GA_AttributeRefMapCache stores thread-specific information
175  /// that may allow accelerating writes or delaying updates.
176  class GA_API Cache : UT_NonCopyable
177  {
178  public:
179  class GA_API Data : UT_NonCopyable
180  {
181  public:
182  GA_RWBatchHandleS &s_w(GA_Attribute *attrib)
183  {
184  if (!myStrW)
185  {
186  myStrW = UTmakeUnique<GA_RWBatchHandleS>(attrib);
187  }
188  return *myStrW.get();
189  }
190  GA_ROHandleS &s_r(const GA_Attribute *attrib)
191  {
192  if (!myStrR)
193  {
194  myStrR = UTmakeUnique<GA_ROHandleS>(attrib);
195  }
196  return *myStrR.get();
197  }
198  GA_RWBatchHandleDict &dict_w(GA_Attribute *attrib)
199  {
200  if (!myDictW)
201  {
202  myDictW = UTmakeUnique<GA_RWBatchHandleDict>(attrib);
203  }
204  return *myDictW.get();
205  }
206  GA_ROHandleDict &dict_r(const GA_Attribute *attrib)
207  {
208  if (!myDictR)
209  {
210  myDictR = UTmakeUnique<GA_ROHandleDict>(attrib);
211  }
212  return *myDictR.get();
213  }
214  private:
219  };
220 
221  Data *getData(int idx)
222  {
223  return &myData.forcedRef(idx);
224  }
225 
226  private:
227  UT_Array<Data> myData;
228  };
229 
230  void bumpAllDestDataIds()
231  {
232  for (int i = 0, n = entries(); i < n; ++i)
233  {
234  GA_Attribute *attrib = getDestAttribute(i);
235  attrib->bumpDataId();
236  }
237  }
238 
239  /// Bind details. If the @c src detail is @c NULL, the destination will be
240  /// used as the source.
241  void bind(GA_Detail &dest, const GA_Detail &src);
242 
243  /// Unbind details.
244  void unbind();
245 
246  /// Clears the list of attributes.
247  /// NOTE: Just the list is cleared. No attributes are modified, and the
248  /// detail(s) stay bound.
249  void clear();
250 
251  /// Call on a bound instance to replace the source detail as an efficient
252  /// alternative to binding both a new destination and source.
253  ///
254  /// Set @c as_custom_map to true to use the current source attributes as
255  /// the template to look up attributes in the new source detail instead
256  /// of the destination attributes (default).
257  void replaceSource(const GA_Detail &src, bool as_custom_map = false);
258 
259  /// Prepare the handle for use in a separate thread. This is necessary
260  /// to unshare any objects that cannot be safely shared with a handle
261  /// used by another thread.
262  ///
263  /// Typically code will populate a template handle and then allocate a
264  /// handle for each thread using the copy constructor, resulting in all
265  /// handles sharing some objects, like the vertex pool. This method is
266  /// then called to disassociate each thread's handle from that sharing.
267  void initThreadInstance();
268 
269  /// Access to the vertex pool. In most situations you'll want to bind it
270  /// to a GA_WorkVertexBuffer instead of manipulating it directly.
271  GA_VertexPool &getVertexPool();
272  /// @{
273  /// Map from a GA_VertexPoolIndex to a GA_Offset.
274  ///
275  /// It's recommended to use a GA_WorkVertexBuffer instead of calling these
276  /// methods directly.
277  GA_Offset getTempVertex(GA_VertexPoolIndex i) const;
278  GA_Offset getTempPoint(GA_VertexPoolIndex i) const;
279  /// @}
280  /// @{
281  /// Allocate a temporary vertex/point.
282  ///
283  /// It's recommended to use a GA_WorkVertexBuffer instead of calling these
284  /// methods directly.
285  GA_VertexPoolIndex appendTempVertex(GA_Offset pt=GA_INVALID_OFFSET)
286  { return getVertexPool().appendVertex(pt); }
287  GA_VertexPoolIndex appendTempPoint()
288  { return getVertexPool().appendPoint(); }
289  /// @}
290  /// @{
291  /// Free a temporary vertex/point.
292  ///
293  /// It's recommended to use a GA_WorkVertexBuffer instead of calling these
294  /// methods directly.
295  void freeTempVertex(GA_VertexPoolIndex v)
296  { getVertexPool().freeVertex(v); }
297  void freeTempPoint(GA_VertexPoolIndex p)
298  { getVertexPool().freePoint(p); }
299  /// @}
300 
301  /// @{
302  /// Perform attribute lookup. Since it's possible that there are two
303  /// details involved in the handle, this method provides a convenient
304  /// method to look up one attribute given the other.
305  const GA_Attribute *findSourceAttribute(GA_Attribute *dest_atr) const;
306  GA_Attribute *findDestAttribute(const GA_Attribute *src_atr) const;
307  /// @}
308 
309  /// Add an attribute to the handle. The function fails if the attributes
310  /// were not defined on the correct detail.
311  ///
312  /// @param dest The destination attribute must be defined on the dest detail
313  /// @param src The source attribute must be defined on the source detail
314  bool append(GA_Attribute *dest, const GA_Attribute *src);
315 
316  /// Append an attribute from the destination detail
317  bool appendDest(GA_Attribute *dest)
318  {
319  const GA_Attribute *src = findSourceAttribute(dest);
320  return src ? append(dest, src) : false;
321  }
322  /// Append an attribute from the source detail
323  bool appendSource(const GA_Attribute *src)
324  {
325  GA_Attribute *dest = findDestAttribute(src);
326  return dest ? append(dest, src) : false;
327  }
328 
329  /// @{
330  /// Add attributes based on an attribute filter. Returns the number of
331  /// attributes added.
332  int append(const GA_AttributeFilter &filter,
333  const GA_AttributeOwner search_order[],
334  int search_order_size);
335  int append(const GA_AttributeFilter &filter,
336  GA_AttributeOwner owner)
337  { return append(filter, &owner, 1); }
338  /// @}
339 
340  /// @{
341  /// One common scenario we encounter is the use of a temporary detail as
342  /// the destination when evaluating attributes from a constant detail.
343  /// In this scenario the original constant detail acts as the source and
344  /// we populate our reference map by cloning the attributes we want to
345  /// evaluate in the destination detail.
346 
347  /// Clone and append an attribute from the source detail in the destination
348  /// detail.
349  bool cloneAndAppendSource(const GA_Attribute *src);
350 
351  /// Clone and append an attribute from the source detail, based on name, in
352  /// the destination detail.
353  bool cloneAndAppendSource(GA_AttributeOwner owner,
354  GA_AttributeScope scope,
355  const char *name);
356 
357  /// Clone and append attributes based on an attribute filter. Returns the
358  /// number of attributes added.
359  int cloneAndAppendFromSource(const GA_AttributeFilter &filter,
360  const GA_AttributeOwner search_order[],
361  int search_order_size);
362  /// Clone and append attributes based on an attribute filter. Returns the
363  /// number of attributes added.
364  int cloneAndAppendFromSource(const GA_AttributeFilter &filter,
365  GA_AttributeOwner owner)
366  { return cloneAndAppendFromSource(filter, &owner, 1); }
367 
368  /// @}
369 
370  /// Return the number of attributes in the list
371  int entries() const;
372 
373  /// Return the nth destination attribute
374  GA_Attribute *getDestAttribute(int i) const;
375  /// Return the nth source attribute
376  const GA_Attribute *getSourceAttribute(int i) const;
377 
378  /// Add attributes from two different details, mapping attributes by name.
379  /// The attributes may come from different element classes.
380  int append(GA_AttributeSet *dest, GA_AttributeOwner downer,
381  const GA_AttributeSet *src, GA_AttributeOwner sowner);
382  int append(GA_AttributeSet *dest, GA_AttributeOwner downer,
383  const GA_AttributeFilter &dfilter,
384  const GA_AttributeSet *src, GA_AttributeOwner sowner,
385  const GA_AttributeFilter &sfilter);
386 
387  /// Return the number of attributes in the list that are paired with the
388  /// source being P.
389  int entriesWithSourceP() const;
390 
391  /// Homogenize any rational attributes of the target element
392  void homogenize(GA_AttributeOwner dest_owner, GA_Offset dest) const;
393  void homogenize(OffsetMap &dest) const;
394  /// Dehomogenize any rational attributes of the target element
395  void dehomogenize(GA_AttributeOwner dest_owner,GA_Offset dest) const;
396  void dehomogenize(OffsetMap &dest) const;
397 
398  /// Copy operation: @code dest = source @endcode
399  /// This is the generic copy operation
400  void copyValue(GA_AttributeOwner downer, GA_Offset doffset,
401  GA_AttributeOwner sowner, GA_Offset soffset,
402  Cache *cache = 0) const;
403  void copyValue(OffsetMap &dest,
404  GA_AttributeOwner sowner, GA_Offset soffset,
405  Cache *cache = 0) const;
406 
407  /// @{
408  /// Compare value with another elements
409  bool isEqual(GA_AttributeOwner aowner, GA_Offset aoffset,
410  GA_AttributeOwner bowner, GA_Offset boffset) const;
411  bool isEqual(OffsetMap &a,
412  GA_AttributeOwner bowner, GA_Offset boffset) const;
413  bool isAlmostEqual(GA_AttributeOwner aowner, GA_Offset aoffset,
414  GA_AttributeOwner bowner, GA_Offset boffset) const;
415  bool isAlmostEqual(OffsetMap &a,
416  GA_AttributeOwner bowner, GA_Offset boffset) const;
417  /// @}
418  /// @{
419  /// Copy operations: @code dest = position @endcode
420  /// Sets any attributes that read the position attribute to an explicit
421  /// value.
422  void copyExplicitPosition(GA_AttributeOwner downer, GA_Offset dest,
423  const UT_Vector2 &p) const;
424  void copyExplicitPosition(OffsetMap &dest,
425  const UT_Vector2 &p) const;
426  void copyExplicitPosition(GA_AttributeOwner downer, GA_Offset dest,
427  const UT_Vector2D &p) const;
428  void copyExplicitPosition(OffsetMap &dest,
429  const UT_Vector2D &p) const;
430  void copyExplicitPosition(GA_AttributeOwner downer, GA_Offset dest,
431  const UT_Vector3 &p) const;
432  void copyExplicitPosition(OffsetMap &dest,
433  const UT_Vector3 &p) const;
434  void copyExplicitPosition(GA_AttributeOwner downer, GA_Offset dest,
435  const UT_Vector3D &p) const;
436  void copyExplicitPosition(OffsetMap &dest,
437  const UT_Vector3D &p) const;
438  void copyExplicitPosition(GA_AttributeOwner downer, GA_Offset dest,
439  const UT_Vector4 &p) const;
440  void copyExplicitPosition(OffsetMap &dest,
441  const UT_Vector4 &p) const;
442  void copyExplicitPosition(GA_AttributeOwner downer, GA_Offset dest,
443  const UT_Vector4D &p) const;
444  void copyExplicitPosition(OffsetMap &dest,
445  const UT_Vector4D &p) const;
446  /// @}
447 
448  /// Add operation: @code dest += source*scale @endcode
449  /// This is the generic add operation
450  void addValue(GA_AttributeOwner downer, GA_Offset dest,
451  GA_AttributeOwner owner, GA_Offset source_index,
452  fpreal scale=1) const;
453  void addValue(OffsetMap &dest,
454  GA_AttributeOwner owner, GA_Offset source_index,
455  fpreal scale=1) const;
456 
457  /// Sub operation: @code dest -= source @endcode
458  /// This is the generic sub operation
459  void subValue(GA_AttributeOwner downer, GA_Offset dest,
460  GA_AttributeOwner owner, GA_Offset source_index) const;
461  void subValue(OffsetMap &dest,
462  GA_AttributeOwner owner, GA_Offset source_index) const;
463 
464  /// Multiply operation: @code dest *= source @endcode
465  /// This is the generic mul operation
466  void mulValue(GA_AttributeOwner downer, GA_Offset dest,
467  GA_AttributeOwner owner, GA_Offset source_index) const;
468  void mulValue(OffsetMap &dest,
469  GA_AttributeOwner owner, GA_Offset source_index) const;
470 
471  /// Linear interpolation operation: @code dest = s0 + (s1 - s0)*t @endcode
472  /// Generic linear interpolation between two of the same elements
473  void lerpValue(GA_AttributeOwner downer, GA_Offset dest,
475  fpreal t) const;
476  void lerpValue(OffsetMap &dest,
478  fpreal t) const;
479  void lerpHValue(GA_AttributeOwner downer, GA_Offset dest,
481  fpreal t) const;
482  void lerpHValue(OffsetMap &dest,
484  fpreal t) const;
485 
486  /// @{
487  /// Weighted sum operation: @code dest = sum(w[i]*s[i]) @endcode
488  /// @code
489  /// // Compute the average value of the P attribute and store in a
490  /// // global attribute "averageP".
491  /// GA_WeightedSum sum;
492  /// GA_AttributeRefMap map(gdp);
493  /// GA_AttributeRefMap::Handle gah(map);
494  /// int npts;
495  /// map.append( detail.findGlobalAttribute("averageP"),
496  /// detail.findPointAttribute("P") );
497  /// gah.setGlobal(); // Write to global attributes
498  /// gah.startSum(sum);
499  /// for (GA_Iterator it = gdp.getPointRange(); !it.atEnd(); ++it)
500  /// gah.sumPoint(sum, it.getOffset(), 1);
501  /// npts = gdp.getNumPoints();
502  /// gah.finishSum(sum, npts ? 1./npts : 0);
503  /// @endcode
504  void startSum(const GA_WeightedSum &sum, GA_AttributeOwner downer,
505  GA_Offset dest) const;
506  void startSum(const GA_WeightedSum &sum, OffsetMap &dest) const;
507  void startHSum(const GA_WeightedSum &sum, GA_AttributeOwner downer,
508  GA_Offset dest) const { startSum(sum, downer, dest); }
509  void startHSum(const GA_WeightedSum &sum, OffsetMap &dest) const
510  { startSum(sum, dest); }
511  void finishSum(const GA_WeightedSum &sum, GA_AttributeOwner downer,
512  GA_Offset dest, fpreal normalization=1) const;
513  void finishSum(const GA_WeightedSum &sum, OffsetMap &dest,
514  fpreal normalization=1) const;
515  void finishHSum(const GA_WeightedSum &sum, GA_AttributeOwner downer,
516  GA_Offset dest, fpreal normalization=1) const;
517  void finishHSum(const GA_WeightedSum &sum, OffsetMap &dest,
518  fpreal normalization=1) const;
519  /// @}
520 
521  /// Add a value into the weighted sum. This advances the weighted sum with
522  /// the weight given.
523  void addSumValue(GA_WeightedSum &sum,
524  GA_AttributeOwner downer, GA_Offset dest,
525  GA_AttributeOwner owner, GA_Offset source_index,
526  fpreal w) const;
527  void addSumValue(GA_WeightedSum &sum,
528  OffsetMap &dest,
529  GA_AttributeOwner owner, GA_Offset source_index,
530  fpreal w) const;
531  void addHSumValue(GA_WeightedSum &sum,
532  GA_AttributeOwner downer, GA_Offset dest,
533  GA_AttributeOwner owner, GA_Offset source_index,
534  fpreal w) const;
535  void addHSumValue(GA_WeightedSum &sum,
536  OffsetMap &dest,
537  GA_AttributeOwner owner, GA_Offset source_index,
538  fpreal w) const;
539 
540  /// Compute barycentric coordinates for 3 values
541  /// @code result = (1 - u - v)*p0 + u*p1 + v*p2 @endcode
542  void barycentricValue(GA_AttributeOwner downer, GA_Offset dest,
543  GA_AttributeOwner owner,
544  GA_Offset p0, GA_Offset p1, GA_Offset p2,
545  fpreal u, fpreal v) const;
546  void barycentricValue(OffsetMap &dest,
547  GA_AttributeOwner owner,
548  GA_Offset p0, GA_Offset p1, GA_Offset p2,
549  fpreal u, fpreal v) const;
550 
551  void barycentricValue(GA_AttributeOwner downer, GA_Offset dest,
552  GA_AttributeOwner owner,
553  GA_Offset p0, GA_Offset p1,
554  GA_Offset p2, GA_Offset p3,
555  fpreal u, fpreal v, fpreal w) const;
556  void barycentricValue(OffsetMap &dest,
557  GA_AttributeOwner owner,
558  GA_Offset p0, GA_Offset p1,
559  GA_Offset p2, GA_Offset p3,
560  fpreal u, fpreal v, fpreal w) const;
561 
562  /// Compute bilinear interpolation over 4 values of a quadrilateral. The
563  /// math is the same as SYSbilerp(): @code
564  /// (u=0,v=1) u0v1 u1v1 (u=1,v=1)
565  /// +--------+
566  /// | |
567  /// | |
568  /// +--------+
569  /// (u=0,v=0) u0v0 u1v0 (u=1,v=0)
570  /// @endcode
571  void bilinearValue(GA_AttributeOwner downer, GA_Offset dest,
572  GA_AttributeOwner owner,
573  GA_Offset u0v0, GA_Offset u1v0,
574  GA_Offset u0v1, GA_Offset u1v1,
575  fpreal u, fpreal v) const;
576  void bilinearValue(OffsetMap &dest,
577  GA_AttributeOwner owner,
578  GA_Offset u0v0, GA_Offset u1v0,
579  GA_Offset u0v1, GA_Offset u1v1,
580  fpreal u, fpreal v) const;
581 
582  /// Zero an attribute. This is equivalent to a weighted sum of 0 elements.
583  void zeroElement(GA_AttributeOwner downer, GA_Offset dest) const;
584  void zeroElement(OffsetMap &dest) const;
585 
586  /// Multiply operation: @code dest *= scale @endcode
587  void multiply(GA_AttributeOwner downer, GA_Offset dest,
588  fpreal scale) const;
589  void multiply(OffsetMap &dest, fpreal scale) const;
590 
591  /// @{
592  /// Transform attributes. This uses tags on the attribute to determine how
593  /// to perform the transform.
594  /// @param m The transform matrix
595  /// @param im The inverse of @m (i.e. @c m.invert(im) )
596  /// Transforms are independent of the source geometry.
597  void transform(const UT_Matrix4 &m, const UT_Matrix4 &im,
598  GA_AttributeOwner downer, GA_Offset dest) const;
599  void transform(const UT_Matrix4 &m, const UT_Matrix4 &im,
600  OffsetMap &dest) const;
601  void transform(const UT_DMatrix4 &m, const UT_DMatrix4 &im,
602  GA_AttributeOwner downer, GA_Offset dest) const;
603  void transform(const UT_DMatrix4 &m, const UT_DMatrix4 &im,
604  OffsetMap &dest) const;
605  /// @}
606 
607  /// @{
608  /// Standard operations read the source and write to the destination.
609  /// However. These operations operate by reading and writing the
610  /// destination.
611  /// @see copyValue(), addValue(), subValue(), lerpValue()
612  void copyDestValue(GA_AttributeOwner downer, GA_Offset dest,
613  GA_AttributeOwner owner, GA_Offset offset) const;
614  void copyDestValue(OffsetMap &dest,
615  GA_AttributeOwner owner, GA_Offset offset) const;
616 
617  void addDestValue(GA_AttributeOwner downer, GA_Offset dest,
618  GA_AttributeOwner owner, GA_Offset offset) const;
619  void addDestValue(OffsetMap &dest,
620  GA_AttributeOwner owner, GA_Offset offset) const;
621 
622  void subDestValue(GA_AttributeOwner downer, GA_Offset dest,
623  GA_AttributeOwner owner, GA_Offset offset) const;
624  void subDestValue(OffsetMap &dest,
625  GA_AttributeOwner owner, GA_Offset offset) const;
626 
627  void lerpDestValue(GA_AttributeOwner downer, GA_Offset dest,
628  GA_AttributeOwner owner,
629  GA_Offset s0, GA_Offset s1, fpreal t) const;
630  void lerpDestValue(OffsetMap &dest,
631  GA_AttributeOwner owner,
632  GA_Offset s0, GA_Offset s1, fpreal t) const;
633 
634  void addSumDestValue(GA_WeightedSum &sum,
635  GA_AttributeOwner downer, GA_Offset dest,
637  fpreal w) const;
638  void addSumDestValue(GA_WeightedSum &sum,
639  OffsetMap &dest,
641  fpreal w) const;
642  void addHSumDestValue(GA_WeightedSum &sum,
643  GA_AttributeOwner downer, GA_Offset dest,
645  fpreal w) const;
646  void addHSumDestValue(GA_WeightedSum &sum,
647  OffsetMap &dest,
649  fpreal w) const;
650  /// @}
651 
652  /// Debug statement to dump all the attributes to stdout
653  void dump(GA_AttributeOwner downer, GA_Offset dest,
654  const char *msg, ...) const;
655  void dump(OffsetMap &dest,
656  const char *msg, ...) const;
657  void vdump(GA_AttributeOwner downer, GA_Offset dest,
658  const char *msg, va_list args) const;
659  void vdump(OffsetMap &dest,
660  const char *msg, va_list args) const;
661 
662  GA_Detail *getDestDetail() const { return myD; }
663  const GA_Detail *getSourceDetail() const { return myS; }
664 
665  /// A specialized filter that can match multiple attributes
666  /// in a space-separated string, and will accept "Pw" in the
667  /// pattern to refer to the "P" attribute, if there's no "Pw"
668  /// attribute.
670  {
671  public:
672  // Filter based on a pattern string
673  FilterPattern(const char *pattern,
674  bool matchPw=false)
675  : myPattern(pattern)
676  , myMatchPw(matchPw)
677  {}
678  ~FilterPattern() override { }
679  bool match(const GA_Attribute *a) const override
680  {
681  UT_String name(a->getName());
682  if (name.multiMatch(myPattern) != 0)
683  return true;
684  if (myMatchPw &&
685  a->getOwner() == GA_ATTRIB_POINT &&
686  strcmp(a->getName(), "P") == 0)
687  {
688  name = "Pw";
689  return name.multiMatch(myPattern) != 0;
690  }
691  return false;
692  }
693  const char *const myPattern;
694  const bool myMatchPw;
695  };
696 
697  /// Appends all sourceowner source attributes matching matchpattern
698  /// to this attribute map. If the attribute doesn't exist on the
699  /// destination, it will be created based on the source attribute.
700  /// If alreadymappeddest is non-null and the destination attribute
701  /// is in alreadymappeddest, it won't be appended, and all appended
702  /// attributes will be added to alreadymappeddest, to help avoid
703  /// collisions. Ordered groups on the destination will be changed
704  /// to unordered groups before being added. If matchpattern is null,
705  /// no attributes will be matched.
706  void appendAndCreateAllSource(
707  GA_AttributeOwner destowner,
708  GA_AttributeOwner sourceowner,
709  const char *matchpattern,
710  UT_ArraySet<const GA_Attribute *> *alreadymappeddest = nullptr,
711  bool includegroups = true);
712 
713 private:
714 
715  GA_Detail *myD;
716  const GA_Detail *myS;
717 
719  UT_SharedPtr<ga_VertexPoolProxy> myVertexPoolProxy;
720 };
721 
722 #endif
SYS_FORCE_INLINE void bumpDataId()
Definition: GA_Attribute.h:303
Definition of a geometry attribute.
Definition: GA_Attribute.h:196
bool match(const GA_Attribute *a) const override
GLenum src
Definition: glew.h:2410
GLuint const GLchar * name
Definition: glew.h:1814
const Args & args
Definition: printf.h:628
GLuint GLenum GLenum transform
Definition: glew.h:14742
GLenum GLenum GLenum GLenum GLenum scale
Definition: glew.h:13880
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:9477
void startHSum(const GA_WeightedSum &sum, GA_AttributeOwner downer, GA_Offset dest) const
SYS_FORCE_INLINE const HOLDER & get(GA_Offset off, int comp=0) const
Get the string at the given offset.
Definition: GA_Handle.h:825
const GA_Detail * getSourceDetail() const
void clearOrdered()
Clear all order information, including any mixed entries.
Manages allocation/deletion of temporary vertex/points for a detail.
Definition: GA_VertexPool.h:35
Context to keep track of weighted sums.
const GLdouble * m
Definition: glew.h:9124
#define GA_API
Definition: GA_API.h:12
const GLdouble * v
Definition: glew.h:1391
FilterPattern(const char *pattern, bool matchPw=false)
GA_Size GA_VertexPoolIndex
Definition: GA_VertexPool.h:20
4D Vector class.
Definition: UT_Vector4.h:166
const UT_StringHolder & getName() const
Definition: GA_Attribute.h:280
virtual void tryCompressAllPages(GA_Offset start_offset=GA_Offset(0), GA_Offset end_offset=GA_INVALID_OFFSET)=0
#define GA_INVALID_OFFSET
Definition: GA_Types.h:676
std::unique_ptr< T, Deleter > UT_UniquePtr
A smart pointer for unique ownership of dynamically allocated objects.
Definition: UT_UniquePtr.h:33
GA_Size GA_Offset
Definition: GA_Types.h:639
GA_AttributeScope
Definition: GA_Types.h:141
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glew.h:2981
void startHSum(const GA_WeightedSum &sum, OffsetMap &dest) const
std::shared_ptr< T > UT_SharedPtr
Wrapper around std::shared_ptr.
Definition: UT_SharedPtr.h:28
GLubyte GLubyte GLubyte GLubyte w
Definition: glew.h:1890
GLsizei n
Definition: glew.h:4040
A handle to simplify manipulation of multiple attributes.
GA_AttributeScope getScope() const
Definition: GA_Attribute.h:210
GA_AttributeOwner getOwner() const
GA_AttributeRefMapOffsetMap OffsetMap
GLfloat GLfloat p
Definition: glew.h:16321
GA_AttributeOwner
Definition: GA_Types.h:33
fpreal64 fpreal
Definition: SYS_Types.h:277
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
Definition: glew.h:12681
Container class for all geometry.
Definition: GA_Detail.h:95
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s0
Definition: glew.h:12681
GLubyte * pattern
Definition: glew.h:5711
GA_Detail * getDestDetail() const
SYS_FORCE_INLINE HOLDER get(GA_Offset off, int comp=0) const
Get the string at the given offset.
Definition: GA_Handle.h:1004
virtual void hardenAllPages(GA_Offset start_offset=GA_Offset(0), GA_Offset end_offset=GA_INVALID_OFFSET)=0
GLdouble GLdouble t
Definition: glew.h:1398
void invalidateGroupEntries()
GLboolean GLuint group
Definition: glew.h:2745
GLintptr offset
Definition: glew.h:1682