HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GEO_ParallelWiringUtil.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: GEO_ParallelWiringUtil.h (GEO Library, C++)
7  *
8  * COMMENTS: Parallel functors for wiring points to vertices are here.
9  * It's not *completely* impossible to follow, but it gets
10  * rather messy. See GEO_Face::buildBlock or
11  * GEO_PrimPolySoup::build for usage examples.
12  */
13 
14 #ifndef __GEO_ParallelWiringUtil__
15 #define __GEO_ParallelWiringUtil__
16 
17 #include "GEO_SurfaceType.h"
18 
19 #include <GA/GA_ATITopology.h>
20 #include <GA/GA_Edge.h>
21 #include <GA/GA_Iterator.h>
22 #include <GA/GA_OffsetList.h>
23 #include <GA/GA_SplittableRange.h>
24 #include <GA/GA_Types.h>
25 
26 #if UT_ASSERT_LEVEL >= UT_ASSERT_LEVEL_PARANOID
27 #include <GA/GA_Detail.h>
28 #endif
29 
30 #include <UT/UT_Array.h>
31 #include <UT/UT_IntArray.h>
32 #include <UT/UT_Interrupt.h>
33 #include <UT/UT_Lock.h>
34 #include <UT/UT_ParallelUtil.h>
35 
36 namespace {
37 
38 /// This class sets the vertex-to-point topology attribute (the easy one)
39 /// in parallel.
40 template<typename INT_T>
41 class geo_SetTopoMappedParallel
42 {
43 public:
44  geo_SetTopoMappedParallel(GA_ATITopology *topology, const GA_Offset startto,
45  const GA_Offset startfrom, const INT_T *map)
46  : myTopology(topology)
47  , myStartTo(startto)
48  , myStartFrom(startfrom)
49  , myMap(map)
50  {}
51 
52  template<typename DEST_T>
53  void typedImpl(const GA_SplittableRange &r) const
54  {
55  GA_PageArray<DEST_T, 1> &topology = myTopology->getData().castType<DEST_T>();
56  if (myMap)
57  {
59  GA_Offset end;
60  for (GA_Iterator it(r); it.blockAdvance(start, end); )
61  {
62  for (GA_Offset off = start; off < end; ++off)
63  {
64  GA_Offset to = myMap[off - myStartFrom] + myStartTo;
65  UT_ASSERT_P(GAisValid(to) && to < myTopology->getDetail().getIndexMap(myTopology->getLinkOwner()).offsetSize());
66  topology.set(off, DEST_T(to));
67  }
68  }
69  }
70  else
71  {
72  // If myMap is NULL, the points are contiguous starting from
73  // myStartPt, e.g. for independent curves.
75  GA_Offset end;
76  for (GA_Iterator it(r); it.blockAdvance(start, end); )
77  {
78  for (GA_Offset off = start, to = (start - myStartFrom) + myStartTo; off < end; ++off, ++to)
79  {
80  UT_ASSERT_P(GAisValid(to) && to < myTopology->getDetail().getIndexMap(myTopology->getLinkOwner()).offsetSize());
81  topology.set(off, DEST_T(to));
82  }
83  }
84  }
85  }
86 
87  void operator()(const GA_SplittableRange &r) const
88  {
89  // For added performance, we check the type once outside the loops,
90  // instead of having setLink (really UT_PageArray::set) check it
91  // every time in the innermost loop.
92  if (myTopology->getStorage() == GA_STORE_INT16)
93  typedImpl<int16>(r);
94  else if (myTopology->getStorage() == GA_STORE_INT32)
95  typedImpl<int32>(r);
96  else
97  {
98  UT_ASSERT(myTopology->getStorage() == GA_STORE_INT64);
99  typedImpl<int64>(r);
100  }
101  }
102 
103 private:
104  GA_ATITopology *const myTopology;
105  const GA_Offset myStartTo;
106  const GA_Offset myStartFrom;
107  const INT_T *const myMap;
108 };
109 
110 /// This class sets the point-to-vertex topology attribute with a reverse
111 /// mapping in parallel.
112 /// NOTE: The relevant pages of the topology attribute
113 /// must already be hardened.
114 /// NOTE: This functor requires that there be
115 /// no two vertices that map to the same point, else the results
116 /// will be nondeterministic.
117 /// NOTE: The range used must be a range over vertices, not points!
118 template<typename INT_T>
119 class geo_SetTopoRevMappedParallel
120 {
121 public:
122  geo_SetTopoRevMappedParallel(GA_ATITopology *pt_to_vtx_topo, const GA_Offset startpt,
123  const GA_Offset startvtx, const INT_T *vtx_to_pt_map)
124  // Relevant pages are required to be hardened already, so this can have PAGESHARDENED=true.
125  : myPtToVtxTopology((GA_PageArray<void,1,true,true>&)(pt_to_vtx_topo->getData()))
126  , myStartPt(startpt)
127  , myStartVtx(startvtx)
128  , myVtxToPtMap(vtx_to_pt_map)
129  {
130  UT_ASSERT(myVtxToPtMap);
131  UT_ASSERT(pt_to_vtx_topo->getOwner() == GA_ATTRIB_POINT);
132  UT_ASSERT(pt_to_vtx_topo->getLinkOwner() == GA_ATTRIB_VERTEX);
133  }
134 
135  void operator()(const GA_SplittableRange &r) const
136  {
138  GA_Offset end;
139  for (GA_Iterator it(r); it.blockAdvance(start, end); )
140  {
141  for (GA_Offset off = start; off < end; ++off)
142  {
143  GA_Offset pt = myVtxToPtMap[off - myStartVtx] + myStartPt;
144  UT_ASSERT_P(GAisValid(pt) && pt < myPtToVtxTopology.size());
145  myPtToVtxTopology.set(pt, int64(off));
146  }
147  }
148  }
149 
150 private:
151  // Relevant pages are required to be hardened already, so this can have PAGESHARDENED=true.
152  GA_PageArray<void,1,true,true> &myPtToVtxTopology;
153  const GA_Offset myStartPt;
154  const GA_Offset myStartVtx;
155  const INT_T *const myVtxToPtMap;
156 };
157 
158 /// This class, in parallel, initializes an array to 0, 1, 2, 3,...
159 /// It may not sound related, but the next step is to sort it by the
160 /// point offset of the vertex whose offset is in another array at this
161 /// array element's position. See below.
162 template<typename INT_T>
163 class geo_TrivialArrayParallel
164 {
165 public:
166  geo_TrivialArrayParallel(UT_Array<INT_T> &array) : myArray(array.getArray()) {}
167  geo_TrivialArrayParallel(INT_T *array) : myArray(array) {}
168 
169  void operator()(const UT_BlockedRange<GA_Size> &r) const
170  {
171  for (GA_Size i = r.begin(); i < r.end(); ++i)
172  myArray[i] = i;
173  }
174 
175 private:
176  INT_T *const myArray;
177 };
178 
179 /// This class is a comparator for use with UTparallelSort, to sort
180 /// an array comprising indices into myArray based on the values in myArray.
181 /// This is used to create the mapping that would sort vertices by the points
182 /// to which they refer.
183 template <typename INT_T,bool force_stable=true>
184 class geo_VerticesByPointCompare
185 {
186 public:
187  geo_VerticesByPointCompare(const INT_T *array) : myArray(array) {}
188 
189  bool operator()(const INT_T &a, const INT_T &b) const
190  {
191  // NOTE: For platform consistency, we must force the sort to be stable.
192  // tbb::parallel_sort is normally unstable and thus so is
193  // UTparallelSort.
194  // a and b are the original positions in the array being sorted,
195  // so we can do this by enforcing that a < b when the values are equal.
196  if (force_stable)
197  return (myArray[a] < myArray[b])
198  || ((myArray[a] == myArray[b]) && (a < b));
199  else
200  return (myArray[a] < myArray[b]);
201  }
202 private:
203  const INT_T *const myArray;
204 };
205 
206 
207 /// This class creates arrays for the next vertex and prev vertex in parallel.
208 /// If we wanted to do this in geo_LinkToposParallel, we would first have to
209 /// create an inverse map anyway to find out where vertices are in map, so
210 /// this saves re-traversing things.
211 template<typename INT_T>
212 class geo_NextPrevParallel
213 {
214 public:
215  geo_NextPrevParallel(
216  const INT_T *order,
217  const exint order_size,
218  const INT_T *pointnumbers,
219  INT_T *nextarray,
220  INT_T *prevarray,
221  const GA_Offset startvtx,
222  const GA_Offset startpt,
223  const GA_ATITopology *pt2vtx,
224  GA_ATITopology *prevvtx,
225  UT_Lock &lock)
226  : myOrder(order)
227  , myOrderSize(order_size)
228  , myPointNumbers(pointnumbers)
229  , myNextArray(nextarray)
230  , myPrevArray(prevarray)
231  , myStartVtx(startvtx)
232  , myStartPt(startpt)
233  , myPt2Vtx(pt2vtx)
234  , myPrevVtx(prevvtx)
235  , myUpdateExistingLock(lock)
236  {}
237 
238  void operator()(const UT_BlockedRange<GA_Size> &r) const
239  {
240  // NOTE: Even though GA_Edge is supposed to be for point offset pairs,
241  // these are vertex offset pairs.
242  UT_Array<GA_Edge> prevlinks;
243 
244  GA_Size i = r.begin();
245  INT_T vtx = myOrder[i];
246  INT_T pt = myPointNumbers[vtx];
247  // NOTE: Use INT_MIN instead of -1, because myNextArray needs to be able
248  // to refer to existing vertices, which would have negative
249  // relative offsets.
250  INT_T prev = (i-1 >= 0 && myPointNumbers[myOrder[i - 1]] == pt) ? myOrder[i - 1] : std::numeric_limits<INT_T>::min();
251  for (; i < r.end(); ++i)
252  {
253  myPrevArray[vtx] = prev;
254 
255  INT_T next = (i+1 < myOrderSize && myPointNumbers[myOrder[i + 1]] == pt) ? myOrder[i + 1] : std::numeric_limits<INT_T>::min();
256  if (next >= 0)
257  {
258  myNextArray[vtx] = next;
259  prev = vtx;
260  vtx = next;
261  }
262  else
263  {
264  GA_Offset existingvtx = myPt2Vtx->getLink(pt + myStartPt);
265  // If not sharing points with existing geometry, things are easy
266  if (!GAisValid(existingvtx))
267  {
268  myNextArray[vtx] = std::numeric_limits<INT_T>::min();
269  }
270  // Otherwise, we need to update the existing vertex's prev link
271  // very carefully.
272  else
273  {
274  myNextArray[vtx] = existingvtx - myStartVtx;
275  prevlinks.append(GA_Edge(existingvtx, vtx + myStartVtx));
276  }
277  if (i+1 < myOrderSize)
278  {
280  vtx = myOrder[i + 1];
281  pt = myPointNumbers[vtx];
282  }
283  }
284  }
285 
286  // Add any prev links from existing geometry to the new geometry
287  if (prevlinks.entries())
288  {
289  UT_AutoLock lock(myUpdateExistingLock);
290  for (GA_Size i = 0; i < prevlinks.entries(); ++i)
291  myPrevVtx->setLink(prevlinks(i).p0(), prevlinks(i).p1());
292  }
293  }
294 
295 private:
296  const INT_T *const myOrder;
297  const exint myOrderSize;
298  const INT_T *const myPointNumbers;
299  INT_T *const myNextArray;
300  INT_T *const myPrevArray;
301 
302  // The following are only needed for handling the case when existing
303  // geometry has used the same points
304  const GA_Offset myStartPt;
305  const GA_Offset myStartVtx;
306  const GA_ATITopology *myPt2Vtx;
307  GA_ATITopology *myPrevVtx;
308  UT_Lock &myUpdateExistingLock;
309 };
310 
311 /// This class is a comparator used in geo_Pt2VtxTopoParallel to find the
312 /// start of a point's range in the specified order.
313 template<typename INT_T>
314 class geo_VertexVsPointCompare
315 {
316 public:
317  geo_VertexVsPointCompare(const INT_T *pointnumbers)
318  : myPointNumbers(pointnumbers)
319  {}
320 
321  bool operator()(const INT_T &relativevtx, const GA_Size &relativept) const
322  { return (myPointNumbers[relativevtx] < relativept); }
323 
324 private:
325  const INT_T *myPointNumbers;
326 };
327 
328 /// This class fills in the point-to-vertex topology attribute, selecting
329 /// a first vertex for each point.
330 template<typename INT_T>
331 class geo_Pt2VtxTopoParallel
332 {
333 public:
334  geo_Pt2VtxTopoParallel(
335  GA_ATITopology *pt2vtx, const INT_T *order, exint order_size,
336  const INT_T *pointnumbers,
337  const GA_Offset startvtx, const GA_Offset startpt)
338  : myPt2Vtx(pt2vtx)
339  , myOrder(order)
340  , myOrderSize(order_size)
341  , myPointNumbers(pointnumbers)
342  , myStartVtx(startvtx)
343  , myStartPt(startpt)
344  {}
345 
346  void operator()(const GA_SplittableRange &r) const
347  {
348  if (!myOrderSize)
349  return;
350 
352  GA_Offset end;
353  for (GA_Iterator it = r.begin(); it.blockAdvance(start, end); )
354  {
355  const INT_T *orderend = myOrder + myOrderSize;
356  // If we don't have any points as large as start, we're done
357  if (myPointNumbers[orderend[-1]] < GA_Size(start - myStartPt))
358  break;
359  // If we don't have any points smaller than end, this iteration
360  // won't find anything
361  if (myPointNumbers[myOrder[0]] >= GA_Size(end - myStartPt))
362  continue;
363 
364  // Find the start of where the points in question appear
365  const INT_T *pvtx = std::lower_bound(myOrder, orderend, GA_Size(start - myStartPt), geo_VertexVsPointCompare<INT_T>(myPointNumbers));
366 
367  // For each point offset
368  for (GA_Offset i = start; i < end; ++i)
369  {
370  if (i == myPointNumbers[pvtx[0]] + myStartPt)
371  {
372  UT_ASSERT_P(GAisValid(pvtx[0] + myStartVtx) && pvtx[0] + myStartVtx < myPt2Vtx->getDetail().getNumVertexOffsets());
373  myPt2Vtx->setLink(i, pvtx[0] + myStartVtx);
374  // Skip to the next point
375  while (pvtx + 1 < orderend
376  && myPointNumbers[pvtx[0]] == myPointNumbers[pvtx[1]])
377  ++pvtx;
378  ++pvtx;
379  if (pvtx == orderend)
380  break;
381  }
382  }
383  }
384  }
385 
386 private:
387  GA_ATITopology *const myPt2Vtx;
388  const INT_T *const myOrder;
389  const exint myOrderSize;
390  const INT_T *const myPointNumbers;
391  const GA_Offset myStartVtx;
392  const GA_Offset myStartPt;
393 };
394 
395 /// This class (finally) writes out the vertex-to-next-vertex and
396 /// vertex-to-previous-vertex linked-list topology attributes.
397 template<typename INT_T>
398 class geo_LinkToposParallel
399 {
400 public:
401  geo_LinkToposParallel(
402  GA_ATITopology *nextvtx, GA_ATITopology *prevvtx,
403  const INT_T *nextarray,
404  const INT_T *prevarray,
405  const GA_Offset startvtx)
406  : myNextVtx(nextvtx)
407  , myPrevVtx(prevvtx)
408  , myNextArray(nextarray)
409  , myPrevArray(prevarray)
410  , myStartVtx(startvtx)
411  {}
412 
413  void operator()(const GA_SplittableRange &r) const
414  {
416  GA_Offset end;
417  for (GA_Iterator it = r.begin(); it.blockAdvance(start, end); )
418  {
419  // Separate loops for better caching
420  for (GA_Offset off = start; off < end; ++off)
421  {
422  INT_T next = myNextArray[off - myStartVtx];
423  myNextVtx->setLink(off, (next != std::numeric_limits<INT_T>::min()) ? next + myStartVtx : GA_INVALID_OFFSET);
424  }
425 
426  for (GA_Offset off = start; off < end; ++off)
427  {
428  INT_T prev = myPrevArray[off - myStartVtx];
429  myPrevVtx->setLink(off, (prev != std::numeric_limits<INT_T>::min()) ? prev + myStartVtx : GA_INVALID_OFFSET);
430  }
431  }
432  }
433 
434 private:
435  GA_ATITopology *const myNextVtx;
436  GA_ATITopology *const myPrevVtx;
437  const INT_T *const myNextArray;
438  const INT_T *const myPrevArray;
439  const GA_Offset myStartVtx;
440 };
441 
442 
443 
444 
445 /// This class unlinks vertices that are the only vertex linked to their point
446 class geo_UnlinkSingletonsParallel
447 {
448 public:
449  geo_UnlinkSingletonsParallel(const GA_ATITopology *nextvtx, const GA_ATITopology *prevvtx,
450  GA_ATITopology *vtx2pt, GA_ATITopology *pt2vtx)
451  : myNextVtx(nextvtx)
452  , myPrevVtx(prevvtx)
453  , myVtx2Pt(vtx2pt)
454  , myPt2Vtx(pt2vtx)
455  , myNonSingletons()
456  {
457  UT_ASSERT(nextvtx && prevvtx && vtx2pt && pt2vtx);
458  }
459 
460  geo_UnlinkSingletonsParallel(const geo_UnlinkSingletonsParallel &that, UT_Split)
461  : myNextVtx(that.myNextVtx)
462  , myPrevVtx(that.myPrevVtx)
463  , myVtx2Pt(that.myVtx2Pt)
464  , myPt2Vtx(that.myPt2Vtx)
465  , myNonSingletons()
466  {}
467 
468  // NOTE: This is GA_Range instead of GA_SplittableRange *ONLY* so that
469  // this can be used serially, since it is only threadsafe with
470  // GA_SplittableRange.
471  void operator()(const GA_Range &r)
472  {
474  GA_Offset end;
475  for (GA_Iterator it = r.begin(); it.blockAdvance(start, end); )
476  {
477  for (GA_Offset off = start; off < end; ++off)
478  {
479  if (!GAisValid(myNextVtx->getLink(off)) && !GAisValid(myPrevVtx->getLink(off)))
480  {
481  GA_Offset ptoff = myVtx2Pt->getLink(off);
482  myVtx2Pt->setLink(off, GA_INVALID_OFFSET);
483  // NOTE: We can't have multiple points mapping to the same
484  // vertex, and ptoff should be pointing to off, so
485  // the page should be hardened already. Otherwise,
486  // this wouldn't be threadsafe.
487  myPt2Vtx->setLink(ptoff, GA_INVALID_OFFSET);
488  }
489  else
490  {
491  myNonSingletons.append(off);
492  }
493  }
494  }
495  }
496 
497  void join(const geo_UnlinkSingletonsParallel &that)
498  {
499  if (!that.myNonSingletons.entries())
500  return;
501  if (!myNonSingletons.entries())
502  myNonSingletons = that.myNonSingletons;
503  else
504  myNonSingletons.append(that.myNonSingletons);
505  }
506 
507  GA_OffsetList &getNonSingletons()
508  { return myNonSingletons; }
509 
510 private:
511  const GA_ATITopology *const myNextVtx;
512  const GA_ATITopology *const myPrevVtx;
513  GA_ATITopology *const myVtx2Pt;
514  GA_ATITopology *const myPt2Vtx;
515  GA_OffsetList myNonSingletons;
516 };
517 
518 
519 /// This class finds the minimum and maximum point offset used by
520 /// a GA_OffsetList of vertex offsets.
521 class geo_PointRangeParallel
522 {
523 public:
524  geo_PointRangeParallel(const GA_OffsetList &vertices,
525  const GA_ATITopology *vtx2pt)
526  : myVtx2Pt(vtx2pt)
527  , myVertices(vertices)
528  , myMinPoint(GA_INVALID_OFFSET)
529  , myMaxPoint(GA_INVALID_OFFSET)
530  {
531  UT_ASSERT(vtx2pt);
532  }
533 
534  geo_PointRangeParallel(const geo_PointRangeParallel &that, UT_Split)
535  : myVtx2Pt(that.myVtx2Pt)
536  , myVertices(that.myVertices)
537  , myMinPoint(GA_INVALID_OFFSET)
538  , myMaxPoint(GA_INVALID_OFFSET)
539  {}
540 
541  void operator()(const UT_BlockedRange<GA_Size> &r)
542  {
543  GA_Size i = r.begin();
544  // NOTE: Can't assign myMinPoint or myMaxPoint here,
545  // because UTparallelReduce can re-use this object
546  // for multiple ranges. myMinPoint and myMaxPoint
547  // are accumulated below.
548  GA_Offset minpoint = myVtx2Pt->getLink(myVertices(i));
549  GA_Offset maxpoint = minpoint;
550  for (++i; i < r.end(); ++i)
551  {
552  GA_Offset ptoff = myVtx2Pt->getLink(myVertices(i));
553  minpoint = SYSmin(minpoint, ptoff);
554  maxpoint = SYSmax(maxpoint, ptoff);
555  }
556  if (!GAisValid(myMinPoint))
557  {
558  myMinPoint = minpoint;
559  myMaxPoint = maxpoint;
560  }
561  else
562  {
563  myMinPoint = SYSmin(myMinPoint, minpoint);
564  myMaxPoint = SYSmax(myMaxPoint, maxpoint);
565  }
566  }
567 
568  void join(const geo_PointRangeParallel &that)
569  {
570  if (!GAisValid(myMinPoint))
571  {
572  myMinPoint = that.myMinPoint;
573  myMaxPoint = that.myMaxPoint;
574  }
575  else
576  {
577  myMinPoint = SYSmin(myMinPoint, that.myMinPoint);
578  myMaxPoint = SYSmax(myMaxPoint, that.myMaxPoint);
579  }
580  }
581 
582  GA_Offset getStart() const
583  { return myMinPoint; }
584 
585  GA_Offset getEnd() const
586  { return myMaxPoint + 1; }
587 
588 private:
589  const GA_ATITopology *myVtx2Pt;
590  const GA_OffsetList &myVertices;
591  GA_Offset myMinPoint;
592  GA_Offset myMaxPoint;
593 };
594 
595 /// This just subtracts start from every element in input, and puts the result
596 /// as an int in output.
597 class geo_OffsetListToRelative
598 {
599 public:
600  geo_OffsetListToRelative(const GA_OffsetList &input, int *output, GA_Offset start)
601  : myInput(input)
602  , myOutput(output)
603  , myStart(start)
604  {}
605 
606  void operator()(const UT_BlockedRange<GA_Size> &r) const
607  {
608  for (GA_Size i = r.begin(); i < r.end(); ++i)
609  {
610  myOutput[i] = int(GA_Size(myInput(i) - myStart));
611  }
612  }
613 
614 private:
615  const GA_OffsetList &myInput;
616  int *const myOutput;
617  const GA_Offset myStart;
618 };
619 
620 template<typename INT_TYPE=int>
621 class geo_QuadGridVertsParallel
622 {
623 public:
624  geo_QuadGridVertsParallel(GA_Size rows, GA_Size cols, INT_TYPE *pointnums,
625  bool wrappedu=false, bool wrappedv=false,
626  INT_TYPE startptnum=0, UT_Interrupt *interrupt=nullptr,
627  bool start_pole_row=false, bool end_pole_row=false)
628  : myRows(rows)
629  , myCols(cols)
630  , myInterrupt(interrupt)
631  , myPointNums(pointnums)
632  , myStartPtNum(startptnum)
633  , myWrappedU(wrappedu)
634  , myWrappedV(wrappedv)
635  , myStartPole(start_pole_row)
636  , myEndPole(end_pole_row)
637  , myTriangularPoles(false)
638  {
639  }
640 #if 0
641  void setupSphere(bool triangular_poles) const
642  {
643  myWrappedU = true;
644  myWrappedV = false;
645  myStartPole = true;
646  myEndPole = true;
647  myTriangularPoles = triangular_poles;
648  }
649  void setupTube() const
650  {
651  myWrappedU = true;
652  myWrappedV = false;
653  myStartPole = false;
654  myEndPole = false;
655  }
656  void setupGrid() const
657  {
658  myWrappedU = false;
659  myWrappedV = false;
660  myStartPole = false;
661  myEndPole = false;
662  }
663  void setupTorus() const
664  {
665  myWrappedU = true;
666  myWrappedV = true;
667  myStartPole = false;
668  myEndPole = false;
669  }
670 #endif
671 
672  void operator()(const UT_BlockedRange<GA_Size> &r) const
673  {
674  char bcnt = 0;
675  UT_Interrupt *const interrupt = myInterrupt;
676 
677  GA_Size nquadcols = myCols - !myWrappedU;
678 
679  int startrow; int startcol;
680  SYSdivMod(r.begin(), nquadcols, startrow, startcol);
681  GA_Size i = 4*r.begin();
682  GA_Size end = 4*r.end();
683 
684  INT_TYPE pt = myStartPtNum;
685  if (myStartPole && startrow == 0)
686  {
687  // Handle starting pole row
688  for (int col = startcol; col < myCols-1 && i < end; ++col)
689  {
690  if (interrupt && !bcnt++ && interrupt->opInterrupt())
691  {
692  i = end;
693  break;
694  }
695 
696  myPointNums[i++] = pt;
697  if (!myTriangularPoles)
698  myPointNums[i++] = pt;
699  myPointNums[i++] = pt+1 + col + 1;
700  myPointNums[i++] = pt+1 + col;
701  }
702  if (myWrappedU && i < end)
703  {
704  myPointNums[i++] = pt;
705  if (!myTriangularPoles)
706  myPointNums[i++] = pt;
707  myPointNums[i++] = pt + 1;
708  myPointNums[i++] = pt + myCols;
709  }
710  startcol = 0;
711  startrow = 1;
712  ++pt;
713  }
714  else
715  {
716  pt += startrow*myCols + startcol;
717  }
718 
719  for (int row = startrow; i < end; ++row)
720  {
721  if ((myWrappedV && row == myRows-1) || (!myWrappedV && myEndPole && row == myRows-2))
722  break;
723  for (int col = startcol; col < myCols-1 && i < end; ++col)
724  {
725  if (interrupt && !bcnt++ && interrupt->opInterrupt())
726  {
727  i = end;
728  break;
729  }
730 
731  myPointNums[i++] = pt;
732  myPointNums[i++] = pt + 1;
733  myPointNums[i++] = pt + myCols + 1;
734  myPointNums[i++] = pt + myCols;
735 
736  pt++;
737  }
738  if (myWrappedU && i < end)
739  {
740  myPointNums[i++] = pt;
741  myPointNums[i++] = pt - myCols + 1;
742  myPointNums[i++] = pt + 1;
743  myPointNums[i++] = pt + myCols;
744  }
745  // The last point of the row gets skipped if not wrapping U
746  pt++;
747  startcol = 0;
748  }
749 
750  // If not wrapping V or handling end pole, we're done
751  if (i == end)
752  return;
753 
754  if (myEndPole)
755  {
756  // End pole point is starting point if wrapping.
757  INT_TYPE endpolept = myWrappedV ? myStartPtNum : (pt+myCols);
758  for (int col = startcol; col < myCols-1 && i < end; ++col)
759  {
760  if (interrupt && !bcnt++ && interrupt->opInterrupt())
761  break;
762 
763  myPointNums[i++] = pt;
764  myPointNums[i++] = pt + 1;
765  myPointNums[i++] = endpolept;
766  if (!myTriangularPoles)
767  myPointNums[i++] = endpolept;
768 
769  pt++;
770  }
771  if (myWrappedU && i < end)
772  {
773  myPointNums[i++] = pt;
774  myPointNums[i++] = pt - myCols + 1;
775  myPointNums[i++] = endpolept;
776  if (!myTriangularPoles)
777  myPointNums[i++] = endpolept;
778  }
779  return;
780  }
781 
782  // If at last row and wrapping V
783  for (int col = startcol; col < myCols-1 && i < end; ++col)
784  {
785  if (interrupt && !bcnt++ && interrupt->opInterrupt())
786  break;
787 
788  myPointNums[i++] = pt;
789  myPointNums[i++] = pt + 1;
790  myPointNums[i++] = myStartPtNum + col + 1;
791  myPointNums[i++] = myStartPtNum + col;
792 
793  pt++;
794  }
795  if (myWrappedU && i < end)
796  {
797  myPointNums[i++] = pt;
798  myPointNums[i++] = pt - myCols + 1;
799  myPointNums[i++] = myStartPtNum;
800  myPointNums[i++] = myStartPtNum + myCols - 1;
801  }
802  }
803 
804 private:
805  const GA_Size myRows;
806  const GA_Size myCols;
807  UT_Interrupt *const myInterrupt;
808  INT_TYPE *const myPointNums;
809  const INT_TYPE myStartPtNum;
810  const bool myWrappedU;
811  const bool myWrappedV;
812  const bool myStartPole;
813  const bool myEndPole;
814  const bool myTriangularPoles;
815 };
816 
817 template<typename INT_TYPE=int>
818 class geo_TriGridVertsParallel
819 {
820 public:
821  geo_TriGridVertsParallel(
822  GA_Size rows, GA_Size cols, INT_TYPE *pointnums,
823  bool wrappedu, bool wrappedv,
824  GEO_SurfaceType type, INT_TYPE startptnum=0,
825  UT_Interrupt *interrupt=nullptr,
826  bool start_pole_row=false, bool end_pole_row=false)
827  : myRows(rows)
828  , myCols(cols)
829  , myPointNums(pointnums)
830  , myStartPtNum(startptnum)
831  , myType(type)
832  , myWrappedU(wrappedu)
833  , myWrappedV(wrappedv)
834  , myInterrupt(interrupt)
835  , myStartPole(start_pole_row)
836  , myEndPole(end_pole_row)
837  , myTriangularPoles(false)
838  {}
839 
840  void operator()(const UT_BlockedRange<GA_Size> &r) const
841  {
842  char bcnt = 0;
843  UT_Interrupt *const interrupt = myInterrupt;
844 
845  bool alt = (myType == GEO_PATCH_ALTTRIANGLE);
846  bool rev = (myType == GEO_PATCH_REVTRIANGLE);
847 
848  GA_Size nquadcols = myCols - !myWrappedU;
849 
850  int startrow; int startcol;
851  SYSdivMod(r.begin(), nquadcols, startrow, startcol);
852  GA_Size i = 6*r.begin();
853  GA_Size end = 6*r.end();
854  INT_TYPE pt = myStartPtNum + startrow*myCols + startcol;
855  for (int row = startrow; i < end; ++row)
856  {
857  if (myWrappedV && row == myRows-1)
858  break;
859  for (int col = startcol; col < myCols-1 && i < end; ++col)
860  {
861  if (interrupt && !bcnt++ && interrupt->opInterrupt())
862  {
863  i = end;
864  break;
865  }
866 
867  // Switch diagonal with checkerboard pattern
868  bool switched = (rev || (alt && ((row^col)&1)));
869 
870  myPointNums[i++] = pt;
871  myPointNums[i++] = pt + 1;
872  myPointNums[i++] = pt + myCols + int(!switched);
873 
874  myPointNums[i++] = pt + int(switched);
875  myPointNums[i++] = pt + myCols + 1;
876  myPointNums[i++] = pt + myCols;
877 
878  pt++;
879  }
880  if (myWrappedU && i < end)
881  {
882  // Switch diagonal with checkerboard pattern
883  bool switched = (rev || (alt && ((row^(myCols-1))&1)));
884 
885  myPointNums[i++] = pt;
886  myPointNums[i++] = pt - myCols + 1;
887  myPointNums[i++] = pt + (switched ? myCols : 1);
888 
889  myPointNums[i++] = pt + (switched ? (-myCols + 1) : 0);
890  myPointNums[i++] = pt + 1;
891  myPointNums[i++] = pt + myCols;
892  }
893  // The last point of the row gets skipped if not wrapping U
894  pt++;
895  startcol = 0;
896  }
897 
898  // If not wrapping V, we're done
899  if (i == end)
900  return;
901 
902  // If at last row and wrapping V
903  for (int col = startcol; col < myCols-1 && i < end; ++col)
904  {
905  if (interrupt && !bcnt++ && interrupt->opInterrupt())
906  break;
907 
908  // Switch diagonal with checkerboard pattern
909  bool switched = (rev || (alt && (((myRows-1)^col)&1)));
910 
911  myPointNums[i++] = pt;
912  myPointNums[i++] = pt + 1;
913  myPointNums[i++] = myStartPtNum + col + int(!switched);
914 
915  myPointNums[i++] = pt + int(switched);
916  myPointNums[i++] = myStartPtNum + col + 1;
917  myPointNums[i++] = myStartPtNum + col;
918 
919  pt++;
920  }
921  if (myWrappedU && i < end)
922  {
923  // Switch diagonal with checkerboard pattern
924  bool switched = (rev || (alt && (((myRows-1)^(myCols-1))&1)));
925 
926  myPointNums[i++] = pt;
927  myPointNums[i++] = pt - myCols + 1;
928  myPointNums[i++] = myStartPtNum + (switched ? (myCols-1) : 0);
929 
930  myPointNums[i++] = pt + (switched ? (-myCols + 1) : 0);
931  myPointNums[i++] = myStartPtNum + 0;
932  myPointNums[i++] = myStartPtNum + myCols-1;
933  }
934  }
935 
936 private:
937  const GA_Size myRows;
938  const GA_Size myCols;
939  UT_Interrupt *const myInterrupt;
940  INT_TYPE *const myPointNums;
941  const INT_TYPE myStartPtNum;
942  const GEO_SurfaceType myType;
943  const bool myWrappedU;
944  const bool myWrappedV;
945  const bool myStartPole;
946  const bool myEndPole;
947  const bool myTriangularPoles;
948 };
949 
950 template<typename INT_TYPE=int>
951 class geo_CurveGridVertsParallel
952 {
953 public:
954  geo_CurveGridVertsParallel(GA_Size rows, GA_Size cols, INT_TYPE *pointnums,
955  bool unrollcurves, GEO_SurfaceType type,
956  INT_TYPE startptnum=0, UT_Interrupt *interrupt=nullptr,
957  bool start_pole_row=false, bool end_pole_row=false)
958  : myRows(rows)
959  , myCols(cols)
960  , myInterrupt(interrupt)
961  , myPointNums(pointnums)
962  , myStartPtNum(startptnum)
963  , myType(type)
964  , myUnrollCurves(unrollcurves)
965  , myStartPole(start_pole_row)
966  , myEndPole(end_pole_row)
967  {
968  UT_ASSERT(type == GEO_PATCH_ROWS || type == GEO_PATCH_COLS);
969  }
970 
971  void operator()(const UT_BlockedRange<GA_Size> &r) const
972  {
973  const bool unrollcurves = myUnrollCurves;
974  const GA_Size nrows = myRows;
975  const GA_Size ncols = myCols;
976  INT_TYPE *pointnums = myPointNums + r.begin();
977 
978  if (myType == GEO_PATCH_ROWS)
979  {
980  GA_Size startrow = r.begin()/ncols;
981  const GA_Size startcol = r.begin()%ncols;
982  const GA_Size endrow = r.end()/ncols;
983  const GA_Size endcol = r.end()%ncols;
984  INT_TYPE v = myStartPtNum + r.begin();
985  if (startrow == endrow)
986  {
987  for (GA_Size col = startcol; col < endcol; ++col, ++v, ++pointnums)
988  *pointnums = v;
989  return;
990  }
991  if (startcol != 0)
992  {
993  // Partial first row
994  for (GA_Size col = startcol; col < ncols; ++col, ++v, ++pointnums)
995  *pointnums = v;
996 
997  if (unrollcurves)
998  {
999  *pointnums = v-ncols;
1000  ++pointnums;
1001  }
1002  ++startrow;
1003  }
1004  // Middle rows
1005  for (GA_Size row = startrow; row < endrow; ++row)
1006  {
1007  for (GA_Size col = 0; col < ncols; ++col, ++v, ++pointnums)
1008  *pointnums = v;
1009 
1010  if (unrollcurves)
1011  {
1012  *pointnums = v-ncols;
1013  ++pointnums;
1014  }
1015  }
1016  // Partial final row
1017  for (GA_Size col = 0; col < endcol; ++col, ++v, ++pointnums)
1018  *pointnums = v;
1019  }
1020  else
1021  {
1022  // GEO_PATCH_COLS
1023 
1024  const GA_Size nmeshpoints = nrows*ncols;
1025  GA_Size startcol = r.begin()/nrows;
1026  const GA_Size startrow = r.begin()%nrows;
1027  const GA_Size endcol = r.end()/nrows;
1028  const GA_Size endrow = r.end()%nrows;
1029  // NOTE: v uses ncols as normal; it's the output & iteration order
1030  // that's the opposite of the above.
1031  INT_TYPE v = myStartPtNum + startrow*ncols + startcol;
1032  if (startcol == endcol)
1033  {
1034  for (GA_Size row = startrow; row < endrow; ++row, v += ncols, ++pointnums)
1035  *pointnums = v;
1036  return;
1037  }
1038  if (startrow != 0)
1039  {
1040  // Partial first col
1041  for (GA_Size row = startrow; row < nrows; ++row, v += ncols, ++pointnums)
1042  *pointnums = v;
1043 
1044  if (unrollcurves)
1045  {
1046  *pointnums = v-nmeshpoints;
1047  ++pointnums;
1048  }
1049  ++startcol;
1050  v -= (nmeshpoints-1);
1051  }
1052  // Middle cols
1053  for (GA_Size col = startcol; col < endcol; ++col, v -= (nmeshpoints-1))
1054  {
1055  for (GA_Size row = 0; row < nrows; ++row, v += ncols, ++pointnums)
1056  *pointnums = v;
1057 
1058  if (unrollcurves)
1059  {
1060  *pointnums = v-nmeshpoints;
1061  ++pointnums;
1062  }
1063  }
1064  // Partial final col
1065  for (GA_Size row = 0; row < endrow; ++row, v += ncols, ++pointnums)
1066  *pointnums = v;
1067  }
1068  }
1069 
1070 private:
1071  const GA_Size myRows;
1072  const GA_Size myCols;
1073  UT_Interrupt *const myInterrupt;
1074  INT_TYPE *const myPointNums;
1075  const INT_TYPE myStartPtNum;
1076  const GEO_SurfaceType myType;
1077  const bool myUnrollCurves;
1078  const bool myStartPole;
1079  const bool myEndPole;
1080 };
1081 
1082 } // end of anonymous namespace
1083 
1084 #endif
1085 
#define SYSmax(a, b)
Definition: SYS_Math.h:1538
typedef int(APIENTRYP RE_PFNGLXSWAPINTERVALSGIPROC)(int)
tbb::split UT_Split
Definition: GA_PolyCounts.h:24
Iteration over a range of elements.
Definition: GA_Iterator.h:29
void
Definition: png.h:1083
int myOrder
Definition: GT_CurveEval.h:263
const GLdouble * v
Definition: glcorearb.h:837
bool blockAdvance(GA_Offset &start, GA_Offset &end)
GLuint start
Definition: glcorearb.h:475
bool GAisValid(GA_Size v)
Definition: GA_Types.h:649
int64 exint
Definition: SYS_Types.h:125
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
GA_EdgeT< GA_Offset, false > GA_Edge
Definition: GA_Edge.h:90
SYS_FORCE_INLINE void set(GA_Offseti, SRC_DATA_T v)
component == 0 in this version
Definition: UT_PageArray.h:624
exint GA_Size
Defines the bit width for index and offset types in GA.
Definition: GA_Types.h:235
#define GA_INVALID_OFFSET
Definition: GA_Types.h:678
A range of elements in an index-map.
Definition: GA_Range.h:42
GA_AttributeOwner getLinkOwner() const
GA_Size GA_Offset
Definition: GA_Types.h:641
int opInterrupt(int percent=-1)
GA_Iterator begin() const
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:155
GT_API const UT_StringHolder topology
GLuint GLuint end
Definition: glcorearb.h:475
GLdouble GLdouble GLint GLint order
Definition: glad.h:2676
long long int64
Definition: SYS_Types.h:116
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
exint append()
Definition: UT_Array.h:142
exint entries() const
Alias of size(). size() is preferred.
Definition: UT_Array.h:648
GEO_SurfaceType
SYS_FORCE_INLINE GA_AttributeOwner getOwner() const
Definition: GA_Attribute.h:210
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
GLenum GLenum GLsizei void * row
Definition: glad.h:5135
GLboolean r
Definition: glcorearb.h:1222
#define SYSmin(a, b)
Definition: SYS_Math.h:1539
type
Definition: core.h:1059
Declare prior to use.
auto join(It begin, Sentinel end, string_view sep) -> join_view< It, Sentinel >
Definition: format.h:2559