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