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 
52 ///
53 ///  \brief Applies refinement operations to generic primvar data.
54 ///
55 template <typename REAL>
56 class PrimvarRefinerReal {
57 
58 public:
PrimvarRefinerReal(TopologyRefiner const & refiner)59     PrimvarRefinerReal(TopologyRefiner const & refiner) : _refiner(refiner) { }
~PrimvarRefinerReal()60     ~PrimvarRefinerReal() { }
61 
GetTopologyRefiner()62     TopologyRefiner const & GetTopologyRefiner() const { return _refiner; }
63 
64     //@{
65     ///  @name Primvar data interpolation
66     ///
67     /// \anchor templating
68     ///
69     /// \note Interpolation methods template both the source and destination
70     ///       data buffer classes. Client-code is expected to provide interfaces
71     ///       that implement the functions specific to its primitive variable
72     ///       data layout. Template APIs must implement the following:
73     ///       <br><br> \code{.cpp}
74     ///
75     ///       class MySource {
76     ///           MySource & operator[](int index);
77     ///       };
78     ///
79     ///       class MyDestination {
80     ///           void Clear();
81     ///           void AddWithWeight(MySource const & value, float weight);
82     ///           void AddWithWeight(MyDestination const & value, float weight);
83     ///       };
84     ///
85     ///       \endcode
86     ///       <br>
87     ///       It is possible to implement a single interface only and use it as
88     ///       both source and destination.
89     ///       <br><br>
90     ///       Primitive variable buffers are expected to be arrays of instances,
91     ///       passed either as direct pointers or with a container
92     ///       (ex. std::vector<MyVertex>).
93     ///       Some interpolation methods however allow passing the buffers by
94     ///       reference: this allows to work transparently with arrays and
95     ///       containers (or other schemes that overload the '[]' operator)
96     ///       <br><br>
97     ///       See the <a href=http://graphics.pixar.com/opensubdiv/docs/tutorials.html>
98     ///       Far tutorials</a> for code examples.
99     ///
100 
101     /// \brief Apply vertex interpolation weights to a primvar buffer for a single
102     ///        level of refinement.
103     ///
104     /// The destination buffer must allocate an array of data for all the
105     /// refined vertices, i.e. at least refiner.GetLevel(level).GetNumVertices()
106     ///
107     /// @param level  The refinement level
108     ///
109     /// @param src    Source primvar buffer (\ref templating control vertex data)
110     ///
111     /// @param dst    Destination primvar buffer (\ref templating refined vertex data)
112     ///
113     template <class T, class U> void Interpolate(int level, T const & src, U & dst) const;
114 
115     /// \brief Apply only varying interpolation weights to a primvar buffer
116     ///        for a single level of refinement.
117     ///
118     /// This method can useful if the varying primvar data does not need to be
119     /// re-computed over time.
120     ///
121     /// The destination buffer must allocate an array of data for all the
122     /// refined vertices, i.e. at least refiner.GetLevel(level).GetNumVertices()
123     ///
124     /// @param level  The refinement level
125     ///
126     /// @param src    Source primvar buffer (\ref templating control vertex data)
127     ///
128     /// @param dst    Destination primvar buffer (\ref templating refined vertex data)
129     ///
130     template <class T, class U> void InterpolateVarying(int level, T const & src, U & dst) const;
131 
132     /// \brief Refine uniform (per-face) primvar data between levels.
133     ///
134     /// Data is simply copied from a parent face to its child faces and does not involve
135     /// any weighting.  Setting the source primvar data for the base level to be the index
136     /// of each face allows the propagation of the base face to primvar data for child
137     /// faces in all levels.
138     ///
139     /// The destination buffer must allocate an array of data for all the refined faces,
140     /// i.e. at least refiner.GetLevel(level).GetNumFaces()
141     ///
142     /// @param level  The refinement level
143     ///
144     /// @param src    Source primvar buffer
145     ///
146     /// @param dst    Destination primvar buffer
147     ///
148     template <class T, class U> void InterpolateFaceUniform(int level, T const & src, U & dst) const;
149 
150     /// \brief Apply face-varying interpolation weights to a primvar buffer
151     ///        associated with a particular face-varying channel.
152     ///
153     /// Unlike vertex and varying primvar buffers, there is not a 1-to-1 correspondence
154     /// between vertices and face-varying values -- typically there are more face-varying
155     /// values than vertices.  Each face-varying channel is also independent in how its
156     /// values relate to the vertices.
157     ///
158     /// The destination buffer must allocate an array of data for all the refined values,
159     /// i.e. at least refiner.GetLevel(level).GetNumFVarValues(channel).
160     ///
161     template <class T, class U> void InterpolateFaceVarying(int level, T const & src, U & dst, int channel = 0) const;
162 
163 
164     /// \brief Apply limit weights to a primvar buffer
165     ///
166     /// The source buffer must refer to an array of previously interpolated
167     /// vertex data for the last refinement level.  The destination buffer
168     /// must allocate an array for all vertices at the last refinement level,
169     /// i.e. at least refiner.GetLevel(refiner.GetMaxLevel()).GetNumVertices()
170     ///
171     /// @param src     Source primvar buffer (refined data) for last level
172     ///
173     /// @param dstPos  Destination primvar buffer (data at the limit)
174     ///
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 
182     //@}
183 
184 private:
185     typedef REAL Weight;
186 
187     //  Non-copyable:
PrimvarRefinerReal(PrimvarRefinerReal const & src)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:
Mask(Weight * v,Weight * e,Weight * f)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 
~Mask()223         ~Mask() { }
224 
225     public:  //  Generic interface expected of <typename MASK>:
GetNumVertexWeights()226         int GetNumVertexWeights() const { return _vertCount; }
GetNumEdgeWeights()227         int GetNumEdgeWeights()   const { return _edgeCount; }
GetNumFaceWeights()228         int GetNumFaceWeights()   const { return _faceCount; }
229 
SetNumVertexWeights(int count)230         void SetNumVertexWeights(int count) { _vertCount = count; }
SetNumEdgeWeights(int count)231         void SetNumEdgeWeights(  int count) { _edgeCount = count; }
SetNumFaceWeights(int count)232         void SetNumFaceWeights(  int count) { _faceCount = count; }
233 
VertexWeight(int index)234         Weight const& VertexWeight(int index) const { return _vertWeights[index]; }
EdgeWeight(int index)235         Weight const& EdgeWeight(  int index) const { return _edgeWeights[index]; }
FaceWeight(int index)236         Weight const& FaceWeight(  int index) const { return _faceWeights[index]; }
237 
VertexWeight(int index)238         Weight& VertexWeight(int index) { return _vertWeights[index]; }
EdgeWeight(int index)239         Weight& EdgeWeight(  int index) { return _edgeWeights[index]; }
FaceWeight(int index)240         Weight& FaceWeight(  int index) { return _faceWeights[index]; }
241 
AreFaceWeightsForFaceCenters()242         bool AreFaceWeightsForFaceCenters() const  { return _faceWeightsForFaceCenters; }
SetFaceWeightsForFaceCenters(bool on)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
Interpolate(int level,T const & src,U & dst)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;
282     case Sdc::SCHEME_BILINEAR:
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
InterpolateFaceVarying(int level,T const & src,U & dst,int channel)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;
308     case Sdc::SCHEME_BILINEAR:
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
Limit(T const & src,U & dst)319 PrimvarRefinerReal<REAL>::Limit(T const & src, U & dst) const {
320 
321     if (_refiner.getLevel(_refiner.GetMaxLevel()).getNumVertexEdgesTotal() == 0) {
322         Error(FAR_RUNTIME_ERROR,
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;
335     case Sdc::SCHEME_BILINEAR:
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
Limit(T const & src,U & dstPos,U1 & dstTan1,U2 & dstTan2)344 PrimvarRefinerReal<REAL>::Limit(T const & src, U & dstPos, U1 & dstTan1, U2 & dstTan2) const {
345 
346     if (_refiner.getLevel(_refiner.GetMaxLevel()).getNumVertexEdgesTotal() == 0) {
347         Error(FAR_RUNTIME_ERROR,
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;
360     case Sdc::SCHEME_BILINEAR:
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
LimitFaceVarying(T const & src,U & dst,int channel)369 PrimvarRefinerReal<REAL>::LimitFaceVarying(T const & src, U & dst, int channel) const {
370 
371     if (_refiner.getLevel(_refiner.GetMaxLevel()).getNumVertexEdgesTotal() == 0) {
372         Error(FAR_RUNTIME_ERROR,
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;
385     case Sdc::SCHEME_BILINEAR:
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
InterpolateFaceUniform(int level,T const & src,U & dst)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
InterpolateVarying(int level,T const & src,U & dst)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
interpFromFaces(int level,T const & src,U & dst)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 
484     Vtr::internal::StackBuffer<Weight,16> fVertWeights(parent.getMaxValence());
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
interpFromEdges(int level,T const & src,U & dst)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
interpFromVerts(int level,T const & src,U & dst)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
interpFVarFromFaces(int level,T const & src,U & dst,int channel)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
interpFVarFromEdges(int level,T const & src,U & dst,int channel)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)
757                                         ? Sdc::Crease::RULE_CREASE : Sdc::Crease::RULE_SMOOTH;
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
interpFVarFromVerts(int level,T const & src,U & dst,int channel)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
limit(T const & src,U & dstPos,U1 * dstTan1Ptr,U2 * dstTan2Ptr)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
limitFVar(T const & src,U & dst,int channel)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:
PrimvarRefiner(TopologyRefiner const & refiner)1262     PrimvarRefiner(TopologyRefiner const & refiner)
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 */
1273