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