HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros 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, bool wrappedv,
545  INT_TYPE startptnum=0, UT_Interrupt *interrupt=nullptr)
546  : myRows(rows)
547  , myCols(cols)
548  , myInterrupt(interrupt)
549  , myPointNums(pointnums)
550  , myStartPtNum(startptnum)
551  , myWrappedU(wrappedu)
552  , myWrappedV(wrappedv)
553  {}
554 
555  void operator()(const UT_BlockedRange<GA_Size> &r) const
556  {
557  char bcnt = 0;
558  UT_Interrupt *const interrupt = myInterrupt;
559 
560  GA_Size nquadcols = myCols - !myWrappedU;
561 
562  int startrow; int startcol;
563  SYSdivMod(r.begin(), nquadcols, startrow, startcol);
564  GA_Size i = 4*r.begin();
565  GA_Size end = 4*r.end();
566  INT_TYPE pt = myStartPtNum + startrow*myCols + startcol;
567  for (int row = startrow; i < end; ++row)
568  {
569  if (myWrappedV && row == myRows-1)
570  break;
571  for (int col = startcol; col < myCols-1 && i < end; ++col)
572  {
573  if (interrupt && !bcnt++ && interrupt->opInterrupt())
574  {
575  i = end;
576  break;
577  }
578 
579  myPointNums[i++] = pt;
580  myPointNums[i++] = pt + 1;
581  myPointNums[i++] = pt + myCols + 1;
582  myPointNums[i++] = pt + myCols;
583 
584  pt++;
585  }
586  if (myWrappedU && i < end)
587  {
588  myPointNums[i++] = pt;
589  myPointNums[i++] = pt - myCols + 1;
590  myPointNums[i++] = pt + 1;
591  myPointNums[i++] = pt + myCols;
592  }
593  // The last point of the row gets skipped if not wrapping U
594  pt++;
595  startcol = 0;
596  }
597 
598  // If not wrapping V, we're done
599  if (i == end)
600  return;
601 
602  // If at last row and wrapping V
603  for (int col = startcol; col < myCols-1 && i < end; ++col)
604  {
605  if (interrupt && !bcnt++ && interrupt->opInterrupt())
606  break;
607 
608  myPointNums[i++] = pt;
609  myPointNums[i++] = pt + 1;
610  myPointNums[i++] = myStartPtNum + col + 1;
611  myPointNums[i++] = myStartPtNum + col;
612 
613  pt++;
614  }
615  if (myWrappedU && i < end)
616  {
617  myPointNums[i++] = pt;
618  myPointNums[i++] = pt - myCols + 1;
619  myPointNums[i++] = myStartPtNum;
620  myPointNums[i++] = myStartPtNum + myCols - 1;
621  }
622  }
623 
624 private:
625  const GA_Size myRows;
626  const GA_Size myCols;
627  UT_Interrupt *const myInterrupt;
628  INT_TYPE *const myPointNums;
629  const INT_TYPE myStartPtNum;
630  const bool myWrappedU;
631  const bool myWrappedV;
632 };
633 
634 template<typename INT_TYPE=int>
635 class geo_TriGridVertsParallel
636 {
637 public:
638  geo_TriGridVertsParallel(
639  GA_Size rows, GA_Size cols, INT_TYPE *pointnums,
640  bool wrappedu, bool wrappedv,
641  GEO_SurfaceType type, INT_TYPE startptnum=0,
642  UT_Interrupt *interrupt=nullptr)
643  : myRows(rows)
644  , myCols(cols)
645  , myPointNums(pointnums)
646  , myStartPtNum(startptnum)
647  , myType(type)
648  , myWrappedU(wrappedu)
649  , myWrappedV(wrappedv)
650  , myInterrupt(interrupt)
651  {}
652 
653  void operator()(const UT_BlockedRange<GA_Size> &r) const
654  {
655  char bcnt = 0;
656  UT_Interrupt *const interrupt = myInterrupt;
657 
658  bool alt = (myType == GEO_PATCH_ALTTRIANGLE);
659  bool rev = (myType == GEO_PATCH_REVTRIANGLE);
660 
661  GA_Size nquadcols = myCols - !myWrappedU;
662 
663  int startrow; int startcol;
664  SYSdivMod(r.begin(), nquadcols, startrow, startcol);
665  GA_Size i = 6*r.begin();
666  GA_Size end = 6*r.end();
667  INT_TYPE pt = myStartPtNum + startrow*myCols + startcol;
668  for (int row = startrow; i < end; ++row)
669  {
670  if (myWrappedV && row == myRows-1)
671  break;
672  for (int col = startcol; col < myCols-1 && i < end; ++col)
673  {
674  if (interrupt && !bcnt++ && interrupt->opInterrupt())
675  {
676  i = end;
677  break;
678  }
679 
680  // Switch diagonal with checkerboard pattern
681  bool switched = (rev || (alt && ((row^col)&1)));
682 
683  myPointNums[i++] = pt;
684  myPointNums[i++] = pt + 1;
685  myPointNums[i++] = pt + myCols + int(!switched);
686 
687  myPointNums[i++] = pt + int(switched);
688  myPointNums[i++] = pt + myCols + 1;
689  myPointNums[i++] = pt + myCols;
690 
691  pt++;
692  }
693  if (myWrappedU && i < end)
694  {
695  // Switch diagonal with checkerboard pattern
696  bool switched = (rev || (alt && ((row^(myCols-1))&1)));
697 
698  myPointNums[i++] = pt;
699  myPointNums[i++] = pt - myCols + 1;
700  myPointNums[i++] = pt + (switched ? myCols : 1);
701 
702  myPointNums[i++] = pt + (switched ? (-myCols + 1) : 0);
703  myPointNums[i++] = pt + 1;
704  myPointNums[i++] = pt + myCols;
705  }
706  // The last point of the row gets skipped if not wrapping U
707  pt++;
708  startcol = 0;
709  }
710 
711  // If not wrapping V, we're done
712  if (i == end)
713  return;
714 
715  // If at last row and wrapping V
716  for (int col = startcol; col < myCols-1 && i < end; ++col)
717  {
718  if (interrupt && !bcnt++ && interrupt->opInterrupt())
719  break;
720 
721  // Switch diagonal with checkerboard pattern
722  bool switched = (rev || (alt && (((myRows-1)^col)&1)));
723 
724  myPointNums[i++] = pt;
725  myPointNums[i++] = pt + 1;
726  myPointNums[i++] = myStartPtNum + col + int(!switched);
727 
728  myPointNums[i++] = pt + int(switched);
729  myPointNums[i++] = myStartPtNum + col + 1;
730  myPointNums[i++] = myStartPtNum + col;
731 
732  pt++;
733  }
734  if (myWrappedU && i < end)
735  {
736  // Switch diagonal with checkerboard pattern
737  bool switched = (rev || (alt && (((myRows-1)^(myCols-1))&1)));
738 
739  myPointNums[i++] = pt;
740  myPointNums[i++] = pt - myCols + 1;
741  myPointNums[i++] = myStartPtNum + (switched ? (myCols-1) : 0);
742 
743  myPointNums[i++] = pt + (switched ? (-myCols + 1) : 0);
744  myPointNums[i++] = myStartPtNum + 0;
745  myPointNums[i++] = myStartPtNum + myCols-1;
746  }
747  }
748 
749 private:
750  const GA_Size myRows;
751  const GA_Size myCols;
752  UT_Interrupt *const myInterrupt;
753  INT_TYPE *const myPointNums;
754  const INT_TYPE myStartPtNum;
755  const GEO_SurfaceType myType;
756  const bool myWrappedU;
757  const bool myWrappedV;
758 };
759 
760 template<typename INT_TYPE=int>
761 class geo_CurveGridVertsParallel
762 {
763 public:
764  geo_CurveGridVertsParallel(GA_Size rows, GA_Size cols, INT_TYPE *pointnums,
765  bool unrollcurves, GEO_SurfaceType type,
766  INT_TYPE startptnum=0, UT_Interrupt *interrupt=nullptr)
767  : myRows(rows)
768  , myCols(cols)
769  , myInterrupt(interrupt)
770  , myPointNums(pointnums)
771  , myStartPtNum(startptnum)
772  , myType(type)
773  , myUnrollCurves(unrollcurves)
774  {
775  UT_ASSERT(type == GEO_PATCH_ROWS || type == GEO_PATCH_COLS);
776  }
777 
778  void operator()(const UT_BlockedRange<GA_Size> &r) const
779  {
780  const bool unrollcurves = myUnrollCurves;
781  const GA_Size nrows = myRows;
782  const GA_Size ncols = myCols;
783  INT_TYPE *pointnums = myPointNums + r.begin();
784 
785  if (myType == GEO_PATCH_ROWS)
786  {
787  GA_Size startrow = r.begin()/ncols;
788  const GA_Size startcol = r.begin()%ncols;
789  const GA_Size endrow = r.end()/ncols;
790  const GA_Size endcol = r.end()%ncols;
791  INT_TYPE v = myStartPtNum + r.begin();
792  if (startrow == endrow)
793  {
794  for (GA_Size col = startcol; col < endcol; ++col, ++v, ++pointnums)
795  *pointnums = v;
796  return;
797  }
798  if (startcol != 0)
799  {
800  // Partial first row
801  for (GA_Size col = startcol; col < ncols; ++col, ++v, ++pointnums)
802  *pointnums = v;
803 
804  if (unrollcurves)
805  {
806  *pointnums = v-ncols;
807  ++pointnums;
808  }
809  ++startrow;
810  }
811  // Middle rows
812  for (GA_Size row = startrow; row < endrow; ++row)
813  {
814  for (GA_Size col = 0; col < ncols; ++col, ++v, ++pointnums)
815  *pointnums = v;
816 
817  if (unrollcurves)
818  {
819  *pointnums = v-ncols;
820  ++pointnums;
821  }
822  }
823  // Partial final row
824  for (GA_Size col = 0; col < endcol; ++col, ++v, ++pointnums)
825  *pointnums = v;
826  }
827  else
828  {
829  // GEO_PATCH_COLS
830 
831  const GA_Size nmeshpoints = nrows*ncols;
832  GA_Size startcol = r.begin()/nrows;
833  const GA_Size startrow = r.begin()%nrows;
834  const GA_Size endcol = r.end()/nrows;
835  const GA_Size endrow = r.end()%nrows;
836  // NOTE: v uses ncols as normal; it's the output & iteration order
837  // that's the opposite of the above.
838  INT_TYPE v = myStartPtNum + startrow*ncols + startcol;
839  if (startcol == endcol)
840  {
841  for (GA_Size row = startrow; row < endrow; ++row, v += ncols, ++pointnums)
842  *pointnums = v;
843  return;
844  }
845  if (startrow != 0)
846  {
847  // Partial first col
848  for (GA_Size row = startrow; row < nrows; ++row, v += ncols, ++pointnums)
849  *pointnums = v;
850 
851  if (unrollcurves)
852  {
853  *pointnums = v-nmeshpoints;
854  ++pointnums;
855  }
856  ++startcol;
857  v -= (nmeshpoints-1);
858  }
859  // Middle cols
860  for (GA_Size col = startcol; col < endcol; ++col, v -= (nmeshpoints-1))
861  {
862  for (GA_Size row = 0; row < nrows; ++row, v += ncols, ++pointnums)
863  *pointnums = v;
864 
865  if (unrollcurves)
866  {
867  *pointnums = v-nmeshpoints;
868  ++pointnums;
869  }
870  }
871  // Partial final col
872  for (GA_Size row = 0; row < endrow; ++row, v += ncols, ++pointnums)
873  *pointnums = v;
874  }
875  }
876 
877 private:
878  const GA_Size myRows;
879  const GA_Size myCols;
880  UT_Interrupt *const myInterrupt;
881  INT_TYPE *const myPointNums;
882  const INT_TYPE myStartPtNum;
883  const GEO_SurfaceType myType;
884  const bool myUnrollCurves;
885 };
886 
887 } // end of anonymous namespace
888 
889 #endif
890 
#define SYSmax(a, b)
Definition: SYS_Math.h:1365
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
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:101
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(ZZ)
Definition: UT_Assert.h:102
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:446
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
GLboolean r
Definition: glcorearb.h:1221
#define SYSmin(a, b)
Definition: SYS_Math.h:1366
Declare prior to use.