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