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