All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
scheme.h
Go to the documentation of this file.
1 //
2 // Copyright 2014 DreamWorks Animation LLC.
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 #ifndef SDC_SCHEME_H
25 #define SDC_SCHEME_H
26 
27 #include "../version.h"
28 
29 #include "../sdc/type.h"
30 #include "../sdc/options.h"
31 #include "../sdc/crease.h"
32 
33 #include <cassert>
34 #include <cstdlib>
35 #include <vector>
36 
37 namespace OpenSubdiv {
38 namespace OPENSUBDIV_VERSION {
39 
40 namespace Sdc {
41 
42 //
43 // Scheme is a class template which provides all implementation for the subdivision schemes
44 // supported by OpenSubdiv through specializations of the methods of each. An instance of
45 // Scheme<SCHEME> includes a set of Options that will dictate the variable aspects of its
46 // behavior.
47 //
48 // The primary purpose of Scheme is to provide the mask weights for vertices generated by
49 // subdivision. Methods to determine the masks are given topological neighborhoods from which
50 // to compute the appropriate weights for neighboring components. While these neighborhoods
51 // may require sharpness values for creasing, the computation of subdivided crease values is
52 // independent of the scheme type and is available through the Crease class.
53 //
54 // (Since the primary purpose is the vertex mask queries, and there is not much else required
55 // of this class in terms of methods, so it may be more approprate to name it more specific to
56 // that purpose, e.g. MaskQuery or some other term to indicate that the work it does is
57 // computing masks.)
58 //
59 // Mask queries are assisted by two utility classes -- a Neighborhood class defining the set
60 // of relevant data in the topological neighborhood of the vertex being subdivided, and a Mask
61 // class into which the associated mask weights will be stored. Depending on where and how
62 // these queries are used, more or less information may be available. See the details of the
63 // Neighborhood classes as appropriate initialization of them is critical. It is generally best
64 // to initialize them with what data is known and accessible, but subclasses can be created to
65 // gather it lazily if desired.
66 //
67 //
68 // Future consideration -- ideas for storing/managing sets of masks:
69 // The vast majority of vertices tend to use a small number of common masks, e.g. regular
70 // interior (smooth), regular boundary (crease) and regular interior crease (crease). The first
71 // of these will dominate while the other two may be significant in the presence of heavy use of
72 // creasing. The cases that remain, i.e. the trivial Corner rule and transitions between rules,
73 // should be marginal.
74 // To assist clients that are trying to manage/store masks for repeated application, some
75 // indication that the mask is one of these common types is worthwhile. They can then use
76 // references to the sets of weights for common masks to avoid replicating them.
77 // Defining an enum and returning a result from the mask query methods may be a simple way
78 // to enable this. What their format is for storing the weights is probably best left to them
79 // (they could choose to filter zero weights in the common crease cases) so static methods to
80 // populate a Mask for the fixed set of common cases would provide them the necessary weights
81 // to be managed as they // see fit.
82 // For instance, a nested type and methods of Scheme may be:
83 //
84 // // The exact cases need to be considered and named more carefully...
85 // enum MaskType { UNCOMMON, REG_INT_SMOOTH, REG_INT_CREASE, REG_BOUNDARY }
86 //
87 // MaskType ComputeFaceVertexMask(...);
88 //
89 // static void populateCommonMask(MaskType type, MASK& mask);
90 //
91 // This does start to raise more questions than it answers though and warrants a lot more thought.
92 // The bottom line is that anything internal to OpenSubdiv, e.g. a Vtr or Far class, will be wasting
93 // a lot of memory if it stores a unique mask for every refined vertex...
94 //
95 
96 template <Type SCHEME_TYPE>
97 class Scheme {
98 
99 public:
100 
101  Scheme() : _options() { }
102 
103  Scheme(Options const& options) : _options(options) { }
104 
105  ~Scheme() { }
106 
107  Options GetOptions() const { return _options; }
108  void SetOptions(const Options& newOptions) { _options = newOptions; }
109 
110  // Consider new enum and return value for mask queries (see note above)
111 
112  //
113  // Face-vertex masks - trivial for all current schemes:
114  //
115  template <typename FACE, typename MASK>
116  void ComputeFaceVertexMask(FACE const& faceNeighborhood, MASK& faceVertexMask) const;
117 
118  //
119  // Edge-vertex masks:
120  // If known, the Rule for the edge and/or the derived vertex can be specified to
121  // accelerate the computation (though the Rule for the parent is trivially determined).
122  // In particular, knowing the child rule can avoid the need to subdivide the sharpness
123  // of the edge to see if it is a transitional crease that warrants fractional blending.
124  //
125  // Whether to use the "Rules" in this interface is really debatable -- the parent Rule
126  // is really based on the edge and its sharpness, while the child Rule is technically
127  // based on the neighborhood of the child vertex, but it can be deduced from the two
128  // child edges' sharpness. So the Crease methods used to compute these rules differ
129  // from those for the vertex-vertex mask. Perhaps a simple pair of new methods for
130  // Crease should be added specific to the edge-vertex case, i.e. one that takes a
131  // single sharpness (for the parent rule) and one that takes a pair (for the child).
132  //
133  template <typename EDGE, typename MASK>
134  void ComputeEdgeVertexMask(EDGE const& edgeNeighborhood, MASK& edgeVertexMask,
135  Crease::Rule parentRule = Crease::RULE_UNKNOWN,
136  Crease::Rule childRule = Crease::RULE_UNKNOWN) const;
137 
138  //
139  // Vertex-vertex masks:
140  // If known, a single Rule or pair of Rules can be specified (indicating a crease
141  // transition) to accelerate the computation. Either no Rules, the first, or both should
142  // be specified. Specification of only the first Rule implies it to be true for both
143  // (wish the compiler would allow such default value specification), i.e. no transition.
144  // The case of knowing the parent Rule but deferring determination of the child Rule to
145  // this method is not supported.
146  //
147  template <typename VERTEX, typename MASK>
148  void ComputeVertexVertexMask(VERTEX const& vertexNeighborhood, MASK& vertexVertexMask,
149  Crease::Rule parentRule = Crease::RULE_UNKNOWN,
150  Crease::Rule childRule = Crease::RULE_UNKNOWN) const;
151 
152  //
153  // UNDER CONSIDERATION -- NOT YET IMPLEMENTED...
154  //
155  // Masks for limit points and tangents -- note that these require the vertex be
156  // suitably isolated such that its limit is well-defined. These will also require
157  // internal methods for the boundary and interior cases to be specialized for each
158  // scheme.
159  //
160  template <typename VERTEX, typename MASK>
161  void ComputeVertexLimitMask(VERTEX const& vertexNeighborhood, MASK& positionMask) const;
162 
163  template <typename VERTEX, typename MASK>
164  void ComputeVertexLimitMask(VERTEX const& vertexNeighborhood, MASK& positionMask,
165  MASK& tangent1Mask,
166  MASK& tangent2Mask) const;
167 
168 protected:
169  //
170  // Supporting internal methods -- optionally implemented, depending on specialization:
171  //
172 
173  // For edge-vertex masks -- two kinds of basic mask:
174  template <typename EDGE, typename MASK>
175  void assignCreaseMaskForEdge(EDGE const& edge, MASK& mask) const;
176 
177  template <typename EDGE, typename MASK>
178  void assignSmoothMaskForEdge(EDGE const& edge, MASK& mask) const;
179 
180  // For vertex-vertex masks -- three kinds of basic mask:
181  template <typename VERTEX, typename MASK>
182  void assignCornerMaskForVertex(VERTEX const& edge, MASK& mask) const;
183 
184  template <typename VERTEX, typename MASK>
185  void assignCreaseMaskForVertex(VERTEX const& edge, MASK& mask, float const sharpness[]) const;
186 
187  template <typename VERTEX, typename MASK>
188  void assignSmoothMaskForVertex(VERTEX const& edge, MASK& mask) const;
189 
190 protected:
191  //
192  // We need a local "mask" class to be declared locally within the vertex-vertex mask query
193  // to hold one of the two possible mask required and to combine the local mask with the mask
194  // the caller provides. It has been parameterized by <WEIGHT> so that a version compatible
195  // with the callers mask class is created.
196  //
197  template <typename WEIGHT>
198  class LocalMask {
199 
200  public:
201  typedef WEIGHT Weight;
202 
203  public:
204  LocalMask(Weight* v, Weight* e, Weight* f) : _vWeights(v), _eWeights(e), _fWeights(f) { }
206 
207  public:
208 
209  //
210  // Methods required for general mask assignments and queries:
211  //
212  int GetNumVertexWeights() const { return _vCount; }
213  int GetNumEdgeWeights() const { return _eCount; }
214  int GetNumFaceWeights() const { return _fCount; }
215 
216  void SetNumVertexWeights(int count) { _vCount = count; }
217  void SetNumEdgeWeights( int count) { _eCount = count; }
218  void SetNumFaceWeights( int count) { _fCount = count; }
219 
220  Weight const& VertexWeight(int index) const { return _vWeights[index]; }
221  Weight const& EdgeWeight( int index) const { return _eWeights[index]; }
222  Weight const& FaceWeight( int index) const { return _fWeights[index]; }
223 
224  Weight& VertexWeight(int index) { return _vWeights[index]; }
225  Weight& EdgeWeight( int index) { return _eWeights[index]; }
226  Weight& FaceWeight( int index) { return _fWeights[index]; }
227 
228  public:
229 
230  //
231  // Additional methods -- mainly the blending method for vertex-vertex masks:
232  //
233  template <typename USER_MASK>
234  inline void
235  CombineVertexVertexMasks(Weight thisCoeff, Weight dstCoeff, USER_MASK& dst) const {
236 
237  //
238  // This implementation is convoluted by the potential sparsity of each mask. Since
239  // it is specific to a vertex-vertex mask, we are guaranteed to have exactly one
240  // vertex-weight for both masks, but the edge- and face-weights are optional. The
241  // child mask (the "source") should have a superset of the weights of the parent
242  // (the "destination") given its reduced sharpness, so we fortunately don't need to
243  // test all permutations.
244  //
245  dst.VertexWeight(0) = dstCoeff * dst.VertexWeight(0) + thisCoeff * this->VertexWeight(0);
246 
247  int edgeWeightCount = this->GetNumEdgeWeights();
248  if (edgeWeightCount) {
249  if (dst.GetNumEdgeWeights() == 0) {
250  dst.SetNumEdgeWeights(edgeWeightCount);
251  for (int i = 0; i < edgeWeightCount; ++i) {
252  dst.EdgeWeight(i) = thisCoeff * this->EdgeWeight(i);
253  }
254  } else {
255  for (int i = 0; i < edgeWeightCount; ++i) {
256  dst.EdgeWeight(i) = dstCoeff * dst.EdgeWeight(i) + thisCoeff * this->EdgeWeight(i);
257  }
258  }
259  }
260 
261  int faceWeightCount = this->GetNumFaceWeights();
262  if (faceWeightCount) {
263  if (dst.GetNumFaceWeights() == 0) {
264  dst.SetNumFaceWeights(faceWeightCount);
265  for (int i = 0; i < faceWeightCount; ++i) {
266  dst.FaceWeight(i) = thisCoeff * this->FaceWeight(i);
267  }
268  } else {
269  for (int i = 0; i < faceWeightCount; ++i) {
270  dst.FaceWeight(i) = dstCoeff * dst.FaceWeight(i) + thisCoeff * this->FaceWeight(i);
271  }
272  }
273  }
274  }
275 
276  private:
277  Weight* _vWeights;
278  Weight* _eWeights;
279  Weight* _fWeights;
280  int _vCount;
281  int _eCount;
282  int _fCount;
283  };
284 
285 private:
286  Options _options;
287 };
288 
289 
290 //
291 // Crease and corner masks are common to most schemes -- the rest need to be provided
292 // for each Scheme specialization.
293 //
294 template <Sdc::Type SCHEME>
295 template <typename EDGE, typename MASK>
296 inline void
297 Scheme<SCHEME>::assignCreaseMaskForEdge(EDGE const&, MASK& mask) const {
298 
299  mask.SetNumVertexWeights(2);
300  mask.SetNumEdgeWeights(0);
301  mask.SetNumFaceWeights(0);
302 
303  mask.VertexWeight(0) = 0.5f;
304  mask.VertexWeight(1) = 0.5f;
305 }
306 
307 template <Sdc::Type SCHEME>
308 template <typename VERTEX, typename MASK>
309 inline void
310 Scheme<SCHEME>::assignCornerMaskForVertex(VERTEX const&, MASK& mask) const {
311 
312  mask.SetNumVertexWeights(1);
313  mask.SetNumEdgeWeights(0);
314  mask.SetNumFaceWeights(0);
315 
316  mask.VertexWeight(0) = 1.0f;
317 }
318 
319 
320 //
321 // The computation of a face-vertex mask is trivial and consistent for all schemes:
322 //
323 template <Sdc::Type SCHEME>
324 template <typename FACE, typename MASK>
325 void
326 Scheme<SCHEME>::ComputeFaceVertexMask(FACE const& face, MASK& mask) const {
327 
328  int vertCount = face.GetNumVertices();
329 
330  mask.SetNumVertexWeights(vertCount);
331  mask.SetNumEdgeWeights(0);
332  mask.SetNumFaceWeights(0);
333 
334  typename MASK::Weight vWeight = 1.0f / (typename MASK::Weight) vertCount;
335  for (int i = 0; i < vertCount; ++i) {
336  mask.VertexWeight(i) = vWeight;
337  }
338 }
339 
340 
341 //
342 // The computation of an edge-vertex mask requires inspection of sharpness values to
343 // determine if smooth or a crease, and also to detect and apply a transition from a
344 // crease to smooth. Using the protected methods to assign the specific masks (only
345 // two -- smooth or crease) this implementation should serve all non-linear schemes
346 // (currently Catmark and Loop) and only need to be specialized it for Bilinear to
347 // trivialize it to the crease case.
348 //
349 // The implementation here is slightly complicated by combining two scenarios into a
350 // single implementation -- either the caller knows the parent and child rules and
351 // provides them, or they don't and the Rules have to be determined from sharpness
352 // values. Both cases include quick return once the parent is determined to be
353 // smooth or the child a crease, leaving the transitional case remaining.
354 //
355 // The overall process is as follows:
356 //
357 // - quickly detect the most common specified or detected Smooth case and return
358 // - quickly detect a full Crease by child Rule assignment and return
359 // - determine from sharpness if unspecified child is a crease -- return if so
360 // - compute smooth mask for child and combine with crease from parent
361 //
362 // Usage of the parent Rule here allows some misuse in that only three of five possible
363 // assignments are legitimate for the parent and four for the child (Dart being only
364 // valid for the child and Corner for neither). Results are undefined in these cases.
365 //
366 template <Sdc::Type SCHEME>
367 template <typename EDGE, typename MASK>
368 void
370  MASK& mask,
371  Crease::Rule parentRule,
372  Crease::Rule childRule) const {
373 
374  //
375  // If the parent was specified or determined to be Smooth, we can quickly return
376  // with a Smooth mask. Otherwise the parent is a crease -- if the child was
377  // also specified to be a crease, we can quickly return with a Crease mask.
378  //
379  if ((parentRule == Crease::RULE_SMOOTH) ||
380  ((parentRule == Crease::RULE_UNKNOWN) && (edge.GetSharpness() <= 0.0f))) {
381  assignSmoothMaskForEdge(edge, mask);
382  return;
383  }
384  if (childRule == Crease::RULE_CREASE) {
385  assignCreaseMaskForEdge(edge, mask);
386  return;
387  }
388 
389  //
390  // We have a Crease on the parent and the child was either specified as Smooth
391  // or was not specified at all -- deal with the unspecified case first (again
392  // returning a Crease mask if the child is also determined to be a Crease) and
393  // continue if we have a transition to Smooth.
394  //
395  // Note when qualifying the child that if the parent sharpness > 1.0, regardless
396  // of the creasing method, whether the child sharpness values decay to zero is
397  // irrelevant -- the fractional weight for such a case (the value of the parent
398  // sharpness) is > 1.0, and when clamped to 1 effectively yields a full crease.
399  //
400  if (childRule == Crease::RULE_UNKNOWN) {
401  Crease crease(_options);
402 
403  bool childIsCrease = false;
404  if (parentRule == Crease::RULE_CREASE) {
405  // Child unknown as default value but parent Rule specified as Crease
406  childIsCrease = true;
407  } else if (edge.GetSharpness() >= 1.0f) {
408  // Sharpness >= 1.0 always a crease -- see note above
409  childIsCrease = true;
410  } else if (crease.IsUniform()) {
411  // Sharpness < 1.0 is guaranteed to decay to 0.0 for Uniform child edges
412  childIsCrease = false;
413  } else {
414  // Sharpness <= 1.0 does not necessarily decay to 0.0 for both child edges...
415  float cEdgeSharpness[2];
416  edge.GetChildSharpnesses(crease, cEdgeSharpness);
417  childIsCrease = (cEdgeSharpness[0] > 0.0f) && (cEdgeSharpness[1] > 0.0f);
418  }
419  if (childIsCrease) {
420  assignCreaseMaskForEdge(edge, mask);
421  return;
422  }
423  }
424 
425  //
426  // We are now left with have the Crease-to-Smooth case -- compute the Smooth mask
427  // for the child and augment it with the transitional Crease of the parent.
428  //
429  // A general combination of separately assigned masks here (as done in the vertex-
430  // vertex case) is overkill -- trivially combine the 0.5f vertex coefficient for
431  // the Crease of the parent with the vertex weights and attenuate the face weights
432  // accordingly.
433  //
434  assignSmoothMaskForEdge(edge, mask);
435 
436  typedef typename MASK::Weight Weight;
437 
438  Weight pWeight = edge.GetSharpness();
439  Weight cWeight = 1.0f - pWeight;
440 
441  mask.VertexWeight(0) = pWeight * 0.5f + cWeight * mask.VertexWeight(0);
442  mask.VertexWeight(1) = pWeight * 0.5f + cWeight * mask.VertexWeight(1);
443 
444  int faceCount = mask.GetNumFaceWeights();
445  for (int i = 0; i < faceCount; ++i) {
446  mask.FaceWeight(i) *= cWeight;
447  }
448 }
449 
450 //
451 // The computation of a vertex-vertex mask requires inspection of creasing sharpness values
452 // to determine what subdivision Rules apply to the parent and its child vertex, and also to
453 // detect and apply a transition between two differing Rules. Using the protected methods to
454 // assign specific masks, this implementation should serve all non-linear schemes (currently
455 // Catmark and Loop) and only need to be specialized for Bilinear to remove all unnecessary
456 // complexity relating to creasing, Rules, etc.
457 //
458 // The implementation here is slightly complicated by combining two scenarios into one --
459 // either the caller knows the parent and child rules and provides them, or they don't and
460 // the Rules have to be determined from sharpness values. Even when the Rules are known and
461 // provided though, there are cases where the parent and child sharpness values need to be
462 // identified, so accounting for the unknown Rules too is not much of an added complication.
463 //
464 // The benefit of supporting specified Rules is that they can often often be trivially
465 // determined from context (e.g. a vertex derived from a face at a previous level will always
466 // be smooth) rather than more generally, and at greater cost, inspecting neighboring and
467 // they are often the same for parent and child.
468 //
469 // The overall process is as follows:
470 //
471 // - quickly detect the most common Smooth case when specified and return
472 // - determine if sharpness for parent is required and gather if so
473 // - if unspecified, determine the parent rule
474 // - assign mask for the parent rule -- returning if Smooth/Dart
475 // - return if child rule matches parent
476 // - gather sharpness for child to determine or combine child rule
477 // - if unspecified, determine the child rule, returning if it matches parent
478 // - assign local mask for child rule
479 // - combine local child mask with the parent mask
480 //
481 // Remember -- if the parent rule is specified but the child is not, this implies only one
482 // of the two optional rules was specified and is meant to indicate there is no transition,
483 // so the child rule should be assigned to be the same (wish the compiler would allow this
484 // in default value assignment).
485 //
486 template <Type SCHEME>
487 template <typename VERTEX, typename MASK>
488 void
490  MASK& mask,
491  Crease::Rule pRule,
492  Crease::Rule cRule) const {
493 
494  // Quick assignment and return for the most common case:
495  if ((pRule == Crease::RULE_SMOOTH) || (pRule == Crease::RULE_DART)) {
496  assignSmoothMaskForVertex(vertex, mask);
497  return;
498  }
499  // If unspecified, assign the child rule to match the parent rule if specified:
500  if ((cRule == Crease::RULE_UNKNOWN) && (pRule != Crease::RULE_UNKNOWN)) {
501  cRule = pRule;
502  }
503  int valence = vertex.GetNumEdges();
504 
505  //
506  // Determine if we need the parent edge sharpness values -- identify/gather if so
507  // and use it to compute the parent rule if unspecified:
508  //
509  float * pEdgeSharpnessBuffer = (float *)alloca(valence*sizeof(float)),
510  * pEdgeSharpness = 0,
511  pVertexSharpness = 0.0f;
512 
513  bool requireParentSharpness = (pRule == Crease::RULE_UNKNOWN) ||
514  (pRule == Crease::RULE_CREASE) ||
515  (pRule != cRule);
516  if (requireParentSharpness) {
517  pVertexSharpness = vertex.GetSharpness();
518  pEdgeSharpness = vertex.GetSharpnessPerEdge(pEdgeSharpnessBuffer);
519 
520  if (pRule == Crease::RULE_UNKNOWN) {
521  Crease crease(_options);
522  pRule = crease.DetermineVertexVertexRule(pVertexSharpness, valence, pEdgeSharpness);
523  }
524  }
525  if ((pRule == Crease::RULE_SMOOTH) || (pRule == Crease::RULE_DART)) {
526  assignSmoothMaskForVertex(vertex, mask);
527  return; // As done on entry, we can return immediately if parent is Smooth/Dart
528  } else if (pRule == Crease::RULE_CREASE) {
529  assignCreaseMaskForVertex(vertex, mask, pEdgeSharpness);
530  } else {
531  assignCornerMaskForVertex(vertex, mask);
532  }
533  if (cRule == pRule) return;
534 
535  //
536  // Identify/gather child sharpness to combine masks for the two differing Rules:
537  //
538  Crease crease(_options);
539 
540  float * cEdgeSharpnessBuffer = (float *)alloca(valence*sizeof(float)),
541  * cEdgeSharpness = vertex.GetChildSharpnessPerEdge(crease, cEdgeSharpnessBuffer),
542  cVertexSharpness = vertex.GetChildSharpness(crease);
543 
544  if (cRule == Crease::RULE_UNKNOWN) {
545  cRule = crease.DetermineVertexVertexRule(cVertexSharpness, valence, cEdgeSharpness);
546  if (cRule == pRule) return;
547  }
548 
549  //
550  // Intialize a local child mask, compute the fractional weight from parent and child
551  // sharpness values and combine the two masks:
552  //
553  typedef typename MASK::Weight Weight;
554 
555  Weight * cMaskWeights = (Weight *)alloca((1 + 2 * valence)*sizeof(Weight));
556  LocalMask<Weight> cMask(cMaskWeights, cMaskWeights + 1, cMaskWeights + 1 + valence);
557 
558  if ((cRule == Crease::RULE_SMOOTH) || (cRule == Crease::RULE_DART)) {
559  assignSmoothMaskForVertex(vertex, cMask);
560  } else if (cRule == Crease::RULE_CREASE) {
561  assignCreaseMaskForVertex(vertex, cMask, cEdgeSharpness);
562  } else {
563  assignCornerMaskForVertex(vertex, cMask);
564  }
565 
566  Weight pWeight = crease.ComputeFractionalWeightAtVertex(pVertexSharpness, cVertexSharpness,
567  valence, pEdgeSharpness, cEdgeSharpness);
568  Weight cWeight = 1.0f - pWeight;
569 
570  cMask.CombineVertexVertexMasks(cWeight, pWeight, mask);
571 }
572 
573 } // end namespace sdc
574 
575 } // end namespace OPENSUBDIV_VERSION
576 using namespace OPENSUBDIV_VERSION;
577 } // end namespace OpenSubdiv
578 
579 #endif /* SDC_SCHEME_H */
580 
void ComputeVertexVertexMask(VERTEX const &vertexNeighborhood, MASK &vertexVertexMask, Crease::Rule parentRule=Crease::RULE_UNKNOWN, Crease::Rule childRule=Crease::RULE_UNKNOWN) const
Definition: scheme.h:489
void assignSmoothMaskForVertex(VERTEX const &edge, MASK &mask) const
void ComputeEdgeVertexMask(EDGE const &edgeNeighborhood, MASK &edgeVertexMask, Crease::Rule parentRule=Crease::RULE_UNKNOWN, Crease::Rule childRule=Crease::RULE_UNKNOWN) const
Definition: scheme.h:369
void ComputeVertexLimitMask(VERTEX const &vertexNeighborhood, MASK &positionMask) const
void assignSmoothMaskForEdge(EDGE const &edge, MASK &mask) const
void ComputeFaceVertexMask(FACE const &faceNeighborhood, MASK &faceVertexMask) const
Definition: scheme.h:326
void assignCornerMaskForVertex(VERTEX const &edge, MASK &mask) const
Definition: scheme.h:310
void assignCreaseMaskForVertex(VERTEX const &edge, MASK &mask, float const sharpness[]) const
Weight const & FaceWeight(int index) const
Definition: scheme.h:222
LocalMask(Weight *v, Weight *e, Weight *f)
Definition: scheme.h:204
Rule DetermineVertexVertexRule(float vertexSharpness, int incidentEdgeCount, float const *incidentEdgeSharpness) const
float ComputeFractionalWeightAtVertex(float vertexSharpness, float childVertexSharpness, int incidentEdgeCount, float const *incidentEdgeSharpness, float const *childEdgesSharpness) const
void CombineVertexVertexMasks(Weight thisCoeff, Weight dstCoeff, USER_MASK &dst) const
Definition: scheme.h:235
Weight const & VertexWeight(int index) const
Definition: scheme.h:220
Scheme(Options const &options)
Definition: scheme.h:103
void SetOptions(const Options &newOptions)
Definition: scheme.h:108
Weight const & EdgeWeight(int index) const
Definition: scheme.h:221
void assignCreaseMaskForEdge(EDGE const &edge, MASK &mask) const
Definition: scheme.h:297