1 //
2 //   Copyright 2018 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 
25 #include "../far/patchBuilder.h"
26 #include "../far/catmarkPatchBuilder.h"
27 #include "../far/loopPatchBuilder.h"
28 #include "../far/bilinearPatchBuilder.h"
29 #include "../vtr/level.h"
30 #include "../vtr/fvarLevel.h"
31 #include "../vtr/refinement.h"
32 #include "../vtr/stackBuffer.h"
33 
34 #include <cassert>
35 #include <cstdio>
36 
37 namespace OpenSubdiv {
38 namespace OPENSUBDIV_VERSION {
39 
40 using Vtr::Array;
41 using Vtr::ConstArray;
42 using Vtr::internal::Level;
43 using Vtr::internal::FVarLevel;
44 using Vtr::internal::Refinement;
45 using Vtr::internal::StackBuffer;
46 
47 namespace Far {
48 
49 //
50 //  Local helper functions for topology queries:
51 //
52 namespace {
53 
54     //
55     //  Inline methods to encapsulate fast and specific modulus operations.
56     //  The mod-4 case is trivial.  For mod-N, since we are always doing
57     //  the test (i + 1) % N, or (i - 1 + N) % N, the subtraction suffices.
58     //
fastMod4(int x)59     inline int fastMod4(int x) {
60         return x & 0x3;
61     }
fastMod3(int x)62     inline int fastMod3(int x) {
63         static int const mod3Array[] = { 0, 1, 2, 0, 1, 2 };
64         return mod3Array[x];
65     }
fastModN(int x,int N)66     inline int fastModN(int x, int N) {
67         return (x < N) ? x : (x - N);
68     }
69 
70     //
71     //  Local helper functions for identifying the subset of a ring around a
72     //  corner that contributes to a patch -- parameterized by a mask that
73     //  indicates what kind of edge is to delimit the span.
74     //
75     //  Note that the two main methods need both face-verts and face-edges
76     //  for each corner, and that we don't really need the face-index once
77     //  we have them -- consider passing the fVerts and fEdges as arguments
78     //  as they will otherwise be retrieved repeatedly for each corner.
79     //
80     //  (As these mature it is likely they will be moved to Vtr, as a method
81     //  to identify a VSpan would complement the existing method to gather
82     //  the vertex/values associated with it.  The manifold vs non-manifold
83     //  choice would then also be encapsulated -- provided both remain free
84     //  of PatchTable-specific logic.)
85     //
86     inline Level::ETag
getSingularEdgeMask(bool includeAllInfSharpEdges=false)87     getSingularEdgeMask(bool includeAllInfSharpEdges = false) {
88 
89         Level::ETag eTagMask;
90         eTagMask.clear();
91         eTagMask._boundary = true;
92         eTagMask._nonManifold = true;
93         eTagMask._infSharp = includeAllInfSharpEdges;
94         return eTagMask;
95     }
96 
97     inline bool
isEdgeSingular(Level const & level,FVarLevel const * fvarLevel,Index eIndex,Level::ETag eTagMask)98     isEdgeSingular(Level const & level, FVarLevel const * fvarLevel,
99                    Index eIndex, Level::ETag eTagMask)
100     {
101         Level::ETag eTag = level.getEdgeTag(eIndex);
102         if (fvarLevel) {
103             eTag = fvarLevel->getEdgeTag(eIndex).combineWithLevelETag(eTag);
104         }
105         return (eTag.getBits() & eTagMask.getBits()) > 0;
106     }
107 
108     void
identifyManifoldCornerSpan(Level const & level,Index fIndex,int fCorner,Level::ETag eTagMask,Level::VSpan & vSpan,int fvc=-1)109     identifyManifoldCornerSpan(Level const & level, Index fIndex,
110                                int fCorner, Level::ETag eTagMask,
111                                Level::VSpan & vSpan, int fvc = -1)
112     {
113         FVarLevel const * fvarLevel = (fvc < 0) ? 0 : &level.getFVarLevel(fvc);
114 
115         ConstIndexArray fVerts = level.getFaceVertices(fIndex);
116         ConstIndexArray fEdges = level.getFaceEdges(fIndex);
117 
118         ConstIndexArray vEdges = level.getVertexEdges(fVerts[fCorner]);
119         int             nEdges = vEdges.size();
120 
121         int iLeadingStart  = vEdges.FindIndex(fEdges[fCorner]);
122         int iTrailingStart = fastModN(iLeadingStart + 1, nEdges);
123 
124         vSpan.clear();
125         vSpan._numFaces = 1;
126         vSpan._cornerInSpan = 0;
127 
128         int iLeading  = iLeadingStart;
129         while (! isEdgeSingular(level, fvarLevel, vEdges[iLeading], eTagMask)) {
130             ++vSpan._numFaces;
131             ++vSpan._cornerInSpan;
132             iLeading = fastModN(iLeading + nEdges - 1, nEdges);
133             if (iLeading == iTrailingStart) break;
134         }
135 
136         int iTrailing = iTrailingStart;
137         if (iTrailing != iLeading) {
138             while (!isEdgeSingular(level, fvarLevel, vEdges[iTrailing], eTagMask)) {
139                 ++vSpan._numFaces;
140                 iTrailing = fastModN(iTrailing + 1, nEdges);
141                 if (iTrailing == iLeadingStart) break;
142             }
143         }
144         vSpan._startFace = (LocalIndex) iLeading;
145     }
146 
147     void
identifyNonManifoldCornerSpan(Level const & level,Index fIndex,int fCorner,Level::ETag eTagMask,Level::VSpan & vSpan,int fvc=-1)148     identifyNonManifoldCornerSpan(Level const & level, Index fIndex,
149                                   int fCorner, Level::ETag eTagMask,
150                                   Level::VSpan & vSpan, int fvc = -1)
151     {
152         FVarLevel const * fvarLevel = (fvc < 0) ? 0 : &level.getFVarLevel(fvc);
153 
154         ConstIndexArray fEdges = level.getFaceEdges(fIndex);
155 
156         Index eLeadingStart  = fEdges[fCorner];
157         Index eTrailingStart = fEdges[(fCorner + fEdges.size() - 1) % fEdges.size()];
158 
159         vSpan.clear();
160         vSpan._numFaces = 1;
161         vSpan._cornerInSpan = 0;
162 
163         Index startFace   = fIndex;
164         int   startCorner = fCorner;
165 
166         //  Traverse clockwise to find the leading edge of the span -- keeping
167         //  track of the starting face and corner to use later:
168         Index fLeading = fIndex;
169         Index eLeading = eLeadingStart;
170         while (!isEdgeSingular(level, fvarLevel, eLeading, eTagMask)) {
171             ++vSpan._numFaces;
172             ++vSpan._cornerInSpan;
173 
174             //  Identify the face opposite the current leading edge, identify
175             //  the edges of the next face, and then the next leading edge:
176             //
177             ConstIndexArray eFaces = level.getEdgeFaces(eLeading);
178             assert(eFaces.size() == 2);
179             fLeading = (eFaces[0] == fLeading) ? eFaces[1] : eFaces[0];
180             fEdges = level.getFaceEdges(fLeading);
181 
182             startFace   = fLeading;
183             startCorner = (fEdges.FindIndex(eLeading) + 1) % fEdges.size();
184 
185             eLeading = fEdges[startCorner];
186             if (eLeading == eTrailingStart) {
187                 vSpan._periodic = !isEdgeSingular(level, fvarLevel, eLeading, eTagMask);
188                 break;
189             }
190         }
191 
192         //  Traverse counter-clockwise to find the trailing edge of the span (unless
193         //  the above traversal reached where it started):
194         Index fTrailing = fIndex;
195         Index eTrailing = eTrailingStart;
196         if (eTrailing != eLeading) {
197             while (!isEdgeSingular(level, fvarLevel, eTrailing, eTagMask)) {
198                 ++vSpan._numFaces;
199 
200                 //  Identify the face opposite the current trailing edge, identify
201                 //  the edges of the next face, and then the next trailing edge:
202                 //
203                 ConstIndexArray eFaces = level.getEdgeFaces(eTrailing);
204                 assert(eFaces.size() == 2);
205                 fTrailing = (eFaces[0] == fTrailing) ? eFaces[1] : eFaces[0];
206                 fEdges = level.getFaceEdges(fTrailing);
207 
208                 eTrailing = fEdges[(fEdges.FindIndex(eTrailing) + fEdges.size() - 1) % fEdges.size()];
209                 if (eTrailing == eLeadingStart) {
210                     vSpan._periodic = !isEdgeSingular(level, fvarLevel, eTrailing, eTagMask);
211                     break;
212                 }
213             }
214         }
215 
216         //  Identify the span's starting point relative to the incident components
217         //  of the vertex, using the start face and corner of the leading edge:
218         //
219         Index vIndex = level.getFaceVertices(fIndex)[fCorner];
220 
221         ConstIndexArray      vFaces   = level.getVertexFaces(vIndex);
222         ConstLocalIndexArray vInFaces = level.getVertexFaceLocalIndices(vIndex);
223 
224         vSpan._startFace = vFaces.size();
225         for (int i = 0; i < vFaces.size(); ++i) {
226             if ((vFaces[i] == startFace) && (vInFaces[i] == startCorner)) {
227                 vSpan._startFace = i;
228                 break;
229             }
230         }
231         assert(vSpan._startFace < vFaces.size());
232     }
233 
234     //  Simple conveniences for the span search functions:
235     inline int
countManifoldCornerSpan(Level const & level,Index fIndex,int fCorner,Level::ETag eTagMask,int fvc=-1)236     countManifoldCornerSpan(Level const & level, Index fIndex, int fCorner,
237                             Level::ETag eTagMask, int fvc = -1)
238     {
239         Level::VSpan vSpan;
240         identifyManifoldCornerSpan(level, fIndex, fCorner, eTagMask, vSpan, fvc);
241         return vSpan._numFaces;
242     }
243     inline int
countNonManifoldCornerSpan(Level const & level,Index fIndex,int fCorner,Level::ETag eTagMask,int fvc=-1)244     countNonManifoldCornerSpan(Level const & level, Index fIndex, int fCorner,
245                                Level::ETag eTagMask, int fvc = -1)
246     {
247         Level::VSpan vSpan;
248         identifyNonManifoldCornerSpan(level, fIndex, fCorner, eTagMask, vSpan, fvc);
249         return vSpan._numFaces;
250     }
251 
252 
253     //
254     //  Gathering the one-ring of vertices from triangles surrounding a vertex:
255     //      - the neighborhood of the vertex is assumed to be tri-regular (manifold)
256     //
257     //  Ordering of resulting vertices:
258     //      The surrounding one-ring follows the ordering of the incident faces.  For each
259     //  incident tri, the vertex opposite its leading edge is added.  If the vertex is on a
260     //  boundary, a second vertex on the boundary edge will be contributed from the last face.
261     //
262     int
gatherTriRegularRingAroundVertex(Level const & level,Index vIndex,int ringPoints[],int fvarChannel)263     gatherTriRegularRingAroundVertex(Level const& level,
264         Index vIndex, int ringPoints[], int fvarChannel) {
265 
266         ConstIndexArray vEdges = level.getVertexEdges(vIndex);
267 
268         ConstIndexArray vFaces = level.getVertexFaces(vIndex);
269         ConstLocalIndexArray vInFaces = level.getVertexFaceLocalIndices(vIndex);
270 
271         bool isBoundary = (vEdges.size() > vFaces.size());
272 
273         int ringIndex = 0;
274         for (int i = 0; i < vFaces.size(); ++i) {
275             //
276             //  For each tri, we want the the vertex at the end of the leading edge:
277             //
278             ConstIndexArray fPoints = (fvarChannel < 0)
279                                     ? level.getFaceVertices(vFaces[i])
280                                     : level.getFaceFVarValues(vFaces[i], fvarChannel);
281 
282             int vInThisFace = vInFaces[i];
283 
284             ringPoints[ringIndex++] = fPoints[fastMod3(vInThisFace + 1)];
285 
286             if (isBoundary && (i == (vFaces.size() - 1))) {
287                 ringPoints[ringIndex++] = fPoints[fastMod3(vInThisFace + 2)];
288             }
289         }
290         return ringIndex;
291     }
292 
293     int
gatherRegularPartialRingAroundVertex(Level const & level,Index vIndex,Level::VSpan const & span,int ringPoints[],int fvarChannel)294     gatherRegularPartialRingAroundVertex(Level const& level,
295         Index vIndex, Level::VSpan const & span, int ringPoints[], int fvarChannel) {
296 
297         bool isManifold = !level.isVertexNonManifold(vIndex);
298 
299         ConstIndexArray      vFaces   = level.getVertexFaces(vIndex);
300         ConstLocalIndexArray vInFaces = level.getVertexFaceLocalIndices(vIndex);
301 
302         int nFaces    = span._numFaces;
303         int startFace = span._startFace;
304 
305         Index nextFace    = vFaces[startFace];
306         int   vInNextFace = vInFaces[startFace];
307 
308         int ringIndex = 0;
309         for (int i = 0; i < nFaces; ++i) {
310             Index thisFace    = nextFace;
311             int   vInThisFace = vInNextFace;
312 
313             ConstIndexArray fPoints = (fvarChannel < 0)
314                                     ? level.getFaceVertices(thisFace)
315                                     : level.getFaceFVarValues(thisFace, fvarChannel);
316 
317             bool isQuad = (fPoints.size() == 4);
318             if (isQuad) {
319                 ringPoints[ringIndex++] = fPoints[fastMod4(vInThisFace + 1)];
320                 ringPoints[ringIndex++] = fPoints[fastMod4(vInThisFace + 2)];
321             } else {
322                 ringPoints[ringIndex++] = fPoints[fastMod3(vInThisFace + 1)];
323             }
324 
325             if (i == (nFaces - 1)) {
326                 if (!span._periodic) {
327                     if (isQuad) {
328                         ringPoints[ringIndex++] = fPoints[fastMod4(vInThisFace + 3)];
329                     } else {
330                         ringPoints[ringIndex++] = fPoints[fastMod3(vInThisFace + 2)];
331                     }
332                 }
333             } else if (isManifold) {
334                 int iNext = fastModN(startFace + i + 1, vFaces.size());
335 
336                 nextFace    = vFaces[iNext];
337                 vInNextFace = vInFaces[iNext];
338             } else {
339                 int nextInThisFace = fastModN(vInThisFace + fPoints.size() - 1, fPoints.size());
340 
341                 Index nextEdge = level.getFaceEdges(thisFace)[nextInThisFace];
342                 ConstIndexArray eFaces = level.getEdgeFaces(nextEdge);
343 
344                 nextFace    = (eFaces[0] == thisFace) ? eFaces[1] : eFaces[0];
345                 vInNextFace = level.getFaceEdges(nextFace).FindIndex(nextEdge);
346             }
347         }
348         return ringIndex;
349     }
350 
351     //
352     //  Functions to encode/decode the 5-bit boundary mask for a triangular patch
353     //  from the two 3-bit boundary vertex and bounday edge masks.  When referring
354     //  to a "boundary vertex" in the encoded bits, we are referring to a vertex on
355     //  a boundary while its incident edges of the triangle are not boundaries --
356     //  topologically distinct from a vertex at the end of a boundary edge.
357     //
358     //  The 5-bit encoding is as follows:
359     //
360     //      - the upper 2 bits indicate how to interpret the lower 3 bits:
361     //          0 - as boundary edges only (all boundary vertices are implicit)
362     //          1 - as "boundary vertices" only (no boundary edges)
363     //          2 - a single boundary edge with opposite "boundary vertex"
364     //
365     //      - the lower 3 bits are set according to boundary features present
366     //
367     //  There are a total of 18 possible boundary configurations:
368     //
369     //      - no boundaries at all (1 case)
370     //      - one boundary edge (3 cases)
371     //      - two boundary edges (3 cases)
372     //      - three boundary edges (1 case)
373     //      - one boundary vertex (3 cases)
374     //      - two boundary vertices (3 cases)
375     //      - three boundarey vertices (1 case)
376     //      - one boundary edge with opposite boundary vertex (3 cases)
377     //
unpackTriBoundaryMaskLower(int mask)378     inline int unpackTriBoundaryMaskLower(int mask) { return mask & 0x7; }
unpackTriBoundaryMaskUpper(int mask)379     inline int unpackTriBoundaryMaskUpper(int mask) { return (mask >> 3) & 0x3; }
380 
packTriBoundaryMask(int upper,int lower)381     inline int packTriBoundaryMask(int upper, int lower) { return (upper << 3) | lower; }
382 
383     int
encodeTriBoundaryMask(int eBits,int vBits)384     encodeTriBoundaryMask(int eBits, int vBits)
385     {
386         int upperBits = 0;
387         int lowerBits = eBits;
388 
389         if (vBits) {
390             if (eBits == 0) {
391                 upperBits = 1;
392                 lowerBits = vBits;
393             } else if ((vBits == 7) && ((eBits == 1) || (eBits == 2) || (eBits == 4))) {
394                 upperBits = 2;
395                 lowerBits = eBits;
396             }
397         }
398         return packTriBoundaryMask(upperBits, lowerBits);
399     }
400     void
decodeTriBoundaryMask(int mask,int & eBits,int & vBits)401     decodeTriBoundaryMask(int mask, int & eBits, int & vBits)
402     {
403         static int const eBitsToVBits[] = { 0, 3, 6, 7, 5, 7, 7, 7 };
404 
405         int lowerBits = unpackTriBoundaryMaskLower(mask);
406         int upperBits = unpackTriBoundaryMaskUpper(mask);
407 
408         switch (upperBits) {
409         case 0:
410             eBits = lowerBits;
411             vBits = eBitsToVBits[eBits];
412             break;
413         case 1:
414             eBits = 0;
415             vBits = lowerBits;
416             break;
417         case 2:
418             eBits = lowerBits;
419             vBits = 0x7;
420             break;
421         }
422     }
423 
424     inline Index
getNextFaceInVertFaces(Level const & level,int thisFaceInVFaces,ConstIndexArray const & vFaces,ConstLocalIndexArray const & vInFaces,bool manifold,int & vInNextFace)425     getNextFaceInVertFaces(Level const & level, int thisFaceInVFaces,
426                            ConstIndexArray const & vFaces,
427                            ConstLocalIndexArray const & vInFaces,
428                            bool manifold, int & vInNextFace) {
429 
430         Index nextFace;
431         if (manifold) {
432             int nextFaceInVFaces = fastModN(thisFaceInVFaces + 1, vFaces.size());
433 
434             nextFace    = vFaces[nextFaceInVFaces];
435             vInNextFace = vInFaces[nextFaceInVFaces];
436         } else {
437             Index thisFace    = vFaces[thisFaceInVFaces];
438             int   vInThisFace = vInFaces[thisFaceInVFaces];
439 
440             ConstIndexArray fEdges = level.getFaceEdges(thisFace);
441 
442             Index nextEdge = fEdges[fastModN((vInThisFace + fEdges.size() - 1), fEdges.size())];
443 
444             ConstIndexArray eFaces = level.getEdgeFaces(nextEdge);
445             assert(eFaces.size() == 2);
446 
447             nextFace = (eFaces[0] == thisFace) ? eFaces[1] : eFaces[0];
448 
449             int edgeInNextFace = level.getFaceEdges(nextFace).FindIndex(nextEdge);
450 
451             vInNextFace = edgeInNextFace;
452         }
453         return nextFace;
454     }
455     inline Index
getPrevFaceInVertFaces(Level const & level,int thisFaceInVFaces,ConstIndexArray const & vFaces,ConstLocalIndexArray const & vInFaces,bool manifold,int & vInPrevFace)456     getPrevFaceInVertFaces(Level const & level, int thisFaceInVFaces,
457                            ConstIndexArray const & vFaces,
458                            ConstLocalIndexArray const & vInFaces,
459                            bool manifold, int & vInPrevFace) {
460 
461         Index prevFace;
462         if (manifold) {
463             int prevFaceInVFaces = (thisFaceInVFaces ? thisFaceInVFaces : vFaces.size()) - 1;
464 
465             prevFace    = vFaces[prevFaceInVFaces];
466             vInPrevFace = vInFaces[prevFaceInVFaces];
467         } else {
468             Index thisFace    = vFaces[thisFaceInVFaces];
469             int   vInThisFace = vInFaces[thisFaceInVFaces];
470 
471             ConstIndexArray fEdges = level.getFaceEdges(thisFace);
472 
473             Index prevEdge = fEdges[vInThisFace];
474 
475             ConstIndexArray eFaces = level.getEdgeFaces(prevEdge);
476             assert(eFaces.size() == 2);
477 
478             prevFace = (eFaces[0] == thisFace) ? eFaces[1] : eFaces[0];
479 
480             int edgeInPrevFace = level.getFaceEdges(prevFace).FindIndex(prevEdge);
481 
482             vInPrevFace = fastModN(edgeInPrevFace + 1, fEdges.size());
483         }
484         return prevFace;
485     }
486 
487     inline ConstIndexArray
getFacePoints(Level const & level,Index faceIndex,int fvarChannel)488     getFacePoints(Level const& level, Index faceIndex, int fvarChannel)
489     {
490         return (fvarChannel < 0) ? level.getFaceVertices(faceIndex)
491                                  : level.getFaceFVarValues(faceIndex, fvarChannel);
492     }
493 
494 } // namespace anon
495 
496 
497 //
498 //  Factory method and constructor:
499 //
500 PatchBuilder*
Create(TopologyRefiner const & refiner,Options const & options)501 PatchBuilder::Create(TopologyRefiner const& refiner, Options const& options) {
502 
503     switch (refiner.GetSchemeType()) {
504     case Sdc::SCHEME_BILINEAR:
505         return new BilinearPatchBuilder(refiner, options);
506     case Sdc::SCHEME_CATMARK:
507         return new CatmarkPatchBuilder(refiner, options);
508     case Sdc::SCHEME_LOOP:
509         return new LoopPatchBuilder(refiner, options);
510     }
511     assert("Unrecognized Sdc::SchemeType for PatchBuilder construction" == 0);
512     return 0;
513 }
514 
PatchBuilder(TopologyRefiner const & refiner,Options const & options)515 PatchBuilder::PatchBuilder(
516     TopologyRefiner const& refiner, Options const& options) :
517         _refiner(refiner), _options(options) {
518 
519     //
520     //  Initialize members with properties of the subdivision scheme and patch
521     //  choices for quick retrieval:
522     //
523     _schemeType        = refiner.GetSchemeType();
524     _schemeRegFaceSize = Sdc::SchemeTypeTraits::GetRegularFaceSize(_schemeType);
525     _schemeIsLinear    = Sdc::SchemeTypeTraits::GetLocalNeighborhoodSize(_schemeType) == 0;
526 
527     //  Initialization of members involving patch types is deferred to the
528     //  subclass for the scheme
529 }
530 
~PatchBuilder()531 PatchBuilder::~PatchBuilder() {
532 }
533 
534 
535 //
536 //  Topology inspections methods for a particular face in the hierarchy:
537 //
538 bool
IsFaceAPatch(int levelIndex,Index faceIndex) const539 PatchBuilder::IsFaceAPatch(int levelIndex, Index faceIndex) const {
540 
541     Level const & level = _refiner.getLevel(levelIndex);
542 
543     //  Faces tagged as holes are not patches (no limit surface)
544     if (_refiner.HasHoles() && level.isFaceHole(faceIndex)) return false;
545 
546     //  Base faces are patches unless an irregular face or incident one:
547     if (levelIndex == 0) {
548         if (_schemeIsLinear) {
549             return level.getFaceVertices(faceIndex).size() == _schemeRegFaceSize;
550         } else {
551             return !level.getFaceCompositeVTag(faceIndex)._incidIrregFace;
552         }
553     }
554 
555     //  Refined faces are patches unless "incomplete", i.e. they exist solely to
556     //  support an adjacent patch (can only use the more commonly used combined
557     //  VTag for all corners for quads -- need a Refinement tag for tris):
558     if (_schemeRegFaceSize == 4) {
559         return !level.getFaceCompositeVTag(faceIndex)._incomplete;
560     } else {
561         Refinement const & refinement = _refiner.getRefinement(levelIndex - 1);
562         return !refinement.getChildFaceTag(faceIndex)._incomplete;
563     }
564 }
565 
566 bool
IsFaceALeaf(int levelIndex,Index faceIndex) const567 PatchBuilder::IsFaceALeaf(int levelIndex, Index faceIndex) const {
568 
569     //  All faces in the last level are leaves
570     if (levelIndex < _refiner.GetMaxLevel()) {
571         //  Faces selected for further refinement are not leaves
572         if (_refiner.getRefinement(levelIndex).
573                         getParentFaceSparseTag(faceIndex)._selected) {
574             return false;
575         }
576     }
577     return true;
578 }
579 
580 bool
IsPatchRegular(int levelIndex,Index faceIndex,int fvc) const581 PatchBuilder::IsPatchRegular(int levelIndex, Index faceIndex, int fvc) const {
582 
583     if (_schemeIsLinear) {
584         //  The previous face-is-a-patch test precludes an irregular patch
585         return true;
586     }
587 
588     Level const & level = _refiner.getLevel(levelIndex);
589 
590     //
591     //  Retrieve individual VTags for the four corners and combine, as we may
592     //  need the individual VTags for closer inspection.
593     //
594     //  Immediately return regular status based on xordinary bit if completely
595     //  smooth at all corners, i.e. no inf-sharp corners or boundaries present
596     //  (which also rules out the presence of non-manifold vertices)
597     //
598     Level::VTag vTags[4];
599     level.getFaceVTags(faceIndex, vTags, fvc);
600 
601     Level::VTag fCompVTag = Level::VTag::BitwiseOr(vTags, _schemeRegFaceSize);
602 
603     if (!fCompVTag._infSharp && !fCompVTag._infSharpEdges) {
604         return !fCompVTag._xordinary;
605     }
606 
607     //
608     //  Irregular features will exist at corners that are either non-manifold,
609     //  extra-ordinary, or that are tagged with inf-sharp irregularities (may
610     //  be regular even if extra-ordinary or vice versa -- depending on the
611     //  specific inf-sharp edges present around the vertex).
612     //
613     //  Build a bit-mask for the irregular features -- if the composite tag
614     //  has no irregular features, we can immediately return.
615     //
616     bool testInfSharpFeatures = !_options.approxInfSharpWithSmooth;
617 
618     Level::VTag irregFeatureTag(0);
619     irregFeatureTag._nonManifold  = true;
620     irregFeatureTag._xordinary    = true;
621     irregFeatureTag._infIrregular = testInfSharpFeatures;
622 
623     int irregFeatureMask = irregFeatureTag.getBits();
624 
625     if ((fCompVTag.getBits() & irregFeatureMask) == 0) {
626         return true;
627     }
628 
629     //
630     //  If the irregular feature is isolated, we can use the combined corner
631     //  tags to determine regularity -- unless specified options require a
632     //  closer inspection of the single irregular feature:
633     //
634     bool mayHaveIrregFaces  = _refiner._hasIrregFaces;
635     int  needsExtraIsoLevel = fCompVTag._xordinary && mayHaveIrregFaces;
636 
637     bool featureIsIsolated = levelIndex > needsExtraIsoLevel;
638     if (featureIsIsolated) {
639         bool featureRequiresFurtherInspection = fCompVTag._nonManifold ||
640                 (_options.approxSmoothCornerWithSharp &&
641                         fCompVTag._xordinary && fCompVTag._boundary) ||
642                 (testInfSharpFeatures &&
643                         fCompVTag._infIrregular && fCompVTag._infSharpEdges);
644 
645         if (!featureRequiresFurtherInspection) {
646             if (testInfSharpFeatures) {
647                 return !fCompVTag._infIrregular;
648             } else {
649                 return !fCompVTag._xordinary;
650             }
651         }
652     }
653 
654     //
655     //  Inspect all or the single isolated corner.  Use the irregular feature
656     //  mask to quickly skip regular corners and return on the first irregular
657     //  feature encountered:
658     //
659     int nRegBoundaryFaces = (_schemeRegFaceSize == 4) ? 2 : 3;
660 
661     for (int i = 0; i < _schemeRegFaceSize; ++i) {
662         Level::VTag vTag = vTags[i];
663 
664         if ((vTag.getBits() & irregFeatureMask) == 0) continue;
665 
666         if (vTag._nonManifold) {
667             //  Identify the span containing the face and assess:
668             int nSpanFaces = countNonManifoldCornerSpan(level, faceIndex, i,
669                 getSingularEdgeMask(testInfSharpFeatures), fvc);
670             if (vTag._infSharp) {
671                 if (nSpanFaces != 1) return false;
672             } else {
673                 if (nSpanFaces != (nRegBoundaryFaces)) return false;
674             }
675             continue;
676         }
677 
678         if (vTag._xordinary) {
679             //  A smooth xordinary vertex is always irregular
680             if (!vTag._infSharpEdges) return false;
681 
682             //  A smooth corner vertex may be interpreted as regular:
683             if (_options.approxSmoothCornerWithSharp &&
684                     vTag._boundary && !vTag._infSharp) {
685                 Level::ETag eTags[4];
686                 level.getFaceETags(faceIndex, eTags, fvc);
687                 int iPrev = i ? (i - 1) : (_schemeRegFaceSize - 1);
688                 if (eTags[i]._boundary && eTags[iPrev]._boundary) {
689                     continue;
690                 }
691             }
692 
693             //  All others irregular, unless further inspecting inf-sharp
694             if (!testInfSharpFeatures) return false;
695         }
696 
697         if (vTag._infIrregular) {
698             //  Inf-sharp vertex with no inf-sharp edges:
699             if (!vTag._infSharpEdges) return false;
700 
701             //  Irregular boundary crease:
702             if (vTag._infSharpCrease && vTag._boundary) return false;
703 
704             //  Identify the span containing the face and assess:
705             int nSpanFaces = countManifoldCornerSpan(level, faceIndex, i,
706                 getSingularEdgeMask(true), fvc);
707             if (vTag._infSharpCrease) {
708                 if (nSpanFaces != (nRegBoundaryFaces)) return false;
709             } else {
710                 if (nSpanFaces != 1) return false;
711             }
712         }
713     }
714     return true;
715 }
716 
717 int
GetRegularPatchBoundaryMask(int levelIndex,Index faceIndex,int fvarChannel) const718 PatchBuilder::GetRegularPatchBoundaryMask(int levelIndex, Index faceIndex,
719     int fvarChannel) const {
720 
721     if (_schemeIsLinear) {
722         //  Boundaries for patches not dependent on the 1-ring are ignored
723         return 0;
724     }
725 
726     Level const & level = _refiner.getLevel(levelIndex);
727 
728     //  Gather tags for the four corners and edges.  Regardless of the
729     //  options for treating non-manifold or inf-sharp patches, for a
730     //  regular patch we can infer all that we need from these tags:
731     //
732     Level::VTag vTags[4];
733     Level::ETag eTags[4];
734 
735     level.getFaceVTags(faceIndex, vTags, fvarChannel);
736 
737     Level::VTag fTag = Level::VTag::BitwiseOr(vTags, _schemeRegFaceSize);
738     if (!fTag._infSharpEdges) {
739         return 0;
740     }
741 
742     level.getFaceETags(faceIndex, eTags, fvarChannel);
743 
744     //
745     //  Test the edge tags for boundary features.  For quads this is
746     //  sufficient, so return the edge bits.
747     //
748     bool testInfSharpFeatures = !_options.approxInfSharpWithSmooth;
749 
750     Level::ETag eFeatureTag(0);
751     eFeatureTag._boundary    = true;
752     eFeatureTag._infSharp    = testInfSharpFeatures;
753     eFeatureTag._nonManifold = true;
754 
755     int eFeatureMask = eFeatureTag.getBits();
756 
757     int eBits = (((eTags[0].getBits() & eFeatureMask) != 0) << 0) |
758                 (((eTags[1].getBits() & eFeatureMask) != 0) << 1) |
759                 (((eTags[2].getBits() & eFeatureMask) != 0) << 2);
760     if (_schemeRegFaceSize == 4) {
761         eBits |= (((eTags[3].getBits() & eFeatureMask) != 0) << 3);
762         return eBits;
763     }
764 
765     //
766     //  For triangles, test the vertex tags for boundary features (we
767     //  can have boundary vertices with no boundary edges) and return
768     //  the encoded result of the two sets of 3 bits:
769     //
770     Level::VTag vFeatureTag(0);
771     vFeatureTag._boundary      = true;
772     vFeatureTag._infSharpEdges = testInfSharpFeatures;
773     vFeatureTag._nonManifold   = true;
774 
775     int vFeatureMask = vFeatureTag.getBits();
776 
777     int vBits = (((vTags[0].getBits() & vFeatureMask) != 0) << 0) |
778                 (((vTags[1].getBits() & vFeatureMask) != 0) << 1) |
779                 (((vTags[2].getBits() & vFeatureMask) != 0) << 2);
780 
781     return (eBits || vBits) ? encodeTriBoundaryMask(eBits, vBits) : 0;
782 }
783 
784 void
GetIrregularPatchCornerSpans(int levelIndex,Index faceIndex,Level::VSpan cornerSpans[4],int fvarChannel) const785 PatchBuilder::GetIrregularPatchCornerSpans(int levelIndex, Index faceIndex,
786         Level::VSpan cornerSpans[4], int fvarChannel) const {
787 
788     Level const & level = _refiner.getLevel(levelIndex);
789 
790     //  Retrieve tags and identify other information for the corner vertices:
791     Level::VTag vTags[4];
792     level.getFaceVTags(faceIndex, vTags, fvarChannel);
793 
794     FVarLevel::ValueTag fvarTags[4];
795     if (fvarChannel >= 0) {
796         level.getFVarLevel(fvarChannel).getFaceValueTags(faceIndex, fvarTags);
797     }
798 
799     //
800     //  For each corner, identify the span of interest around the vertex,
801     //  using the complete neighborhood when possible (which does not require
802     //  a search):
803     //
804     bool testInfSharpFeatures = !_options.approxInfSharpWithSmooth;
805 
806     Level::ETag singularEdgeMask = getSingularEdgeMask(testInfSharpFeatures);
807 
808     for (int i = 0; i < _schemeRegFaceSize; ++i) {
809         Level::VTag vTag = vTags[i];
810 
811         bool isNonManifold = vTag._nonManifold;
812 
813         bool isFVarMisMatch = (fvarChannel >= 0) && fvarTags[i]._mismatch;
814 
815         bool testInfSharpEdges = testInfSharpFeatures &&
816                 vTag._infSharpEdges && (vTag._rule != Sdc::Crease::RULE_DART);
817 
818         //
819         //  Identify a discontinuity in the one-ring, otherwise use an
820         //  unassigned (cleared) span to indicate use of the full ring:
821         //
822         if (testInfSharpEdges || isFVarMisMatch || isNonManifold) {
823             if (isNonManifold) {
824                 identifyNonManifoldCornerSpan(level, faceIndex,
825                         i, singularEdgeMask, cornerSpans[i], fvarChannel);
826             } else {
827                 identifyManifoldCornerSpan(level, faceIndex,
828                         i, singularEdgeMask, cornerSpans[i], fvarChannel);
829             }
830         } else {
831             cornerSpans[i].clear();
832         }
833 
834         //  Sharpen the span if a corner or subject to inf-sharp features:
835         if (vTag._corner) {
836             //  Corners tagged in FVar space need additional qualification:
837             if (isFVarMisMatch) {
838                 cornerSpans[i]._sharp = (cornerSpans[i]._numFaces == 1) || isNonManifold;
839             } else {
840                 cornerSpans[i]._sharp = true;
841             }
842         } else if (isNonManifold) {
843             cornerSpans[i]._sharp = vTag._infSharp;
844         } else if (testInfSharpFeatures) {
845             cornerSpans[i]._sharp = testInfSharpEdges
846                     ? !vTag._infSharpCrease : vTag._infSharp;
847         }
848 
849         //  Legacy option -- reinterpret a smooth corner as sharp:
850         bool smoothCorner = !cornerSpans[i]._sharp;
851         if (smoothCorner && _options.approxSmoothCornerWithSharp && vTag._xordinary &&
852                 vTag._boundary && !vTag._infSharp && !vTag._nonManifold) {
853             int nFaces = cornerSpans[i].isAssigned()
854                 ? cornerSpans[i]._numFaces
855                 : level.getVertexFaces(level.getFaceVertices(faceIndex)[i]).size();
856             cornerSpans[i]._sharp = (nFaces == 1);
857         }
858     }
859 }
860 
861 int
getRegularFacePoints(int levelIndex,Index faceIndex,Index patchPoints[],int fvarChannel) const862 PatchBuilder::getRegularFacePoints(int levelIndex, Index faceIndex,
863         Index patchPoints[], int fvarChannel) const {
864 
865     Level const & level = _refiner.getLevel(levelIndex);
866 
867     ConstIndexArray facePoints = (fvarChannel < 0)
868                                ? level.getFaceVertices(faceIndex)
869                                : level.getFaceFVarValues(faceIndex, fvarChannel);
870 
871     for (int i = 0; i < facePoints.size(); ++i) {
872         patchPoints[i] = facePoints[i];
873     }
874     return facePoints.size();
875 }
876 
877 int
getQuadRegularPatchPoints(int levelIndex,Index faceIndex,int regBoundaryMask,Index patchPoints[],int fvarChannel) const878 PatchBuilder::getQuadRegularPatchPoints(int levelIndex, Index faceIndex,
879         int regBoundaryMask, Index patchPoints[],
880         int fvarChannel) const {
881 
882     if (regBoundaryMask < 0) {
883         regBoundaryMask = GetRegularPatchBoundaryMask(levelIndex, faceIndex);
884     }
885     bool interiorPatch = (regBoundaryMask == 0);
886 
887     static int const patchPointsPerCorner[4][4] = { {  5,  4,  0,  1 },
888                                                     {  6,  2,  3,  7 },
889                                                     { 10, 11, 15, 14 },
890                                                     {  9, 13, 12,  8 } };
891 
892     int eMask = regBoundaryMask;
893 
894     Level const & level = _refiner.getLevel(levelIndex);
895 
896     ConstIndexArray fVerts  = level.getFaceVertices(faceIndex);
897     ConstIndexArray fPoints = getFacePoints(level, faceIndex, fvarChannel);
898 
899     Index boundaryPoint = INDEX_INVALID;
900     if (!interiorPatch && _options.fillMissingBoundaryPoints) {
901         boundaryPoint = fPoints[0];
902     }
903 
904     for (int i = 0; i < 4; ++i) {
905         Index v = fVerts[i];
906 
907         const int* cornerPointIndices = patchPointsPerCorner[i];
908 
909         ConstIndexArray      vFaces   = level.getVertexFaces(v);
910         ConstLocalIndexArray vInFaces = level.getVertexFaceLocalIndices(v);
911 
912         //  Identify the patch face in the ring of incident faces.  (There's
913         //  no need to deal with multiple occurrences of the face in the ring
914         //  here -- as can happen with non-manifold vertices -- as such corners
915         //  will be sharp, regular boundaries and not need the incident faces.)
916         //
917         Index f = faceIndex;
918         int fInVFaces = vFaces.FindIndex(f);
919 
920         //  Identify the exterior points for this corner from the appropriate
921         //  incident face:
922         //
923         bool interiorCorner = interiorPatch || (((eMask & (1 << i)) |
924                                                  (eMask & (1 << fastMod4(i+3)))) == 0);
925         if (interiorCorner) {
926             int fOppInVFaces = fastMod4(fInVFaces + 2);
927 
928             Index fOpp = vFaces[fOppInVFaces];
929             int vInFOpp = vInFaces[fOppInVFaces];
930             ConstIndexArray fOppPoints = getFacePoints(level, fOpp, fvarChannel);
931 
932             patchPoints[cornerPointIndices[1]] = fOppPoints[fastMod4(vInFOpp + 1)];
933             patchPoints[cornerPointIndices[2]] = fOppPoints[fastMod4(vInFOpp + 2)];
934             patchPoints[cornerPointIndices[3]] = fOppPoints[fastMod4(vInFOpp + 3)];
935         } else if ((eMask & (1 << i)) && (eMask & (1 << fastMod4(i+3)))) {
936             //  Two indicent boundary edges -- no incident faces
937             patchPoints[cornerPointIndices[1]] = boundaryPoint;
938             patchPoints[cornerPointIndices[2]] = boundaryPoint;
939             patchPoints[cornerPointIndices[3]] = boundaryPoint;
940         } else if (eMask & (1 << i)) {
941             //  Leading/outgoing boundary edge -- need next face:
942             int vInFNext;
943             Index fNext = getNextFaceInVertFaces(level, fInVFaces, vFaces, vInFaces,
944                                    !level.getVertexTag(v)._nonManifold, vInFNext);
945 
946             ConstIndexArray fNextPoints = getFacePoints(level, fNext, fvarChannel);
947 
948             patchPoints[cornerPointIndices[1]] = fNextPoints[fastMod4(vInFNext + 3)];
949             patchPoints[cornerPointIndices[2]] = boundaryPoint;
950             patchPoints[cornerPointIndices[3]] = boundaryPoint;
951         } else {
952             //  Trailing/incoming boundary edge -- need previous face:
953             int vInFPrev;
954             Index fPrev = getPrevFaceInVertFaces(level, fInVFaces, vFaces, vInFaces,
955                                    !level.getVertexTag(v)._nonManifold, vInFPrev);
956 
957             ConstIndexArray fPrevPoints = getFacePoints(level, fPrev, fvarChannel);
958 
959             patchPoints[cornerPointIndices[1]] = boundaryPoint;
960             patchPoints[cornerPointIndices[2]] = boundaryPoint;
961             patchPoints[cornerPointIndices[3]] = fPrevPoints[fastMod4(vInFPrev + 1)];
962         }
963         patchPoints[cornerPointIndices[0]] = fPoints[i];
964     }
965     return 16;
966 }
967 
968 int
getTriRegularPatchPoints(int levelIndex,Index faceIndex,int regBoundaryMask,Index patchPoints[],int fvarChannel) const969 PatchBuilder::getTriRegularPatchPoints(int levelIndex, Index faceIndex,
970         int regBoundaryMask, Index patchPoints[],
971         int fvarChannel) const {
972 
973     if (regBoundaryMask < 0) {
974         regBoundaryMask = GetRegularPatchBoundaryMask(levelIndex, faceIndex);
975     }
976     bool interiorPatch = (regBoundaryMask == 0);
977 
978     static int const patchPointsPerCorner[3][4] = { { 4, 7, 3, 0 },
979                                                     { 5, 1, 2, 6 },
980                                                     { 8, 9, 11, 10 } };
981 
982     int vMask = 0;
983     int eMask = 0;
984     if (!interiorPatch) {
985         decodeTriBoundaryMask(regBoundaryMask, eMask, vMask);
986     }
987 
988     Level const & level = _refiner.getLevel(levelIndex);
989 
990     ConstIndexArray fVerts  = level.getFaceVertices(faceIndex);
991     ConstIndexArray fPoints = getFacePoints(level, faceIndex, fvarChannel);
992 
993     Index boundaryPoint = INDEX_INVALID;
994     if (!interiorPatch && _options.fillMissingBoundaryPoints) {
995         boundaryPoint = fPoints[0];
996     }
997 
998     for (int i = 0; i < 3; ++i) {
999         Index v = fVerts[i];
1000 
1001         const int* cornerPointIndices = patchPointsPerCorner[i];
1002 
1003         ConstIndexArray      vFaces   = level.getVertexFaces(v);
1004         ConstLocalIndexArray vInFaces = level.getVertexFaceLocalIndices(v);
1005 
1006         //  Identify the patch face in the ring of incident faces.  (There's
1007         //  no need to deal with multiple occurrences of the face in the ring
1008         //  here -- as can happen with non-manifold vertices -- as such corners
1009         //  will be sharp, regular boundaries and not need the incident faces.)
1010         //
1011         Index f = faceIndex;
1012         int fInVFaces = vFaces.FindIndex(f);
1013 
1014         //  Identify the exterior points for this corner from the appropriate
1015         //  incident faces:
1016         //
1017         bool interiorCorner = interiorPatch || ((vMask & (1 << i)) == 0);
1018         if (interiorCorner) {
1019             int f2InVFaces = fastModN(fInVFaces + 2, 6);
1020             int f3InVFaces = fastModN(fInVFaces + 3, 6);
1021 
1022             Index f2 = vFaces[f2InVFaces];
1023             Index f3 = vFaces[f3InVFaces];
1024 
1025             int vInf2 = vInFaces[f2InVFaces];
1026             int vInf3 = vInFaces[f3InVFaces];
1027 
1028             ConstIndexArray f2Points = getFacePoints(level, f2, fvarChannel);
1029             ConstIndexArray f3Points = getFacePoints(level, f3, fvarChannel);
1030 
1031             patchPoints[cornerPointIndices[1]] = f2Points[fastMod3(vInf2 + 1)];
1032             patchPoints[cornerPointIndices[2]] = f3Points[fastMod3(vInf3 + 1)];
1033             patchPoints[cornerPointIndices[3]] = f3Points[fastMod3(vInf3 + 2)];
1034         } else if ((eMask & (1 << i)) && (eMask & (1 << fastMod3(i+2)))) {
1035             //  Two indicent boundary edges -- no incident faces
1036 
1037             patchPoints[cornerPointIndices[1]] = boundaryPoint;
1038             patchPoints[cornerPointIndices[2]] = boundaryPoint;
1039             patchPoints[cornerPointIndices[3]] = boundaryPoint;
1040         } else if (eMask & (1 << i)) {
1041             //  Leading/outgoing boundary edge, i.e. f0 of {f0,f1,f2}, need f2:
1042             int f2InVFaces = fastModN(fInVFaces + 2, vFaces.size());
1043 
1044             Index f2 = vFaces[f2InVFaces];
1045             int vInf2 = vInFaces[f2InVFaces];
1046 
1047             if (level.getVertexTag(v)._nonManifold) {
1048                 Index f1 = getNextFaceInVertFaces(level, fInVFaces,
1049                                             vFaces, vInFaces, false, vInf2);
1050                 f2 = getNextFaceInVertFaces(level, vFaces.FindIndex(f1),
1051                                             vFaces, vInFaces, false, vInf2);
1052             }
1053             ConstIndexArray f2Points = getFacePoints(level, f2, fvarChannel);
1054 
1055             patchPoints[cornerPointIndices[1]] = f2Points[fastMod3(vInf2 + 1)];
1056             patchPoints[cornerPointIndices[2]] = f2Points[fastMod3(vInf2 + 2)];
1057             patchPoints[cornerPointIndices[3]] = boundaryPoint;
1058         } else if (eMask & (1 << fastMod3(i+2))) {
1059             //  Trailing/incoming boundary edge, i.e. f2 of {f0,f1,f2}, need f0:
1060             int f0InVFaces = fastModN(fInVFaces + vFaces.size() - 2, vFaces.size());
1061 
1062             Index f0 = vFaces[f0InVFaces];
1063             int vInf0 = vInFaces[f0InVFaces];
1064 
1065             if (level.getVertexTag(v)._nonManifold) {
1066                 Index f1 = getPrevFaceInVertFaces(level, fInVFaces,
1067                                             vFaces, vInFaces, false, vInf0);
1068                 f0 = getPrevFaceInVertFaces(level, vFaces.FindIndex(f1),
1069                                             vFaces, vInFaces, false, vInf0);
1070             }
1071             ConstIndexArray f0Points = getFacePoints(level, f0, fvarChannel);
1072 
1073             patchPoints[cornerPointIndices[1]] = boundaryPoint;
1074             patchPoints[cornerPointIndices[2]] = boundaryPoint;
1075             patchPoints[cornerPointIndices[3]] = f0Points[fastMod3(vInf0 + 1)];
1076         } else {
1077             //  Boundary vertex on edge, i.e. f1 of {f0,f1,f2}, need next face f2:
1078             int vInf2;
1079             Index f2 = getNextFaceInVertFaces(level, fInVFaces, vFaces, vInFaces,
1080                                        !level.getVertexTag(v)._nonManifold, vInf2);
1081 
1082             ConstIndexArray f2Points = getFacePoints(level, f2, fvarChannel);
1083 
1084             patchPoints[cornerPointIndices[1]] = f2Points[fastMod3(vInf2 + 2)];
1085             patchPoints[cornerPointIndices[2]] = boundaryPoint;
1086             patchPoints[cornerPointIndices[3]] = boundaryPoint;
1087         }
1088         patchPoints[cornerPointIndices[0]] = fPoints[i];
1089     }
1090     return 12;
1091 }
1092 
1093 int
GetRegularPatchPoints(int levelIndex,Index faceIndex,int regBoundaryMask,Index patchPoints[],int fvarChannel) const1094 PatchBuilder::GetRegularPatchPoints(int levelIndex, Index faceIndex,
1095         int regBoundaryMask, Index patchPoints[],
1096         int fvarChannel) const {
1097 
1098     if (_schemeIsLinear) {
1099         return getRegularFacePoints(
1100             levelIndex, faceIndex, patchPoints, fvarChannel);
1101     } else if (_schemeRegFaceSize == 4) {
1102         return getQuadRegularPatchPoints(
1103             levelIndex, faceIndex, regBoundaryMask, patchPoints, fvarChannel);
1104     } else {
1105         return getTriRegularPatchPoints(
1106             levelIndex, faceIndex, regBoundaryMask, patchPoints, fvarChannel);
1107     }
1108     return 0;
1109 }
1110 
1111 int
assembleIrregularSourcePatch(int levelIndex,Index faceIndex,Level::VSpan const cornerSpans[],SourcePatch & sourcePatch) const1112 PatchBuilder::assembleIrregularSourcePatch(
1113         int levelIndex, Index faceIndex, Level::VSpan const cornerSpans[],
1114         SourcePatch & sourcePatch) const {
1115 
1116     //
1117     //  Initialize the four Patch corners and finalize the patch:
1118     //
1119     Level const & level = _refiner.getLevel(levelIndex);
1120 
1121     ConstIndexArray fVerts = level.getFaceVertices(faceIndex);
1122 
1123     for (int corner = 0; corner < fVerts.size(); ++corner) {
1124         //
1125         //  Retrieve corner properties from the VSpan when explicitly assigned.
1126         //  Otherwise, identify properties from the incident faces and tags and
1127         //  find the face for the patch within the set of incident faces:
1128         //
1129         Level::VTag vTag = level.getVertexTag(fVerts[corner]);
1130 
1131         SourcePatch::Corner & patchCorner = sourcePatch._corners[corner];
1132 
1133         if (cornerSpans[corner].isAssigned()) {
1134             patchCorner._numFaces  = cornerSpans[corner]._numFaces;
1135             patchCorner._patchFace = cornerSpans[corner]._cornerInSpan;
1136             patchCorner._boundary  = !cornerSpans[corner]._periodic;
1137         } else {
1138             ConstIndexArray vFaces = level.getVertexFaces(fVerts[corner]);
1139 
1140             patchCorner._numFaces  = vFaces.size();
1141             patchCorner._patchFace = vFaces.FindIndex(faceIndex);
1142             patchCorner._boundary  = vTag._boundary;
1143         }
1144         patchCorner._sharp = cornerSpans[corner]._sharp;
1145         patchCorner._dart  = (vTag._rule == Sdc::Crease::RULE_DART) && vTag._infSharpEdges;
1146     }
1147     sourcePatch.Finalize(fVerts.size());
1148 
1149     return sourcePatch.GetNumSourcePoints();
1150 }
1151 
1152 
1153 //
1154 //  Gather patch points from around the face of a level given a previously
1155 //  initialized SourcePatch.  This is historically specific to an irregular
1156 //  patch and still relies on the cornerSpans (which may or may not have been
1157 //  initialized when the SourcePatch was created) rather than inspecting the
1158 //  corners of the SourcePatch.
1159 //
1160 //  We need temporary/local space for rings around each corner -- both for
1161 //  the Vtr::Level and the corresponding rings of the patch.
1162 //
1163 //  Get the corresponding rings from the Vtr::Level and the patch descriptor:
1164 //  the values of the latter will be indices for points[] whose values will
1165 //  come from values of former, i.e. points[localRing[i]] = sourceRing[i].
1166 //  Points that overlap will be assigned multiple times, but messy logic to
1167 //  deal with overlap while determining the correspondence is avoided.
1168 //
1169 int
gatherIrregularSourcePoints(int levelIndex,Index faceIndex,Level::VSpan const cornerSpans[4],SourcePatch & sourcePatch,Index patchVerts[],int fvarChannel) const1170 PatchBuilder::gatherIrregularSourcePoints(
1171         int levelIndex, Index faceIndex,
1172         Level::VSpan const cornerSpans[4], SourcePatch & sourcePatch,
1173         Index patchVerts[], int fvarChannel) const {
1174 
1175     //
1176     //  Allocate temporary space for rings around the corners in both the Level
1177     //  and the Patch, then retrieve corresponding rings and assign the source
1178     //  vertices to the given array of patch points
1179     //
1180     int numSourceVerts = sourcePatch.GetNumSourcePoints();
1181 
1182     StackBuffer<Index,64,true> sourceRingVertices(sourcePatch.GetMaxRingSize());
1183     StackBuffer<Index,64,true> patchRingPoints(sourcePatch.GetMaxRingSize());
1184 
1185     Level const & level = _refiner.getLevel(levelIndex);
1186 
1187     ConstIndexArray faceVerts = level.getFaceVertices(faceIndex);
1188     for (int corner = 0; corner < sourcePatch._numCorners; ++corner) {
1189         Index cornerVertex = faceVerts[corner];
1190 
1191         //  Gather the ring of source points from the Vtr level:
1192         int sourceRingSize = 0;
1193         if (cornerSpans[corner].isAssigned()) {
1194             sourceRingSize = gatherRegularPartialRingAroundVertex(level,
1195                 cornerVertex, cornerSpans[corner], sourceRingVertices,
1196                 fvarChannel);
1197         } else if (sourcePatch._numCorners == 4) {
1198             sourceRingSize = level.gatherQuadRegularRingAroundVertex(
1199                 cornerVertex, sourceRingVertices,
1200                 fvarChannel);
1201         } else {
1202             sourceRingSize = gatherTriRegularRingAroundVertex(level,
1203                 cornerVertex, sourceRingVertices,
1204                 fvarChannel);
1205         }
1206 
1207         //  Gather the ring of local points from the patch:
1208         int patchRingSize = sourcePatch.GetCornerRingPoints(
1209                 corner, patchRingPoints);
1210         assert(patchRingSize == sourceRingSize);
1211 
1212         //  Identify source points for corresponding local patch points of ring:
1213         for (int i = 0; i < patchRingSize; ++i) {
1214             assert(patchRingPoints[i] < numSourceVerts);
1215             patchVerts[patchRingPoints[i]] = sourceRingVertices[i];
1216         }
1217     }
1218     return numSourceVerts;
1219 }
1220 
1221 int
GetIrregularPatchSourcePoints(int levelIndex,Index faceIndex,Level::VSpan const cornerSpans[],Index sourcePoints[],int fvarChannel) const1222 PatchBuilder::GetIrregularPatchSourcePoints(
1223         int levelIndex, Index faceIndex, Level::VSpan const cornerSpans[],
1224         Index sourcePoints[], int fvarChannel) const {
1225 
1226     SourcePatch sourcePatch;
1227     assembleIrregularSourcePatch(
1228             levelIndex, faceIndex, cornerSpans, sourcePatch);
1229 
1230     return gatherIrregularSourcePoints(levelIndex, faceIndex,
1231         cornerSpans, sourcePatch, sourcePoints, fvarChannel);
1232 }
1233 
1234 //
1235 //  Template conversion methods for the matrix type -- explicit instantiation
1236 //  for float and double is required and follows the definition:
1237 //
1238 template <typename REAL>
1239 int
GetIrregularPatchConversionMatrix(int levelIndex,Index faceIndex,Level::VSpan const cornerSpans[],SparseMatrix<REAL> & conversionMatrix) const1240 PatchBuilder::GetIrregularPatchConversionMatrix(
1241         int levelIndex, Index faceIndex,
1242         Level::VSpan const cornerSpans[],
1243         SparseMatrix<REAL> & conversionMatrix) const {
1244 
1245     SourcePatch sourcePatch;
1246     assembleIrregularSourcePatch(
1247             levelIndex, faceIndex, cornerSpans, sourcePatch);
1248 
1249     return convertToPatchType(
1250         sourcePatch, GetIrregularPatchType(), conversionMatrix);
1251 }
1252 template int PatchBuilder::GetIrregularPatchConversionMatrix<float>(
1253         int levelIndex, Index faceIndex, Level::VSpan const cornerSpans[],
1254         SparseMatrix<float> & conversionMatrix) const;
1255 template int PatchBuilder::GetIrregularPatchConversionMatrix<double>(
1256         int levelIndex, Index faceIndex, Level::VSpan const cornerSpans[],
1257         SparseMatrix<double> & conversionMatrix) const;
1258 
1259 
1260 bool
IsRegularSingleCreasePatch(int levelIndex,Index faceIndex,SingleCreaseInfo & creaseInfo) const1261 PatchBuilder::IsRegularSingleCreasePatch(int levelIndex, Index faceIndex,
1262         SingleCreaseInfo & creaseInfo) const {
1263 
1264     if (_schemeRegFaceSize != 4) return false;
1265 
1266     Level const & level = _refiner.getLevel(levelIndex);
1267 
1268     return level.isSingleCreasePatch(faceIndex,
1269                 &creaseInfo.creaseSharpness, &creaseInfo.creaseEdgeInFace);
1270 }
1271 
1272 PatchParam
ComputePatchParam(int levelIndex,Index faceIndex,PtexIndices const & ptexIndices,bool isRegular,int boundaryMask,bool computeTransitionMask) const1273 PatchBuilder::ComputePatchParam(int levelIndex, Index faceIndex,
1274         PtexIndices const& ptexIndices, bool isRegular,
1275         int boundaryMask, bool computeTransitionMask) const {
1276 
1277     // Move up the hierarchy accumulating u,v indices to the coarse level:
1278     int depth = levelIndex;
1279     int childIndexInParent = 0,
1280         u = 0,
1281         v = 0,
1282         ofs = 1;
1283 
1284     int regFaceSize = _schemeRegFaceSize;
1285 
1286     bool irregBase =
1287         _refiner.GetLevel(depth).GetFaceVertices(faceIndex).size() !=
1288         regFaceSize;
1289 
1290     // For triangle refinement, the parameterization is rotated at
1291     // the fourth triangle subface at each level. The u and v values
1292     // computed for rotated triangles will be negative while we are
1293     // walking through the refinement levels.
1294     bool rotatedTriangle = false;
1295 
1296     int childFaceIndex = faceIndex;
1297     for (int i = depth; i > 0; --i) {
1298         Refinement const& refinement  = _refiner.getRefinement(i-1);
1299         Level const&      parentLevel = _refiner.getLevel(i-1);
1300 
1301         Index parentFaceIndex =
1302             refinement.getChildFaceParentFace(childFaceIndex);
1303 
1304         irregBase =
1305             parentLevel.getFaceVertices(parentFaceIndex).size() !=
1306             regFaceSize;
1307 
1308         if (_schemeRegFaceSize == 3) {
1309             // For now, we don't consider irregular faces for
1310             // triangle refinement.
1311 
1312             childIndexInParent =
1313                 refinement.getChildFaceInParentFace(childFaceIndex);
1314 
1315             if (rotatedTriangle) {
1316                 switch ( childIndexInParent ) {
1317                     case 0 :                     break;
1318                     case 1 : { u-=ofs;         } break;
1319                     case 2 : {         v-=ofs; } break;
1320                     case 3 : { u+=ofs; v+=ofs; rotatedTriangle = false; } break;
1321                 }
1322             } else {
1323                 switch ( childIndexInParent ) {
1324                     case 0 :                     break;
1325                     case 1 : { u+=ofs;         } break;
1326                     case 2 : {         v+=ofs; } break;
1327                     case 3 : { u-=ofs; v-=ofs; rotatedTriangle = true; } break;
1328                 }
1329             }
1330             ofs = (unsigned short)(ofs << 1);
1331         } else if (!irregBase) {
1332             childIndexInParent =
1333                 refinement.getChildFaceInParentFace(childFaceIndex);
1334 
1335             switch ( childIndexInParent ) {
1336                 case 0 :                     break;
1337                 case 1 : { u+=ofs;         } break;
1338                 case 2 : { u+=ofs; v+=ofs; } break;
1339                 case 3 : {         v+=ofs; } break;
1340             }
1341             ofs = (unsigned short)(ofs << 1);
1342         } else {
1343             // If the root face is not a quad, we need to offset the ptex index
1344             // CCW to match the correct child face
1345             ConstIndexArray children =
1346                 refinement.getFaceChildFaces(parentFaceIndex);
1347 
1348             for (int j=0; j<children.size(); ++j) {
1349                 if (children[j] == childFaceIndex) {
1350                     childIndexInParent = j;
1351                     break;
1352                 }
1353             }
1354         }
1355         childFaceIndex = parentFaceIndex;
1356     }
1357     if (rotatedTriangle) {
1358         // If the triangle is tagged as rotated at this point then the
1359         // computed u and v parameters will both be negative and we map
1360         // them onto positive values in the opposite diagonal of the
1361         // parameter space.
1362         u += ofs;
1363         v += ofs;
1364     }
1365     int baseFaceIndex = childFaceIndex;
1366 
1367     //  Need to store ptex index from base face and child of an irregular face:
1368     Index ptexIndex = ptexIndices.GetFaceId(baseFaceIndex);
1369     assert(ptexIndex != -1);
1370     if (irregBase) {
1371         ptexIndex += childIndexInParent;
1372     }
1373 
1374     //  Compute/identify the transition mask if requested, otherwise leave it 0:
1375     int transitionMask = 0;
1376     if (computeTransitionMask && (levelIndex < _refiner.GetMaxLevel())) {
1377         transitionMask = _refiner.getRefinement(levelIndex).
1378                             getParentFaceSparseTag(faceIndex)._transitional;
1379     }
1380 
1381     PatchParam param;
1382     param.Set(ptexIndex, (short)u, (short)v, (unsigned short) depth, irregBase,
1383               (unsigned short) boundaryMask, (unsigned short) transitionMask,
1384               (unsigned short) isRegular);
1385     return param;
1386 }
1387 
1388 
1389 //
1390 //  SourcePatch
1391 //
1392 //  This class allows the full topological specification of the neighborhood
1393 //  of vertices and edges around a face that collectively define a rectangular
1394 //  piece of surface corresponding to that face.  All components are declared
1395 //  in terms of local indices and explicitly avoid any references/indices to
1396 //  an external representation.  It is assembled by specifying the topology
1397 //  of each corner (number of faces/edges, boundary, etc.) and finalization
1398 //  determines a set of source vertices in a canonical orientation relative
1399 //  to the face and any patch which may be derived from it.
1400 //
1401 //  Any/all corners can be arbitrarily irregular.  Information for each corner
1402 //  is similar to what is provided in a Vtr::Level::VSpan but does not require
1403 //  any Vtr dependent orientation (e.g. the leading edge) and also requires
1404 //  identification of the incident face that corresponds to the patch (i.e.
1405 //  the "patch face").
1406 //
1407 //  The set of local source vertices begins with the corner vertices of the
1408 //  face corresponding to the patch.  Since the 1-rings of the corner vertices
1409 //  overlap, a subset of the 1-rings is identified as the "local ring points"
1410 //  for a corner, which are the points most associated with the corner.  While
1411 //  one of these local ring points may overlap with an adjacent corner, the
1412 //  local ring points for each corner are indexed successively for each corner.
1413 //
1414 //  The cumulative set of source points forming the 1-ring around the patch
1415 //  face is indexed successively in a counter-clockwise orientation beginning
1416 //  with the first edge-vertex of the first corner, e.g. for a patch with
1417 //  three regular corners and an irregular boundary:
1418 //
1419 //     13          12       11         10
1420 //        x--------x--------x--------x
1421 //        |        |        |        |
1422 //        |        |        |        |
1423 //        |        |        |        |
1424 //        |        |        |        |
1425 //     14 x--------x--------x--------x 9
1426 //        |        |3      2|        |
1427 //        |        |        |        |
1428 //        |        |        |        |
1429 //        |        |0      1|        |
1430 //      4 x--------x--------x--------x 8
1431 //        |        |        |
1432 //        |        |        |
1433 //        |        |        |
1434 //        |        |        |
1435 //        x--------x--------x
1436 //      5          6         7
1437 //
1438 //  The set of source points consists of the corner points {0,1,2,3} followed
1439 //  by the four sets of points {4,5,6}, {7,8}, {9,10,11} and {12,13,14} --
1440 //  each being the exterior subset of the points of the one-ring for the
1441 //  corresponding corner point.
1442 //
1443 //  The 1-ring for each corner is made available for both assembling the points
1444 //  of the resulting Gregory patch and for defining correspondence between the
1445 //  original source of the vertices.  All 1-rings are oriented counter-clockwise
1446 //  and begin with a vertex at the end of an edge.  The 1-rings for boundaries
1447 //  begin/end with vertices at the ends of the leading/trailing edges.  Interior
1448 //  1-rings are ordered such that the patch-face vertices occur as specified.
1449 //
1450 
1451 //
1452 //  SourcePatch method to initialize other internal members once required
1453 //  members of all corners have been explicitly initialized.  This deals with
1454 //  all of the awkward ways in which rings of vertices around each corner
1455 //  overlap in order to define the canonical ordering of vertices (and avoiding
1456 //  have the same vertex twice).
1457 //
1458 //  Note:  Considering passing Corner[4] to a constructor so that this is all
1459 //  dealt with in the constructor.
1460 //
1461 void
Finalize(int size)1462 SourcePatch::Finalize(int size) {
1463 
1464     //
1465     //  Determine the sizes of the rings and the total number of points
1466     //  involved.  In the process, identify which corners share ring points
1467     //  with their neighbors and accumulate maximal ring sizes and valence:
1468     //
1469     bool isQuad = (size == 4);
1470 
1471     _numCorners = size;
1472 
1473     _maxValence = 0;
1474     _maxRingSize = 0;
1475     _numSourcePoints = _numCorners;
1476 
1477     for (int cIndex = 0; cIndex < _numCorners; ++cIndex) {
1478         //
1479         //  Need valence-2 information for neighbors as it affects sizing:
1480         //
1481         int cPrev = fastModN(cIndex + 2 + isQuad, _numCorners);
1482         int cNext = fastModN(cIndex + 1,          _numCorners);
1483 
1484         bool prevIsVal2Interior = ((_corners[cPrev]._numFaces == 2) &&
1485                                    !_corners[cPrev]._boundary);
1486         bool thisIsVal2Interior = ((_corners[cIndex]._numFaces == 2) &&
1487                                    !_corners[cIndex]._boundary);
1488         bool nextIsVal2Interior = ((_corners[cNext]._numFaces == 2) &&
1489                                    !_corners[cNext]._boundary);
1490 
1491         Corner & corner = _corners[cIndex];
1492 
1493         corner._val2Interior = thisIsVal2Interior;
1494         corner._val2Adjacent = prevIsVal2Interior || nextIsVal2Interior;
1495 
1496         //
1497         //  General cases are >= 3-face interior and >= 2-face boundary:
1498         //
1499         if ((corner._numFaces + corner._boundary) > 2) {
1500             //
1501             //  Quads generally share with both prev and next, but triangles
1502             //  never share with prev because of the necessary asymmetry of
1503             //  the local ring points.
1504             //
1505             if (corner._boundary) {
1506                 corner._sharesWithPrev = isQuad && (corner._patchFace != (corner._numFaces - 1));
1507                 corner._sharesWithNext = (corner._patchFace != 0);
1508             } else if (corner._dart) {
1509                 Corner & cP = _corners[cPrev];
1510                 Corner & cN = _corners[cNext];
1511 
1512                 bool cPrevOnDartEdge = cP._boundary && (cP._patchFace == 0);
1513                 bool cNextOnDartEdge = cN._boundary && (cN._patchFace == cN._numFaces - 1);
1514 
1515                 corner._sharesWithPrev = isQuad && !cPrevOnDartEdge;
1516                 corner._sharesWithNext = !cNextOnDartEdge;
1517             } else {
1518                 corner._sharesWithPrev = isQuad;
1519                 corner._sharesWithNext = true;
1520             }
1521 
1522             _ringSizes[cIndex]      = corner._numFaces * (1 + isQuad) + corner._boundary;
1523             _localRingSizes[cIndex] = _ringSizes[cIndex] - (_numCorners - 1)
1524                                     - corner._sharesWithPrev - corner._sharesWithNext;
1525 
1526             if (corner._val2Adjacent) {
1527                 _localRingSizes[cIndex] -= prevIsVal2Interior;
1528                 _localRingSizes[cIndex] -= (nextIsVal2Interior && isQuad);
1529             }
1530         } else {
1531             corner._sharesWithPrev = false;
1532             corner._sharesWithNext = false;
1533 
1534             //  Single-face boundary/corner and valence-2 interior:
1535             if (corner._numFaces == 1) {
1536                 _ringSizes[cIndex]      = _numCorners - 1;
1537                 _localRingSizes[cIndex] = 0;
1538             } else {
1539                 _ringSizes[cIndex]      = 2 * (1 + isQuad);
1540                 _localRingSizes[cIndex] = isQuad;
1541             }
1542         }
1543         _localRingOffsets[cIndex] = _numSourcePoints;
1544 
1545         _maxValence  = std::max(_maxValence, corner._numFaces + corner._boundary);
1546         _maxRingSize = std::max(_maxRingSize, _ringSizes[cIndex]);
1547 
1548         _numSourcePoints += _localRingSizes[cIndex];
1549     }
1550 }
1551 
1552 
1553 int
GetCornerRingPoints(int corner,int ringPoints[]) const1554 SourcePatch::GetCornerRingPoints(int corner, int ringPoints[]) const {
1555 
1556     bool isQuad = (_numCorners == 4);
1557 
1558     int cNext = fastModN(corner + 1,          _numCorners);
1559     int cOpp  = fastModN(corner + 1 + isQuad, _numCorners);
1560     int cPrev = fastModN(corner + 2 + isQuad, _numCorners);
1561 
1562     //
1563     //  Assemble the ring in a canonical ordering beginning with the points of
1564     //  the 2 or 3 other corners of the face followed by the local ring -- with
1565     //  any shared or compensating points (for valence-2 interior) preceding
1566     //  and following the points local to the ring.
1567     //
1568     int ringSize = 0;
1569 
1570     //  The adjacent corner points:
1571     ringPoints[ringSize++] = cNext;
1572     if (isQuad) {
1573         ringPoints[ringSize++] = cOpp;
1574     }
1575     ringPoints[ringSize++] = cPrev;
1576 
1577     //  Shared points preceding the local ring points:
1578     if (_corners[cPrev]._val2Interior) {
1579         ringPoints[ringSize++] = isQuad ? cOpp : cNext;
1580     }
1581     if (_corners[corner]._sharesWithPrev) {
1582         ringPoints[ringSize++] = _localRingOffsets[cPrev] + _localRingSizes[cPrev] - 1;
1583     }
1584 
1585     //  The local ring points:
1586     for (int i = 0; i < _localRingSizes[corner]; ++i) {
1587         ringPoints[ringSize++] = _localRingOffsets[corner] + i;
1588     }
1589 
1590     //  Shared points following the local ring points:
1591     if (isQuad) {
1592         if (_corners[corner]._sharesWithNext) {
1593             ringPoints[ringSize++] = _localRingOffsets[cNext];
1594         }
1595         if (_corners[cNext]._val2Interior) {
1596             ringPoints[ringSize++] = cOpp;
1597         }
1598     } else {
1599         if (_corners[corner]._sharesWithNext) {
1600             if (_corners[cNext]._val2Interior) {
1601                 ringPoints[ringSize++] = cPrev;
1602             } else if (_localRingSizes[cNext] == 0) {
1603                 ringPoints[ringSize++] = _localRingOffsets[cPrev];
1604             } else {
1605                 ringPoints[ringSize++] = _localRingOffsets[cNext];
1606             }
1607         }
1608     }
1609     assert(ringSize == _ringSizes[corner]);
1610 
1611     //  The assembled ordering matches the desired ordering if the patch-face
1612     //  is first, so rotate the assembled ring if that's not the case:
1613     //
1614     if (_corners[corner]._patchFace) {
1615         int rotationOffset = ringSize - (1 + isQuad) * _corners[corner]._patchFace;
1616         std::rotate(ringPoints, ringPoints + rotationOffset, ringPoints + ringSize);
1617     }
1618     return ringSize;
1619 }
1620 
1621 } // end namespace Far
1622 
1623 } // end namespace OPENSUBDIV_VERSION
1624 } // end namespace OpenSubdiv
1625