HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GU_Grid.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  * Definition of GU_GridT structure to aid in iterating over grids.
27  */
28 
29 #pragma once
30 
31 #ifndef __HDK_GU_GRID__
32 #define __HDK_GU_GRID__
33 
34 #include <GEO/GEO_SurfaceType.h>
35 #include <GA/GA_Types.h>
36 #include <UT/UT_Assert.h>
37 #include <UT/UT_UniquePtr.h>
38 #include <SYS/SYS_Types.h>
39 
40 namespace HDK_Sample {
41 
42 template<typename INT_TYPE=GA_Offset>
43 struct GU_GridT
44 {
45  /// These are the number of edge rows and edge columns.
46  /// @{
49  /// @}
50 
51  /// These members specify the points of the grid
52  /// @{
53  INT_TYPE myCorners[4];
54  INT_TYPE myRow0Start;
55  union {
56  INT_TYPE myRow0Step;
57  INT_TYPE *myRow0Array;
58  };
59  INT_TYPE myRow1Start;
60  union {
61  INT_TYPE myRow1Step;
62  INT_TYPE *myRow1Array;
63  };
64  INT_TYPE myCol0Start;
65  union {
66  INT_TYPE myCol0Step;
67  INT_TYPE *myCol0Array;
68  };
69  INT_TYPE myCol1Start;
70  union {
71  INT_TYPE myCol1Step;
72  INT_TYPE *myCol1Array;
73  };
74  INT_TYPE myMiddleStart;
75  INT_TYPE myMiddleColStep;
76  INT_TYPE myMiddleRowStep;
77  /// @}
78 
80 
81  enum class PrimitiveType : unsigned char {
82  POLYGON,
83  MESH,
84  NURBS,
85  BEZIER,
86  POLYSOUP,
87  POINTS
88  };
89 
91 
92  /// NOTE: Basis orders for NURBS and Bezier surfaces must be in the range
93  /// [2,GA_MAX_ORDER], which fits in 4 bits, since GA_MAX_ORDER==11.
94  unsigned char myBasisOrderU:4;
95  unsigned char myBasisOrderV:4;
97 
98  /// If mySurfaceType is rows, cols, or rows and cols, and a particular
99  /// row or column wraps around (row0[col]==row1[col] or col0[row]==col1[row]),
100  /// This indicates to create an open curve with an extra vertex (if true),
101  /// instead of a closed polygon (if false).
103 
104  /// If mySurfaceType is rows or rows and cols, and columns aren't wrapped,
105  /// if this is true, the first row is present (the usual), else it's not
106  /// (e.g. the grid might be connected to an existing mesh).
108 
109  /// If mySurfaceType is rows or rows and cols, and columns aren't wrapped,
110  /// if this is true, the final row is present (the usual), else it's not
111  /// (e.g. the grid might be connected to an existing mesh).
113 
114  /// If mySurfaceType is cols or rows and cols, and rows aren't wrapped,
115  /// if this is true, the first col is present (the usual), else it's not
116  /// (e.g. the grid might be connected to an existing mesh).
118 
119  /// If mySurfaceType is cols or rows and cols, and rows aren't wrapped,
120  /// if this is true, the final col is present (the usual), else it's not
121  /// (e.g. the grid might be connected to an existing mesh).
123 
124  /// If adjacent points on the boundary are equal, and mySurfaceType is
125  /// one of the triangle options or quads, the appropriate polygons
126  /// will be simple triangles, instead of quads or pairs of triangles.
127  /// If a boundary quad becomes fully degenerate, no polygon will be output
128  /// for it.
130 
131  /// If myPrimitiveType is NURBS or BEZIER, and mySurfaceType is
132  /// GEO_PATCH_ROWS or GEO_PATCH_COLS or GEO_PATCH_ROWCOL, this
133  /// indicates whether to create separate curve primitives (true),
134  /// or a surface primitive with its surface type set correspondingly.
136 
137  /// NOTE: The following members are cached values computed from the members
138  /// above, not used for input.
139  /// After setting the other members, either precompute() must be
140  /// called or these members must be manually set, before any other
141  /// functions can be called.
142  /// @{
143  bool myAllWrapU:1;
144  bool myAllWrapV:1;
145  bool myNoWrapU:1;
146  bool myNoWrapV:1;
149  /// @}
150 
151  /// NOTE: The bools can't be in-class initialized, since they're bitfields,
152  /// and the C++ standard evidently missed the case of bitfields.
153  /// NOTE: The row and col starts are non-negative, so that destructing
154  /// a default constructed grid won't crash.
156  : myRow0Start(0)
157  , myRow1Start(0)
158  , myCol0Start(0)
159  , myCol1Start(0)
161  , myPrimitiveType(PrimitiveType::POLYGON)
162  , myUnrollCurves(false)
163  , myFirstRowIfNotWrapped(true)
164  , myLastRowIfNotWrapped(true)
165  , myFirstColIfNotWrapped(true)
166  , myLastColIfNotWrapped(true)
167  , myTriangularPoles(false)
168  , myCurvesIfBasisRowCol(false)
169  {}
170  ~GU_GridT() { clear(); }
171 
172  /// This computes myAllWrapU, myAllWrapV, myNoWrapU, and myNoWrapV
173  /// after everything else is set.
174  void precompute();
175 
176  /// NOTE: mySurfaceType & myPrimitiveType must be set before calling, and so should
177  /// myFirstRowIfNotWrapped, myLastRowIfNotWrapped, myFirstColIfNotWrapped,
178  /// and myLastColIfNotWrapped if rows/cols/rowcol.
179  /// NOTE: You don't need to call precompute() after this.
180  void initSingleGrid(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0));
181 
182  /// NOTE: mySurfaceType & myPrimitiveType must be set before calling, and so should
183  /// myFirstRowIfNotWrapped, myLastRowIfNotWrapped,
184  /// and myUnrollCurves if rows/cols/rowcol.
185  /// NOTE: You don't need to call precompute() after this.
186  void initColTube(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0));
187 
188  /// NOTE: mySurfaceType & myPrimitiveType must be set before calling, and so should
189  /// myFirstColIfNotWrapped, myLastColIfNotWrapped,
190  /// and myUnrollCurves if rows/cols/rowcol.
191  /// NOTE: You don't need to call precompute() after this.
192  void initRowTube(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0));
193 
194  /// This is the sphere most people expect, with north and south poles (row=0/nedgerows).
195  /// NOTE: mySurfaceType & myPrimitiveType must be set before calling, and so should
196  /// myFirstRowIfNotWrapped, myLastRowIfNotWrapped,
197  /// and myUnrollCurves if rows/cols/rowcol, or
198  /// myTriangularPoles if quads/tris.
199  /// NOTE: You'll probably want to set myFirstRowIfNotWrapped and
200  /// myLastRowIfNotWrapped to false, to match the Sphere SOP.
201  /// NOTE: You don't need to call precompute() after this.
202  void initColSphere(exint nedgerows, exint nedgecols,
203  INT_TYPE start_pt=INT_TYPE(0), INT_TYPE end_pt=INT_TYPE(1),
204  INT_TYPE start_mid_pt=INT_TYPE(2));
205 
206  /// This is the sphere most people DON'T expect, with east and west poles (col=0/nedgecols).
207  /// NOTE: mySurfaceType & myPrimitiveType must be set before calling, and so should
208  /// myFirstColIfNotWrapped, myLastColIfNotWrapped,
209  /// and myUnrollCurves if rows/cols/rowcol, or
210  /// myTriangularPoles if quads/tris.
211  /// NOTE: You'll probably want to set myFirstColIfNotWrapped and
212  /// myLastColIfNotWrapped to false, to match the Sphere SOP.
213  /// NOTE: You don't need to call precompute() after this.
214  void initRowSphere(exint nedgerows, exint nedgecols,
215  INT_TYPE start_pt=INT_TYPE(0), INT_TYPE end_pt=INT_TYPE(1),
216  INT_TYPE start_mid_pt=INT_TYPE(2));
217 
218  /// This is effectively a slice of a col sphere, with north and south poles (row=0/nedgerows).
219  /// NOTE: mySurfaceType & myPrimitiveType must be set before calling, and so should
220  /// myFirstRowIfNotWrapped, myLastRowIfNotWrapped,
221  /// and myUnrollCurves if rows/cols/rowcol, or
222  /// myTriangularPoles if quads/tris.
223  /// NOTE: You'll probably want to set myFirstRowIfNotWrapped and
224  /// myLastRowIfNotWrapped to false, to match the Sphere SOP.
225  /// NOTE: You don't need to call precompute() after this.
226  void initSplitColSphere(exint nedgerows, exint nedgecols,
227  INT_TYPE start_pt=INT_TYPE(0), INT_TYPE end_pt=INT_TYPE(1),
228  INT_TYPE start_mid_pt=INT_TYPE(2));
229 
230  /// NOTE: mySurfaceType & myPrimitiveType must be set before calling, and so should
231  /// myUnrollCurves if rows/cols/rowcol.
232  /// NOTE: You don't need to call precompute() after this.
233  void initTorus(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0));
234 
235  /// NOTE: mySurfaceType & myPrimitiveType must be set before calling, and so should
236  /// myFirstRowIfNotWrapped, myLastRowIfNotWrapped,
237  /// and myUnrollCurves if rows/cols/rowcol, or
238  /// myTriangularPoles if quads/tris.
239  /// NOTE: You'll probably want to set myFirstRowIfNotWrapped or
240  /// myLastRowIfNotWrapped to false, depending on row0_pole.
241  /// NOTE: You don't need to call precompute() after this.
242  void initColCone(exint nedgerows, exint nedgecols, bool row0_pole=true,
243  INT_TYPE start_pt=INT_TYPE(0), INT_TYPE start_mid_pt=INT_TYPE(1));
244 
245  /// Free memory allocations owned by this.
246  /// NOTE: This intentionally does not clear myPrimitiveType,
247  /// mySurfaceType, myBasisOrderU, myBasisOrderV, or myUnrollCurves.
248  void clear()
249  {
250  if (myRow0Start < INT_TYPE(0))
251  {
252  delete [] myRow0Array;
253  myRow0Start = INT_TYPE(0);
254  }
255  if (myRow1Start < INT_TYPE(0))
256  {
257  delete [] myRow1Array;
258  myRow1Start = INT_TYPE(0);
259  }
260  if (myCol0Start < INT_TYPE(0))
261  {
262  delete [] myCol0Array;
263  myCol0Start = INT_TYPE(0);
264  }
265  if (myCol1Start < INT_TYPE(0))
266  {
267  delete [] myCol1Array;
268  myCol1Start = INT_TYPE(0);
269  }
270  }
271 
272  INT_TYPE getPoint(exint row, exint col) const
273  {
274  UT_ASSERT_P(row >= 0 && row <= myNumEdgeRows);
275  UT_ASSERT_P(col >= 0 && col <= myNumEdgeCols);
276  if (row == 0)
277  {
278  if (col == 0)
279  return myCorners[0];
280  if (col == myNumEdgeCols)
281  return myCorners[1];
282  --col;
283  return (myRow0Start < INT_TYPE(0)) ? myRow0Array[col] : (myRow0Start + myRow0Step*col);
284  }
285  if (row == myNumEdgeRows)
286  {
287  if (col == 0)
288  return myCorners[2];
289  if (col == myNumEdgeCols)
290  return myCorners[3];
291  --col;
292  return (myRow1Start < INT_TYPE(0)) ? myRow1Array[col] : (myRow1Start + myRow1Step*col);
293  }
294  --row;
295  if (col == 0)
296  return (myCol0Start < INT_TYPE(0)) ? myCol0Array[row] : (myCol0Start + myCol0Step*row);
297  if (col == myNumEdgeCols)
298  return (myCol1Start < INT_TYPE(0)) ? myCol1Array[row] : (myCol1Start + myCol1Step*row);
299  --col;
300  return myMiddleStart + myMiddleRowStep*row + myMiddleColStep*col;
301  }
302 
303  bool doesRowWrap(exint row) const
304  {
305  if (row == 0)
306  return myCorners[0] == myCorners[1];
307  if (row == myNumEdgeRows)
308  return myCorners[2] == myCorners[3];
309  UT_ASSERT_P(row > 0 && row < myNumEdgeRows);
310  --row;
311  INT_TYPE pt0 = (myCol0Start < INT_TYPE(0)) ? myCol0Array[row] : (myCol0Start + myCol0Step*row);
312  INT_TYPE pt1 = (myCol1Start < INT_TYPE(0)) ? myCol1Array[row] : (myCol1Start + myCol1Step*row);
313  return pt0 == pt1;
314  }
315  bool doesColWrap(exint col) const
316  {
317  if (col == 0)
318  return myCorners[0] == myCorners[2];
319  if (col == myNumEdgeCols)
320  return myCorners[1] == myCorners[3];
321  UT_ASSERT_P(col > 0 && col < myNumEdgeCols);
322  --col;
323  INT_TYPE pt0 = (myRow0Start < INT_TYPE(0)) ? myRow0Array[col] : (myRow0Start + myRow0Step*col);
324  INT_TYPE pt1 = (myRow1Start < INT_TYPE(0)) ? myRow1Array[col] : (myRow1Start + myRow1Step*col);
325  return pt0 == pt1;
326  }
327 
328  // Adjusts the points of the grid such that the effective starting point is different.
329  void shiftPoints(INT_TYPE shift)
330  {
331  for (int i = 0; i < 4; ++i)
332  myCorners[i] += shift;
333 
334  if (myRow0Start >= INT_TYPE(0))
335  myRow0Start += shift;
336  else
337  {
338  for (exint col = 1; col < myNumEdgeCols; ++col)
339  myRow0Array[col-1] += shift;
340  }
341  if (myRow1Start >= INT_TYPE(0))
342  myRow1Start += shift;
343  else
344  {
345  for (exint col = 1; col < myNumEdgeCols; ++col)
346  myRow1Array[col-1] += shift;
347  }
348  if (myCol0Start >= INT_TYPE(0))
349  myCol0Start += shift;
350  else
351  {
352  for (exint row = 1; row < myNumEdgeRows; ++row)
353  myCol0Array[row-1] += shift;
354  }
355  if (myCol1Start >= INT_TYPE(0))
356  myCol1Start += shift;
357  else
358  {
359  for (exint row = 1; row < myNumEdgeRows; ++row)
360  myCol1Array[row-1] += shift;
361  }
362  myMiddleStart += shift;
363  }
364 
365  bool isInvalidTPSurf() const
366  {
367  const bool is_nurbs = (myPrimitiveType == PrimitiveType::NURBS);
368  const bool is_bezier = (myPrimitiveType == PrimitiveType::BEZIER);
369 
370  if (!is_nurbs && !is_bezier)
371  return false;
372 
373  // If number of row vertices or col vertices is smaller than
374  // the corresponding basis order, reject this grid.
376  exint nvtxcols = myNumEdgeCols + exint(myNoWrapU || myUnrollCurves);
377  if (nvtxrows < myBasisOrderV || nvtxcols < myBasisOrderU)
378  return true;
379  // Beziers need the edge count along an axis to be a multiple of (order-1)
380  if (is_bezier && ((myNumEdgeRows % (myBasisOrderV-1)) != 0 || (myNumEdgeCols % (myBasisOrderU-1)) != 0))
381  return true;
382  return false;
383  }
384 
385  void fixTPSurf()
386  {
387  const bool is_nurbs = (myPrimitiveType == PrimitiveType::NURBS);
388  const bool is_bezier = (myPrimitiveType == PrimitiveType::BEZIER);
389  if (!is_nurbs && !is_bezier)
390  return;
391 
392  // Order must be between 2 and GA_MAX_ORDER (inclusive).
395 
396  // If number of row vertices or col vertices is smaller than
397  // the corresponding basis order, increase it.
398  const exint nvtxrows = myNumEdgeRows + exint(myNoWrapV || myUnrollCurves);
399  const exint nvtxcols = myNumEdgeCols + exint(myNoWrapU || myUnrollCurves);
400  if (nvtxrows < myBasisOrderV)
401  myNumEdgeRows += myBasisOrderV-nvtxrows;
402  if (nvtxcols < myBasisOrderU)
403  myNumEdgeCols += myBasisOrderU-nvtxcols;
404  if (is_bezier)
405  {
406  // Beziers need the edge count along an axis to be a multiple of (order-1)
407  const exint row_excess = myNumEdgeRows % (myBasisOrderV-1);
408  const exint col_excess = myNumEdgeCols % (myBasisOrderU-1);
409  if (row_excess != 0)
410  myNumEdgeRows += (myBasisOrderV-1) - row_excess;
411  if (col_excess != 0)
412  myNumEdgeCols += (myBasisOrderU-1) - col_excess;
413  }
414  }
415 };
416 
418 
419 } // End of HDK_Sample namespace
420 
421 #endif
INT_TYPE getPoint(exint row, exint col) const
Definition: GU_Grid.h:272
INT_TYPE myRow0Step
Definition: GU_Grid.h:56
INT_TYPE myMiddleRowStep
Definition: GU_Grid.h:76
void initTorus(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0))
Definition: GU_GridImpl.h:1656
PrimitiveType myPrimitiveType
Definition: GU_Grid.h:90
#define GA_MAX_ORDER
Definition: GA_Types.h:186
INT_TYPE myRow0Start
Definition: GU_Grid.h:54
GEO_SurfaceType mySurfaceType
Definition: GU_Grid.h:79
int64 exint
Definition: SYS_Types.h:125
INT_TYPE * myRow1Array
Definition: GU_Grid.h:62
INT_TYPE myCol0Start
Definition: GU_Grid.h:64
INT_TYPE * myRow0Array
Definition: GU_Grid.h:57
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
INT_TYPE myCorners[4]
Definition: GU_Grid.h:53
bool myFirstColIfNotWrapped
Definition: GU_Grid.h:117
bool doesColWrap(exint col) const
Definition: GU_Grid.h:315
SYS_STATIC_ASSERT(GA_MAX_ORDER< 16)
INT_TYPE myCol1Start
Definition: GU_Grid.h:69
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
INT_TYPE myMiddleStart
Definition: GU_Grid.h:74
unsigned char myBasisOrderU
Definition: GU_Grid.h:94
void initRowTube(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0))
Definition: GU_GridImpl.h:1293
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:155
UT_Vector3T< T > SYSclamp(const UT_Vector3T< T > &v, const UT_Vector3T< T > &min, const UT_Vector3T< T > &max)
Definition: UT_Vector3.h:1057
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
INT_TYPE myCol0Step
Definition: GU_Grid.h:66
INT_TYPE myMiddleColStep
Definition: GU_Grid.h:75
bool myLastRowIfNotWrapped
Definition: GU_Grid.h:112
void shiftPoints(INT_TYPE shift)
Definition: GU_Grid.h:329
void initColCone(exint nedgerows, exint nedgecols, bool row0_pole=true, INT_TYPE start_pt=INT_TYPE(0), INT_TYPE start_mid_pt=INT_TYPE(1))
INT_TYPE myRow1Step
Definition: GU_Grid.h:61
INT_TYPE myRow1Start
Definition: GU_Grid.h:59
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
unsigned char myBasisOrderV
Definition: GU_Grid.h:95
GLenum GLenum GLsizei void * row
Definition: glad.h:5135
bool myCurvesIfBasisRowCol
Definition: GU_Grid.h:135
INT_TYPE * myCol1Array
Definition: GU_Grid.h:72
bool doesRowWrap(exint row) const
Definition: GU_Grid.h:303
INT_TYPE myCol1Step
Definition: GU_Grid.h:71
INT_TYPE * myCol0Array
Definition: GU_Grid.h:67