All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends
primvarRefiner.h
Go to the documentation of this file.
1 //
2 // Copyright 2015 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 OPENSUBDIV3_FAR_PRIMVAR_REFINER_H
25 #define OPENSUBDIV3_FAR_PRIMVAR_REFINER_H
26 
27 #include "../version.h"
28 
29 #include "../sdc/types.h"
30 #include "../sdc/options.h"
31 #include "../sdc/bilinearScheme.h"
32 #include "../sdc/catmarkScheme.h"
33 #include "../sdc/loopScheme.h"
34 #include "../vtr/level.h"
35 #include "../vtr/fvarLevel.h"
36 #include "../vtr/refinement.h"
37 #include "../vtr/fvarRefinement.h"
38 #include "../vtr/stackBuffer.h"
39 #include "../vtr/componentInterfaces.h"
40 #include "../far/types.h"
41 #include "../far/error.h"
42 #include "../far/topologyLevel.h"
43 #include "../far/topologyRefiner.h"
44 
45 #include <cassert>
46 
47 namespace OpenSubdiv {
48 namespace OPENSUBDIV_VERSION {
49 
50 namespace Far {
51 
55 template <typename REAL>
57 
58 public:
59  PrimvarRefinerReal(TopologyRefiner const & refiner) : _refiner(refiner) { }
61 
62  TopologyRefiner const & GetTopologyRefiner() const { return _refiner; }
63 
65 
113  template <class T, class U> void Interpolate(int level, T const & src, U & dst) const;
114 
130  template <class T, class U> void InterpolateVarying(int level, T const & src, U & dst) const;
131 
148  template <class T, class U> void InterpolateFaceUniform(int level, T const & src, U & dst) const;
149 
161  template <class T, class U> void InterpolateFaceVarying(int level, T const & src, U & dst, int channel = 0) const;
162 
163 
175  template <class T, class U> void Limit(T const & src, U & dstPos) const;
176 
177  template <class T, class U, class U1, class U2>
178  void Limit(T const & src, U & dstPos, U1 & dstTan1, U2 & dstTan2) const;
179 
180  template <class T, class U> void LimitFaceVarying(T const & src, U & dst, int channel = 0) const;
181 
183 
184 private:
185  typedef REAL Weight;
186 
187  // Non-copyable:
188  PrimvarRefinerReal(PrimvarRefinerReal const & src) : _refiner(src._refiner) { }
189  PrimvarRefinerReal & operator=(PrimvarRefinerReal const &) { return *this; }
190 
191  template <Sdc::SchemeType SCHEME, class T, class U> void interpFromFaces(int, T const &, U &) const;
192  template <Sdc::SchemeType SCHEME, class T, class U> void interpFromEdges(int, T const &, U &) const;
193  template <Sdc::SchemeType SCHEME, class T, class U> void interpFromVerts(int, T const &, U &) const;
194 
195  template <Sdc::SchemeType SCHEME, class T, class U> void interpFVarFromFaces(int, T const &, U &, int) const;
196  template <Sdc::SchemeType SCHEME, class T, class U> void interpFVarFromEdges(int, T const &, U &, int) const;
197  template <Sdc::SchemeType SCHEME, class T, class U> void interpFVarFromVerts(int, T const &, U &, int) const;
198 
199  template <Sdc::SchemeType SCHEME, class T, class U, class U1, class U2>
200  void limit(T const & src, U & pos, U1 * tan1, U2 * tan2) const;
201 
202  template <Sdc::SchemeType SCHEME, class T, class U>
203  void limitFVar(T const & src, U & dst, int channel) const;
204 
205 private:
206  TopologyRefiner const & _refiner;
207 
208 private:
209  //
210  // Local class to fulfill interface for <typename MASK> in the Scheme mask queries:
211  //
212  class Mask {
213  public:
214  typedef REAL Weight; // Also part of the expected interface
215 
216  public:
217  Mask(Weight* v, Weight* e, Weight* f) :
218  _vertWeights(v), _edgeWeights(e), _faceWeights(f),
219  _vertCount(0), _edgeCount(0), _faceCount(0),
220  _faceWeightsForFaceCenters(false)
221  { }
222 
223  ~Mask() { }
224 
225  public: // Generic interface expected of <typename MASK>:
226  int GetNumVertexWeights() const { return _vertCount; }
227  int GetNumEdgeWeights() const { return _edgeCount; }
228  int GetNumFaceWeights() const { return _faceCount; }
229 
230  void SetNumVertexWeights(int count) { _vertCount = count; }
231  void SetNumEdgeWeights( int count) { _edgeCount = count; }
232  void SetNumFaceWeights( int count) { _faceCount = count; }
233 
234  Weight const& VertexWeight(int index) const { return _vertWeights[index]; }
235  Weight const& EdgeWeight( int index) const { return _edgeWeights[index]; }
236  Weight const& FaceWeight( int index) const { return _faceWeights[index]; }
237 
238  Weight& VertexWeight(int index) { return _vertWeights[index]; }
239  Weight& EdgeWeight( int index) { return _edgeWeights[index]; }
240  Weight& FaceWeight( int index) { return _faceWeights[index]; }
241 
242  bool AreFaceWeightsForFaceCenters() const { return _faceWeightsForFaceCenters; }
243  void SetFaceWeightsForFaceCenters(bool on) { _faceWeightsForFaceCenters = on; }
244 
245  private:
246  Weight* _vertWeights;
247  Weight* _edgeWeights;
248  Weight* _faceWeights;
249 
250  int _vertCount;
251  int _edgeCount;
252  int _faceCount;
253 
254  bool _faceWeightsForFaceCenters;
255  };
256 };
257 
258 
259 //
260 // Public entry points to the methods. Queries of the scheme type and its
261 // use as a template parameter in subsequent implementation will be factored
262 // out of a later release:
263 //
264 template <typename REAL>
265 template <class T, class U>
266 inline void
267 PrimvarRefinerReal<REAL>::Interpolate(int level, T const & src, U & dst) const {
268 
269  assert(level>0 && level<=(int)_refiner._refinements.size());
270 
271  switch (_refiner._subdivType) {
272  case Sdc::SCHEME_CATMARK:
273  interpFromFaces<Sdc::SCHEME_CATMARK>(level, src, dst);
274  interpFromEdges<Sdc::SCHEME_CATMARK>(level, src, dst);
275  interpFromVerts<Sdc::SCHEME_CATMARK>(level, src, dst);
276  break;
277  case Sdc::SCHEME_LOOP:
278  interpFromFaces<Sdc::SCHEME_LOOP>(level, src, dst);
279  interpFromEdges<Sdc::SCHEME_LOOP>(level, src, dst);
280  interpFromVerts<Sdc::SCHEME_LOOP>(level, src, dst);
281  break;
283  interpFromFaces<Sdc::SCHEME_BILINEAR>(level, src, dst);
284  interpFromEdges<Sdc::SCHEME_BILINEAR>(level, src, dst);
285  interpFromVerts<Sdc::SCHEME_BILINEAR>(level, src, dst);
286  break;
287  }
288 }
289 
290 template <typename REAL>
291 template <class T, class U>
292 inline void
293 PrimvarRefinerReal<REAL>::InterpolateFaceVarying(int level, T const & src, U & dst, int channel) const {
294 
295  assert(level>0 && level<=(int)_refiner._refinements.size());
296 
297  switch (_refiner._subdivType) {
298  case Sdc::SCHEME_CATMARK:
299  interpFVarFromFaces<Sdc::SCHEME_CATMARK>(level, src, dst, channel);
300  interpFVarFromEdges<Sdc::SCHEME_CATMARK>(level, src, dst, channel);
301  interpFVarFromVerts<Sdc::SCHEME_CATMARK>(level, src, dst, channel);
302  break;
303  case Sdc::SCHEME_LOOP:
304  interpFVarFromFaces<Sdc::SCHEME_LOOP>(level, src, dst, channel);
305  interpFVarFromEdges<Sdc::SCHEME_LOOP>(level, src, dst, channel);
306  interpFVarFromVerts<Sdc::SCHEME_LOOP>(level, src, dst, channel);
307  break;
309  interpFVarFromFaces<Sdc::SCHEME_BILINEAR>(level, src, dst, channel);
310  interpFVarFromEdges<Sdc::SCHEME_BILINEAR>(level, src, dst, channel);
311  interpFVarFromVerts<Sdc::SCHEME_BILINEAR>(level, src, dst, channel);
312  break;
313  }
314 }
315 
316 template <typename REAL>
317 template <class T, class U>
318 inline void
319 PrimvarRefinerReal<REAL>::Limit(T const & src, U & dst) const {
320 
321  if (_refiner.getLevel(_refiner.GetMaxLevel()).getNumVertexEdgesTotal() == 0) {
323  "Failure in PrimvarRefiner::Limit() -- "
324  "last level of refinement does not include full topology.");
325  return;
326  }
327 
328  switch (_refiner._subdivType) {
329  case Sdc::SCHEME_CATMARK:
330  limit<Sdc::SCHEME_CATMARK>(src, dst, (U*)0, (U*)0);
331  break;
332  case Sdc::SCHEME_LOOP:
333  limit<Sdc::SCHEME_LOOP>(src, dst, (U*)0, (U*)0);
334  break;
336  limit<Sdc::SCHEME_BILINEAR>(src, dst, (U*)0, (U*)0);
337  break;
338  }
339 }
340 
341 template <typename REAL>
342 template <class T, class U, class U1, class U2>
343 inline void
344 PrimvarRefinerReal<REAL>::Limit(T const & src, U & dstPos, U1 & dstTan1, U2 & dstTan2) const {
345 
346  if (_refiner.getLevel(_refiner.GetMaxLevel()).getNumVertexEdgesTotal() == 0) {
348  "Failure in PrimvarRefiner::Limit() -- "
349  "last level of refinement does not include full topology.");
350  return;
351  }
352 
353  switch (_refiner._subdivType) {
354  case Sdc::SCHEME_CATMARK:
355  limit<Sdc::SCHEME_CATMARK>(src, dstPos, &dstTan1, &dstTan2);
356  break;
357  case Sdc::SCHEME_LOOP:
358  limit<Sdc::SCHEME_LOOP>(src, dstPos, &dstTan1, &dstTan2);
359  break;
361  limit<Sdc::SCHEME_BILINEAR>(src, dstPos, &dstTan1, &dstTan2);
362  break;
363  }
364 }
365 
366 template <typename REAL>
367 template <class T, class U>
368 inline void
369 PrimvarRefinerReal<REAL>::LimitFaceVarying(T const & src, U & dst, int channel) const {
370 
371  if (_refiner.getLevel(_refiner.GetMaxLevel()).getNumVertexEdgesTotal() == 0) {
373  "Failure in PrimvarRefiner::LimitFaceVarying() -- "
374  "last level of refinement does not include full topology.");
375  return;
376  }
377 
378  switch (_refiner._subdivType) {
379  case Sdc::SCHEME_CATMARK:
380  limitFVar<Sdc::SCHEME_CATMARK>(src, dst, channel);
381  break;
382  case Sdc::SCHEME_LOOP:
383  limitFVar<Sdc::SCHEME_LOOP>(src, dst, channel);
384  break;
386  limitFVar<Sdc::SCHEME_BILINEAR>(src, dst, channel);
387  break;
388  }
389 }
390 
391 template <typename REAL>
392 template <class T, class U>
393 inline void
394 PrimvarRefinerReal<REAL>::InterpolateFaceUniform(int level, T const & src, U & dst) const {
395 
396  assert(level>0 && level<=(int)_refiner._refinements.size());
397 
398  Vtr::internal::Refinement const & refinement = _refiner.getRefinement(level-1);
399  Vtr::internal::Level const & child = refinement.child();
400 
401  for (int cFace = 0; cFace < child.getNumFaces(); ++cFace) {
402 
403  Vtr::Index pFace = refinement.getChildFaceParentFace(cFace);
404 
405  dst[cFace] = src[pFace];
406  }
407 }
408 
409 template <typename REAL>
410 template <class T, class U>
411 inline void
412 PrimvarRefinerReal<REAL>::InterpolateVarying(int level, T const & src, U & dst) const {
413 
414  assert(level>0 && level<=(int)_refiner._refinements.size());
415 
416  Vtr::internal::Refinement const & refinement = _refiner.getRefinement(level-1);
417  Vtr::internal::Level const & parent = refinement.parent();
418 
419  //
420  // Group values to interpolate based on origin -- note that there may
421  // be none originating from faces:
422  //
423  if (refinement.getNumChildVerticesFromFaces() > 0) {
424 
425  for (int face = 0; face < parent.getNumFaces(); ++face) {
426 
427  Vtr::Index cVert = refinement.getFaceChildVertex(face);
428  if (Vtr::IndexIsValid(cVert)) {
429 
430  // Apply the weights to the parent face's vertices:
431  ConstIndexArray fVerts = parent.getFaceVertices(face);
432 
433  Weight fVaryingWeight = 1.0f / (Weight) fVerts.size();
434 
435  dst[cVert].Clear();
436  for (int i = 0; i < fVerts.size(); ++i) {
437  dst[cVert].AddWithWeight(src[fVerts[i]], fVaryingWeight);
438  }
439  }
440  }
441  }
442  for (int edge = 0; edge < parent.getNumEdges(); ++edge) {
443 
444  Vtr::Index cVert = refinement.getEdgeChildVertex(edge);
445  if (Vtr::IndexIsValid(cVert)) {
446 
447  // Apply the weights to the parent edges's vertices
448  ConstIndexArray eVerts = parent.getEdgeVertices(edge);
449 
450  dst[cVert].Clear();
451  dst[cVert].AddWithWeight(src[eVerts[0]], 0.5f);
452  dst[cVert].AddWithWeight(src[eVerts[1]], 0.5f);
453  }
454  }
455  for (int vert = 0; vert < parent.getNumVertices(); ++vert) {
456 
457  Vtr::Index cVert = refinement.getVertexChildVertex(vert);
458  if (Vtr::IndexIsValid(cVert)) {
459 
460  // Essentially copy the parent vertex:
461  dst[cVert].Clear();
462  dst[cVert].AddWithWeight(src[vert], 1.0f);
463  }
464  }
465 }
466 
467 
468 //
469 // Internal implementation methods -- grouping vertices to be interpolated
470 // based on the type of parent component from which they originated:
471 //
472 template <typename REAL>
473 template <Sdc::SchemeType SCHEME, class T, class U>
474 inline void
475 PrimvarRefinerReal<REAL>::interpFromFaces(int level, T const & src, U & dst) const {
476 
477  Vtr::internal::Refinement const & refinement = _refiner.getRefinement(level-1);
478  Vtr::internal::Level const & parent = refinement.parent();
479 
480  if (refinement.getNumChildVerticesFromFaces() == 0) return;
481 
482  Sdc::Scheme<SCHEME> scheme(_refiner._subdivOptions);
483 
485 
486  for (int face = 0; face < parent.getNumFaces(); ++face) {
487 
488  Vtr::Index cVert = refinement.getFaceChildVertex(face);
489  if (!Vtr::IndexIsValid(cVert))
490  continue;
491 
492  // Declare and compute mask weights for this vertex relative to its parent face:
493  ConstIndexArray fVerts = parent.getFaceVertices(face);
494 
495  Mask fMask(fVertWeights, 0, 0);
496  Vtr::internal::FaceInterface fHood(fVerts.size());
497 
498  scheme.ComputeFaceVertexMask(fHood, fMask);
499 
500  // Apply the weights to the parent face's vertices:
501  dst[cVert].Clear();
502 
503  for (int i = 0; i < fVerts.size(); ++i) {
504 
505  dst[cVert].AddWithWeight(src[fVerts[i]], fVertWeights[i]);
506  }
507  }
508 }
509 
510 template <typename REAL>
511 template <Sdc::SchemeType SCHEME, class T, class U>
512 inline void
513 PrimvarRefinerReal<REAL>::interpFromEdges(int level, T const & src, U & dst) const {
514 
515  Vtr::internal::Refinement const & refinement = _refiner.getRefinement(level-1);
516  Vtr::internal::Level const & parent = refinement.parent();
517  Vtr::internal::Level const & child = refinement.child();
518 
519  Sdc::Scheme<SCHEME> scheme(_refiner._subdivOptions);
520 
521  Vtr::internal::EdgeInterface eHood(parent);
522 
523  Weight eVertWeights[2];
524  Vtr::internal::StackBuffer<Weight,8> eFaceWeights(parent.getMaxEdgeFaces());
525 
526  for (int edge = 0; edge < parent.getNumEdges(); ++edge) {
527 
528  Vtr::Index cVert = refinement.getEdgeChildVertex(edge);
529  if (!Vtr::IndexIsValid(cVert))
530  continue;
531 
532  // Declare and compute mask weights for this vertex relative to its parent edge:
533  ConstIndexArray eVerts = parent.getEdgeVertices(edge),
534  eFaces = parent.getEdgeFaces(edge);
535 
536  Mask eMask(eVertWeights, 0, eFaceWeights);
537 
538  eHood.SetIndex(edge);
539 
540  Sdc::Crease::Rule pRule = (parent.getEdgeSharpness(edge) > 0.0f) ? Sdc::Crease::RULE_CREASE : Sdc::Crease::RULE_SMOOTH;
541  Sdc::Crease::Rule cRule = child.getVertexRule(cVert);
542 
543  scheme.ComputeEdgeVertexMask(eHood, eMask, pRule, cRule);
544 
545  // Apply the weights to the parent edges's vertices and (if applicable) to
546  // the child vertices of its incident faces:
547  dst[cVert].Clear();
548  dst[cVert].AddWithWeight(src[eVerts[0]], eVertWeights[0]);
549  dst[cVert].AddWithWeight(src[eVerts[1]], eVertWeights[1]);
550 
551  if (eMask.GetNumFaceWeights() > 0) {
552 
553  for (int i = 0; i < eFaces.size(); ++i) {
554 
555  if (eMask.AreFaceWeightsForFaceCenters()) {
556  assert(refinement.getNumChildVerticesFromFaces() > 0);
557  Vtr::Index cVertOfFace = refinement.getFaceChildVertex(eFaces[i]);
558 
559  assert(Vtr::IndexIsValid(cVertOfFace));
560  dst[cVert].AddWithWeight(dst[cVertOfFace], eFaceWeights[i]);
561  } else {
562  Vtr::Index pFace = eFaces[i];
563  ConstIndexArray pFaceEdges = parent.getFaceEdges(pFace),
564  pFaceVerts = parent.getFaceVertices(pFace);
565 
566  int eInFace = 0;
567  for ( ; pFaceEdges[eInFace] != edge; ++eInFace ) ;
568 
569  int vInFace = eInFace + 2;
570  if (vInFace >= pFaceVerts.size()) vInFace -= pFaceVerts.size();
571 
572  Vtr::Index pVertNext = pFaceVerts[vInFace];
573  dst[cVert].AddWithWeight(src[pVertNext], eFaceWeights[i]);
574  }
575  }
576  }
577  }
578 }
579 
580 template <typename REAL>
581 template <Sdc::SchemeType SCHEME, class T, class U>
582 inline void
583 PrimvarRefinerReal<REAL>::interpFromVerts(int level, T const & src, U & dst) const {
584 
585  Vtr::internal::Refinement const & refinement = _refiner.getRefinement(level-1);
586  Vtr::internal::Level const & parent = refinement.parent();
587  Vtr::internal::Level const & child = refinement.child();
588 
589  Sdc::Scheme<SCHEME> scheme(_refiner._subdivOptions);
590 
591  Vtr::internal::VertexInterface vHood(parent, child);
592 
593  Vtr::internal::StackBuffer<Weight,32> weightBuffer(2*parent.getMaxValence());
594 
595  for (int vert = 0; vert < parent.getNumVertices(); ++vert) {
596 
597  Vtr::Index cVert = refinement.getVertexChildVertex(vert);
598  if (!Vtr::IndexIsValid(cVert))
599  continue;
600 
601  // Declare and compute mask weights for this vertex relative to its parent edge:
602  ConstIndexArray vEdges = parent.getVertexEdges(vert),
603  vFaces = parent.getVertexFaces(vert);
604 
605  Weight vVertWeight,
606  * vEdgeWeights = weightBuffer,
607  * vFaceWeights = vEdgeWeights + vEdges.size();
608 
609  Mask vMask(&vVertWeight, vEdgeWeights, vFaceWeights);
610 
611  vHood.SetIndex(vert, cVert);
612 
613  Sdc::Crease::Rule pRule = parent.getVertexRule(vert);
614  Sdc::Crease::Rule cRule = child.getVertexRule(cVert);
615 
616  scheme.ComputeVertexVertexMask(vHood, vMask, pRule, cRule);
617 
618  // Apply the weights to the parent vertex, the vertices opposite its incident
619  // edges, and the child vertices of its incident faces:
620  //
621  // In order to improve numerical precision, it's better to apply smaller weights
622  // first, so begin with the face-weights followed by the edge-weights and the
623  // vertex weight last.
624  dst[cVert].Clear();
625 
626  if (vMask.GetNumFaceWeights() > 0) {
627  assert(vMask.AreFaceWeightsForFaceCenters());
628 
629  for (int i = 0; i < vFaces.size(); ++i) {
630 
631  Vtr::Index cVertOfFace = refinement.getFaceChildVertex(vFaces[i]);
632  assert(Vtr::IndexIsValid(cVertOfFace));
633  dst[cVert].AddWithWeight(dst[cVertOfFace], vFaceWeights[i]);
634  }
635  }
636  if (vMask.GetNumEdgeWeights() > 0) {
637 
638  for (int i = 0; i < vEdges.size(); ++i) {
639 
640  ConstIndexArray eVerts = parent.getEdgeVertices(vEdges[i]);
641  Vtr::Index pVertOppositeEdge = (eVerts[0] == vert) ? eVerts[1] : eVerts[0];
642 
643  dst[cVert].AddWithWeight(src[pVertOppositeEdge], vEdgeWeights[i]);
644  }
645  }
646  dst[cVert].AddWithWeight(src[vert], vVertWeight);
647  }
648 }
649 
650 
651 //
652 // Internal face-varying implementation details:
653 //
654 template <typename REAL>
655 template <Sdc::SchemeType SCHEME, class T, class U>
656 inline void
657 PrimvarRefinerReal<REAL>::interpFVarFromFaces(int level, T const & src, U & dst, int channel) const {
658 
659  Vtr::internal::Refinement const & refinement = _refiner.getRefinement(level-1);
660 
661  if (refinement.getNumChildVerticesFromFaces() == 0) return;
662 
663  Sdc::Scheme<SCHEME> scheme(_refiner._subdivOptions);
664 
665  Vtr::internal::Level const & parentLevel = refinement.parent();
666  Vtr::internal::Level const & childLevel = refinement.child();
667 
668  Vtr::internal::FVarLevel const & parentFVar = parentLevel.getFVarLevel(channel);
669  Vtr::internal::FVarLevel const & childFVar = childLevel.getFVarLevel(channel);
670 
671  Vtr::internal::StackBuffer<Weight,16> fValueWeights(parentLevel.getMaxValence());
672 
673  for (int face = 0; face < parentLevel.getNumFaces(); ++face) {
674 
675  Vtr::Index cVert = refinement.getFaceChildVertex(face);
676  if (!Vtr::IndexIsValid(cVert))
677  continue;
678 
679  Vtr::Index cVertValue = childFVar.getVertexValueOffset(cVert);
680 
681  // The only difference for face-varying here is that we get the values associated
682  // with each face-vertex directly from the FVarLevel, rather than using the parent
683  // face-vertices directly. If any face-vertex has any sibling values, then we may
684  // get the wrong one using the face-vertex index directly.
685 
686  // Declare and compute mask weights for this vertex relative to its parent face:
687  ConstIndexArray fValues = parentFVar.getFaceValues(face);
688 
689  Mask fMask(fValueWeights, 0, 0);
690  Vtr::internal::FaceInterface fHood(fValues.size());
691 
692  scheme.ComputeFaceVertexMask(fHood, fMask);
693 
694  // Apply the weights to the parent face's vertices:
695  dst[cVertValue].Clear();
696 
697  for (int i = 0; i < fValues.size(); ++i) {
698  dst[cVertValue].AddWithWeight(src[fValues[i]], fValueWeights[i]);
699  }
700  }
701 }
702 
703 template <typename REAL>
704 template <Sdc::SchemeType SCHEME, class T, class U>
705 inline void
706 PrimvarRefinerReal<REAL>::interpFVarFromEdges(int level, T const & src, U & dst, int channel) const {
707 
708  Vtr::internal::Refinement const & refinement = _refiner.getRefinement(level-1);
709 
710  Sdc::Scheme<SCHEME> scheme(_refiner._subdivOptions);
711 
712  Vtr::internal::Level const & parentLevel = refinement.parent();
713  Vtr::internal::Level const & childLevel = refinement.child();
714 
715  Vtr::internal::FVarRefinement const & refineFVar = refinement.getFVarRefinement(channel);
716  Vtr::internal::FVarLevel const & parentFVar = parentLevel.getFVarLevel(channel);
717  Vtr::internal::FVarLevel const & childFVar = childLevel.getFVarLevel(channel);
718 
719  //
720  // Allocate and initialize (if linearly interpolated) interpolation weights for
721  // the edge mask:
722  //
723  Weight eVertWeights[2];
724  Vtr::internal::StackBuffer<Weight,8> eFaceWeights(parentLevel.getMaxEdgeFaces());
725 
726  Mask eMask(eVertWeights, 0, eFaceWeights);
727 
728  bool isLinearFVar = parentFVar.isLinear() || (_refiner._subdivType == Sdc::SCHEME_BILINEAR);
729  if (isLinearFVar) {
730  eMask.SetNumVertexWeights(2);
731  eMask.SetNumEdgeWeights(0);
732  eMask.SetNumFaceWeights(0);
733 
734  eVertWeights[0] = 0.5f;
735  eVertWeights[1] = 0.5f;
736  }
737 
738  Vtr::internal::EdgeInterface eHood(parentLevel);
739 
740  for (int edge = 0; edge < parentLevel.getNumEdges(); ++edge) {
741 
742  Vtr::Index cVert = refinement.getEdgeChildVertex(edge);
743  if (!Vtr::IndexIsValid(cVert))
744  continue;
745 
746  ConstIndexArray cVertValues = childFVar.getVertexValues(cVert);
747 
748  bool fvarEdgeVertMatchesVertex = childFVar.valueTopologyMatches(cVertValues[0]);
749  if (fvarEdgeVertMatchesVertex) {
750  //
751  // If smoothly interpolated, compute new weights for the edge mask:
752  //
753  if (!isLinearFVar) {
754  eHood.SetIndex(edge);
755 
756  Sdc::Crease::Rule pRule = (parentLevel.getEdgeSharpness(edge) > 0.0f)
758  Sdc::Crease::Rule cRule = childLevel.getVertexRule(cVert);
759 
760  scheme.ComputeEdgeVertexMask(eHood, eMask, pRule, cRule);
761  }
762 
763  // Apply the weights to the parent edge's vertices and (if applicable) to
764  // the child vertices of its incident faces:
765  //
766  // Even though the face-varying topology matches the vertex topology, we need
767  // to be careful here when getting values corresponding to the two end-vertices.
768  // While the edge may be continuous, the vertices at their ends may have
769  // discontinuities elsewhere in their neighborhood (i.e. on the "other side"
770  // of the end-vertex) and so have sibling values associated with them. In most
771  // cases the topology for an end-vertex will match and we can use it directly,
772  // but we must still check and retrieve as needed.
773  //
774  // Indices for values corresponding to face-vertices are guaranteed to match,
775  // so we can use the child-vertex indices directly.
776  //
777  // And by "directly", we always use getVertexValue(vertexIndex) to reference
778  // values in the "src" to account for the possible indirection that may exist at
779  // level 0 -- where there may be fewer values than vertices and an additional
780  // indirection is necessary. We can use a vertex index directly for "dst" when
781  // it matches.
782  //
783  Vtr::Index eVertValues[2];
784 
785  parentFVar.getEdgeFaceValues(edge, 0, eVertValues);
786 
787  Index cVertValue = cVertValues[0];
788 
789  dst[cVertValue].Clear();
790  dst[cVertValue].AddWithWeight(src[eVertValues[0]], eVertWeights[0]);
791  dst[cVertValue].AddWithWeight(src[eVertValues[1]], eVertWeights[1]);
792 
793  if (eMask.GetNumFaceWeights() > 0) {
794 
795  ConstIndexArray eFaces = parentLevel.getEdgeFaces(edge);
796 
797  for (int i = 0; i < eFaces.size(); ++i) {
798  if (eMask.AreFaceWeightsForFaceCenters()) {
799 
800  Vtr::Index cVertOfFace = refinement.getFaceChildVertex(eFaces[i]);
801  assert(Vtr::IndexIsValid(cVertOfFace));
802 
803  Vtr::Index cValueOfFace = childFVar.getVertexValueOffset(cVertOfFace);
804  dst[cVertValue].AddWithWeight(dst[cValueOfFace], eFaceWeights[i]);
805  } else {
806  Vtr::Index pFace = eFaces[i];
807  ConstIndexArray pFaceEdges = parentLevel.getFaceEdges(pFace),
808  pFaceVerts = parentLevel.getFaceVertices(pFace);
809 
810  int eInFace = 0;
811  for ( ; pFaceEdges[eInFace] != edge; ++eInFace ) ;
812 
813  // Edge "i" spans vertices [i,i+1] so we want i+2...
814  int vInFace = eInFace + 2;
815  if (vInFace >= pFaceVerts.size()) vInFace -= pFaceVerts.size();
816 
817  Vtr::Index pValueNext = parentFVar.getFaceValues(pFace)[vInFace];
818  dst[cVertValue].AddWithWeight(src[pValueNext], eFaceWeights[i]);
819  }
820  }
821  }
822  } else {
823  //
824  // Mismatched edge-verts should just be linearly interpolated between the pairs of
825  // values for each sibling of the child edge-vertex -- the question is: which face
826  // holds that pair of values for a given sibling?
827  //
828  // In the manifold case, the sibling and edge-face indices will correspond. We
829  // will eventually need to update this to account for > 3 incident faces.
830  //
831  for (int i = 0; i < cVertValues.size(); ++i) {
832  Vtr::Index eVertValues[2];
833  int eFaceIndex = refineFVar.getChildValueParentSource(cVert, i);
834  assert(eFaceIndex == i);
835 
836  parentFVar.getEdgeFaceValues(edge, eFaceIndex, eVertValues);
837 
838  Index cVertValue = cVertValues[i];
839 
840  dst[cVertValue].Clear();
841  dst[cVertValue].AddWithWeight(src[eVertValues[0]], 0.5);
842  dst[cVertValue].AddWithWeight(src[eVertValues[1]], 0.5);
843  }
844  }
845  }
846 }
847 
848 template <typename REAL>
849 template <Sdc::SchemeType SCHEME, class T, class U>
850 inline void
851 PrimvarRefinerReal<REAL>::interpFVarFromVerts(int level, T const & src, U & dst, int channel) const {
852 
853  Vtr::internal::Refinement const & refinement = _refiner.getRefinement(level-1);
854 
855  Sdc::Scheme<SCHEME> scheme(_refiner._subdivOptions);
856 
857  Vtr::internal::Level const & parentLevel = refinement.parent();
858  Vtr::internal::Level const & childLevel = refinement.child();
859 
860  Vtr::internal::FVarRefinement const & refineFVar = refinement.getFVarRefinement(channel);
861  Vtr::internal::FVarLevel const & parentFVar = parentLevel.getFVarLevel(channel);
862  Vtr::internal::FVarLevel const & childFVar = childLevel.getFVarLevel(channel);
863 
864  bool isLinearFVar = parentFVar.isLinear() || (_refiner._subdivType == Sdc::SCHEME_BILINEAR);
865 
866  Vtr::internal::StackBuffer<Weight,32> weightBuffer(2*parentLevel.getMaxValence());
867 
868  Vtr::internal::StackBuffer<Vtr::Index,16> vEdgeValues(parentLevel.getMaxValence());
869 
870  Vtr::internal::VertexInterface vHood(parentLevel, childLevel);
871 
872  for (int vert = 0; vert < parentLevel.getNumVertices(); ++vert) {
873 
874  Vtr::Index cVert = refinement.getVertexChildVertex(vert);
875  if (!Vtr::IndexIsValid(cVert))
876  continue;
877 
878  ConstIndexArray pVertValues = parentFVar.getVertexValues(vert),
879  cVertValues = childFVar.getVertexValues(cVert);
880 
881  bool fvarVertVertMatchesVertex = childFVar.valueTopologyMatches(cVertValues[0]);
882  if (isLinearFVar && fvarVertVertMatchesVertex) {
883  dst[cVertValues[0]].Clear();
884  dst[cVertValues[0]].AddWithWeight(src[pVertValues[0]], 1.0f);
885  continue;
886  }
887 
888  if (fvarVertVertMatchesVertex) {
889  //
890  // Declare and compute mask weights for this vertex relative to its parent edge:
891  //
892  // (We really need to encapsulate this somewhere else for use here and in the
893  // general case)
894  //
895  ConstIndexArray vEdges = parentLevel.getVertexEdges(vert);
896 
897  Weight vVertWeight;
898  Weight * vEdgeWeights = weightBuffer;
899  Weight * vFaceWeights = vEdgeWeights + vEdges.size();
900 
901  Mask vMask(&vVertWeight, vEdgeWeights, vFaceWeights);
902 
903  vHood.SetIndex(vert, cVert);
904 
905  Sdc::Crease::Rule pRule = parentLevel.getVertexRule(vert);
906  Sdc::Crease::Rule cRule = childLevel.getVertexRule(cVert);
907 
908  scheme.ComputeVertexVertexMask(vHood, vMask, pRule, cRule);
909 
910  // Apply the weights to the parent vertex, the vertices opposite its incident
911  // edges, and the child vertices of its incident faces:
912  //
913  // Even though the face-varying topology matches the vertex topology, we need
914  // to be careful here when getting values corresponding to vertices at the
915  // ends of edges. While the edge may be continuous, the end vertex may have
916  // discontinuities elsewhere in their neighborhood (i.e. on the "other side"
917  // of the end-vertex) and so have sibling values associated with them. In most
918  // cases the topology for an end-vertex will match and we can use it directly,
919  // but we must still check and retrieve as needed.
920  //
921  // Indices for values corresponding to face-vertices are guaranteed to match,
922  // so we can use the child-vertex indices directly.
923  //
924  // And by "directly", we always use getVertexValue(vertexIndex) to reference
925  // values in the "src" to account for the possible indirection that may exist at
926  // level 0 -- where there may be fewer values than vertices and an additional
927  // indirection is necessary. We can use a vertex index directly for "dst" when
928  // it matches.
929  //
930  // As with applying the mask to vertex data, in order to improve numerical
931  // precision, it's better to apply smaller weights first, so begin with the
932  // face-weights followed by the edge-weights and the vertex weight last.
933  //
934  Vtr::Index pVertValue = pVertValues[0];
935  Vtr::Index cVertValue = cVertValues[0];
936 
937  dst[cVertValue].Clear();
938  if (vMask.GetNumFaceWeights() > 0) {
939  assert(vMask.AreFaceWeightsForFaceCenters());
940 
941  ConstIndexArray vFaces = parentLevel.getVertexFaces(vert);
942 
943  for (int i = 0; i < vFaces.size(); ++i) {
944 
945  Vtr::Index cVertOfFace = refinement.getFaceChildVertex(vFaces[i]);
946  assert(Vtr::IndexIsValid(cVertOfFace));
947 
948  Vtr::Index cValueOfFace = childFVar.getVertexValueOffset(cVertOfFace);
949  dst[cVertValue].AddWithWeight(dst[cValueOfFace], vFaceWeights[i]);
950  }
951  }
952  if (vMask.GetNumEdgeWeights() > 0) {
953 
954  parentFVar.getVertexEdgeValues(vert, vEdgeValues);
955 
956  for (int i = 0; i < vEdges.size(); ++i) {
957  dst[cVertValue].AddWithWeight(src[vEdgeValues[i]], vEdgeWeights[i]);
958  }
959  }
960  dst[cVertValue].AddWithWeight(src[pVertValue], vVertWeight);
961  } else {
962  //
963  // Each FVar value associated with a vertex will be either a corner or a crease,
964  // or potentially in transition from corner to crease:
965  // - if the CHILD is a corner, there can be no transition so we have a corner
966  // - otherwise if the PARENT is a crease, both will be creases (no transition)
967  // - otherwise the parent must be a corner and the child a crease (transition)
968  //
969  Vtr::internal::FVarLevel::ConstValueTagArray pValueTags = parentFVar.getVertexValueTags(vert);
970  Vtr::internal::FVarLevel::ConstValueTagArray cValueTags = childFVar.getVertexValueTags(cVert);
971 
972  for (int cSibling = 0; cSibling < cVertValues.size(); ++cSibling) {
973  int pSibling = refineFVar.getChildValueParentSource(cVert, cSibling);
974  assert(pSibling == cSibling);
975 
976  Vtr::Index pVertValue = pVertValues[pSibling];
977  Vtr::Index cVertValue = cVertValues[cSibling];
978 
979  dst[cVertValue].Clear();
980  if (isLinearFVar || cValueTags[cSibling].isCorner()) {
981  dst[cVertValue].AddWithWeight(src[pVertValue], 1.0f);
982  } else {
983  //
984  // We have either a crease or a transition from corner to crease -- in
985  // either case, we need the end values for the full/fractional crease:
986  //
987  Index pEndValues[2];
988  parentFVar.getVertexCreaseEndValues(vert, pSibling, pEndValues);
989 
990  Weight vWeight = 0.75f;
991  Weight eWeight = 0.125f;
992 
993  //
994  // If semi-sharp we need to apply fractional weighting -- if made sharp because
995  // of the other sibling (dependent-sharp) use the fractional weight from that
996  // other sibling (should only occur when there are 2):
997  //
998  if (pValueTags[pSibling].isSemiSharp()) {
999  Weight wCorner = pValueTags[pSibling].isDepSharp()
1000  ? refineFVar.getFractionalWeight(vert, !pSibling, cVert, !cSibling)
1001  : refineFVar.getFractionalWeight(vert, pSibling, cVert, cSibling);
1002  Weight wCrease = 1.0f - wCorner;
1003 
1004  vWeight = wCrease * 0.75f + wCorner;
1005  eWeight = wCrease * 0.125f;
1006  }
1007  dst[cVertValue].AddWithWeight(src[pEndValues[0]], eWeight);
1008  dst[cVertValue].AddWithWeight(src[pEndValues[1]], eWeight);
1009  dst[cVertValue].AddWithWeight(src[pVertValue], vWeight);
1010  }
1011  }
1012  }
1013  }
1014 }
1015 
1016 template <typename REAL>
1017 template <Sdc::SchemeType SCHEME, class T, class U, class U1, class U2>
1018 inline void
1019 PrimvarRefinerReal<REAL>::limit(T const & src, U & dstPos, U1 * dstTan1Ptr, U2 * dstTan2Ptr) const {
1020 
1021  Sdc::Scheme<SCHEME> scheme(_refiner._subdivOptions);
1022 
1023  Vtr::internal::Level const & level = _refiner.getLevel(_refiner.GetMaxLevel());
1024 
1025  int maxWeightsPerMask = 1 + 2 * level.getMaxValence();
1026  bool hasTangents = (dstTan1Ptr && dstTan2Ptr);
1027  int numMasks = 1 + (hasTangents ? 2 : 0);
1028 
1029  Vtr::internal::StackBuffer<Index,33> indexBuffer(maxWeightsPerMask);
1030  Vtr::internal::StackBuffer<Weight,99> weightBuffer(numMasks * maxWeightsPerMask);
1031 
1032  Weight * vPosWeights = weightBuffer,
1033  * ePosWeights = vPosWeights + 1,
1034  * fPosWeights = ePosWeights + level.getMaxValence();
1035  Weight * vTan1Weights = vPosWeights + maxWeightsPerMask,
1036  * eTan1Weights = ePosWeights + maxWeightsPerMask,
1037  * fTan1Weights = fPosWeights + maxWeightsPerMask;
1038  Weight * vTan2Weights = vTan1Weights + maxWeightsPerMask,
1039  * eTan2Weights = eTan1Weights + maxWeightsPerMask,
1040  * fTan2Weights = fTan1Weights + maxWeightsPerMask;
1041 
1042  Mask posMask( vPosWeights, ePosWeights, fPosWeights);
1043  Mask tan1Mask(vTan1Weights, eTan1Weights, fTan1Weights);
1044  Mask tan2Mask(vTan2Weights, eTan2Weights, fTan2Weights);
1045 
1046  // This is a bit obscure -- assigning both parent and child as last level -- but
1047  // this mask type was intended for another purpose. Consider one for the limit:
1048  Vtr::internal::VertexInterface vHood(level, level);
1049 
1050  for (int vert = 0; vert < level.getNumVertices(); ++vert) {
1051  ConstIndexArray vEdges = level.getVertexEdges(vert);
1052 
1053  // Incomplete vertices (present in sparse refinement) do not have their full
1054  // topological neighborhood to determine a proper limit -- just leave the
1055  // vertex at the refined location and continue to the next:
1056  if (level.getVertexTag(vert)._incomplete || (vEdges.size() == 0)) {
1057  dstPos[vert].Clear();
1058  dstPos[vert].AddWithWeight(src[vert], 1.0);
1059  if (hasTangents) {
1060  (*dstTan1Ptr)[vert].Clear();
1061  (*dstTan2Ptr)[vert].Clear();
1062  }
1063  continue;
1064  }
1065 
1066  //
1067  // Limit masks require the subdivision Rule for the vertex in order to deal
1068  // with infinitely sharp features correctly -- including boundaries and corners.
1069  // The vertex neighborhood is minimally defined with vertex and edge counts.
1070  //
1071  Sdc::Crease::Rule vRule = level.getVertexRule(vert);
1072 
1073  // This is a bit obscure -- child vertex index will be ignored here
1074  vHood.SetIndex(vert, vert);
1075 
1076  if (hasTangents) {
1077  scheme.ComputeVertexLimitMask(vHood, posMask, tan1Mask, tan2Mask, vRule);
1078  } else {
1079  scheme.ComputeVertexLimitMask(vHood, posMask, vRule);
1080  }
1081 
1082  //
1083  // Gather the neighboring vertices of this vertex -- the vertices opposite its
1084  // incident edges, and the opposite vertices of its incident faces:
1085  //
1086  Index * eIndices = indexBuffer;
1087  Index * fIndices = indexBuffer + vEdges.size();
1088 
1089  for (int i = 0; i < vEdges.size(); ++i) {
1090  ConstIndexArray eVerts = level.getEdgeVertices(vEdges[i]);
1091 
1092  eIndices[i] = (eVerts[0] == vert) ? eVerts[1] : eVerts[0];
1093  }
1094  if (posMask.GetNumFaceWeights() || (hasTangents && tan1Mask.GetNumFaceWeights())) {
1095  ConstIndexArray vFaces = level.getVertexFaces(vert);
1096  ConstLocalIndexArray vInFace = level.getVertexFaceLocalIndices(vert);
1097 
1098  for (int i = 0; i < vFaces.size(); ++i) {
1099  ConstIndexArray fVerts = level.getFaceVertices(vFaces[i]);
1100 
1101  LocalIndex vOppInFace = (vInFace[i] + 2);
1102  if (vOppInFace >= fVerts.size()) vOppInFace -= (LocalIndex)fVerts.size();
1103 
1104  fIndices[i] = level.getFaceVertices(vFaces[i])[vOppInFace];
1105  }
1106  }
1107 
1108  //
1109  // Combine the weights and indices for position and tangents. As with applying
1110  // refinement masks to vertex data, in order to improve numerical precision, it's
1111  // better to apply smaller weights first, so begin with the face-weights followed
1112  // by the edge-weights and the vertex weight last.
1113  //
1114  dstPos[vert].Clear();
1115  for (int i = 0; i < posMask.GetNumFaceWeights(); ++i) {
1116  dstPos[vert].AddWithWeight(src[fIndices[i]], fPosWeights[i]);
1117  }
1118  for (int i = 0; i < posMask.GetNumEdgeWeights(); ++i) {
1119  dstPos[vert].AddWithWeight(src[eIndices[i]], ePosWeights[i]);
1120  }
1121  dstPos[vert].AddWithWeight(src[vert], vPosWeights[0]);
1122 
1123  //
1124  // Apply the tangent masks -- both will have the same number of weights and
1125  // indices (one tangent may be "padded" to accommodate the other), but these
1126  // may differ from those of the position:
1127  //
1128  if (hasTangents) {
1129  assert(tan1Mask.GetNumFaceWeights() == tan2Mask.GetNumFaceWeights());
1130  assert(tan1Mask.GetNumEdgeWeights() == tan2Mask.GetNumEdgeWeights());
1131 
1132  U1 & dstTan1 = *dstTan1Ptr;
1133  U2 & dstTan2 = *dstTan2Ptr;
1134 
1135  dstTan1[vert].Clear();
1136  dstTan2[vert].Clear();
1137  for (int i = 0; i < tan1Mask.GetNumFaceWeights(); ++i) {
1138  dstTan1[vert].AddWithWeight(src[fIndices[i]], fTan1Weights[i]);
1139  dstTan2[vert].AddWithWeight(src[fIndices[i]], fTan2Weights[i]);
1140  }
1141  for (int i = 0; i < tan1Mask.GetNumEdgeWeights(); ++i) {
1142  dstTan1[vert].AddWithWeight(src[eIndices[i]], eTan1Weights[i]);
1143  dstTan2[vert].AddWithWeight(src[eIndices[i]], eTan2Weights[i]);
1144  }
1145  dstTan1[vert].AddWithWeight(src[vert], vTan1Weights[0]);
1146  dstTan2[vert].AddWithWeight(src[vert], vTan2Weights[0]);
1147  }
1148  }
1149 }
1150 
1151 template <typename REAL>
1152 template <Sdc::SchemeType SCHEME, class T, class U>
1153 inline void
1154 PrimvarRefinerReal<REAL>::limitFVar(T const & src, U & dst, int channel) const {
1155 
1156  Sdc::Scheme<SCHEME> scheme(_refiner._subdivOptions);
1157 
1158  Vtr::internal::Level const & level = _refiner.getLevel(_refiner.GetMaxLevel());
1159  Vtr::internal::FVarLevel const & fvarChannel = level.getFVarLevel(channel);
1160 
1161  int maxWeightsPerMask = 1 + 2 * level.getMaxValence();
1162 
1163  Vtr::internal::StackBuffer<Weight,33> weightBuffer(maxWeightsPerMask);
1164  Vtr::internal::StackBuffer<Index,16> vEdgeBuffer(level.getMaxValence());
1165 
1166  // This is a bit obscure -- assign both parent and child as last level
1167  Vtr::internal::VertexInterface vHood(level, level);
1168 
1169  for (int vert = 0; vert < level.getNumVertices(); ++vert) {
1170 
1171  ConstIndexArray vEdges = level.getVertexEdges(vert);
1172  ConstIndexArray vValues = fvarChannel.getVertexValues(vert);
1173 
1174  // Incomplete vertices (present in sparse refinement) do not have their full
1175  // topological neighborhood to determine a proper limit -- just leave the
1176  // values (perhaps more than one per vertex) at the refined location.
1177  //
1178  // The same can be done if the face-varying channel is purely linear.
1179  //
1180  bool isIncomplete = (level.getVertexTag(vert)._incomplete || (vEdges.size() == 0));
1181  if (isIncomplete || fvarChannel.isLinear()) {
1182  for (int i = 0; i < vValues.size(); ++i) {
1183  Vtr::Index vValue = vValues[i];
1184 
1185  dst[vValue].Clear();
1186  dst[vValue].AddWithWeight(src[vValue], 1.0f);
1187  }
1188  continue;
1189  }
1190 
1191  bool fvarVertMatchesVertex = fvarChannel.valueTopologyMatches(vValues[0]);
1192  if (fvarVertMatchesVertex) {
1193 
1194  // Assign the mask weights to the common buffer and compute the mask:
1195  //
1196  Weight * vWeights = weightBuffer,
1197  * eWeights = vWeights + 1,
1198  * fWeights = eWeights + vEdges.size();
1199 
1200  Mask vMask(vWeights, eWeights, fWeights);
1201 
1202  vHood.SetIndex(vert, vert);
1203 
1204  scheme.ComputeVertexLimitMask(vHood, vMask, level.getVertexRule(vert));
1205 
1206  //
1207  // Apply mask to corresponding FVar values for neighboring vertices:
1208  //
1209  Vtr::Index vValue = vValues[0];
1210 
1211  dst[vValue].Clear();
1212  if (vMask.GetNumFaceWeights() > 0) {
1213  assert(!vMask.AreFaceWeightsForFaceCenters());
1214 
1215  ConstIndexArray vFaces = level.getVertexFaces(vert);
1216  ConstLocalIndexArray vInFace = level.getVertexFaceLocalIndices(vert);
1217 
1218  for (int i = 0; i < vFaces.size(); ++i) {
1219  ConstIndexArray faceValues = fvarChannel.getFaceValues(vFaces[i]);
1220  LocalIndex vOppInFace = vInFace[i] + 2;
1221  if (vOppInFace >= faceValues.size()) vOppInFace -= faceValues.size();
1222 
1223  Index vValueOppositeFace = faceValues[vOppInFace];
1224 
1225  dst[vValue].AddWithWeight(src[vValueOppositeFace], fWeights[i]);
1226  }
1227  }
1228  if (vMask.GetNumEdgeWeights() > 0) {
1229  Index * vEdgeValues = vEdgeBuffer;
1230  fvarChannel.getVertexEdgeValues(vert, vEdgeValues);
1231 
1232  for (int i = 0; i < vEdges.size(); ++i) {
1233  dst[vValue].AddWithWeight(src[vEdgeValues[i]], eWeights[i]);
1234  }
1235  }
1236  dst[vValue].AddWithWeight(src[vValue], vWeights[0]);
1237  } else {
1238  //
1239  // Sibling FVar values associated with a vertex will be either a corner or a crease:
1240  //
1241  for (int i = 0; i < vValues.size(); ++i) {
1242  Vtr::Index vValue = vValues[i];
1243 
1244  dst[vValue].Clear();
1245  if (fvarChannel.getValueTag(vValue).isCorner()) {
1246  dst[vValue].AddWithWeight(src[vValue], 1.0f);
1247  } else {
1248  Index vEndValues[2];
1249  fvarChannel.getVertexCreaseEndValues(vert, i, vEndValues);
1250 
1251  dst[vValue].AddWithWeight(src[vEndValues[0]], 1.0f/6.0f);
1252  dst[vValue].AddWithWeight(src[vEndValues[1]], 1.0f/6.0f);
1253  dst[vValue].AddWithWeight(src[vValue], 2.0f/3.0f);
1254  }
1255  }
1256  }
1257  }
1258 }
1259 
1260 class PrimvarRefiner : public PrimvarRefinerReal<float> {
1261 public:
1263  : PrimvarRefinerReal<float>(refiner) { }
1264 };
1265 
1266 } // end namespace Far
1267 
1268 } // end namespace OPENSUBDIV_VERSION
1269 using namespace OPENSUBDIV_VERSION;
1270 } // end namespace OpenSubdiv
1271 
1272 #endif /* OPENSUBDIV3_FAR_PRIMVAR_REFINER_H */
TopologyRefiner const & GetTopologyRefiner() const
void LimitFaceVarying(T const &src, U &dst, int channel=0) const
Vtr::LocalIndex LocalIndex
Definition: types.h:42
void InterpolateVarying(int level, T const &src, U &dst) const
Apply only varying interpolation weights to a primvar buffer for a single level of refinement...
bool IndexIsValid(Index index)
Definition: types.h:58
Issue a generic runtime error, but continue execution.
Definition: error.h:40
void Interpolate(int level, T const &src, U &dst) const
Apply vertex interpolation weights to a primvar buffer for a single level of refinement.
Stores topology data for a specified set of refinement options.
void Limit(T const &src, U &dstPos) const
Apply limit weights to a primvar buffer.
Vtr::ConstLocalIndexArray ConstLocalIndexArray
Definition: types.h:48
Applies refinement operations to generic primvar data.
ConstIndexArray getFaceVertices(Index faceIndex) const
Definition: level.h:548
void Error(ErrorType err, const char *format,...)
Sends an OSD error with a message (internal use only)
Vtr::ConstIndexArray ConstIndexArray
Definition: types.h:47
void InterpolateFaceVarying(int level, T const &src, U &dst, int channel=0) const
Apply face-varying interpolation weights to a primvar buffer associated with a particular face-varyin...
void InterpolateFaceUniform(int level, T const &src, U &dst) const
Refine uniform (per-face) primvar data between levels.
Scheme is a class template which provides all implementation for the subdivision schemes supported by...
Definition: scheme.h:66
ConstIndexArray getEdgeVertices(Index edgeIndex) const
Definition: level.h:673