All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
catmark.h
Go to the documentation of this file.
1 //
2 // Copyright 2013 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 
25 #ifndef HBRCATMARK_H
26 #define HBRCATMARK_H
27 
28 /*#define HBR_DEBUG */
29 #include "../hbr/subdivision.h"
30 
31 #include "../version.h"
32 
33 namespace OpenSubdiv {
34 namespace OPENSUBDIV_VERSION {
35 
36 template <class T>
38 public:
40  : HbrSubdivision<T>(), triangleSubdivision(k_Normal) {}
41 
43  : HbrSubdivision<T>(), triangleSubdivision(old.triangleSubdivision) {}
44 
45  virtual HbrSubdivision<T>* Clone() const {
46  return new HbrCatmarkSubdivision<T>(*this);
47  }
48 
49  virtual void Refine(HbrMesh<T>* mesh, HbrFace<T>* face);
50  virtual HbrFace<T>* RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, HbrVertex<T>* vertex);
51  virtual void GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
52  virtual void GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
53 
54  virtual bool HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face);
55  virtual bool HasLimit(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
56  virtual bool HasLimit(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
57 
58  virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face);
59  virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
60  virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
61 
62  virtual bool VertexIsExtraordinary(HbrMesh<T> const * /* mesh */, HbrVertex<T>* vertex) { return vertex->GetValence() != 4; }
63  virtual bool FaceIsExtraordinary(HbrMesh<T> const* /* mesh */, HbrFace<T>* face) { return face->GetNumVertices() != 4; }
64 
65  // Triangle subdivision rules, which modifies the rules for
66  // triangular faces in order to make them smoother. The "normal"
67  // rule is the standard Catmull-Clark rule. The "old" rule
68  // modifies only the subdivision rules for a face to vertex
69  // refinement. The "new" rule modifies only the subdivision rules
70  // for an edge to vertex refinement. These rules are only applied
71  // to the top level face, since only top level faces can be
72  // triangular; after one level of refinement everything becomes
73  // quads.
78  };
79  TriangleSubdivision GetTriangleSubdivisionMethod() const { return triangleSubdivision; }
80  void SetTriangleSubdivisionMethod(TriangleSubdivision method) { triangleSubdivision = method; }
81 
82  virtual int GetFaceChildrenCount(int nvertices) const { return nvertices; }
83 
84 private:
85 
86  // Transfers facevarying data from a parent face to a child face
87  void transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, HbrFace<T>* child, int index);
88 
89  // Transfers vertex and edge edits from a parent face to a child face
90  void transferEditsToChild(HbrFace<T>* face, HbrFace<T>* child, int index);
91 
92  TriangleSubdivision triangleSubdivision;
93 };
94 
95 template <class T>
96 void
98 
100  const int fvarcount = mesh->GetFVarCount();
101  int fvarindex = 0;
102  const int nv = face->GetNumVertices();
103  bool extraordinary = (nv != 4);
104  HbrVertex<T> *v = face->GetVertex(index), *childVertex;
105  HbrHalfedge<T>* edge;
106 
107  // We do the face subdivision rule first, because we may reuse the
108  // result (stored in fv2) for the other subdivisions.
109  float weight = 1.0f / nv;
110  // For the face center vertex, the facevarying data can be cleared
111  // and averaged en masse, since the subdivision rules don't change
112  // for any of the data - we use the smooth rule for all of it.
113  // And since we know that the fvardata for this particular vertex
114  // is smooth and therefore shareable amongst all incident faces,
115  // we don't have to allocate extra storage for it. We also don't
116  // have to compute it if some other face got to it first (as
117  // indicated by the IsInitialized() flag).
118  HbrFVarData<T>& fv2 = child->GetFVarData(extraordinary ? 2 : (index+2)%4);
119  if (!fv2.IsInitialized()) {
120  const int totalfvarwidth = mesh->GetTotalFVarWidth();
121  fv2.ClearAll(totalfvarwidth);
122  for (int j = 0; j < nv; ++j) {
123  fv2.AddWithWeightAll(face->GetFVarData(j), totalfvarwidth, weight);
124  }
125  }
126  assert(fv2.IsInitialized());
127 
128  v->GuaranteeNeighbors();
129 
130  // Make sure that that each of the vertices of the child face have
131  // the appropriate facevarying storage as needed. If there are
132  // discontinuities in any facevarying datum, the vertex must
133  // allocate a new block of facevarying storage specific to the
134  // child face.
135  bool fv0IsSmooth, fv1IsSmooth, fv3IsSmooth;
136 
137  childVertex = child->GetVertex(extraordinary ? 0 : (index+0)%4);
138  fv0IsSmooth = v->IsFVarAllSmooth();
139  if (!fv0IsSmooth) {
140  childVertex->NewFVarData(child);
141  }
142  HbrFVarData<T>& fv0 = childVertex->GetFVarData(child);
143 
144  edge = face->GetEdge(index);
145  GuaranteeNeighbor(mesh, edge);
146  assert(edge->GetOrgVertex() == v);
147  childVertex = child->GetVertex(extraordinary ? 1 : (index+1)%4);
148  fv1IsSmooth = !edge->IsFVarInfiniteSharpAnywhere();
149  if (!fv1IsSmooth) {
150  childVertex->NewFVarData(child);
151  }
152  HbrFVarData<T>& fv1 = childVertex->GetFVarData(child);
153 
154  edge = edge->GetPrev();
155  GuaranteeNeighbor(mesh, edge);
156  assert(edge == face->GetEdge((index + nv - 1) % nv));
157  assert(edge->GetDestVertex() == v);
158  childVertex = child->GetVertex(extraordinary ? 3 : (index+3)%4);
159  fv3IsSmooth = !edge->IsFVarInfiniteSharpAnywhere();
160  if (!fv3IsSmooth) {
161  childVertex->NewFVarData(child);
162  }
163  HbrFVarData<T>& fv3 = childVertex->GetFVarData(child);
164  fvarindex = 0;
165  for (int fvaritem = 0; fvaritem < fvarcount; ++fvaritem) {
166  // Vertex subdivision rule. Analyze whether the vertex is on the
167  // boundary and whether it's an infinitely sharp corner. We
168  // determine the last by checking the propagate corners flag on
169  // the mesh; if it's off, we check the two edges of this face
170  // incident to that vertex and determining whether they are
171  // facevarying boundary edges - this is analogous to what goes on
172  // for the interpolateboundary tag (which when set to
173  // EDGEANDCORNER marks vertices with a valence of two as being
174  // sharp corners). If propagate corners is on, we check *all*
175  // faces to see if two edges side by side are facevarying boundary
176  // edges. The facevarying boundary check ignores geometric
177  // sharpness, otherwise we may swim at geometric creases which
178  // aren't actually discontinuous.
179  bool infcorner = false;
180  const int fvarwidth = mesh->GetFVarWidths()[fvaritem];
181  const unsigned char fvarmask = v->GetFVarMask(fvaritem);
182  if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryEdgeAndCorner) {
183  if (fvarmask >= HbrVertex<T>::k_Corner) {
184  infcorner = true;
185  } else if (mesh->GetFVarPropagateCorners()) {
186  if (v->IsFVarCorner(fvaritem)) {
187  infcorner = true;
188  }
189  } else {
190  if (face->GetEdge(index)->GetFVarSharpness(fvaritem, true) && face->GetEdge(index)->GetPrev()->GetFVarSharpness(fvaritem, true)) {
191  infcorner = true;
192  }
193  }
194  }
195 
196  // Infinitely sharp vertex rule. Applied if the vertex is:
197  // - undergoing no facevarying boundary interpolation;
198  // - at a geometric crease, in either boundary interpolation case; or
199  // - is an infinitely sharp facevarying vertex, in the EDGEANDCORNER case; or
200  // - has a mask equal or greater than one, in the "always
201  // sharp" interpolate boundary case
202  if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
203  (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryAlwaysSharp &&
204  fvarmask >= 1) ||
205  v->GetSharpness() > HbrVertex<T>::k_Smooth ||
206  infcorner) {
207  fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 1.0f);
208  }
209  // Dart rule: unlike geometric creases, because there's two
210  // discontinuous values for the one incident edge, we use the
211  // boundary rule and not the smooth rule
212  else if (fvarmask == 1) {
213  assert(!v->OnBoundary());
214 
215  // Use 0.75 of the current vert
216  fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.75f);
217 
218  // 0.125 of "two adjacent edge vertices", which in actuality
219  // are the facevarying values of the same vertex but on each
220  // side of the single incident facevarying sharp edge
221  HbrHalfedge<T>* start = v->GetIncidentEdge(), *nextedge;
222  edge = start;
223  while (edge) {
224  if (edge->GetFVarSharpness(fvaritem)) {
225  break;
226  }
227  nextedge = v->GetNextEdge(edge);
228  if (nextedge == start) {
229  assert(0); // we should have found it by now
230  break;
231  } else if (!nextedge) {
232  // should never get into this case - if the vertex is
233  // on a boundary, it can never be a facevarying dart
234  // vertex
235  assert(0);
236  edge = edge->GetPrev();
237  break;
238  } else {
239  edge = nextedge;
240  }
241  }
242  HbrVertex<T>* w = edge->GetDestVertex();
243  HbrFace<T>* bestface = edge->GetLeftFace();
244  int j;
245  for (j = 0; j < bestface->GetNumVertices(); ++j) {
246  if (bestface->GetVertex(j) == w) break;
247  }
248  assert(j != bestface->GetNumVertices());
249  fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
250  bestface = edge->GetRightFace();
251  for (j = 0; j < bestface->GetNumVertices(); ++j) {
252  if (bestface->GetVertex(j) == w) break;
253  }
254  assert(j != bestface->GetNumVertices());
255  fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
256  }
257  // Boundary vertex rule
258  else if (fvarmask != 0) {
259 
260  // Use 0.75 of the current vert
261  fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.75f);
262 
263  // Compute 0.125 of two adjacent edge vertices. However the
264  // two adjacent edge vertices we use must be part of the
265  // facevarying "boundary". To find the first edge we cycle
266  // counterclockwise around the current vertex v and look for
267  // the first boundary edge
268 
269  HbrFace<T>* bestface = face;
270  HbrHalfedge<T>* bestedge = face->GetEdge(index)->GetPrev();
271  HbrHalfedge<T>* starte = bestedge->GetOpposite();
272  HbrVertex<T>* w = 0;
273  if (!starte) {
274  w = face->GetEdge(index)->GetPrev()->GetOrgVertex();
275  } else {
276  HbrHalfedge<T>* e = starte, *next;
277  assert(starte->GetOrgVertex() == v);
278  do {
279  if (e->GetFVarSharpness(fvaritem) || !e->GetLeftFace()) {
280  bestface = e->GetRightFace();
281  bestedge = e;
282  break;
283  }
284  next = v->GetNextEdge(e);
285  if (!next) {
286  bestface = e->GetLeftFace();
287  w = e->GetPrev()->GetOrgVertex();
288  break;
289  }
290  e = next;
291  } while (e && e != starte);
292  }
293  if (!w) w = bestedge->GetDestVertex();
294  int j;
295  for (j = 0; j < bestface->GetNumVertices(); ++j) {
296  if (bestface->GetVertex(j) == w) break;
297  }
298  assert(j != bestface->GetNumVertices());
299  fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
300 
301  // Look for the other edge by cycling clockwise around v
302  bestface = face;
303  bestedge = face->GetEdge(index);
304  starte = bestedge;
305  w = 0;
306  if (HbrHalfedge<T>* e = starte) {
307  assert(starte->GetOrgVertex() == v);
308  do {
309  if (e->GetFVarSharpness(fvaritem) || !e->GetRightFace()) {
310  bestface = e->GetLeftFace();
311  bestedge = e;
312  break;
313  }
314  assert(e->GetOpposite());
315  e = v->GetPreviousEdge(e);
316  } while (e && e != starte);
317  }
318  if (!w) w = bestedge->GetDestVertex();
319  for (j = 0; j < bestface->GetNumVertices(); ++j) {
320  if (bestface->GetVertex(j) == w) break;
321  }
322  assert(j != bestface->GetNumVertices());
323  fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
324 
325  }
326  // Smooth rule. Here, we can take a shortcut if we know that
327  // the vertex is smooth and some other vertex has completely
328  // computed the facevarying values
329  else if (!fv0IsSmooth || !fv0.IsInitialized()) {
330  int valence = v->GetValence();
331  float invvalencesquared = 1.0f / (valence * valence);
332 
333  // Use n-2/n of the current vertex value
334  fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, invvalencesquared * valence * (valence - 2));
335 
336  // Add 1/n^2 of surrounding edge vertices and surrounding face
337  // averages. We loop over all surrounding faces..
338  HbrHalfedge<T>* start = v->GetIncidentEdge(), *edge;
339  edge = start;
340  while (edge) {
341  HbrFace<T>* g = edge->GetLeftFace();
342  weight = invvalencesquared / g->GetNumVertices();
343  // .. and compute the average of each face. At the same
344  // time, we look for the edge on that face whose origin is
345  // the same as v, and add a contribution from its
346  // destination vertex value; this takes care of the
347  // surrounding edge vertex addition.
348  for (int j = 0; j < g->GetNumVertices(); ++j) {
349  fv0.AddWithWeight(g->GetFVarData(j), fvarindex, fvarwidth, weight);
350  if (g->GetEdge(j)->GetOrgVertex() == v) {
351  fv0.AddWithWeight(g->GetFVarData((j + 1) % g->GetNumVertices()), fvarindex, fvarwidth, invvalencesquared);
352  }
353  }
354  edge = v->GetNextEdge(edge);
355  if (edge == start) break;
356  }
357  }
358 
359  // Edge subdivision rule
360  edge = face->GetEdge(index);
361 
362  if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
363  edge->GetFVarSharpness(fvaritem) || edge->IsBoundary()) {
364 
365  // Sharp edge rule
366  fv1.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.5f);
367  fv1.AddWithWeight(face->GetFVarData((index + 1) % nv), fvarindex, fvarwidth, 0.5f);
368  } else if (!fv1IsSmooth || !fv1.IsInitialized()) {
369  // Smooth edge subdivision. Add 0.25 of adjacent vertices
370  fv1.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.25f);
371  fv1.AddWithWeight(face->GetFVarData((index + 1) % nv), fvarindex, fvarwidth, 0.25f);
372  // Local subdivided face vertex
373  fv1.AddWithWeight(fv2, fvarindex, fvarwidth, 0.25f);
374  // Add 0.25 * average of neighboring face vertices
375  HbrFace<T>* oppFace = edge->GetRightFace();
376  weight = 0.25f / oppFace->GetNumVertices();
377  for (int j = 0; j < oppFace->GetNumVertices(); ++j) {
378  fv1.AddWithWeight(oppFace->GetFVarData(j), fvarindex, fvarwidth, weight);
379  }
380  }
381 
382 
383  // Edge subdivision rule
384  edge = edge->GetPrev();
385 
386  if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
387  edge->GetFVarSharpness(fvaritem) || edge->IsBoundary()) {
388 
389  // Sharp edge rule
390  fv3.SetWithWeight(face->GetFVarData((index + nv - 1) % nv), fvarindex, fvarwidth, 0.5f);
391  fv3.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.5f);
392  } else if (!fv3IsSmooth || !fv3.IsInitialized()) {
393  // Smooth edge subdivision. Add 0.25 of adjacent vertices
394  fv3.SetWithWeight(face->GetFVarData((index + nv - 1) % nv), fvarindex, fvarwidth, 0.25f);
395  fv3.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.25f);
396  // Local subdivided face vertex
397  fv3.AddWithWeight(fv2, fvarindex, fvarwidth, 0.25f);
398  // Add 0.25 * average of neighboring face vertices
399  HbrFace<T>* oppFace = edge->GetRightFace();
400  weight = 0.25f / oppFace->GetNumVertices();
401  for (int j = 0; j < oppFace->GetNumVertices(); ++j) {
402  fv3.AddWithWeight(oppFace->GetFVarData(j), fvarindex, fvarwidth, weight);
403  }
404  }
405 
406  fvarindex += fvarwidth;
407  }
408  fv0.SetInitialized();
409  fv1.SetInitialized();
410  fv3.SetInitialized();
411 
412 }
413 
414 template <class T>
415 void
416 HbrCatmarkSubdivision<T>::transferEditsToChild(HbrFace<T>* face, HbrFace<T>* child, int index) {
417 
418  // Hand down hole tag
419  child->SetHole(face->IsHole());
420 
421  // Hand down pointers to hierarchical edits
422  if (HbrHierarchicalEdit<T>** edits = face->GetHierarchicalEdits()) {
423  while (HbrHierarchicalEdit<T>* edit = *edits) {
424  if (!edit->IsRelevantToFace(face)) break;
425  if (edit->GetNSubfaces() > face->GetDepth() &&
426  (edit->GetSubface(face->GetDepth()) == index)) {
427  child->SetHierarchicalEdits(edits);
428  break;
429  }
430  edits++;
431  }
432  }
433 }
434 
435 
436 template <class T>
437 void
439 
440  // Create new quadrilateral children faces from this face
441  HbrFace<T>* child;
442  HbrVertex<T>* vertices[4];
443  HbrHalfedge<T>* edge = face->GetFirstEdge();
444  HbrHalfedge<T>* prevedge = edge->GetPrev();
445  HbrHalfedge<T>* childedge;
446  int nv = face->GetNumVertices();
447  float sharpness;
448  bool extraordinary = (nv != 4);
449  // The funny indexing on vertices is done only for
450  // non-extraordinary faces in order to correctly preserve
451  // parametric space through the refinement. If we split an
452  // extraordinary face then it doesn't matter.
453  for (int i = 0; i < nv; ++i) {
454  if (!face->GetChild(i)) {
455 #ifdef HBR_DEBUG
456  std::cerr << "Kid " << i << "\n";
457 #endif
458  HbrVertex<T>* vertex = edge->GetOrgVertex();
459  if (extraordinary) {
460  vertices[0] = vertex->Subdivide();
461  vertices[1] = edge->Subdivide();
462  vertices[2] = face->Subdivide();
463  vertices[3] = prevedge->Subdivide();
464  } else {
465  vertices[i] = vertex->Subdivide();
466  vertices[(i+1)%4] = edge->Subdivide();
467  vertices[(i+2)%4] = face->Subdivide();
468  vertices[(i+3)%4] = prevedge->Subdivide();
469  }
470  child = mesh->NewFace(4, vertices, face, i);
471 #ifdef HBR_DEBUG
472  std::cerr << "Creating face " << *child << " during refine\n";
473 #endif
474 
475  // Hand down edge sharpnesses
476  childedge = vertex->Subdivide()->GetEdge(edge->Subdivide());
477  assert(childedge);
478  if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
480  edge, edge->GetOrgVertex(), childedge);
481  }
482  childedge->CopyFVarInfiniteSharpness(edge);
483 
484  childedge = prevedge->Subdivide()->GetEdge(vertex->Subdivide());
485  assert(childedge);
486  if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
488  prevedge, prevedge->GetDestVertex(), childedge);
489  }
490  childedge->CopyFVarInfiniteSharpness(prevedge);
491 
492  if (mesh->GetTotalFVarWidth()) {
493  transferFVarToChild(mesh, face, child, i);
494  }
495 
496  // Special handling of ptex index for extraordinary faces: make
497  // sure the children get their indices reassigned to be
498  // consecutive within the block reserved for the parent.
499  if (face->GetNumVertices() != 4 && face->GetPtexIndex() != -1) {
500  child->SetPtexIndex(face->GetPtexIndex() + i);
501  }
502 
503  transferEditsToChild(face, child, i);
504  }
505  prevedge = edge;
506  edge = edge->GetNext();
507  }
508 }
509 
510 template <class T>
511 HbrFace<T>*
513 
514 #ifdef HBR_DEBUG
515  std::cerr << " forcing refine on " << *face << " at " << *vertex << '\n';
516 #endif
517 
518  // Create new quadrilateral children faces from this face
519  HbrHalfedge<T>* edge = face->GetFirstEdge();
520  HbrHalfedge<T>* prevedge = edge->GetPrev();
521  HbrHalfedge<T>* childedge;
522  int nv = face->GetNumVertices();
523  float sharpness;
524  bool extraordinary = (nv != 4);
525  // The funny indexing on vertices is done only for
526  // non-extraordinary faces in order to correctly preserve
527  // parametric space through the refinement. If we split an
528  // extraordinary face then it doesn't matter.
529  for (int i = 0; i < nv; ++i) {
530  if (edge->GetOrgVertex() == vertex) {
531  if (!face->GetChild(i)) {
532  HbrFace<T>* child;
533  HbrVertex<T>* vertices[4];
534  if (extraordinary) {
535  vertices[0] = vertex->Subdivide();
536  vertices[1] = edge->Subdivide();
537  vertices[2] = face->Subdivide();
538  vertices[3] = prevedge->Subdivide();
539  } else {
540  vertices[i] = vertex->Subdivide();
541  vertices[(i+1)%4] = edge->Subdivide();
542  vertices[(i+2)%4] = face->Subdivide();
543  vertices[(i+3)%4] = prevedge->Subdivide();
544  }
545 #ifdef HBR_DEBUG
546  std::cerr << "Kid " << i << "\n";
547  std::cerr << " subdivision created " << *vertices[0] << '\n';
548  std::cerr << " subdivision created " << *vertices[1] << '\n';
549  std::cerr << " subdivision created " << *vertices[2] << '\n';
550  std::cerr << " subdivision created " << *vertices[3] << '\n';
551 #endif
552  child = mesh->NewFace(4, vertices, face, i);
553 #ifdef HBR_DEBUG
554  std::cerr << "Creating face " << *child << " during refine\n";
555 #endif
556  // Hand down edge sharpness
557  childedge = vertex->Subdivide()->GetEdge(edge->Subdivide());
558  assert(childedge);
559  if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
561  edge, edge->GetOrgVertex(), childedge);
562  }
563  childedge->CopyFVarInfiniteSharpness(edge);
564 
565  childedge = prevedge->Subdivide()->GetEdge(vertex->Subdivide());
566  assert(childedge);
567  if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
569  prevedge, prevedge->GetDestVertex(), childedge);
570  }
571  childedge->CopyFVarInfiniteSharpness(prevedge);
572 
573  if (mesh->GetTotalFVarWidth()) {
574  transferFVarToChild(mesh, face, child, i);
575  }
576 
577  // Special handling of ptex index for extraordinary faces: make
578  // sure the children get their indices reassigned to be
579  // consecutive within the block reserved for the parent.
580  if (face->GetNumVertices() != 4 && face->GetPtexIndex() != -1) {
581  child->SetPtexIndex(face->GetPtexIndex() + i);
582  }
583 
584  transferEditsToChild(face, child, i);
585  return child;
586  } else {
587  return face->GetChild(i);
588  }
589  }
590  prevedge = edge;
591  edge = edge->GetNext();
592  }
593  return 0;
594 }
595 
596 template <class T>
597 void
599  if (edge->GetOpposite()) {
600  return;
601  }
602 
603  // For the given edge: if the parent of either of its incident
604  // vertices is itself a _face_, then ensuring that this parent
605  // face has refined at a particular vertex is sufficient to
606  // ensure that both of the faces on each side of the edge have
607  // been created.
608  bool destParentWasEdge = true;
609  HbrFace<T>* parentFace = edge->GetOrgVertex()->GetParentFace();
610  HbrHalfedge<T>* parentEdge = edge->GetDestVertex()->GetParentEdge();
611  if (!parentFace) {
612  destParentWasEdge = false;
613  parentFace = edge->GetDestVertex()->GetParentFace();
614  parentEdge = edge->GetOrgVertex()->GetParentEdge();
615  }
616 
617  if (parentFace) {
618 
619  // Make sure we deal with a parent halfedge which is
620  // associated with the parent face
621  if (parentEdge->GetFace() != parentFace) {
622  parentEdge = parentEdge->GetOpposite();
623  }
624  // If one of the vertices had a parent face, the other one MUST
625  // have been a child of an edge
626  assert(parentEdge && parentEdge->GetFace() == parentFace);
627 #ifdef HBR_DEBUG
628  std::cerr << "\nparent edge is " << *parentEdge << "\n";
629 #endif
630 
631  // The vertex to refine at depends on whether the
632  // destination or origin vertex of this edge had a parent
633  // edge
634  if (destParentWasEdge) {
635  RefineFaceAtVertex(mesh, parentFace, parentEdge->GetOrgVertex());
636  } else {
637  RefineFaceAtVertex(mesh, parentFace, parentEdge->GetDestVertex());
638  }
639 
640  // It should always be the case that the opposite now exists -
641  // we can't have a boundary case here
642  assert(edge->GetOpposite());
643  } else {
644  HbrVertex<T>* parentVertex = edge->GetOrgVertex()->GetParentVertex();
645  parentEdge = edge->GetDestVertex()->GetParentEdge();
646  if (!parentVertex) {
647  parentVertex = edge->GetDestVertex()->GetParentVertex();
648  parentEdge = edge->GetOrgVertex()->GetParentEdge();
649  }
650 
651  if (parentVertex) {
652 
653  assert(parentEdge);
654 
655 #ifdef HBR_DEBUG
656  std::cerr << "\nparent edge is " << *parentEdge << "\n";
657 #endif
658 
659  // 1. Go up to the parent of my face
660 
661  parentFace = edge->GetFace()->GetParent();
662 #ifdef HBR_DEBUG
663  std::cerr << "\nparent face is " << *parentFace << "\n";
664 #endif
665 
666  // 2. Ask the opposite face (if it exists) to refine
667  if (parentFace) {
668 
669  // A vertex can be associated with either of two
670  // parent halfedges. If the parent edge that we're
671  // interested in doesn't match then we should look at
672  // its opposite
673  if (parentEdge->GetFace() != parentFace)
674  parentEdge = parentEdge->GetOpposite();
675  assert(parentEdge->GetFace() == parentFace);
676 
677  // Make sure the parent edge has its neighbor as well
678  GuaranteeNeighbor(mesh, parentEdge);
679 
680  // Now access that neighbor and refine it
681  if (parentEdge->GetRightFace()) {
682  RefineFaceAtVertex(mesh, parentEdge->GetRightFace(), parentVertex);
683 
684  // FIXME: assertion?
685  assert(edge->GetOpposite());
686  }
687  }
688  }
689  }
690 }
691 
692 template <class T>
693 void
695 
696 #ifdef HBR_DEBUG
697  std::cerr << "\n\nneighbor guarantee at " << *vertex << " invoked\n";
698 #endif
699 
700  // If the vertex is a child of a face, guaranteeing the neighbors
701  // of the vertex is simply a matter of ensuring the parent face
702  // has refined.
703  HbrFace<T>* parentFace = vertex->GetParentFace();
704  if (parentFace) {
705 
706 #ifdef HBR_DEBUG
707  std::cerr << " forcing full refine on parent face\n";
708 #endif
709  Refine(mesh, parentFace);
710  return;
711  }
712 
713  // Otherwise if the vertex is a child of an edge, we need to
714  // ensure that the parent faces on either side of the parent edge
715  // 1) exist, and 2) have refined at both vertices of the parent
716  // edge
717  HbrHalfedge<T>* parentEdge = vertex->GetParentEdge();
718  if (parentEdge) {
719 
720 #ifdef HBR_DEBUG
721  std::cerr << " forcing full refine on adjacent faces of parent edge\n";
722 #endif
723  HbrVertex<T>* dest = parentEdge->GetDestVertex();
724  HbrVertex<T>* org = parentEdge->GetOrgVertex();
725  GuaranteeNeighbor(mesh, parentEdge);
726  parentFace = parentEdge->GetLeftFace();
727  RefineFaceAtVertex(mesh, parentFace, dest);
728  RefineFaceAtVertex(mesh, parentFace, org);
729 
730 #ifdef HBR_DEBUG
731  std::cerr << " on the right face?\n";
732 #endif
733  parentFace = parentEdge->GetRightFace();
734  // The right face may not necessarily exist even after
735  // GuaranteeNeighbor
736  if (parentFace) {
737  RefineFaceAtVertex(mesh, parentFace, dest);
738  RefineFaceAtVertex(mesh, parentFace, org);
739  }
740 #ifdef HBR_DEBUG
741  std::cerr << " end force\n";
742 #endif
743  return;
744  }
745 
746  // The last case: the vertex is a child of a vertex. In this case
747  // we have to first recursively guarantee that the parent's
748  // adjacent faces also exist.
749  HbrVertex<T>* parentVertex = vertex->GetParentVertex();
750  if (parentVertex) {
751 
752 #ifdef HBR_DEBUG
753  std::cerr << " recursive parent vertex guarantee call\n";
754 #endif
755  parentVertex->GuaranteeNeighbors();
756 
757  // And then we refine all the face neighbors of the
758  // parentVertex
759  HbrHalfedge<T>* start = parentVertex->GetIncidentEdge(), *edge;
760  edge = start;
761  while (edge) {
762  HbrFace<T>* f = edge->GetLeftFace();
763  RefineFaceAtVertex(mesh, f, parentVertex);
764  edge = parentVertex->GetNextEdge(edge);
765  if (edge == start) break;
766  }
767  }
768 }
769 
770 template <class T>
771 bool
773 
774  if (face->IsHole()) return false;
775  // A limit face exists if all the bounding edges have limit curves
776  for (int i = 0; i < face->GetNumVertices(); ++i) {
777  if (!HasLimit(mesh, face->GetEdge(i))) {
778  return false;
779  }
780  }
781  return true;
782 }
783 
784 template <class T>
785 bool
787  // A sharp edge has a limit curve if both endpoints have limits.
788  // A smooth edge has a limit if both endpoints have limits and
789  // the edge isn't on the boundary.
790 
791  if (edge->GetSharpness() >= HbrHalfedge<T>::k_InfinitelySharp) return true;
792 
793  if (!HasLimit(mesh, edge->GetOrgVertex()) || !HasLimit(mesh, edge->GetDestVertex())) return false;
794 
795  return !edge->IsBoundary();
796 }
797 
798 template <class T>
799 bool
801  vertex->GuaranteeNeighbors();
802  switch (vertex->GetMask(false)) {
805  return !vertex->OnBoundary();
806  break;
809  default:
810  if (vertex->IsVolatile()) {
811  // Search for any incident semisharp boundary edge
812  HbrHalfedge<T>* start = vertex->GetIncidentEdge(), *edge, *next;
813  edge = start;
814  while (edge) {
815  if (edge->IsBoundary() && edge->GetSharpness() < HbrHalfedge<T>::k_InfinitelySharp) {
816  return false;
817  }
818  next = vertex->GetNextEdge(edge);
819  if (next == start) {
820  break;
821  } else if (!next) {
822  edge = edge->GetPrev();
823  if (edge->IsBoundary() && edge->GetSharpness() < HbrHalfedge<T>::k_InfinitelySharp) {
824  return false;
825  }
826  break;
827  } else {
828  edge = next;
829  }
830  }
831  }
832  return true;
833  }
834 }
835 
836 template <class T>
839 
840  // Face rule: simply average all vertices on the face
841  HbrVertex<T>* v = mesh->NewVertex();
842  T& data = v->GetData();
843  int nv = face->GetNumVertices();
844  float weight = 1.0f / nv;
845 
846  HbrHalfedge<T>* edge = face->GetFirstEdge();
847  for (int i = 0; i < face->GetNumVertices(); ++i) {
848  HbrVertex<T>* w = edge->GetOrgVertex();
849  // If there are vertex edits we have to make sure the edit
850  // has been applied
851  if (mesh->HasVertexEdits()) {
852  w->GuaranteeNeighbors();
853  }
854  data.AddWithWeight(w->GetData(), weight);
855  data.AddVaryingWithWeight(w->GetData(), weight);
856  edge = edge->GetNext();
857  }
858 #ifdef HBR_DEBUG
859  std::cerr << "Subdividing at " << *face << "\n";
860 #endif
861 
862  // Set the extraordinary flag if the face had anything other than
863  // 4 vertices
864  if (nv != 4) v->SetExtraordinary();
865 
866 #ifdef HBR_DEBUG
867  std::cerr << " created " << *v << "\n";
868 #endif
869  return v;
870 }
871 
872 #if 0
873 // The "old" triangle subdivision method modifies the face subdivision
874 // rule. Unfortunately we can't put simply put this code into the
875 // standard face Subdivide method, because that would disrupt the
876 // averages computed for adjacent edges and vertices (which rely on
877 // face averages computed using the standard Catmull-Clark method).
878 // Instead we must call this after a face has been Subdivided using
879 // the normal rule; this code will modify that face's subdivided
880 // vertex value only.
881 template <class T>
884  assert(face->GetNumVertices() == 3 && triangleSubdivision == k_Old);
885  HbrVertex<T>* w = face->Subdivide();
886  NgpVVectorItem& data = w->GetData();
887  data.Clear();
888 
889  float weight = 1.0f / 6.0f;
890 
891  for (int i = 0; i < 3; ++i) {
892  HbrVertex<T>* w = face->GetVertex(i);
893  HbrHalfedge<T>* e = face->GetEdge(i);
894  data.AddWithWeight(w->Subdivide()->GetData(), weight);
895  data.AddWithWeight(e->Subdivide()->GetData(), weight);
896  }
897 }
898 #endif
899 
900 /* This comment describe the "new" triangle subdivision method, which
901  modifies only the edge subdivision rule:
902 
903  The "smoothtriangles" tag makes triangular faces smoother. This is done
904  by modifying the first level of subdivision in order to generate a limit
905  surface that is closer to what Loop subdivision would yield. Note that
906  there is no extra expense in forcing one level of subdivision, since
907  extraordinary faces need to be subdivided at least once anyway.
908 
909  We have two degrees of freedom to play with, namely the weight assigned
910  to each neighbouring vertex when subdividing a vertex, and the weight
911  assigned to each neighbouring face vertex when subdividing an edge. Our
912  initial strategy for choosing these parameters was to derive the limit
913  masks (position and tangent) for the Catmull-Clark and Loop schemes at
914  three representative points: each original vertex, the center of each
915  original edge, and the center of each original face. The parameter
916  values were then optimized to get the best least-squares match to the
917  limit positions and tangents of the Loop surface at these chosen points.
918  (In the case of tangents an extra scale factor was used so that only the
919  tangent direction is optimized rather than its magnitude.) All this was
920  done using Mathematica.
921 
922  Although the resulting surfaces were much smoother, there was still some
923  degree of "ringing" (probably due to the fact that the surface was
924  optimized at a discrete set of points, rather than by integrating over
925  the surface). We then tried a second strategy, namely choosing the
926  vertex weights to minimize surface curvature. This was done by setting
927  up test cases for extraordinary vertices of each degree, rendering an
928  animation using a range of parameter values, and integrating the
929  curvature over each surface (with a shader and some scripts). We chose
930  to minimize the squared mean curvature, which seemed to have the best
931  correspondence to surfaces that look "smooth".
932 
933  Surprisingly, the vertex weights obtained in this way were not
934  significantly different than the standard Catmull-Clark weights.
935  Thus the final "smooth triangles" technique only modifies the edge
936  subdivision rule: the adjacent face vertices are weighted by
937  HBR_SMOOTH_TRI_EDGE_WEIGHT rather than the standard CC value of 0.25.
938  If there is a mixture of triangular and non-triangular faces, the
939  weights are interpolated. */
940 
941 #define HBR_SMOOTH_TRI_EDGE_WEIGHT 0.470f /* from Mathematica */
942 
943 template <class T>
944 HbrVertex<T>*
946 
947  // Ensure the opposite face exists.
948  GuaranteeNeighbor(mesh, edge);
949 
950  float esharp = edge->GetSharpness();
951 
952 #ifdef HBR_DEBUG
953  std::cerr << "Subdividing at " << *edge << " (sharpness = " << esharp << ")";
954 #endif
955 
956  HbrVertex<T>* v = mesh->NewVertex();
957  T& data = v->GetData();
958 
959  // If there's the possibility of vertex edits on either vertex, we
960  // have to make sure the edit has been applied
961  if (mesh->HasVertexEdits()) {
962  edge->GetOrgVertex()->GuaranteeNeighbors();
963  edge->GetDestVertex()->GuaranteeNeighbors();
964  }
965 
966  if (!edge->IsBoundary() && esharp <= 1.0f) {
967 
968  // Of the two half-edges, pick one of them consistently such
969  // that the left and right faces are also consistent through
970  // multi-threading. It doesn't matter as far as the
971  // theoretical calculation is concerned, but it is desirable
972  // to be consistent about it in the face of the limitations of
973  // floating point commutativity. So we always pick the
974  // half-edge such that its incident face is the smallest of
975  // the two faces, as far as the face paths are concerned.
976  if (edge->GetOpposite() && edge->GetOpposite()->GetFace()->GetPath() < edge->GetFace()->GetPath()) {
977  edge = edge->GetOpposite();
978  }
979 
980  // Handle both the smooth and fractional sharpness cases. We
981  // lerp between the sharp case (average of the two end points)
982  // and the unsharp case (average of two end points plus two
983  // face averages).
984 
985  float leftWeight, rightWeight, faceWeight, vertWeight;
986  HbrFace<T>* rf = edge->GetRightFace();
987  HbrFace<T>* lf = edge->GetLeftFace();
988 
989  // The standard catmull-clark rule for face weights is 0.25.
990  // The modified, new triangle subdivision rule uses a value of
991  // SMOOTH_TRI_EDGE_WEIGHT as defined above. We lerp between
992  // the right and left weights as needed.
993  leftWeight = (triangleSubdivision == k_New && lf->GetNumVertices() == 3) ? HBR_SMOOTH_TRI_EDGE_WEIGHT : 0.25f;
994  rightWeight = (triangleSubdivision == k_New && rf->GetNumVertices() == 3) ? HBR_SMOOTH_TRI_EDGE_WEIGHT : 0.25f;
995  faceWeight = 0.5f * (leftWeight + rightWeight);
996  vertWeight = 0.5f * (1.0f - 2.0f * faceWeight);
997 
998  // Lerp the face weight between non sharp contribution and
999  // sharp contribution (which is zero)
1000  faceWeight *= (1.0f - esharp);
1001 
1002  // Lerp the vert weight between non sharp contribution and
1003  // sharp contribution of 0.5f
1004  vertWeight = 0.5f * esharp + (1.0f - esharp) * vertWeight;
1005 
1006  data.AddWithWeight(edge->GetOrgVertex()->GetData(), vertWeight);
1007  data.AddWithWeight(edge->GetDestVertex()->GetData(), vertWeight);
1008 
1009  data.AddWithWeight(lf->Subdivide()->GetData(), faceWeight);
1010  data.AddWithWeight(rf->Subdivide()->GetData(), faceWeight);
1011  } else {
1012  // Fully sharp edge, just average the two end points
1013  data.AddWithWeight(edge->GetOrgVertex()->GetData(), 0.5f);
1014  data.AddWithWeight(edge->GetDestVertex()->GetData(), 0.5f);
1015  }
1016 
1017  // Varying data is always the average of two end points
1018  data.AddVaryingWithWeight(edge->GetOrgVertex()->GetData(), 0.5f);
1019  data.AddVaryingWithWeight(edge->GetDestVertex()->GetData(), 0.5f);
1020 
1021 #ifdef HBR_DEBUG
1022  std::cerr << " created " << *v << "\n";
1023 #endif
1024  return v;
1025 }
1026 
1027 template <class T>
1028 HbrVertex<T>*
1030 
1031  // Ensure the ring of faces around this vertex exists before
1032  // we compute the valence
1033  vertex->GuaranteeNeighbors();
1034 
1035  float valence = static_cast<float>(vertex->GetValence());
1036  float invvalencesquared = 1.0f / (valence * valence);
1037 
1038 
1039  HbrVertex<T>* v = mesh->NewVertex();
1040  T& data = v->GetData();
1041 
1042  // Due to fractional weights we may need to do two subdivision
1043  // passes
1044  int masks[2];
1045  float weights[2];
1046  int passes;
1047  masks[0] = vertex->GetMask(false);
1048  masks[1] = vertex->GetMask(true);
1049  // If the masks are different, we subdivide twice: once using the
1050  // current mask, once using the mask at the next level of
1051  // subdivision, then use fractional mask weights to weigh
1052  // each weighing
1053  if (masks[0] != masks[1]) {
1054  weights[1] = vertex->GetFractionalMask();
1055  weights[0] = 1.0f - weights[1];
1056  passes = 2;
1057  } else {
1058  weights[0] = 1.0f;
1059  weights[1] = 0.0f;
1060  passes = 1;
1061  }
1062  for (int i = 0; i < passes; ++i) {
1063  switch (masks[i]) {
1065  case HbrVertex<T>::k_Dart: {
1066  // Compute n-2/n of the old vertex value
1067  data.AddWithWeight(vertex->GetData(), weights[i] * invvalencesquared * valence * (valence - 2));
1068  // Add 1 / n^2 * surrounding edge vertices and surrounding face
1069  // subdivided vertices
1071  mesh, vertex, weights[i] * invvalencesquared, &data);
1072 
1073  HbrHalfedge<T>* start = vertex->GetIncidentEdge(), *edge;
1074  edge = start;
1075  while (edge) {
1076  HbrFace<T>* f = edge->GetLeftFace();
1077  data.AddWithWeight(f->Subdivide()->GetData(), weights[i] * invvalencesquared);
1078  edge = vertex->GetNextEdge(edge);
1079  if (edge == start) break;
1080  }
1081  break;
1082  }
1083  case HbrVertex<T>::k_Crease: {
1084  // Compute 3/4 of old vertex value
1085  data.AddWithWeight(vertex->GetData(), weights[i] * 0.75f);
1086 
1087  // Add 0.125f of the (hopefully only two!) neighbouring
1088  // sharp edges
1090  mesh, vertex, i == 1, weights[i] * 0.125f, &data);
1091  break;
1092  }
1094  default: {
1095  // Just copy the old value
1096  data.AddWithWeight(vertex->GetData(), weights[i]);
1097  break;
1098  }
1099  }
1100  }
1101 
1102  // Varying data is always just propagated down
1103  data.AddVaryingWithWeight(vertex->GetData(), 1.0f);
1104 
1105 #ifdef HBR_DEBUG
1106  std::cerr << "Subdividing at " << *vertex << "\n";
1107  std::cerr << " created " << *v << "\n";
1108 #endif
1109  // Inherit extraordinary flag and sharpness
1110  if (vertex->IsExtraordinary()) v->SetExtraordinary();
1111  float sharp = vertex->GetSharpness();
1112  if (sharp >= HbrVertex<T>::k_InfinitelySharp) {
1113  v->SetSharpness(HbrVertex<T>::k_InfinitelySharp);
1114  } else if (sharp > HbrVertex<T>::k_Smooth) {
1115  sharp -= 1.0f;
1116  if (sharp < (float) HbrVertex<T>::k_Smooth) {
1117  sharp = (float) HbrVertex<T>::k_Smooth;
1118  }
1119  v->SetSharpness(sharp);
1120  } else {
1121  v->SetSharpness(HbrVertex<T>::k_Smooth);
1122  }
1123  return v;
1124 }
1125 
1126 } // end namespace OPENSUBDIV_VERSION
1127 using namespace OPENSUBDIV_VERSION;
1128 
1129 } // end namespace OpenSubdiv
1130 
1131 #endif /* HBRCATMARK_H */
1132 
HbrHalfedge< T > * GetEdge(int index) const
Definition: face.h:718
#define HBR_SMOOTH_TRI_EDGE_WEIGHT
Definition: catmark.h:941
HbrVertex< T > * NewVertex(int id, const T &data)
Definition: mesh.h:533
void SetTriangleSubdivisionMethod(TriangleSubdivision method)
Definition: catmark.h:80
HbrFace< T > * GetRightFace() const
Definition: halfedge.h:166
virtual bool HasLimit(HbrMesh< T > *mesh, HbrFace< T > *face)
Definition: catmark.h:772
void AddWithWeightAll(const HbrFVarData &fvvi, int width, float weight)
Definition: fvarData.h:120
InterpolateBoundaryMethod GetFVarInterpolateBoundaryMethod() const
Definition: mesh.h:211
void CopyFVarInfiniteSharpness(HbrHalfedge< T > *edge)
Definition: halfedge.h:185
unsigned char GetMask(bool next)
Definition: vertex.h:1179
HbrHalfedge< T > * GetFirstEdge() const
Definition: face.h:136
void SubdivideCreaseWeight(HbrHalfedge< T > *edge, HbrVertex< T > *vertex, HbrHalfedge< T > *subedge)
Definition: subdivision.h:205
HbrFace< T > * GetChild(int index) const
Definition: face.h:164
virtual HbrSubdivision< T > * Clone() const
Definition: catmark.h:45
HbrHalfedge< T > * GetNext() const
Definition: halfedge.h:80
HbrVertex< T > * GetDestVertex() const
Definition: halfedge.h:143
virtual void GuaranteeNeighbors(HbrMesh< T > *mesh, HbrVertex< T > *vertex)
Definition: catmark.h:694
HbrHalfedge< T > * GetPreviousEdge(const HbrHalfedge< T > *edge) const
Definition: vertex.h:998
HbrFace< T > * GetLeftFace() const
Definition: halfedge.h:169
float GetFVarSharpness(int datum, bool ignoreGeometry=false)
Definition: halfedge.h:684
HbrVertex< T > * GetParentVertex() const
Definition: vertex.h:222
virtual HbrFace< T > * RefineFaceAtVertex(HbrMesh< T > *mesh, HbrFace< T > *face, HbrVertex< T > *vertex)
Definition: catmark.h:512
HbrVertex< T > * Subdivide()
Definition: face.h:786
HbrFVarData< T > & GetFVarData(int index)
Definition: face.h:221
unsigned char GetFVarMask(int datum)
Definition: vertex.h:1251
virtual void GuaranteeNeighbor(HbrMesh< T > *mesh, HbrHalfedge< T > *edge)
Definition: catmark.h:598
HbrHalfedge< T > * GetIncidentEdge() const
Definition: vertex.h:285
HbrHalfedge< T > * GetNextEdge(const HbrHalfedge< T > *edge) const
Definition: vertex.h:990
virtual void Refine(HbrMesh< T > *mesh, HbrFace< T > *face)
Definition: catmark.h:438
void AddCreaseEdgesWithWeight(HbrMesh< T > *mesh, HbrVertex< T > *vertex, bool next, float weight, T *data)
Definition: subdivision.h:283
HbrHalfedge< T > * GetOpposite() const
Definition: halfedge.h:74
virtual bool FaceIsExtraordinary(HbrMesh< T > const *, HbrFace< T > *face)
Definition: catmark.h:63
HbrVertex< T > * GetVertex(int index) const
Definition: face.h:730
HbrVertex< T > * GetOrgVertex() const
Definition: halfedge.h:125
HbrFace< T > * NewFace(int nvertices, const int *vtx, int uindex)
Definition: mesh.h:607
void AddSurroundingVerticesWithWeight(HbrMesh< T > *mesh, HbrVertex< T > *vertex, float weight, T *data)
Definition: subdivision.h:276
TriangleSubdivision GetTriangleSubdivisionMethod() const
Definition: catmark.h:79
virtual bool VertexIsExtraordinary(HbrMesh< T > const *, HbrVertex< T > *vertex)
Definition: catmark.h:62
const int * GetFVarWidths() const
Definition: mesh.h:187
HbrHalfedge< T > * GetPrev() const
Definition: halfedge.h:98
virtual HbrVertex< T > * Subdivide(HbrMesh< T > *mesh, HbrFace< T > *face)
Definition: catmark.h:838
virtual int GetFaceChildrenCount(int nvertices) const
Definition: catmark.h:82