HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GU_GridImpl.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2024
3  * Side Effects Software Inc. All rights reserved.
4  *
5  * Redistribution and use of Houdini Development Kit samples in source and
6  * binary forms, with or without modification, are permitted provided that the
7  * following conditions are met:
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. The name of Side Effects Software may not be used to endorse or
11  * promote products derived from this software without specific prior
12  * written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `AS IS' AND ANY EXPRESS
15  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
17  * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
20  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
23  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  *----------------------------------------------------------------------------
26  * Definitions of functions for iterating over grids and initializing GU_GridT.
27  */
28 
29 #pragma once
30 
31 #include "GU_Grid.h"
32 #include <GEO/GEO_SurfaceType.h>
33 #include <UT/UT_Assert.h>
34 #include <SYS/SYS_Types.h>
35 
36 namespace HDK_Sample {
37 
38 /// This calls functor for each point in grid, as:
39 /// functor(point, row, col)
40 ///
41 /// Consecutive repeated points in a row are skipped,
42 /// as well as points at the beginning and end of a wrap.
43 ///
44 /// Unlike the primitive and vertex iteration functions,
45 /// the points passed to the functor are not in ascending order,
46 /// they are the points in the grid.
47 template<typename INT_TYPE,typename FUNCTOR>
48 void GUiterateGridPoints(const GU_GridT<INT_TYPE> &grid, FUNCTOR &&functor)
49 {
50  const exint nedgerows = grid.myNumEdgeRows;
51  const exint nedgecols = grid.myNumEdgeCols;
52 
53  if (nedgerows < 0 || nedgecols < 0)
54  return;
55 
56  // NOTE: This -1 will never be used, but is here just in case.
57  INT_TYPE prev_pt = INT_TYPE(-1);
58 
59  for (exint row = 0; row < nedgerows; ++row)
60  {
61  for (exint col = 0; col < nedgecols; ++col)
62  {
63  INT_TYPE point = grid.getPoint(row, col);
64  if (col == 0 || point != prev_pt)
65  {
66  functor(point, row, col);
67  prev_pt = point;
68  }
69  }
70  INT_TYPE point = grid.getPoint(row, nedgecols);
71  if (nedgecols == 0 || (!grid.doesRowWrap(row) && point != prev_pt))
72  {
73  functor(point, row, nedgecols);
74  prev_pt = point;
75  }
76  }
77  for (exint col = 0; col < nedgecols; ++col)
78  {
79  INT_TYPE point = grid.getPoint(nedgerows, col);
80  if (nedgerows == 0 || (!grid.doesColWrap(col) && (col == 0 || point != prev_pt)))
81  {
82  functor(point, nedgerows, col);
83  prev_pt = point;
84  }
85  }
86  INT_TYPE point = grid.getPoint(nedgerows, nedgecols);
87  if ((nedgecols == 0 || !grid.doesRowWrap(nedgerows)) && (nedgerows == 0 || !grid.doesColWrap(nedgecols)) && point != prev_pt)
88  {
89  functor(point, nedgerows, nedgecols);
90  prev_pt = point;
91  }
92 }
93 
94 /// This calls functor for each primitive in grid, as:
95 /// functor(primnum, row, col, primvtxcount, closed)
96 template<typename INT_TYPE,typename FUNCTOR>
97 void GUiterateGridPrimitives(const GU_GridT<INT_TYPE> &grid, FUNCTOR &&functor)
98 {
99  using PrimitiveType = typename GU_GridT<INT_TYPE>::PrimitiveType;
100  if (grid.myPrimitiveType == PrimitiveType::POINTS)
101  return;
102 
103  const GEO_SurfaceType surface_type = grid.mySurfaceType;
104  const bool rows_and_cols = (surface_type == GEO_PATCH_ROWCOL);
105  const exint nedgerows = grid.myNumEdgeRows;
106  const exint nedgecols = grid.myNumEdgeCols;
107 
108  if (nedgerows < 0 || nedgecols < 0)
109  return;
110 
111  exint primnum = 0;
112 
113  if (grid.isInvalidTPSurf())
114  return;
115 
116  if (grid.myPrimitiveType != PrimitiveType::POLYGON)
117  {
118  // Only one primitive
119  // FIXME: Support myCurvesIfBasisRowCol!
120  functor(primnum, 0, 0, grid.myNumVertices, false);
121  return;
122  }
123 
124  // Get the special cases out of the way so that it's easier later
125  if (nedgerows == 0)
126  {
127  // Single row
128  if (surface_type == GEO_PATCH_ROWS || rows_and_cols)
129  {
130  exint nvertices = 1; // 1 vertex if both zero, regardless of wrap or unroll.
131  bool closed = false;
132  if (nedgecols > 0)
133  {
134  closed = (grid.doesRowWrap(0) && !grid.myUnrollCurves);
135  nvertices = nedgecols + exint(!closed);
136  }
137  functor(primnum, 0, 0, nvertices, closed);
138  ++primnum;
139 
140  if (!rows_and_cols)
141  return;
142  }
143  if (surface_type == GEO_PATCH_COLS || rows_and_cols)
144  {
145  exint npoints = 1; // 1 point if both zero, regardless of wrap.
146  if (nedgecols > 0)
147  {
148  bool closed_curve = grid.doesRowWrap(0);
149  npoints = nedgecols + exint(!closed_curve);
150  }
151  for (exint col = 0; col < npoints; ++col)
152  {
153  functor(primnum, 0, col, 1, false);
154  ++primnum;
155  }
156  }
157  // Only rows, cols, and rowcol have vertices when a single row.
158  return;
159  }
160  if (nedgecols == 0)
161  {
162  // Single column (and multiple rows, since nedgerows==0 has already returned)
163  if (surface_type == GEO_PATCH_ROWS || rows_and_cols)
164  {
165  bool closed_curve = grid.doesColWrap(0);
166  exint npoints = nedgerows + exint(!closed_curve);
167 
168  for (exint row = 0; row < npoints; ++row)
169  {
170  functor(primnum, row, 0, 1, false);
171  ++primnum;
172  }
173 
174  if (!rows_and_cols)
175  return;
176  }
177  if (surface_type == GEO_PATCH_COLS || rows_and_cols)
178  {
179  bool closed = (grid.doesColWrap(0) && !grid.myUnrollCurves);
180  exint nvertices = nedgerows + exint(!closed);
181  functor(primnum, 0, 0, nvertices, closed);
182  ++primnum;
183  }
184  // Only rows, cols, and rowcol have vertices when a single row.
185  return;
186  }
187 
188  // Main cases; note that nedgerows and nedgecols are both at least 1.
189 
190  if (surface_type == GEO_PATCH_ROWS || rows_and_cols)
191  {
192  bool closed = (grid.myAllWrapU && !grid.myUnrollCurves);
193  exint nvertices = nedgecols + exint(!closed);
194  bool different_nvertices = (!grid.myAllWrapU && !grid.myNoWrapU && !grid.myUnrollCurves);
195 
196  exint first_row = (grid.myNoWrapV && !grid.myFirstRowIfNotWrapped);
197  for (exint row = first_row; row < nedgerows; ++row, ++primnum)
198  {
199  if (different_nvertices)
200  {
201  closed = grid.doesRowWrap(row);
202  nvertices = nedgecols + exint(!closed);
203  }
204  functor(primnum, row, 0, nvertices, closed);
205  }
206 
207  if (!grid.myAllWrapV && grid.myLastRowIfNotWrapped)
208  {
209  if (grid.myNoWrapV)
210  {
211  if (different_nvertices)
212  {
213  closed = grid.doesRowWrap(nedgerows);
214  nvertices = nedgecols + exint(!closed);
215  }
216  functor(primnum, nedgerows, 0, nvertices, closed);
217  ++primnum;
218  }
219  else
220  {
221  exint primvtx = 0;
222  bool col_wraps = grid.doesColWrap(0);
223  bool next_col_wraps;
224  exint primstartcol;
225  for (exint col = 0; col < nedgecols; ++col, col_wraps = next_col_wraps)
226  {
227  next_col_wraps = grid.doesColWrap(col+1);
228  bool currently_in_a_curve = (primvtx != 0);
229  if (!currently_in_a_curve)
230  {
231  if (col_wraps && next_col_wraps)
232  {
233  // If current point and next point are wrapping v,
234  // and we're not currently in a curve, skip.
235  // O=======(O)=======O
236  continue;
237  }
238 
239  // (O)------O //
240  // (O)------O //
241  // or //
242  // (O)-----\ //
243  // (O)------O //
244  // or //
245  // /------O //
246  // O=======(O)-------O //
247  primstartcol = col;
248  primvtx = 1;
249  }
250  else if (col_wraps && next_col_wraps)
251  {
252  // O------\ //
253  // O-------(O)=======O //
254  // Done a curve, so call the functor.
255  functor(primnum, nedgerows, primstartcol, col+1-primstartcol, false);
256  ++primnum;
257  primvtx = 0;
258  }
259  else
260  {
261  // O------\ /------O //
262  // O-------(O)-------O //
263  // or //
264  // O-------(O)-------O //
265  // O--------O--------O //
266  // or //
267  // O-------(O)------\ //
268  // O--------O--------O //
269  // Already in a curve, so no need to call the functor.
270  ++primvtx;
271  }
272  }
273  if ((!grid.doesRowWrap(nedgerows) || grid.myUnrollCurves) && (primvtx != 0))
274  {
275  // O-------(O) //
276  // O-------(O) //
277  // or //
278  // O------\ //
279  // O-------(O) //
280  // or //
281  // /------(O) //
282  // O-------(O) //
283  // Done a curve, so call the functor.
284  functor(primnum, nedgerows, primstartcol, nedgecols+1-primstartcol, false);
285  ++primnum;
286  primvtx = 0;
287  }
288  }
289  }
290 
291  if (!rows_and_cols)
292  return;
293  }
294  if (surface_type == GEO_PATCH_COLS || rows_and_cols)
295  {
296  // Just like the rows case, but with rows and cols (mostly) swapped
297  bool closed = (grid.myAllWrapV && !grid.myUnrollCurves);
298  exint nvertices = nedgerows + exint(!closed);
299  bool different_nvertices = (!grid.myAllWrapV && !grid.myNoWrapV && !grid.myUnrollCurves);
300 
301  exint first_col = (grid.myNoWrapU && !grid.myFirstColIfNotWrapped);
302  for (exint col = first_col; col < nedgecols; ++col, ++primnum)
303  {
304  if (different_nvertices)
305  {
306  closed = grid.doesColWrap(col);
307  nvertices = nedgerows + exint(!closed);
308  }
309  functor(primnum, 0, col, nvertices, closed);
310  }
311 
312  if (!grid.myAllWrapU && grid.myLastColIfNotWrapped)
313  {
314  if (grid.myNoWrapU)
315  {
316  if (different_nvertices)
317  {
318  closed = grid.doesColWrap(nedgecols);
319  nvertices = nedgerows + exint(!closed);
320  }
321  functor(primnum, 0, nedgecols, nvertices, closed);
322  ++primnum;
323  }
324  else
325  {
326  exint primvtx = 0;
327  bool row_wraps = grid.doesRowWrap(0);
328  bool next_row_wraps;
329  exint primstartrow;
330  for (exint row = 0; row < nedgerows; ++row, row_wraps = next_row_wraps)
331  {
332  next_row_wraps = grid.doesRowWrap(row+1);
333  bool currently_in_a_curve = (primvtx != 0);
334  if (!currently_in_a_curve)
335  {
336  if (row_wraps && next_row_wraps)
337  {
338  // If current point and next point are wrapping u,
339  // and we're not currently in a curve, skip.
340  // O=======(O)=======O
341  continue;
342  }
343 
344  // (O)------O //
345  // (O)------O //
346  // or //
347  // (O)-----\ //
348  // (O)------O //
349  // or //
350  // /------O //
351  // O=======(O)-------O //
352  primstartrow = row;
353  primvtx = 1;
354  }
355  else if (row_wraps && next_row_wraps)
356  {
357  // O------\ //
358  // O-------(O)=======O //
359  // Done a curve, so call the functor.
360  functor(primnum, primstartrow, nedgecols, row+1-primstartrow, false);
361  ++primnum;
362  primvtx = 0;
363  }
364  else
365  {
366  // O------\ /------O //
367  // O-------(O)-------O //
368  // or //
369  // O-------(O)-------O //
370  // O--------O--------O //
371  // or //
372  // O-------(O)------\ //
373  // O--------O--------O //
374  // Already in a curve, so no need to call the functor.
375  ++primvtx;
376  }
377  }
378  if ((!grid.doesColWrap(nedgecols) || grid.myUnrollCurves) && (primvtx != 0))
379  {
380  // O-------(O) //
381  // O-------(O) //
382  // or //
383  // O------\ //
384  // O-------(O) //
385  // or //
386  // /------(O) //
387  // O-------(O) //
388  // Done a curve, so call the functor.
389  functor(primnum, primstartrow, nedgecols, nedgerows+1-primstartrow, false);
390  ++primnum;
391  primvtx = 0;
392  }
393  }
394  }
395  return;
396  }
397 
398  UT_ASSERT_MSG(nedgerows >= 1 && nedgecols >= 1, "Caller should have switched quads to rows or cols");
399 
400  if (!grid.myTriangularPoles)
401  {
402  if (surface_type == GEO_PATCH_QUADS)
403  {
404  // All quads: simple.
405  for (exint row = 0, primnum = 0; row < nedgerows; ++row)
406  {
407  for (exint col = 0; col < nedgecols; ++col, ++primnum)
408  {
409  functor(primnum, row, col, 4, true);
410  }
411  }
412  return;
413  }
414 
415  // All tris in the form of quads: simple.
416  for (exint row = 0, primnum = 0; row < nedgerows; ++row)
417  {
418  for (exint col = 0; col < nedgecols; ++col, primnum+=2)
419  {
420  functor(primnum, row, col, 3, true);
421  functor(primnum+1, row, col, 3, true);
422  }
423  }
424  return;
425  }
426 
427  // grid.myTriangularPoles is true, which means that any
428  // adjacent duplicate points on the boundary will result in triangles,
429  // instead of quads. The big caveat is that if there's only one edge row
430  // or only one edge column, things get messy. The smaller caveat is that if
431  // the 3 points of a corner are all the same point, there'd be a degenerate
432  // triangle that should probably be removed, so we will. To deal with
433  // both at the same time, we just deal with all boundary quads the same way.
434 
435  auto &&boundary_quad = [&grid,surface_type,&functor](exint row, exint col, exint &primnum)
436  {
437  // Single "quad", but removing degeneracies.
438 
439  INT_TYPE points[4];
440  points[0] = grid.getPoint(row, col );
441  points[1] = grid.getPoint(row, col+1);
442  points[2] = grid.getPoint(row+1, col );
443  points[3] = grid.getPoint(row+1, col+1);
444 
445  // If the diagonally opposite points are the same, degenerate.
446  if (points[0] == points[2] || points[1] == points[3])
447  return;
448 
449  const bool row0_equal = (points[0] == points[1]);
450  const bool row1_equal = (points[2] == points[3]);
451  const bool col0_equal = (points[0] == points[2]);
452  const bool col1_equal = (points[1] == points[3]);
453  // Both ends equal, so degenerate.
454  if ((row0_equal && row1_equal) || (col0_equal && col1_equal))
455  return;
456 
457  if (!row0_equal && !row1_equal && !col0_equal && !col1_equal)
458  {
459  // Just a quad
460  if (surface_type == GEO_PATCH_QUADS)
461  {
462  functor(primnum, row, col, 4, true);
463  ++primnum;
464  }
465  else
466  {
467  functor(primnum, row, col, 3, true);
468  functor(primnum+1, row, col, 3, true);
469  primnum += 2;
470  }
471  return;
472  }
473 
474  // Exactly one adjacent equal pair, so a triangle
475  functor(primnum, row, col, 3, true);
476  ++primnum;
477  };
478 
479  exint row = 0;
480  for (exint col = 0; col < nedgecols; ++col)
481  {
482  boundary_quad(row, col, primnum);
483  }
484  for (row = 1; row < nedgerows-1; ++row)
485  {
486  exint col = 0;
487  boundary_quad(row, col, primnum);
488 
489  // Interior quads (tris) as normal, ignoring any potential degeneracy.
490  if (surface_type == GEO_PATCH_QUADS)
491  {
492  for (col = 1; col < nedgecols-1; ++col, ++primnum)
493  {
494  functor(primnum, row, col, 4, true);
495  }
496  }
497  else
498  {
499  for (col = 1; col < nedgecols-1; ++col, primnum+=2)
500  {
501  functor(primnum, row, col, 3, true);
502  functor(primnum+1, row, col, 3, true);
503  }
504  }
505 
506  boundary_quad(row, col, primnum);
507  }
508  for (exint col = 0; col < nedgecols; ++col)
509  {
510  boundary_quad(row, col, primnum);
511  }
512 }
513 
514 /// This calls functor for each vertex in grid, as:
515 /// functor(vtxnum, row, col, isrowend, iscolend, primnum, primvtxnum)
516 template<typename INT_TYPE,typename FUNCTOR>
517 void GUiterateGridVertices(const GU_GridT<INT_TYPE> &grid, FUNCTOR &&functor)
518 {
519  using PrimitiveType = typename GU_GridT<INT_TYPE>::PrimitiveType;
520  if (grid.myPrimitiveType == PrimitiveType::POINTS)
521  return;
522 
523  const GEO_SurfaceType surface_type = grid.mySurfaceType;
524  const bool rows_and_cols = (surface_type == GEO_PATCH_ROWCOL);
525  const exint nedgerows = grid.myNumEdgeRows;
526  const exint nedgecols = grid.myNumEdgeCols;
527 
528  if (nedgerows < 0 || nedgecols < 0)
529  return;
530 
531  exint primnum = 0;
532  exint vtxnum = 0;
533 
534  if (grid.isInvalidTPSurf())
535  return;
536 
537  if (grid.myPrimitiveType != PrimitiveType::POLYGON)
538  {
539  // Single primitive
540  // FIXME: Support myCurvesIfBasisRowCol!
541  // "Unroll" in this case allows for UV seams.
542  // FIXME: Does this need to take into account myFirstRowIfNotWrapped,
543  // myLastRowIfNotWrapped, myFirstColIfNotWrapped, myLastColIfNotWrapped
544  // if surface_type is rows or cols or rowcol?
545  const bool has_endrow = grid.myNoWrapV || grid.myUnrollCurves;
546  const bool has_endcol = grid.myNoWrapU || grid.myUnrollCurves;
547  for (exint row = 0; row < nedgerows; ++row)
548  {
549  for (exint col = 0; col < nedgecols; ++col)
550  {
551  functor(vtxnum, row, col, false, false, primnum, vtxnum);
552  ++vtxnum;
553  }
554 
555  if (has_endcol)
556  {
557  functor(vtxnum, row, nedgecols-1, false, true, primnum, vtxnum);
558  ++vtxnum;
559  }
560  }
561 
562  if (has_endrow)
563  {
564  for (exint col = 0; col < nedgecols; ++col)
565  {
566  functor(vtxnum, nedgerows-1, col, true, false, primnum, vtxnum);
567  ++vtxnum;
568  }
569 
570  if (has_endcol)
571  {
572  functor(vtxnum, nedgerows-1, nedgecols-1, true, true, primnum, vtxnum);
573  ++vtxnum;
574  }
575  }
576 
577  return;
578  }
579 
580  // Get the special cases out of the way so that it's easier later
581  if (nedgerows == 0)
582  {
583  if (surface_type == GEO_PATCH_ROWS || rows_and_cols)
584  {
585  if (nedgecols == 0)
586  {
587  // Single vertex
588  functor(vtxnum, 0, 0, false, false, primnum, 0);
589  ++vtxnum;
590  ++primnum;
591  }
592  else
593  {
594  // Single row
595  for (exint col = 0; col < nedgecols; ++col, ++vtxnum)
596  functor(vtxnum, 0, col, false, false, primnum, col);
597 
598  if (!grid.doesRowWrap(0) || grid.myUnrollCurves)
599  {
600  // Last vertex of the curve is treated as end of last edge col.
601  functor(vtxnum, 0, nedgecols-1, false, true, primnum, nedgecols);
602  ++vtxnum;
603  }
604  ++primnum;
605  }
606  if (!rows_and_cols)
607  return;
608  }
609  if (surface_type == GEO_PATCH_COLS || rows_and_cols)
610  {
611  if (nedgecols == 0)
612  {
613  // Single vertex
614  functor(vtxnum, 0, 0, false, false, primnum, 0);
615  ++vtxnum;
616  ++primnum;
617  }
618  else
619  {
620  // Single row
621  for (exint col = 0; col < nedgecols; ++col, ++vtxnum, ++primnum)
622  functor(vtxnum, 0, col, false, false, primnum, 0);
623 
624  if (!grid.doesRowWrap(0))
625  {
626  // Last vertex of the curve is treated as end of last edge col.
627  functor(vtxnum, 0, nedgecols-1, false, true, primnum, 0);
628  ++vtxnum;
629  ++primnum;
630  }
631  }
632  }
633  // Only rows, cols, and rowcol have vertices when a single row.
634  return;
635  }
636 
637  if (nedgecols == 0)
638  {
639  if (surface_type == GEO_PATCH_ROWS || rows_and_cols)
640  {
641  // Single col
642  for (exint row = 0; row < nedgerows; ++row, ++vtxnum, ++primnum)
643  functor(vtxnum, row, 0, false, false, primnum, 0);
644 
645  if (!grid.doesColWrap(0))
646  {
647  // Last vertex of the curve is treated as end of last edge row.
648  functor(vtxnum, nedgerows-1, 0, true, false, primnum, 0);
649  ++vtxnum;
650  ++primnum;
651  }
652  if (!rows_and_cols)
653  return;
654  }
655  if (surface_type == GEO_PATCH_COLS || rows_and_cols)
656  {
657  // Single col
658  for (exint row = 0; row < nedgerows; ++row, ++vtxnum)
659  functor(vtxnum, row, 0, false, false, primnum, row);
660 
661  if (!grid.doesColWrap(0) || grid.myUnrollCurves)
662  {
663  // Last vertex of the curve is treated as end of last edge row.
664  functor(vtxnum, nedgerows-1, 0, true, false, primnum, nedgerows);
665  ++vtxnum;
666  }
667  }
668  // Only rows, cols, and rowcol have vertices when a single col.
669  return;
670  }
671 
672  // Main cases; note that nedgerows and nedgecols are both at least 1.
673 
674  if (surface_type == GEO_PATCH_ROWS || rows_and_cols)
675  {
676  exint first_row = (grid.myNoWrapV && !grid.myFirstRowIfNotWrapped);
677  for (exint row = first_row; row < nedgerows; ++row, ++primnum)
678  {
679  for (exint col = 0; col < nedgecols; ++col, ++vtxnum)
680  functor(vtxnum, row, col, false, false, primnum, col);
681 
682  if (!grid.doesRowWrap(row) || grid.myUnrollCurves)
683  {
684  // Last vertex of the curve is treated as end of last edge col.
685  functor(vtxnum, row, nedgecols-1, false, true, primnum, nedgecols);
686  ++vtxnum;
687  }
688  }
689 
690  if (!grid.myAllWrapV && grid.myLastRowIfNotWrapped)
691  {
692  exint primvtx = 0;
693  bool col_wraps = grid.doesColWrap(0);
694  bool next_col_wraps;
695  for (exint col = 0; col < nedgecols; ++col, col_wraps = next_col_wraps)
696  {
697  next_col_wraps = grid.doesColWrap(col+1);
698  bool currently_in_a_curve = (primvtx != 0);
699  if (!currently_in_a_curve)
700  {
701  if (col_wraps && next_col_wraps)
702  {
703  // If current point and next point are wrapping v,
704  // and we're not currently in a curve, skip.
705  // O=======(O)=======O
706  continue;
707  }
708 
709  // (O)------O //
710  // (O)------O //
711  // or //
712  // (O)-----\ //
713  // (O)------O //
714  // or //
715  // /------O //
716  // O=======(O)-------O //
717  functor(vtxnum, nedgerows-1, col, true, false, primnum, 0);
718  ++vtxnum;
719  primvtx = 1;
720  }
721  else if (col_wraps && next_col_wraps)
722  {
723  // O------\ //
724  // O-------(O)=======O //
725  functor(vtxnum, nedgerows-1, col, true, false, primnum, primvtx);
726  ++vtxnum;
727  ++primnum;
728  primvtx = 0;
729  }
730  else
731  {
732  // O------\ /------O //
733  // O-------(O)-------O //
734  // or //
735  // O-------(O)-------O //
736  // O--------O--------O //
737  // or //
738  // O-------(O)------\ //
739  // O--------O--------O //
740  functor(vtxnum, nedgerows-1, col, true, false, primnum, primvtx);
741  ++vtxnum;
742  ++primvtx;
743  }
744  }
745  if ((!grid.doesRowWrap(nedgerows) || grid.myUnrollCurves) && (primvtx != 0))
746  {
747  // O-------(O) //
748  // O-------(O) //
749  // or //
750  // O------\ //
751  // O-------(O) //
752  // or //
753  // /------(O) //
754  // O-------(O) //
755  functor(vtxnum, nedgerows-1, nedgecols-1, true, true, primnum, primvtx);
756  ++vtxnum;
757  ++primnum;
758  primvtx = 0;
759  }
760  }
761 
762  if (!rows_and_cols)
763  return;
764  }
765  if (surface_type == GEO_PATCH_COLS || rows_and_cols)
766  {
767  // Just like the rows case, but with rows and cols (mostly) swapped
768  exint first_col = (grid.myNoWrapU && !grid.myFirstColIfNotWrapped);
769  for (exint col = first_col; col < nedgecols; ++col, ++primnum)
770  {
771  for (exint row = 0; row < nedgerows; ++row, ++vtxnum)
772  functor(vtxnum, row, col, false, false, primnum, row);
773 
774  if (!grid.doesColWrap(col) || grid.myUnrollCurves)
775  {
776  // Last vertex of the curve is treated as end of last edge row.
777  functor(vtxnum, nedgerows-1, col, true, false, primnum, nedgerows);
778  ++vtxnum;
779  }
780  }
781 
782  if (!grid.myAllWrapU && grid.myLastColIfNotWrapped)
783  {
784  exint primvtx = 0;
785  bool row_wraps = grid.doesRowWrap(0);
786  bool next_row_wraps;
787  for (exint row = 0; row < nedgerows; ++row, row_wraps = next_row_wraps)
788  {
789  next_row_wraps = grid.doesRowWrap(row+1);
790  bool currently_in_a_curve = (primvtx != 0);
791  if (!currently_in_a_curve)
792  {
793  if (row_wraps && next_row_wraps)
794  {
795  // If current point and next point are wrapping u,
796  // and we're not currently in a curve, skip.
797  // O=======(O)=======O
798  continue;
799  }
800 
801  // (O)------O //
802  // (O)------O //
803  // or //
804  // (O)-----\ //
805  // (O)------O //
806  // or //
807  // /------O //
808  // O=======(O)-------O //
809  functor(vtxnum, row, nedgecols-1, false, true, primnum, 0);
810  ++vtxnum;
811  primvtx = 1;
812  }
813  else if (row_wraps && next_row_wraps)
814  {
815  // O------\ //
816  // O-------(O)=======O //
817  functor(vtxnum, row, nedgecols-1, false, true, primnum, primvtx);
818  ++vtxnum;
819  ++primnum;
820  primvtx = 0;
821  }
822  else
823  {
824  // O------\ /------O //
825  // O-------(O)-------O //
826  // or //
827  // O-------(O)-------O //
828  // O--------O--------O //
829  // or //
830  // O-------(O)------\ //
831  // O--------O--------O //
832  functor(vtxnum, row, nedgecols-1, false, true, primnum, primvtx);
833  ++vtxnum;
834  ++primvtx;
835  }
836  }
837  if ((!grid.doesColWrap(nedgecols) || grid.myUnrollCurves) && (primvtx != 0))
838  {
839  // O-------(O) //
840  // O-------(O) //
841  // or //
842  // O------\ //
843  // O-------(O) //
844  // or //
845  // /------(O) //
846  // O-------(O) //
847  functor(vtxnum, nedgerows-1, nedgecols-1, true, true, primnum, primvtx);
848  ++vtxnum;
849  ++primnum;
850  primvtx = 0;
851  }
852  }
853  return;
854  }
855 
856  const bool alt = (surface_type == GEO_PATCH_ALTTRIANGLE);
857  const bool rev = (surface_type == GEO_PATCH_REVTRIANGLE);
858 
859  UT_ASSERT_MSG(nedgerows >= 1 && nedgecols >= 1, "Caller should have switched quads to rows or cols");
860  if (!grid.myTriangularPoles)
861  {
862  if (surface_type == GEO_PATCH_QUADS)
863  {
864  // All quads: simple.
865  for (exint row = 0, primnum = 0; row < nedgerows; ++row)
866  {
867  for (exint col = 0; col < nedgecols; ++col, ++primnum, vtxnum+=4)
868  {
869  functor(vtxnum , row, col, false, false, primnum, 0);
870  functor(vtxnum+1, row, col, false, true, primnum, 1);
871  functor(vtxnum+2, row, col, true, true, primnum, 2);
872  functor(vtxnum+3, row, col, true, false, primnum, 3);
873  }
874  }
875  return;
876  }
877 
878  // All tris in the form of quads: simple.
879  for (exint row = 0, primnum = 0; row < nedgerows; ++row)
880  {
881  for (exint col = 0; col < nedgecols; ++col, primnum+=2, vtxnum+=6)
882  {
883  // Switch diagonal with checkerboard pattern
884  const bool switched = (rev || (alt && ((row^col)&1)));
885 
886  functor(vtxnum , row, col, false, false, primnum , 0);
887  functor(vtxnum+1, row, col, false, true, primnum , 1);
888  functor(vtxnum+2, row, col, true, !switched, primnum , 2);
889 
890  functor(vtxnum+3, row, col, false, switched, primnum+1, 0);
891  functor(vtxnum+4, row, col, true, true, primnum+1, 1);
892  functor(vtxnum+5, row, col, true, false, primnum+1, 2);
893  }
894  }
895  return;
896  }
897 
898  // grid.myTriangularPoles is true, which means that any
899  // adjacent duplicate points on the boundary will result in triangles,
900  // instead of quads. The big caveat is that if there's only one edge row
901  // or only one edge column, things get messy. The smaller caveat is that if
902  // the 3 points of a corner are all the same point, there'd be a degenerate
903  // triangle that should probably be removed, so we will. To deal with
904  // both at the same time, we just deal with all boundary quads the same way.
905 
906  auto &&boundary_quad = [&grid,surface_type,&functor,rev,alt](exint &vtxnum, exint row, exint col, exint &primnum)
907  {
908  // Single "quad", but removing degeneracies.
909 
910  INT_TYPE points[4];
911  points[0] = grid.getPoint(row, col );
912  points[1] = grid.getPoint(row, col+1);
913  points[2] = grid.getPoint(row+1, col );
914  points[3] = grid.getPoint(row+1, col+1);
915 
916  // If the diagonally opposite points are the same, degenerate.
917  if (points[0] == points[2] || points[1] == points[3])
918  return;
919 
920  const bool row0_equal = (points[0] == points[1]);
921  const bool row1_equal = (points[2] == points[3]);
922  const bool col0_equal = (points[0] == points[2]);
923  const bool col1_equal = (points[1] == points[3]);
924  // Both ends equal, so degenerate.
925  if ((row0_equal && row1_equal) || (col0_equal && col1_equal))
926  return;
927 
928  if (!row0_equal && !row1_equal && !col0_equal && !col1_equal)
929  {
930  // Just a quad
931  if (surface_type == GEO_PATCH_QUADS)
932  {
933  functor(vtxnum , row, col, false, false, primnum, 0);
934  functor(vtxnum+1, row, col, false, true, primnum, 1);
935  functor(vtxnum+2, row, col, true, true, primnum, 2);
936  functor(vtxnum+3, row, col, true, false, primnum, 3);
937  ++primnum;
938  vtxnum += 4;
939  }
940  else
941  {
942  // Switch diagonal with checkerboard pattern
943  const bool switched = (rev || (alt && ((row^col)&1)));
944 
945  functor(vtxnum , row, col, false, false, primnum , 0);
946  functor(vtxnum+1, row, col, false, true, primnum , 1);
947  functor(vtxnum+2, row, col, true, !switched, primnum , 2);
948 
949  functor(vtxnum+3, row, col, false, switched, primnum+1, 0);
950  functor(vtxnum+4, row, col, true, true, primnum+1, 1);
951  functor(vtxnum+5, row, col, true, false, primnum+1, 2);
952  primnum += 2;
953  vtxnum += 6;
954  }
955  return;
956  }
957 
958  // Exactly one adjacent equal pair, so a triangle
959  functor(vtxnum, row, col, false, false, primnum, vtxnum);
960  ++vtxnum;
961  if (!row0_equal)
962  {
963  functor(vtxnum, row, col, false, true, primnum, vtxnum);
964  ++vtxnum;
965  }
966  if (!row1_equal && !col1_equal)
967  {
968  functor(vtxnum, row, col, true, true, primnum, vtxnum);
969  ++vtxnum;
970  }
971  if (!col0_equal)
972  {
973  functor(vtxnum, row, col, true, false, primnum, vtxnum);
974  ++vtxnum;
975  }
976  ++primnum;
977  };
978 
979  exint row = 0;
980  for (exint col = 0; col < nedgecols; ++col)
981  {
982  boundary_quad(vtxnum, row, col, primnum);
983  }
984  for (row = 1; row < nedgerows-1; ++row)
985  {
986  exint col = 0;
987  boundary_quad(vtxnum, row, col, primnum);
988 
989  // Interior quads (tris) as normal, ignoring any potential degeneracy.
990  if (surface_type == GEO_PATCH_QUADS)
991  {
992  for (col = 1; col < nedgecols-1; ++col, ++primnum, vtxnum+=4)
993  {
994  functor(vtxnum , row, col, false, false, primnum, 0);
995  functor(vtxnum+1, row, col, false, true, primnum, 1);
996  functor(vtxnum+2, row, col, true, true, primnum, 2);
997  functor(vtxnum+3, row, col, true, false, primnum, 3);
998  }
999  }
1000  else
1001  {
1002  for (col = 1; col < nedgecols-1; ++col, primnum+=2, vtxnum+=6)
1003  {
1004  // Switch diagonal with checkerboard pattern
1005  const bool switched = (rev || (alt && ((row^col)&1)));
1006 
1007  functor(vtxnum , row, col, false, false, primnum , 0);
1008  functor(vtxnum+1, row, col, false, true, primnum , 1);
1009  functor(vtxnum+2, row, col, true, !switched, primnum , 2);
1010 
1011  functor(vtxnum+3, row, col, false, switched, primnum+1, 0);
1012  functor(vtxnum+4, row, col, true, true, primnum+1, 1);
1013  functor(vtxnum+5, row, col, true, false, primnum+1, 2);
1014  }
1015  }
1016 
1017  boundary_quad(vtxnum, row, col, primnum);
1018  }
1019  for (exint col = 0; col < nedgecols; ++col)
1020  {
1021  boundary_quad(vtxnum, row, col, primnum);
1022  }
1023 }
1024 
1025 template<typename INT_TYPE>
1027 {
1028  const exint nedgerows = myNumEdgeRows;
1029  const exint nedgecols = myNumEdgeCols;
1030  if (nedgerows < 0 || nedgecols < 0 || (nedgerows == 0 && nedgecols == 0))
1031  {
1032  myNoWrapU = true;
1033  myNoWrapV = true;
1034  myAllWrapU = false;
1035  myAllWrapV = false;
1036  return;
1037  }
1038  if (nedgerows == 0)
1039  {
1040  const bool wrapu = (myCorners[0] == myCorners[1]);
1041  myNoWrapU = !wrapu;
1042  myNoWrapV = true;
1043  myAllWrapU = wrapu;
1044  myAllWrapV = false;
1045  return;
1046  }
1047  if (nedgecols == 0)
1048  {
1049  const bool wrapv = (myCorners[0] == myCorners[2]);
1050  myNoWrapU = true;
1051  myNoWrapV = !wrapv;
1052  myAllWrapU = false;
1053  myAllWrapV = wrapv;
1054  return;
1055  }
1056 
1057  bool wrapu0 = (myCorners[0] == myCorners[1]);
1058  bool wrapu1 = (myCorners[2] == myCorners[3]);
1059  bool has_wrapu = wrapu0 || wrapu1;
1060  bool has_notwrapu = !wrapu0 || !wrapu1;
1061 
1062  bool wrapv0 = (myCorners[0] == myCorners[2]);
1063  bool wrapv1 = (myCorners[1] == myCorners[3]);
1064  bool has_wrapv = wrapv0 || wrapv1;
1065  bool has_notwrapv = !wrapv0 || !wrapv1;
1066 
1067  if ((myCol0Start < INT_TYPE(0)) || (myCol1Start < INT_TYPE(0)) || (myCol0Step != myCol1Step))
1068  {
1069  // Uncommon case: iterate to check.
1070  for (exint rowm1 = 0; rowm1 < nedgerows-1; ++rowm1)
1071  {
1072  INT_TYPE pt0 = (myCol0Start < INT_TYPE(0)) ? myCol0Array[rowm1] : (myCol0Start + myCol0Step*rowm1);
1073  INT_TYPE pt1 = (myCol1Start < INT_TYPE(0)) ? myCol1Array[rowm1] : (myCol1Start + myCol1Step*rowm1);
1074  bool wrapu = (pt0 == pt1);
1075  has_wrapu |= wrapu;
1076  has_notwrapu |= !wrapu;
1077  }
1078  }
1079  else
1080  {
1081  // Common case: uniform step.
1082  bool wrapu = (myCol0Start == myCol1Start);
1083  has_wrapu |= wrapu;
1084  has_notwrapu |= !wrapu;
1085  }
1086 
1087  if ((myRow0Start < INT_TYPE(0)) || (myRow1Start < INT_TYPE(0)) || (myRow0Step != myRow1Step))
1088  {
1089  // Uncommon case: iterate to check.
1090  for (exint colm1 = 0; colm1 < nedgecols-1; ++colm1)
1091  {
1092  INT_TYPE pt0 = (myRow0Start < INT_TYPE(0)) ? myRow0Array[colm1] : (myRow0Start + myRow0Step*colm1);
1093  INT_TYPE pt1 = (myRow1Start < INT_TYPE(0)) ? myRow1Array[colm1] : (myRow1Start + myRow1Step*colm1);
1094  bool wrapv = (pt0 == pt1);
1095  has_wrapv |= wrapv;
1096  has_notwrapv |= !wrapv;
1097  }
1098  }
1099  else
1100  {
1101  // Common case: uniform step.
1102  bool wrapv = (myRow0Start == myRow1Start);
1103  has_wrapv |= wrapv;
1104  has_notwrapv |= !wrapv;
1105  }
1106 
1107  myAllWrapU = !has_notwrapu;
1108  myAllWrapV = !has_notwrapv;
1109  myNoWrapU = !has_wrapu;
1110  myNoWrapV = !has_wrapv;
1111 }
1112 
1113 template<typename INT_TYPE>
1115  exint nedgerows, exint nedgecols, INT_TYPE start_pt)
1116 {
1117  clear();
1118 
1119  myNumEdgeRows = nedgerows;
1120  myNumEdgeCols = nedgecols;
1121 
1122  myAllWrapU = false;
1123  myAllWrapV = false;
1124  myNoWrapU = true;
1125  myNoWrapV = true;
1126 
1127  fixTPSurf();
1128 
1129  myCorners[0] = start_pt;
1130  myCorners[1] = start_pt + nedgecols;
1131  myCorners[2] = start_pt + nedgerows*(nedgecols+1);
1132  myCorners[3] = start_pt + nedgerows*(nedgecols+1) + nedgecols;
1133 
1134  myRow0Step = INT_TYPE(1);
1135  myRow0Start = myCorners[0]+myRow0Step;
1136  myRow1Step = INT_TYPE(1);
1137  myRow1Start = myCorners[2]+myRow1Step;
1138 
1139  myCol0Step = INT_TYPE(nedgecols+1);
1140  myCol0Start = myCorners[0]+myCol0Step;
1141  myCol1Step = INT_TYPE(nedgecols+1);
1142  myCol1Start = myCorners[1]+myCol1Step;
1143 
1144  myMiddleStart = myCol0Start+1;
1145  myMiddleColStep = myRow0Step;
1146  myMiddleRowStep = myCol0Step;
1147 
1148  if (myPrimitiveType == PrimitiveType::POINTS)
1149  {
1150  myNumPrimitives = 0;
1151  myNumVertices = 0;
1152  return;
1153  }
1154 
1155  if (myPrimitiveType != PrimitiveType::POLYGON)
1156  {
1157  // Single primitive
1158  myNumPrimitives = 1;
1159 
1160  // FIXME: Support myCurvesIfBasisRowCol!
1161 
1162  // FIXME: Does this need to take into account myFirstRowIfNotWrapped,
1163  // myLastRowIfNotWrapped, myFirstColIfNotWrapped, myLastColIfNotWrapped
1164  // if surface_type is rows or cols or rowcol?
1165  const bool has_endrow = myNoWrapV || myUnrollCurves;
1166  const bool has_endcol = myNoWrapU || myUnrollCurves;
1167  const exint nvtxrows = myNumEdgeRows + exint(has_endrow);
1168  const exint nvtxcols = myNumEdgeCols + exint(has_endcol);
1169  myNumVertices = nvtxrows*nvtxcols;
1170  return;
1171  }
1172 
1173  if (mySurfaceType == GEO_PATCH_QUADS)
1174  {
1175  myNumPrimitives = myNumEdgeRows*myNumEdgeCols;
1176  myNumVertices = 4*myNumPrimitives;
1177  return;
1178  }
1179 
1180  // Initialize to zero, so that cols and rowcol case can use +=
1181  myNumPrimitives = 0;
1182  myNumVertices = 0;
1183  if (mySurfaceType == GEO_PATCH_ROWS || mySurfaceType == GEO_PATCH_ROWCOL)
1184  {
1185  myNumPrimitives = myNumEdgeRows-1 + exint(myFirstRowIfNotWrapped) + exint(myLastRowIfNotWrapped);
1186  myNumVertices = myNumPrimitives*(myNumEdgeCols+1);
1187  if (mySurfaceType != GEO_PATCH_ROWCOL)
1188  return;
1189  }
1190  if (mySurfaceType == GEO_PATCH_COLS || mySurfaceType == GEO_PATCH_ROWCOL)
1191  {
1192  exint col_polys = myNumEdgeCols-1 + exint(myFirstColIfNotWrapped) + exint(myLastColIfNotWrapped);
1193  myNumPrimitives += col_polys;
1194  myNumVertices += col_polys*(myNumEdgeRows+1);
1195  return;
1196  }
1197 
1198  // Triangles
1199  myNumPrimitives = 2*myNumEdgeRows*myNumEdgeCols;
1200  myNumVertices = 3*myNumPrimitives;
1201 }
1202 
1203 template<typename INT_TYPE>
1205  exint nedgerows, exint nedgecols, INT_TYPE start_pt)
1206 {
1207  clear();
1208 
1209  myNumEdgeRows = nedgerows;
1210  myNumEdgeCols = nedgecols;
1211 
1212  myAllWrapU = true;
1213  myAllWrapV = false;
1214  myNoWrapU = false;
1215  myNoWrapV = true;
1216 
1217  fixTPSurf();
1218 
1219  myCorners[0] = start_pt;
1220  myCorners[1] = myCorners[0];
1221  myCorners[2] = start_pt + nedgerows*nedgecols;
1222  myCorners[3] = myCorners[2];
1223 
1224  myRow0Step = INT_TYPE(1);
1225  myRow0Start = myCorners[0]+myRow0Step;
1226  myRow1Step = INT_TYPE(1);
1227  myRow1Start = myCorners[2]+myRow1Step;
1228 
1229  myCol0Step = INT_TYPE(nedgecols);
1230  myCol0Start = myCorners[0]+myCol0Step;
1231  myCol1Step = INT_TYPE(nedgecols);
1232  myCol1Start = myCorners[1]+myCol1Step;
1233 
1234  myMiddleStart = myCol0Start+1;
1235  myMiddleColStep = myRow0Step;
1236  myMiddleRowStep = myCol0Step;
1237 
1238  if (myPrimitiveType == PrimitiveType::POINTS)
1239  {
1240  myNumPrimitives = 0;
1241  myNumVertices = 0;
1242  return;
1243  }
1244 
1245  if (myPrimitiveType != PrimitiveType::POLYGON)
1246  {
1247  // Single primitive
1248  myNumPrimitives = 1;
1249 
1250  // FIXME: Support myCurvesIfBasisRowCol!
1251 
1252  // FIXME: Does this need to take into account myFirstRowIfNotWrapped,
1253  // myLastRowIfNotWrapped, myFirstColIfNotWrapped, myLastColIfNotWrapped
1254  // if surface_type is rows or cols or rowcol?
1255  const bool has_endrow = myNoWrapV || myUnrollCurves;
1256  const bool has_endcol = myNoWrapU || myUnrollCurves;
1257  const exint nvtxrows = myNumEdgeRows + exint(has_endrow);
1258  const exint nvtxcols = myNumEdgeCols + exint(has_endcol);
1259  myNumVertices = nvtxrows*nvtxcols;
1260  return;
1261  }
1262 
1263  if (mySurfaceType == GEO_PATCH_QUADS)
1264  {
1265  myNumPrimitives = myNumEdgeRows*myNumEdgeCols;
1266  myNumVertices = 4*myNumPrimitives;
1267  return;
1268  }
1269 
1270  // Initialize to zero, so that cols and rowcol case can use +=
1271  myNumPrimitives = 0;
1272  myNumVertices = 0;
1273  if (mySurfaceType == GEO_PATCH_ROWS || mySurfaceType == GEO_PATCH_ROWCOL)
1274  {
1275  myNumPrimitives = myNumEdgeRows-1 + exint(myFirstRowIfNotWrapped) + exint(myLastRowIfNotWrapped);
1276  myNumVertices = myNumPrimitives*(myNumEdgeCols+myUnrollCurves);
1277  if (mySurfaceType != GEO_PATCH_ROWCOL)
1278  return;
1279  }
1280  if (mySurfaceType == GEO_PATCH_COLS || mySurfaceType == GEO_PATCH_ROWCOL)
1281  {
1282  myNumPrimitives += myNumEdgeCols;
1283  myNumVertices += myNumEdgeCols*(myNumEdgeRows+1);
1284  return;
1285  }
1286 
1287  // Triangles
1288  myNumPrimitives = 2*myNumEdgeRows*myNumEdgeCols;
1289  myNumVertices = 3*myNumPrimitives;
1290 }
1291 
1292 template<typename INT_TYPE>
1294  exint nedgerows, exint nedgecols, INT_TYPE start_pt)
1295 {
1296  clear();
1297 
1298  myNumEdgeRows = nedgerows;
1299  myNumEdgeCols = nedgecols;
1300 
1301  myAllWrapU = false;
1302  myAllWrapV = true;
1303  myNoWrapU = true;
1304  myNoWrapV = false;
1305 
1306  fixTPSurf();
1307 
1308  myCorners[0] = start_pt;
1309  myCorners[1] = start_pt + nedgecols;
1310  myCorners[2] = myCorners[0];
1311  myCorners[3] = myCorners[1];
1312 
1313  myRow0Step = INT_TYPE(1);
1314  myRow0Start = myCorners[0]+myRow0Step;
1315  myRow1Step = INT_TYPE(1);
1316  myRow1Start = myCorners[2]+myRow1Step;
1317 
1318  myCol0Step = INT_TYPE(nedgecols+1);
1319  myCol0Start = myCorners[0]+myCol0Step;
1320  myCol1Step = INT_TYPE(nedgecols+1);
1321  myCol1Start = myCorners[1]+myCol1Step;
1322 
1323  myMiddleStart = myCol0Start+1;
1324  myMiddleColStep = myRow0Step;
1325  myMiddleRowStep = myCol0Step;
1326 
1327  if (myPrimitiveType == PrimitiveType::POINTS)
1328  {
1329  myNumPrimitives = 0;
1330  myNumVertices = 0;
1331  return;
1332  }
1333 
1334  if (myPrimitiveType != PrimitiveType::POLYGON)
1335  {
1336  // Single primitive
1337  myNumPrimitives = 1;
1338 
1339  // FIXME: Support myCurvesIfBasisRowCol!
1340 
1341  // FIXME: Does this need to take into account myFirstRowIfNotWrapped,
1342  // myLastRowIfNotWrapped, myFirstColIfNotWrapped, myLastColIfNotWrapped
1343  // if surface_type is rows or cols or rowcol?
1344  const bool has_endrow = myNoWrapV || myUnrollCurves;
1345  const bool has_endcol = myNoWrapU || myUnrollCurves;
1346  const exint nvtxrows = myNumEdgeRows + exint(has_endrow);
1347  const exint nvtxcols = myNumEdgeCols + exint(has_endcol);
1348  myNumVertices = nvtxrows*nvtxcols;
1349  return;
1350  }
1351 
1352  if (mySurfaceType == GEO_PATCH_QUADS)
1353  {
1354  myNumPrimitives = myNumEdgeRows*myNumEdgeCols;
1355  myNumVertices = 4*myNumPrimitives;
1356  return;
1357  }
1358 
1359  // Initialize to zero, so that cols and rowcol case can use +=
1360  myNumPrimitives = 0;
1361  myNumVertices = 0;
1362  if (mySurfaceType == GEO_PATCH_ROWS || mySurfaceType == GEO_PATCH_ROWCOL)
1363  {
1364  myNumPrimitives = myNumEdgeRows;
1365  myNumVertices = myNumPrimitives*(myNumEdgeCols+1);
1366  if (mySurfaceType != GEO_PATCH_ROWCOL)
1367  return;
1368  }
1369  if (mySurfaceType == GEO_PATCH_COLS || mySurfaceType == GEO_PATCH_ROWCOL)
1370  {
1371  exint col_polys = myNumEdgeCols-1 + exint(myFirstColIfNotWrapped) + exint(myLastColIfNotWrapped);
1372  myNumPrimitives += col_polys;
1373  myNumVertices += col_polys*(myNumEdgeRows+myUnrollCurves);
1374  return;
1375  }
1376 
1377  // Triangles
1378  myNumPrimitives = 2*myNumEdgeRows*myNumEdgeCols;
1379  myNumVertices = 3*myNumPrimitives;
1380 }
1381 
1382 template<typename INT_TYPE>
1384  exint nedgerows, exint nedgecols,
1385  INT_TYPE start_pt, INT_TYPE end_pt, INT_TYPE start_mid_pt)
1386 {
1387  clear();
1388 
1389  myNumEdgeRows = nedgerows;
1390  myNumEdgeCols = nedgecols;
1391 
1392  myAllWrapU = true;
1393  myAllWrapV = false;
1394  myNoWrapU = false;
1395  myNoWrapV = true;
1396 
1397  fixTPSurf();
1398 
1399  myCorners[0] = start_pt;
1400  myCorners[1] = myCorners[0];
1401  myCorners[2] = end_pt;
1402  myCorners[3] = myCorners[2];
1403 
1404  myRow0Step = INT_TYPE(0);
1405  myRow0Start = start_pt;
1406  myRow1Step = INT_TYPE(0);
1407  myRow1Start = end_pt;
1408 
1409  myCol0Step = INT_TYPE(nedgecols);
1410  myCol0Start = start_mid_pt;
1411  myCol1Step = INT_TYPE(nedgecols);
1412  myCol1Start = start_mid_pt;
1413 
1414  myMiddleStart = myCol0Start+1;
1415  myMiddleColStep = INT_TYPE(1);
1416  myMiddleRowStep = INT_TYPE(nedgecols);
1417 
1418  if (myPrimitiveType == PrimitiveType::POINTS)
1419  {
1420  myNumPrimitives = 0;
1421  myNumVertices = 0;
1422  return;
1423  }
1424 
1425  if (myPrimitiveType != PrimitiveType::POLYGON)
1426  {
1427  // Single primitive
1428  myNumPrimitives = 1;
1429 
1430  // FIXME: Support myCurvesIfBasisRowCol!
1431 
1432  // FIXME: Does this need to take into account myFirstRowIfNotWrapped,
1433  // myLastRowIfNotWrapped, myFirstColIfNotWrapped, myLastColIfNotWrapped
1434  // if surface_type is rows or cols or rowcol?
1435  const bool has_endrow = myNoWrapV || myUnrollCurves;
1436  const bool has_endcol = myNoWrapU || myUnrollCurves;
1437  const exint nvtxrows = myNumEdgeRows + exint(has_endrow);
1438  const exint nvtxcols = myNumEdgeCols + exint(has_endcol);
1439  myNumVertices = nvtxrows*nvtxcols;
1440  return;
1441  }
1442 
1443  if (mySurfaceType == GEO_PATCH_QUADS)
1444  {
1445  myNumPrimitives = myNumEdgeRows*myNumEdgeCols;
1446  myNumVertices = 4*myNumPrimitives - (myTriangularPoles ? 2*myNumEdgeCols : 0);
1447  return;
1448  }
1449 
1450  // Initialize to zero, so that cols and rowcol case can use +=
1451  myNumPrimitives = 0;
1452  myNumVertices = 0;
1453  if (mySurfaceType == GEO_PATCH_ROWS || mySurfaceType == GEO_PATCH_ROWCOL)
1454  {
1455  const exint rowprims = myNumEdgeRows-1 + exint(myFirstRowIfNotWrapped) + exint(myLastRowIfNotWrapped);
1456  myNumPrimitives = rowprims;
1457  myNumVertices = rowprims*(myNumEdgeCols+myUnrollCurves);
1458  if (mySurfaceType != GEO_PATCH_ROWCOL)
1459  return;
1460  }
1461  if (mySurfaceType == GEO_PATCH_COLS || mySurfaceType == GEO_PATCH_ROWCOL)
1462  {
1463  myNumPrimitives += myNumEdgeCols;
1464  myNumVertices += myNumEdgeCols*(myNumEdgeRows+1);
1465  return;
1466  }
1467 
1468  // Triangles
1469  myNumPrimitives = (myNumEdgeRows - exint(myTriangularPoles))*2*myNumEdgeCols;
1470  myNumVertices = 3*myNumPrimitives;
1471 }
1472 
1473 template<typename INT_TYPE>
1475  exint nedgerows, exint nedgecols,
1476  INT_TYPE start_pt, INT_TYPE end_pt, INT_TYPE start_mid_pt)
1477 {
1478  clear();
1479 
1480  myNumEdgeRows = nedgerows;
1481  myNumEdgeCols = nedgecols;
1482 
1483  myAllWrapU = false;
1484  myAllWrapV = true;
1485  myNoWrapU = true;
1486  myNoWrapV = false;
1487 
1488  fixTPSurf();
1489 
1490  myCorners[0] = start_pt;
1491  myCorners[1] = end_pt;
1492  myCorners[2] = start_pt;
1493  myCorners[3] = end_pt;
1494 
1495  myRow0Step = INT_TYPE(1);
1496  myRow0Start = start_mid_pt;
1497  myRow1Step = INT_TYPE(1);
1498  myRow1Start = start_mid_pt;
1499 
1500  myCol0Step = INT_TYPE(0);
1501  myCol0Start = start_pt;
1502  myCol1Step = INT_TYPE(0);
1503  myCol1Start = end_pt;
1504 
1505  myMiddleStart = myRow0Start+nedgecols-1;
1506  myMiddleColStep = INT_TYPE(1);
1507  myMiddleRowStep = INT_TYPE(nedgecols-1);
1508 
1509  if (myPrimitiveType == PrimitiveType::POINTS)
1510  {
1511  myNumPrimitives = 0;
1512  myNumVertices = 0;
1513  return;
1514  }
1515 
1516  if (myPrimitiveType != PrimitiveType::POLYGON)
1517  {
1518  // Single primitive
1519  myNumPrimitives = 1;
1520 
1521  // FIXME: Support myCurvesIfBasisRowCol!
1522 
1523  // FIXME: Does this need to take into account myFirstRowIfNotWrapped,
1524  // myLastRowIfNotWrapped, myFirstColIfNotWrapped, myLastColIfNotWrapped
1525  // if surface_type is rows or cols or rowcol?
1526  const bool has_endrow = myNoWrapV || myUnrollCurves;
1527  const bool has_endcol = myNoWrapU || myUnrollCurves;
1528  const exint nvtxrows = myNumEdgeRows + exint(has_endrow);
1529  const exint nvtxcols = myNumEdgeCols + exint(has_endcol);
1530  myNumVertices = nvtxrows*nvtxcols;
1531  return;
1532  }
1533 
1534  if (mySurfaceType == GEO_PATCH_QUADS)
1535  {
1536  myNumPrimitives = myNumEdgeRows*myNumEdgeCols;
1537  myNumVertices = 4*myNumPrimitives - (myTriangularPoles ? 2*myNumEdgeRows : 0);
1538  return;
1539  }
1540 
1541  // Initialize to zero, so that cols and rowcol case can use +=
1542  myNumPrimitives = 0;
1543  myNumVertices = 0;
1544  if (mySurfaceType == GEO_PATCH_ROWS || mySurfaceType == GEO_PATCH_ROWCOL)
1545  {
1546  myNumPrimitives = myNumEdgeRows;
1547  myNumVertices = myNumEdgeRows*(myNumEdgeCols+1);
1548  if (mySurfaceType != GEO_PATCH_ROWCOL)
1549  return;
1550  }
1551  if (mySurfaceType == GEO_PATCH_COLS || mySurfaceType == GEO_PATCH_ROWCOL)
1552  {
1553  const exint colprims = myNumEdgeCols-1 + exint(myFirstColIfNotWrapped) + exint(myLastColIfNotWrapped);
1554  myNumPrimitives += colprims;
1555  myNumVertices += colprims*(myNumEdgeRows+myUnrollCurves);
1556  return;
1557  }
1558 
1559  // Triangles
1560  myNumPrimitives = myNumEdgeRows*2*(myNumEdgeCols - exint(myTriangularPoles));
1561  myNumVertices = 3*myNumPrimitives;
1562 }
1563 
1564 template<typename INT_TYPE>
1566  exint nedgerows, exint nedgecols,
1567  INT_TYPE start_pt, INT_TYPE end_pt, INT_TYPE start_mid_pt)
1568 {
1569  clear();
1570 
1571  myNumEdgeRows = nedgerows;
1572  myNumEdgeCols = nedgecols;
1573 
1574  myAllWrapU = false;
1575  myAllWrapV = false;
1576  myNoWrapU = true;
1577  myNoWrapV = true;
1578 
1579  fixTPSurf();
1580 
1581  myCorners[0] = start_pt;
1582  myCorners[1] = myCorners[0];
1583  myCorners[2] = end_pt;
1584  myCorners[3] = myCorners[2];
1585 
1586  myRow0Step = INT_TYPE(0);
1587  myRow0Start = start_pt;
1588  myRow1Step = INT_TYPE(0);
1589  myRow1Start = end_pt;
1590 
1591  myCol0Step = INT_TYPE(nedgecols+1);
1592  myCol0Start = start_mid_pt;
1593  myCol1Step = INT_TYPE(nedgecols+1);
1594  myCol1Start = start_mid_pt+nedgecols;
1595 
1596  myMiddleStart = myCol0Start+1;
1597  myMiddleColStep = INT_TYPE(1);
1598  myMiddleRowStep = INT_TYPE(nedgecols+1);
1599 
1600  if (myPrimitiveType == PrimitiveType::POINTS)
1601  {
1602  myNumPrimitives = 0;
1603  myNumVertices = 0;
1604  return;
1605  }
1606 
1607  if (myPrimitiveType != PrimitiveType::POLYGON)
1608  {
1609  // Single primitive
1610  myNumPrimitives = 1;
1611 
1612  // FIXME: Support myCurvesIfBasisRowCol!
1613 
1614  // FIXME: Does this need to take into account myFirstRowIfNotWrapped,
1615  // myLastRowIfNotWrapped, myFirstColIfNotWrapped, myLastColIfNotWrapped
1616  // if surface_type is rows or cols or rowcol?
1617  const bool has_endrow = myNoWrapV || myUnrollCurves;
1618  const bool has_endcol = myNoWrapU || myUnrollCurves;
1619  const exint nvtxrows = myNumEdgeRows + exint(has_endrow);
1620  const exint nvtxcols = myNumEdgeCols + exint(has_endcol);
1621  myNumVertices = nvtxrows*nvtxcols;
1622  return;
1623  }
1624 
1625  if (mySurfaceType == GEO_PATCH_QUADS)
1626  {
1627  myNumPrimitives = myNumEdgeRows*myNumEdgeCols;
1628  myNumVertices = 4*myNumPrimitives - (myTriangularPoles ? 2*myNumEdgeCols : 0);
1629  return;
1630  }
1631 
1632  // Initialize to zero, so that cols and rowcol case can use +=
1633  myNumPrimitives = 0;
1634  myNumVertices = 0;
1635  if (mySurfaceType == GEO_PATCH_ROWS || mySurfaceType == GEO_PATCH_ROWCOL)
1636  {
1637  const exint rowprims = myNumEdgeRows-1 + exint(myFirstRowIfNotWrapped) + exint(myLastRowIfNotWrapped);
1638  myNumPrimitives = rowprims;
1639  myNumVertices = rowprims*(myNumEdgeCols+1);
1640  if (mySurfaceType != GEO_PATCH_ROWCOL)
1641  return;
1642  }
1643  if (mySurfaceType == GEO_PATCH_COLS || mySurfaceType == GEO_PATCH_ROWCOL)
1644  {
1645  myNumPrimitives += myNumEdgeCols-1 + exint(myFirstColIfNotWrapped) + exint(myLastColIfNotWrapped);
1646  myNumVertices += (myNumEdgeCols+1)*(myNumEdgeRows+1);
1647  return;
1648  }
1649 
1650  // Triangles
1651  myNumPrimitives = (myNumEdgeRows - exint(myTriangularPoles))*2*myNumEdgeCols;
1652  myNumVertices = 3*myNumPrimitives;
1653 }
1654 
1655 template<typename INT_TYPE>
1657  exint nedgerows, exint nedgecols, INT_TYPE start_pt)
1658 {
1659  clear();
1660 
1661  myNumEdgeRows = nedgerows;
1662  myNumEdgeCols = nedgecols;
1663 
1664  myAllWrapU = true;
1665  myAllWrapV = true;
1666  myNoWrapU = false;
1667  myNoWrapV = false;
1668 
1669  fixTPSurf();
1670 
1671  myCorners[0] = start_pt;
1672  myCorners[1] = start_pt;
1673  myCorners[2] = start_pt;
1674  myCorners[3] = start_pt;
1675 
1676  myRow0Step = INT_TYPE(1);
1677  myRow0Start = myCorners[0]+myRow0Step;
1678  myRow1Step = INT_TYPE(1);
1679  myRow1Start = myCorners[2]+myRow1Step;
1680 
1681  myCol0Step = INT_TYPE(nedgecols);
1682  myCol0Start = myCorners[0]+myCol0Step;
1683  myCol1Step = INT_TYPE(nedgecols);
1684  myCol1Start = myCorners[1]+myCol1Step;
1685 
1686  myMiddleStart = myCol0Start+1;
1687  myMiddleColStep = myRow0Step;
1688  myMiddleRowStep = myCol0Step;
1689 
1690  if (myPrimitiveType == PrimitiveType::POINTS)
1691  {
1692  myNumPrimitives = 0;
1693  myNumVertices = 0;
1694  return;
1695  }
1696 
1697  if (myPrimitiveType != PrimitiveType::POLYGON)
1698  {
1699  // Single primitive
1700  myNumPrimitives = 1;
1701 
1702  // FIXME: Support myCurvesIfBasisRowCol!
1703 
1704  // FIXME: Does this need to take into account myFirstRowIfNotWrapped,
1705  // myLastRowIfNotWrapped, myFirstColIfNotWrapped, myLastColIfNotWrapped
1706  // if surface_type is rows or cols or rowcol?
1707  const bool has_endrow = myNoWrapV || myUnrollCurves;
1708  const bool has_endcol = myNoWrapU || myUnrollCurves;
1709  const exint nvtxrows = myNumEdgeRows + exint(has_endrow);
1710  const exint nvtxcols = myNumEdgeCols + exint(has_endcol);
1711  myNumVertices = nvtxrows*nvtxcols;
1712  return;
1713  }
1714 
1715  if (mySurfaceType == GEO_PATCH_QUADS)
1716  {
1717  myNumPrimitives = myNumEdgeRows*myNumEdgeCols;
1718  myNumVertices = 4*myNumPrimitives;
1719  return;
1720  }
1721 
1722  // Initialize to zero, so that cols and rowcol case can use +=
1723  myNumPrimitives = 0;
1724  myNumVertices = 0;
1725  if (mySurfaceType == GEO_PATCH_ROWS || mySurfaceType == GEO_PATCH_ROWCOL)
1726  {
1727  myNumPrimitives = myNumEdgeRows;
1728  myNumVertices = myNumPrimitives*(myNumEdgeCols+myUnrollCurves);
1729  if (mySurfaceType != GEO_PATCH_ROWCOL)
1730  return;
1731  }
1732  if (mySurfaceType == GEO_PATCH_COLS || mySurfaceType == GEO_PATCH_ROWCOL)
1733  {
1734  myNumPrimitives += myNumEdgeCols;
1735  myNumVertices += myNumEdgeCols*(myNumEdgeRows+myUnrollCurves);
1736  return;
1737  }
1738 
1739  // Triangles
1740  myNumPrimitives = 2*myNumEdgeRows*myNumEdgeCols;
1741  myNumVertices = 3*myNumPrimitives;
1742 }
1743 
1744 } // End of HDK_Sample namespace
INT_TYPE getPoint(exint row, exint col) const
Definition: GU_Grid.h:272
void initTorus(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0))
Definition: GU_GridImpl.h:1656
GLdouble GLdouble GLint GLint const GLdouble * points
Definition: glad.h:2676
PrimitiveType myPrimitiveType
Definition: GU_Grid.h:90
GEO_SurfaceType mySurfaceType
Definition: GU_Grid.h:79
int64 exint
Definition: SYS_Types.h:125
void initSplitColSphere(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0), INT_TYPE end_pt=INT_TYPE(1), INT_TYPE start_mid_pt=INT_TYPE(2))
Definition: GU_GridImpl.h:1565
bool myFirstColIfNotWrapped
Definition: GU_Grid.h:117
bool doesColWrap(exint col) const
Definition: GU_Grid.h:315
void initColSphere(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0), INT_TYPE end_pt=INT_TYPE(1), INT_TYPE start_mid_pt=INT_TYPE(2))
Definition: GU_GridImpl.h:1383
#define UT_ASSERT_MSG(ZZ,...)
Definition: UT_Assert.h:159
void GUiterateGridVertices(const GU_GridT< INT_TYPE > &grid, FUNCTOR &&functor)
Definition: GU_GridImpl.h:517
void initRowTube(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0))
Definition: GU_GridImpl.h:1293
void initRowSphere(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0), INT_TYPE end_pt=INT_TYPE(1), INT_TYPE start_mid_pt=INT_TYPE(2))
Definition: GU_GridImpl.h:1474
void initSingleGrid(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0))
Definition: GU_GridImpl.h:1114
bool myLastRowIfNotWrapped
Definition: GU_Grid.h:112
PrimitiveType myPrimitiveType
Definition: SOP_SweepHDK.C:298
void initColTube(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0))
Definition: GU_GridImpl.h:1204
bool myLastColIfNotWrapped
Definition: GU_Grid.h:122
bool myFirstRowIfNotWrapped
Definition: GU_Grid.h:107
bool isInvalidTPSurf() const
Definition: GU_Grid.h:365
GEO_SurfaceType
GLenum GLenum GLsizei void * row
Definition: glad.h:5135
void GUiterateGridPrimitives(const GU_GridT< INT_TYPE > &grid, FUNCTOR &&functor)
Definition: GU_GridImpl.h:97
bool doesRowWrap(exint row) const
Definition: GU_Grid.h:303
void GUiterateGridPoints(const GU_GridT< INT_TYPE > &grid, FUNCTOR &&functor)
Definition: GU_GridImpl.h:48