1 //
2 //   Copyright 2014 DreamWorks Animation LLC.
3 //
4 //   Licensed under the Apache License, Version 2.0 (the "Apache License")
5 //   with the following modification; you may not use this file except in
6 //   compliance with the Apache License and the following modification to it:
7 //   Section 6. Trademarks. is deleted and replaced with:
8 //
9 //   6. Trademarks. This License does not grant permission to use the trade
10 //      names, trademarks, service marks, or product names of the Licensor
11 //      and its affiliates, except as required to comply with Section 4(c) of
12 //      the License and to reproduce the content of the NOTICE file.
13 //
14 //   You may obtain a copy of the Apache License at
15 //
16 //       http://www.apache.org/licenses/LICENSE-2.0
17 //
18 //   Unless required by applicable law or agreed to in writing, software
19 //   distributed under the Apache License with the above modification is
20 //   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 //   KIND, either express or implied. See the Apache License for the specific
22 //   language governing permissions and limitations under the Apache License.
23 //
24 #include "../sdc/types.h"
25 #include "../sdc/crease.h"
26 #include "../vtr/array.h"
27 #include "../vtr/level.h"
28 #include "../vtr/refinement.h"
29 #include "../vtr/fvarLevel.h"
30 #include "../vtr/stackBuffer.h"
31 
32 #include <cassert>
33 #include <cstdio>
34 #include <cstring>
35 #include <algorithm>
36 #include <vector>
37 #include <map>
38 
39 #ifdef _MSC_VER
40     #define snprintf _snprintf
41 #endif
42 
43 //
44 //  Level:
45 //      This is intended to be a fairly simple container of topology, sharpness and
46 //  other information that is useful to retain for subdivision.  It is intended to
47 //  be constructed by other friend classes, i.e. factories and class specialized to
48 //  construct topology based on various splitting schemes.  So its interface consists
49 //  of simple methods for inspection, and low-level protected methods for populating
50 //  it rather than high-level modifiers.
51 //
52 namespace OpenSubdiv {
53 namespace OPENSUBDIV_VERSION {
54 
55 namespace Vtr {
56 namespace internal {
57 
58 //
59 //  Simple (for now) constructor and destructor:
60 //
Level()61 Level::Level() :
62     _faceCount(0),
63     _edgeCount(0),
64     _vertCount(0),
65     _depth(0),
66     _maxEdgeFaces(0),
67     _maxValence(0) {
68 }
69 
~Level()70 Level::~Level() {
71     for (int i = 0; i < (int)_fvarChannels.size(); ++i) {
72         delete _fvarChannels[i];
73     }
74 }
75 
76 
77 char const *
getTopologyErrorString(TopologyError errCode)78 Level::getTopologyErrorString(TopologyError errCode) {
79 
80     switch (errCode) {
81         case TOPOLOGY_MISSING_EDGE_FACES :
82             return "MISSING_EDGE_FACES";
83         case TOPOLOGY_MISSING_EDGE_VERTS :
84             return "MISSING_EDGE_VERTS";
85         case TOPOLOGY_MISSING_FACE_EDGES :
86             return "MISSING_FACE_EDGES";
87         case TOPOLOGY_MISSING_FACE_VERTS :
88             return "MISSING_FACE_VERTS";
89         case TOPOLOGY_MISSING_VERT_FACES :
90             return "MISSING_VERT_FACES";
91         case TOPOLOGY_MISSING_VERT_EDGES :
92             return "MISSING_VERT_EDGES";
93 
94         case TOPOLOGY_FAILED_CORRELATION_EDGE_FACE :
95             return "FAILED_CORRELATION_EDGE_FACE";
96         case TOPOLOGY_FAILED_CORRELATION_FACE_VERT :
97             return "FAILED_CORRELATION_FACE_VERT";
98         case TOPOLOGY_FAILED_CORRELATION_FACE_EDGE :
99             return "FAILED_CORRELATION_FACE_EDGE";
100 
101         case TOPOLOGY_FAILED_ORIENTATION_INCIDENT_EDGE :
102             return "FAILED_ORIENTATION_INCIDENT_EDGE";
103         case TOPOLOGY_FAILED_ORIENTATION_INCIDENT_FACE :
104             return "FAILED_ORIENTATION_INCIDENT_FACE";
105         case TOPOLOGY_FAILED_ORIENTATION_INCIDENT_FACES_EDGES :
106             return "FAILED_ORIENTATION_INCIDENT_FACES_EDGES";
107 
108         case TOPOLOGY_DEGENERATE_EDGE :
109             return "DEGENERATE_EDGE";
110         case TOPOLOGY_NON_MANIFOLD_EDGE :
111             return "NON_MANIFOLD_EDGE";
112 
113         case TOPOLOGY_INVALID_CREASE_EDGE :
114             return "INVALID_CREASE_EDGE";
115         case TOPOLOGY_INVALID_CREASE_VERT :
116             return "INVALID_CREASE_VERT";
117 
118         default:
119             assert(0);
120     }
121     return 0;
122 }
123 
124 //
125 //  Debugging method to validate topology, i.e. verify appropriate symmetry
126 //  between the relations, etc.
127 //
128 //  Additions that need to be made in the near term:
129 //      * verifying user-applied tags relating to topology:
130 //          - non-manifold in particular (ordering above can be part of this)
131 //          - face holes don't require anything
132 //      - verifying orientation of components, particularly vert-edges and faces:
133 //          - both need to be ordered correctly (when manifold)
134 //          - both need to be in sync for an interior vertex
135 //              ? is a rotation allowed for the interior case?
136 //              - I don't see why not...
137 //      ? verifying sharpness:
138 //          - values < Smooth or > Infinite
139 //          - sharpening of boundary edges (is this necessary, since we do it?)
140 //              - it does ensure our work was not corrupted by client assignments
141 //
142 //  Possibilities:
143 //      - single validate() method, which will call all of:
144 //          - validateTopology()
145 //          - validateSharpness()
146 //          - validateTagging()
147 //      - consider using a mask/struct to choose what to validate, i.e.:
148 //          - bool validate(ValidateOptions const& options) const;
149 //
150 
151 #define REPORT(code, format, ...) \
152     if (callback) { \
153         char const * errStr = getTopologyErrorString(code); \
154         char msg[1024]; \
155         snprintf(msg, 1024, "%s - " format, errStr, ##__VA_ARGS__); \
156         callback(code, msg, clientData); \
157     }
158 
159 bool
validateTopology(ValidationCallback callback,void const * clientData) const160 Level::validateTopology(ValidationCallback callback, void const * clientData) const {
161 
162     //
163     //  Verify internal topological consistency (eventually a Level method?):
164     //      - each face-vert has corresponding vert-face (and child)
165     //      - each face-edge has corresponding edge-face
166     //      - each edge-vert has corresponding vert-edge (and child)
167     //  The above three are enough for most cases, but it is still possible
168     //  the latter relation in each above has no correspondent in the former,
169     //  so apply the symmetric tests:
170     //      - each edge-face has corresponding face-edge
171     //      - each vert-face has corresponding face-vert
172     //      - each vert-edge has corresponding edge-vert
173     //  We are still left with the possibility of duplicate references in
174     //  places we don't want them.  Currently a component can exist multiple
175     //  times in a component of higher dimension.
176     //      - each vert-face <face,child> pair is unique
177     //      - each vert-edge <edge,child> pair is unique
178     //
179     bool returnOnFirstError = true;
180     bool isValid = true;
181 
182     //  Verify each face-vert has corresponding vert-face and child:
183     if ((getNumFaceVerticesTotal() == 0) || (getNumVertexFacesTotal() == 0)) {
184         if (getNumFaceVerticesTotal() == 0) {
185             REPORT(TOPOLOGY_MISSING_FACE_VERTS, "missing face-verts");
186         }
187         if (getNumVertexFacesTotal() == 0) {
188             REPORT(TOPOLOGY_MISSING_VERT_FACES, "missing vert-faces");
189         }
190         return false;
191     }
192     for (int fIndex = 0; fIndex < getNumFaces(); ++fIndex) {
193         ConstIndexArray     fVerts      = getFaceVertices(fIndex);
194         int                 fVertCount  = fVerts.size();
195 
196         for (int i = 0; i < fVertCount; ++i) {
197             Index vIndex = fVerts[i];
198 
199             ConstIndexArray        vFaces = getVertexFaces(vIndex);
200             ConstLocalIndexArray  vInFace = getVertexFaceLocalIndices(vIndex);
201 
202             bool vertFaceOfFaceExists = false;
203             for (int j = 0; j < vFaces.size(); ++j) {
204                 if ((vFaces[j] == fIndex) && (vInFace[j] == i)) {
205                     vertFaceOfFaceExists = true;
206                     break;
207                 }
208             }
209             if (!vertFaceOfFaceExists) {
210                 REPORT(TOPOLOGY_FAILED_CORRELATION_FACE_VERT,
211                     "face %d correlation of vert %d failed", fIndex, i);
212                 if (returnOnFirstError) return false;
213                 isValid = false;
214             }
215         }
216     }
217 
218     //  Verify each face-edge has corresponding edge-face:
219     if ((getNumEdgeFacesTotal() == 0) || (getNumFaceEdgesTotal() == 0)) {
220         if (getNumEdgeFacesTotal() == 0) {
221             REPORT(TOPOLOGY_MISSING_EDGE_FACES, "missing edge-faces");
222         }
223         if (getNumFaceEdgesTotal() == 0) {
224             REPORT(TOPOLOGY_MISSING_FACE_EDGES, "missing face-edges");
225         }
226         return false;
227     }
228     for (int fIndex = 0; fIndex < getNumFaces(); ++fIndex) {
229         ConstIndexArray  fEdges      = getFaceEdges(fIndex);
230         int              fEdgeCount  = fEdges.size();
231 
232         for (int i = 0; i < fEdgeCount; ++i) {
233             int eIndex = fEdges[i];
234 
235             ConstIndexArray       eFaces = getEdgeFaces(eIndex);
236             ConstLocalIndexArray eInFace = getEdgeFaceLocalIndices(eIndex);
237 
238             bool edgeFaceOfFaceExists = false;
239             for (int j = 0; j < eFaces.size(); ++j) {
240                 if ((eFaces[j] == fIndex) && (eInFace[j] == i)) {
241                     edgeFaceOfFaceExists = true;
242                     break;
243                 }
244             }
245             if (!edgeFaceOfFaceExists) {
246                 REPORT(TOPOLOGY_FAILED_CORRELATION_FACE_EDGE,
247                      "face %d correlation of edge %d failed", fIndex, i);
248                 if (returnOnFirstError) return false;
249                 isValid = false;
250             }
251         }
252     }
253 
254     //  Verify each edge-vert has corresponding vert-edge and child:
255     if ((getNumEdgeVerticesTotal() == 0) || (getNumVertexEdgesTotal() == 0)) {
256         if (getNumEdgeVerticesTotal() == 0) {
257             REPORT(TOPOLOGY_MISSING_EDGE_VERTS, "missing edge-verts");
258         }
259         if (getNumVertexEdgesTotal() == 0) {
260             REPORT(TOPOLOGY_MISSING_VERT_EDGES, "missing vert-edges");
261         }
262         return false;
263     }
264     for (int eIndex = 0; eIndex < getNumEdges(); ++eIndex) {
265         ConstIndexArray  eVerts = getEdgeVertices(eIndex);
266 
267         for (int i = 0; i < 2; ++i) {
268             Index vIndex = eVerts[i];
269 
270             ConstIndexArray       vEdges = getVertexEdges(vIndex);
271             ConstLocalIndexArray  vInEdge = getVertexEdgeLocalIndices(vIndex);
272 
273             bool vertEdgeOfEdgeExists = false;
274             for (int j = 0; j < vEdges.size(); ++j) {
275                 if ((vEdges[j] == eIndex) && (vInEdge[j] == i)) {
276                     vertEdgeOfEdgeExists = true;
277                     break;
278                 }
279             }
280             if (!vertEdgeOfEdgeExists) {
281                 REPORT(TOPOLOGY_FAILED_CORRELATION_FACE_VERT,
282                     "edge %d correlation of vert %d failed", eIndex, i);
283                 if (returnOnFirstError) return false;
284                 isValid = false;
285             }
286         }
287     }
288 
289     //  Verify that vert-faces and vert-edges are properly ordered and in sync:
290     //      - currently this requires the relations exactly match those that we construct from
291     //        the ordering method, i.e. we do not allow rotations for interior vertices.
292     internal::StackBuffer<Index,32> indexBuffer(2 * _maxValence);
293 
294     for (int vIndex = 0; vIndex < getNumVertices(); ++vIndex) {
295         if (_vertTags[vIndex]._incomplete || _vertTags[vIndex]._nonManifold) continue;
296 
297         ConstIndexArray  vFaces = getVertexFaces(vIndex);
298         ConstIndexArray  vEdges = getVertexEdges(vIndex);
299 
300         Index * vFacesOrdered = indexBuffer;
301         Index * vEdgesOrdered = indexBuffer + vFaces.size();
302 
303         if (!orderVertexFacesAndEdges(vIndex, vFacesOrdered, vEdgesOrdered)) {
304             REPORT(TOPOLOGY_FAILED_ORIENTATION_INCIDENT_FACES_EDGES,
305                 "vertex %d cannot orient incident faces and edges", vIndex);
306             if (returnOnFirstError) return false;
307             isValid = false;
308         }
309         for (int i = 0; i < vFaces.size(); ++i) {
310             if (vFaces[i] != vFacesOrdered[i]) {
311                 REPORT(TOPOLOGY_FAILED_ORIENTATION_INCIDENT_FACE,
312                     "vertex %d orientation failure at incident face %d", vIndex, i);
313                 if (returnOnFirstError) return false;
314                 isValid = false;
315                 break;
316             }
317         }
318         for (int i = 0; i < vEdges.size(); ++i) {
319             if (vEdges[i] != vEdgesOrdered[i]) {
320                 REPORT(TOPOLOGY_FAILED_ORIENTATION_INCIDENT_EDGE,
321                     "vertex %d orientation failure at incident edge %d", vIndex, i);
322                 if (returnOnFirstError) return false;
323                 isValid = false;
324                 break;
325             }
326         }
327     }
328 
329     //  Verify non-manifold tags are appropriately assigned to edges and vertices:
330     //      - note we have to validate orientation of vertex neighbors to do this rigorously
331     for (int eIndex = 0; eIndex < getNumEdges(); ++eIndex) {
332         Level::ETag const& eTag = _edgeTags[eIndex];
333         if (eTag._nonManifold) continue;
334 
335         ConstIndexArray  eVerts = getEdgeVertices(eIndex);
336         if (eVerts[0] == eVerts[1]) {
337             REPORT(TOPOLOGY_DEGENERATE_EDGE,
338                 "Error in eIndex = %d:  degenerate edge not tagged marked non-manifold", eIndex);
339             if (returnOnFirstError) return false;
340             isValid = false;
341         }
342 
343         ConstIndexArray  eFaces = getEdgeFaces(eIndex);
344         if ((eFaces.size() < 1) || (eFaces.size() > 2)) {
345             REPORT(TOPOLOGY_NON_MANIFOLD_EDGE,
346                 "edge %d with %d incident faces not tagged non-manifold", eIndex, eFaces.size());
347             if (returnOnFirstError) return false;
348             isValid = false;
349         }
350     }
351     return isValid;
352 }
353 
354 //
355 //  Anonymous helper functions for debugging output -- yes, using printf(), this is not
356 //  intended to serve anyone other than myself for now and I favor its formatting control
357 //
358 namespace {
359     template <typename INT_TYPE>
360     void
printIndexArray(ConstArray<INT_TYPE> const & array)361     printIndexArray(ConstArray<INT_TYPE> const& array) {
362 
363         printf("%d [%d", array.size(), array[0]);
364         for (int i = 1; i < array.size(); ++i) {
365             printf(" %d", array[i]);
366         }
367         printf("]\n");
368     }
369 
370     const char*
ruleString(Sdc::Crease::Rule rule)371     ruleString(Sdc::Crease::Rule rule) {
372         switch (rule) {
373             case Sdc::Crease::RULE_UNKNOWN: return "<uninitialized>";
374             case Sdc::Crease::RULE_SMOOTH:  return "Smooth";
375             case Sdc::Crease::RULE_DART:    return "Dart";
376             case Sdc::Crease::RULE_CREASE:  return "Crease";
377             case Sdc::Crease::RULE_CORNER:  return "Corner";
378             default:
379                 assert(0);
380         }
381         return 0;
382     }
383 
384 #ifdef __INTEL_COMPILER
385 #pragma warning (push)
386 #pragma warning disable 1572
387 #endif
isSharpnessEqual(float s1,float s2)388     inline bool isSharpnessEqual(float s1, float s2) { return (s1 == s2); }
389 #ifdef __INTEL_COMPILER
390 #pragma warning (pop)
391 #endif
392 }
393 
394 void
print(const Refinement * pRefinement) const395 Level::print(const Refinement* pRefinement) const {
396 
397     bool printFaceVerts      = true;
398     bool printFaceEdges      = true;
399     bool printFaceChildVerts = false;
400     bool printFaceTags       = true;
401 
402     bool printEdgeVerts      = true;
403     bool printEdgeFaces      = true;
404     bool printEdgeChildVerts = true;
405     bool printEdgeSharpness  = true;
406     bool printEdgeTags       = true;
407 
408     bool printVertFaces      = true;
409     bool printVertEdges      = true;
410     bool printVertChildVerts = false;
411     bool printVertSharpness  = true;
412     bool printVertTags       = true;
413 
414     printf("Level (0x%p):\n", this);
415     printf("  Depth = %d\n", _depth);
416 
417     printf("  Primary component counts:\n");
418     printf("    faces = %d\n", _faceCount);
419     printf("    edges = %d\n", _edgeCount);
420     printf("    verts = %d\n", _vertCount);
421 
422     printf("  Topology relation sizes:\n");
423 
424     printf("    Face relations:\n");
425     printf("      face-vert counts/offset = %lu\n", (unsigned long)_faceVertCountsAndOffsets.size());
426     printf("      face-vert indices = %lu\n", (unsigned long)_faceVertIndices.size());
427     if (_faceVertIndices.size()) {
428         for (int i = 0; printFaceVerts && i < getNumFaces(); ++i) {
429             printf("        face %4d verts:  ", i);
430             printIndexArray(getFaceVertices(i));
431         }
432     }
433     printf("      face-edge indices = %lu\n", (unsigned long)_faceEdgeIndices.size());
434     if (_faceEdgeIndices.size()) {
435         for (int i = 0; printFaceEdges && i < getNumFaces(); ++i) {
436             printf("        face %4d edges:  ", i);
437             printIndexArray(getFaceEdges(i));
438         }
439     }
440     printf("      face tags = %lu\n", (unsigned long)_faceTags.size());
441     for (int i = 0; printFaceTags && i < (int)_faceTags.size(); ++i) {
442         FTag const& fTag = _faceTags[i];
443         printf("        face %4d:", i);
444         printf("  hole = %d",  (int)fTag._hole);
445         printf("\n");
446     }
447     if (pRefinement) {
448         printf("      face child-verts = %lu\n", (unsigned long)pRefinement->_faceChildVertIndex.size());
449         for (int i = 0; printFaceChildVerts && i < (int)pRefinement->_faceChildVertIndex.size(); ++i) {
450             printf("        face %4d child vert:  %d\n", i, pRefinement->_faceChildVertIndex[i]);
451         }
452     }
453 
454     printf("    Edge relations:\n");
455     printf("      edge-vert indices = %lu\n", (unsigned long)_edgeVertIndices.size());
456     if (_edgeVertIndices.size()) {
457         for (int i = 0; printEdgeVerts && i < getNumEdges(); ++i) {
458             printf("        edge %4d verts:  ", i);
459             printIndexArray(getEdgeVertices(i));
460         }
461     }
462     printf("      edge-face counts/offset = %lu\n", (unsigned long)_edgeFaceCountsAndOffsets.size());
463     printf("      edge-face indices       = %lu\n", (unsigned long)_edgeFaceIndices.size());
464     printf("      edge-face local-indices = %lu\n", (unsigned long)_edgeFaceLocalIndices.size());
465     if (_edgeFaceIndices.size()) {
466         for (int i = 0; printEdgeFaces && i < getNumEdges(); ++i) {
467             printf("        edge %4d faces:  ", i);
468             printIndexArray(getEdgeFaces(i));
469 
470             printf("             face-edges:  ");
471             printIndexArray(getEdgeFaceLocalIndices(i));
472         }
473     }
474     if (pRefinement) {
475         printf("      edge child-verts = %lu\n", (unsigned long)pRefinement->_edgeChildVertIndex.size());
476         for (int i = 0; printEdgeChildVerts && i < (int)pRefinement->_edgeChildVertIndex.size(); ++i) {
477             printf("        edge %4d child vert:  %d\n", i, pRefinement->_edgeChildVertIndex[i]);
478         }
479     }
480     printf("      edge sharpness = %lu\n", (unsigned long)_edgeSharpness.size());
481     for (int i = 0; printEdgeSharpness && i < (int)_edgeSharpness.size(); ++i) {
482         printf("        edge %4d sharpness:  %f\n", i, _edgeSharpness[i]);
483     }
484     printf("      edge tags = %lu\n", (unsigned long)_edgeTags.size());
485     for (int i = 0; printEdgeTags && i < (int)_edgeTags.size(); ++i) {
486         ETag const& eTag = _edgeTags[i];
487         printf("        edge %4d:", i);
488         printf("  boundary = %d",  (int)eTag._boundary);
489         printf(", nonManifold = %d", (int)eTag._nonManifold);
490         printf(", semiSharp = %d", (int)eTag._semiSharp);
491         printf(", infSharp = %d",  (int)eTag._infSharp);
492         printf("\n");
493     }
494 
495     printf("    Vert relations:\n");
496     printf("      vert-face counts/offset = %lu\n", (unsigned long)_vertFaceCountsAndOffsets.size());
497     printf("      vert-face indices       = %lu\n", (unsigned long)_vertFaceIndices.size());
498     printf("      vert-face local-indices = %lu\n", (unsigned long)_vertFaceLocalIndices.size());
499     if (_vertFaceIndices.size()) {
500         for (int i = 0; printVertFaces && i < getNumVertices(); ++i) {
501             printf("        vert %4d faces:  ", i);
502             printIndexArray(getVertexFaces(i));
503 
504             printf("             face-verts:  ");
505             printIndexArray(getVertexFaceLocalIndices(i));
506         }
507     }
508     printf("      vert-edge counts/offset = %lu\n", (unsigned long)_vertEdgeCountsAndOffsets.size());
509     printf("      vert-edge indices       = %lu\n", (unsigned long)_vertEdgeIndices.size());
510     printf("      vert-edge local-indices = %lu\n", (unsigned long)_vertEdgeLocalIndices.size());
511     if (_vertEdgeIndices.size()) {
512         for (int i = 0; printVertEdges && i < getNumVertices(); ++i) {
513             printf("        vert %4d edges:  ", i);
514             printIndexArray(getVertexEdges(i));
515 
516             printf("             edge-verts:  ");
517             printIndexArray(getVertexEdgeLocalIndices(i));
518         }
519     }
520     if (pRefinement) {
521         printf("      vert child-verts = %lu\n", (unsigned long)pRefinement->_vertChildVertIndex.size());
522         for (int i = 0; printVertChildVerts && i < (int)pRefinement->_vertChildVertIndex.size(); ++i) {
523             printf("        vert %4d child vert:  %d\n", i, pRefinement->_vertChildVertIndex[i]);
524         }
525     }
526     printf("      vert sharpness = %lu\n", (unsigned long)_vertSharpness.size());
527     for (int i = 0; printVertSharpness && i < (int)_vertSharpness.size(); ++i) {
528         printf("        vert %4d sharpness:  %f\n", i, _vertSharpness[i]);
529     }
530     printf("      vert tags = %lu\n", (unsigned long)_vertTags.size());
531     for (int i = 0; printVertTags && i < (int)_vertTags.size(); ++i) {
532         VTag const& vTag = _vertTags[i];
533         printf("        vert %4d:", i);
534         printf("  rule = %s",           ruleString((Sdc::Crease::Rule)vTag._rule));
535         printf(", boundary = %d",       (int)vTag._boundary);
536         printf(", corner = %d",         (int)vTag._corner);
537         printf(", xordinary = %d",      (int)vTag._xordinary);
538         printf(", nonManifold = %d",    (int)vTag._nonManifold);
539         printf(", infSharp = %d",       (int)vTag._infSharp);
540         printf(", infSharpEdges = %d",  (int)vTag._infSharpEdges);
541         printf(", infSharpCrease = %d", (int)vTag._infSharpCrease);
542         printf(", infIrregular = %d",   (int)vTag._infIrregular);
543         printf(", semiSharp = %d",      (int)vTag._semiSharp);
544         printf(", semiSharpEdges = %d", (int)vTag._semiSharpEdges);
545         printf("\n");
546     }
547     fflush(stdout);
548 }
549 
550 //
551 //  Methods for retrieving and combining tags:
552 //
553 bool
doesVertexFVarTopologyMatch(Index vIndex,int fvarChannel) const554 Level::doesVertexFVarTopologyMatch(Index vIndex, int fvarChannel) const {
555 
556     return getFVarLevel(fvarChannel).valueTopologyMatches(
557              getFVarLevel(fvarChannel).getVertexValueOffset(vIndex));
558 }
559 bool
doesEdgeFVarTopologyMatch(Index eIndex,int fvarChannel) const560 Level::doesEdgeFVarTopologyMatch(Index eIndex, int fvarChannel) const {
561 
562     return getFVarLevel(fvarChannel).edgeTopologyMatches(eIndex);
563 }
564 bool
doesFaceFVarTopologyMatch(Index fIndex,int fvarChannel) const565 Level::doesFaceFVarTopologyMatch(Index fIndex, int fvarChannel) const {
566 
567     return ! getFVarLevel(fvarChannel).getFaceCompositeValueTag(fIndex).isMismatch();
568 }
569 
570 void
getFaceVTags(Index fIndex,VTag vTags[],int fvarChannel) const571 Level::getFaceVTags(Index fIndex, VTag vTags[], int fvarChannel) const {
572 
573     ConstIndexArray fVerts = getFaceVertices(fIndex);
574     if (fvarChannel < 0) {
575         for (int i = 0; i < fVerts.size(); ++i) {
576             vTags[i] = getVertexTag(fVerts[i]);
577         }
578     } else {
579         FVarLevel const & fvarLevel = getFVarLevel(fvarChannel);
580         ConstIndexArray fValues = fvarLevel.getFaceValues(fIndex);
581         for (int i = 0; i < fVerts.size(); ++i) {
582             Index valueIndex = fvarLevel.findVertexValueIndex(fVerts[i], fValues[i]);
583             FVarLevel::ValueTag valueTag = fvarLevel.getValueTag(valueIndex);
584 
585             vTags[i] = valueTag.combineWithLevelVTag(getVertexTag(fVerts[i]));
586         }
587     }
588 }
589 void
getFaceETags(Index fIndex,ETag eTags[],int fvarChannel) const590 Level::getFaceETags(Index fIndex, ETag eTags[], int fvarChannel) const {
591 
592     ConstIndexArray fEdges = getFaceEdges(fIndex);
593     if (fvarChannel < 0) {
594         for (int i = 0; i < fEdges.size(); ++i) {
595             eTags[i] = getEdgeTag(fEdges[i]);
596         }
597     } else {
598         FVarLevel const & fvarLevel = getFVarLevel(fvarChannel);
599         for (int i = 0; i < fEdges.size(); ++i) {
600             FVarLevel::ETag fvarETag = fvarLevel.getEdgeTag(fEdges[i]);
601 
602             eTags[i] = fvarETag.combineWithLevelETag(getEdgeTag(fEdges[i]));
603         }
604     }
605 }
606 
607 Level::VTag
BitwiseOr(VTag const vTags[],int size)608 Level::VTag::BitwiseOr(VTag const vTags[], int size) {
609 
610     VTag::VTagSize tagBits = vTags[0].getBits();
611     for (int i = 1; i < size; ++i) {
612         tagBits |= vTags[i].getBits();
613     }
614     return VTag(tagBits);
615 }
616 Level::ETag
BitwiseOr(ETag const eTags[],int size)617 Level::ETag::BitwiseOr(ETag const eTags[], int size) {
618 
619     ETag::ETagSize tagBits = eTags[0].getBits();
620     for (int i = 1; i < size; ++i) {
621         tagBits |= eTags[i].getBits();
622     }
623     return ETag(tagBits);
624 }
625 
626 Level::VTag
getFaceCompositeVTag(ConstIndexArray & fVerts) const627 Level::getFaceCompositeVTag(ConstIndexArray & fVerts) const {
628 
629     VTag::VTagSize tagBits = _vertTags[fVerts[0]].getBits();
630     for (int i = 1; i < fVerts.size(); ++i) {
631         tagBits |= _vertTags[fVerts[i]].getBits();
632     }
633     return VTag(tagBits);
634 }
635 Level::VTag
getFaceCompositeVTag(Index fIndex,int fvarChannel) const636 Level::getFaceCompositeVTag(Index fIndex, int fvarChannel) const {
637 
638     ConstIndexArray fVerts = getFaceVertices(fIndex);
639     if (fvarChannel < 0) {
640         return getFaceCompositeVTag(fVerts);
641     } else {
642         FVarLevel const & fvarLevel = getFVarLevel(fvarChannel);
643         internal::StackBuffer<FVarLevel::ValueTag,64> fvarTags(fVerts.size());
644         fvarLevel.getFaceValueTags(fIndex, fvarTags);
645 
646         VTag::VTagSize tagBits = fvarTags[0].combineWithLevelVTag(_vertTags[fVerts[0]]).getBits();
647         for (int i = 1; i < fVerts.size(); ++i) {
648             tagBits |= fvarTags[i].combineWithLevelVTag(_vertTags[fVerts[i]]).getBits();
649         }
650         return VTag(tagBits);
651     }
652 }
653 
654 Level::VTag
getVertexCompositeFVarVTag(Index vIndex,int fvarChannel) const655 Level::getVertexCompositeFVarVTag(Index vIndex, int fvarChannel) const {
656 
657     FVarLevel const & fvarLevel = getFVarLevel(fvarChannel);
658 
659     FVarLevel::ConstValueTagArray fvTags = fvarLevel.getVertexValueTags(vIndex);
660 
661     VTag vTag = getVertexTag(vIndex);
662     if (fvTags[0].isMismatch()) {
663         VTag::VTagSize tagBits = fvTags[0].combineWithLevelVTag(vTag).getBits();
664         for (int i = 1; i < fvTags.size(); ++i) {
665             tagBits |= fvTags[i].combineWithLevelVTag(vTag).getBits();
666         }
667         return VTag(tagBits);
668     } else {
669         return vTag;
670     }
671 }
672 
673 //
674 //  High-level topology gathering functions -- used mainly in patch construction.  These
675 //  may eventually be moved elsewhere, possibly to classes specialized for quad- and tri-
676 //  patch identification and construction, but for now somewhere more accessible than the
677 //  patch tables factory is preferable.
678 //
679 //  Note a couple of nuisances...
680 //      - debatable whether we should include the face's face-verts in the face functions
681 //          - we refer to the result as a "patch" when we do
682 //          - otherwise a "ring" of vertices is more appropriate
683 //
684 namespace {
685     template <typename INT_TYPE>
fastMod4(INT_TYPE value)686     inline INT_TYPE fastMod4(INT_TYPE value) {
687 
688         return (value & 0x3);
689     }
690 
691     template <class ARRAY_OF_TYPE, class TYPE>
otherOfTwo(ARRAY_OF_TYPE const & arrayOfTwo,TYPE const & value)692     inline TYPE otherOfTwo(ARRAY_OF_TYPE const& arrayOfTwo, TYPE const& value) {
693 
694         return arrayOfTwo[value == arrayOfTwo[0]];
695     }
696 }
697 
698 //
699 //  Gathering the one-ring of vertices from quads surrounding a vertex:
700 //      - the neighborhood of the vertex is assumed to be quad-regular (manifold)
701 //
702 //  Ordering of resulting vertices:
703 //      The surrounding one-ring follows the ordering of the incident faces.  For each
704 //  incident quad, the two vertices in CCW order within that quad are added.  If the
705 //  vertex is on a boundary, a third vertex on the boundary edge will be contributed from
706 //  the last face.
707 //
708 int
gatherQuadRegularRingAroundVertex(Index vIndex,int ringPoints[],int fvarChannel) const709 Level::gatherQuadRegularRingAroundVertex(
710     Index vIndex, int ringPoints[], int fvarChannel) const {
711 
712     Level const& level = *this;
713 
714     ConstIndexArray vEdges = level.getVertexEdges(vIndex);
715 
716     ConstIndexArray vFaces = level.getVertexFaces(vIndex);
717     ConstLocalIndexArray vInFaces = level.getVertexFaceLocalIndices(vIndex);
718 
719     bool isBoundary = (vEdges.size() > vFaces.size());
720 
721     int ringIndex = 0;
722     for (int i = 0; i < vFaces.size(); ++i) {
723         //
724         //  For every incident quad, we want the two vertices clockwise in each face, i.e.
725         //  the vertex at the end of the leading edge and the vertex opposite this one:
726         //
727         ConstIndexArray fPoints = (fvarChannel < 0)
728                                 ? level.getFaceVertices(vFaces[i])
729                                 : level.getFaceFVarValues(vFaces[i], fvarChannel);
730 
731         int vInThisFace = vInFaces[i];
732 
733         ringPoints[ringIndex++] = fPoints[fastMod4(vInThisFace + 1)];
734         ringPoints[ringIndex++] = fPoints[fastMod4(vInThisFace + 2)];
735 
736         if (isBoundary && (i == (vFaces.size() - 1))) {
737             ringPoints[ringIndex++] = fPoints[fastMod4(vInThisFace + 3)];
738         }
739     }
740     return ringIndex;
741 }
742 
743 int
gatherQuadRegularPartialRingAroundVertex(Index vIndex,VSpan const & span,int ringPoints[],int fvarChannel) const744 Level::gatherQuadRegularPartialRingAroundVertex(
745     Index vIndex, VSpan const & span, int ringPoints[], int fvarChannel) const {
746 
747     Level const& level = *this;
748 
749     assert(! level.isVertexNonManifold(vIndex));
750 
751     ConstIndexArray      vFaces   = level.getVertexFaces(vIndex);
752     ConstLocalIndexArray vInFaces = level.getVertexFaceLocalIndices(vIndex);
753 
754     int nFaces    = span._numFaces;
755     int startFace = span._startFace;
756 
757     int ringIndex = 0;
758     for (int i = 0; i < nFaces; ++i) {
759         //
760         //  For every incident quad, we want the two vertices clockwise in each face, i.e.
761         //  the vertex at the end of the leading edge and the vertex opposite this one:
762         //
763         int fIncident = (startFace + i) % vFaces.size();
764 
765         ConstIndexArray fPoints = (fvarChannel < 0)
766                                 ? level.getFaceVertices(vFaces[fIncident])
767                                 : level.getFaceFVarValues(vFaces[fIncident], fvarChannel);
768 
769         int vInThisFace = vInFaces[fIncident];
770 
771         ringPoints[ringIndex++] = fPoints[fastMod4(vInThisFace + 1)];
772         ringPoints[ringIndex++] = fPoints[fastMod4(vInThisFace + 2)];
773 
774         if ((i == nFaces - 1) && !span._periodic) {
775             ringPoints[ringIndex++] = fPoints[fastMod4(vInThisFace + 3)];
776         }
777     }
778     return ringIndex;
779 }
780 
781 //
782 //  Gathering the 4 vertices of a quad:
783 //
784 //        |     |
785 //      --0-----3--
786 //        |x   x|
787 //        |x   x|
788 //      --1-----2--
789 //        |     |
790 //
791 int
gatherQuadLinearPatchPoints(Index thisFace,Index patchPoints[],int rotation,int fvarChannel) const792 Level::gatherQuadLinearPatchPoints(
793     Index thisFace, Index patchPoints[], int rotation, int fvarChannel) const {
794 
795     Level const& level = *this;
796 
797     assert((0 <= rotation) && (rotation < 4));
798     static int const   rotationSequence[7] = { 0, 1, 2, 3, 0, 1, 2 };
799     int const * rotatedVerts = &rotationSequence[rotation];
800 
801     ConstIndexArray facePoints = (fvarChannel < 0) ?
802                                  level.getFaceVertices(thisFace) :
803                                  level.getFaceFVarValues(thisFace, fvarChannel);
804 
805     patchPoints[0] = facePoints[rotatedVerts[0]];
806     patchPoints[1] = facePoints[rotatedVerts[1]];
807     patchPoints[2] = facePoints[rotatedVerts[2]];
808     patchPoints[3] = facePoints[rotatedVerts[3]];
809 
810     return 4;
811 }
812 
813 //
814 //  Gathering the 16 vertices of a quad-regular interior patch:
815 //      - the neighborhood of the face is assumed to be quad-regular
816 //
817 //  Ordering of resulting vertices:
818 //      It was debatable whether to include the vertices of the original face for a complete
819 //  "patch" or just the surrounding ring -- clearly we ended up with a function for the entire
820 //  patch, but that may change.
821 //      The latter ring of vertices around the face (potentially returned on its own) was
822 //  oriented with respect to the face.  The ring of 12 vertices is gathered as 4 groups of 3
823 //  vertices -- one for each corner vertex, and each group forming the quad opposite each
824 //  corner vertex when combined with that corner vertex.  The four vertices of the face begin
825 //  the patch.
826 //
827 //         |     |     |     |
828 //      ---5-----4-----15----14---
829 //         |     |     |     |
830 //         |     |     |     |
831 //      ---6-----0-----3-----13---
832 //         |     |x   x|     |
833 //         |     |x   x|     |
834 //      ---7-----1-----2-----12---
835 //         |     |     |     |
836 //         |     |     |     |
837 //      ---8-----9-----10----11---
838 //         |     |     |     |
839 //
840 int
gatherQuadRegularInteriorPatchPoints(Index thisFace,Index patchPoints[],int rotation,int fvarChannel) const841 Level::gatherQuadRegularInteriorPatchPoints(
842     Index thisFace, Index patchPoints[], int rotation, int fvarChannel) const {
843 
844     Level const& level = *this;
845 
846     assert((0 <= rotation) && (rotation < 4));
847     static int const   rotationSequence[7] = { 0, 1, 2, 3, 0, 1, 2 };
848     int const * rotatedVerts = &rotationSequence[rotation];
849 
850     ConstIndexArray thisFaceVerts = level.getFaceVertices(thisFace);
851 
852     ConstIndexArray facePoints = (fvarChannel < 0) ? thisFaceVerts :
853                                  level.getFaceFVarValues(thisFace, fvarChannel);
854 
855     patchPoints[0] = facePoints[rotatedVerts[0]];
856     patchPoints[1] = facePoints[rotatedVerts[1]];
857     patchPoints[2] = facePoints[rotatedVerts[2]];
858     patchPoints[3] = facePoints[rotatedVerts[3]];
859 
860     //
861     //  For each of the four corner vertices, there is a face diagonally opposite
862     //  the given/central face.  Each of these faces contains three points of the
863     //  entire ring of points around that given/central face.
864     //
865     int pointIndex = 4;
866     for (int i = 0; i < 4; ++i) {
867         Index v = thisFaceVerts[rotatedVerts[i]];
868 
869         ConstIndexArray      vFaces   = level.getVertexFaces(v);
870         ConstLocalIndexArray vInFaces = level.getVertexFaceLocalIndices(v);
871 
872         int thisFaceInVFaces = vFaces.FindIndexIn4Tuple(thisFace);
873         int intFaceInVFaces  = fastMod4(thisFaceInVFaces + 2);
874 
875         Index intFace    = vFaces[intFaceInVFaces];
876         int   vInIntFace = vInFaces[intFaceInVFaces];
877 
878         facePoints = (fvarChannel < 0) ? level.getFaceVertices(intFace) :
879                      level.getFaceFVarValues(intFace, fvarChannel);
880 
881         patchPoints[pointIndex++] = facePoints[fastMod4(vInIntFace + 1)];
882         patchPoints[pointIndex++] = facePoints[fastMod4(vInIntFace + 2)];
883         patchPoints[pointIndex++] = facePoints[fastMod4(vInIntFace + 3)];
884     }
885     assert(pointIndex == 16);
886     return 16;
887 }
888 
889 //
890 //  Gathering the 12 vertices of a quad-regular boundary patch:
891 //      - the neighborhood of the face is assumed to be quad-regular
892 //      - the single edge of the face that lies on the boundary is specified
893 //      - only one edge of the face is a boundary edge
894 //
895 //  Ordering of resulting vertices:
896 //      It was debatable whether to include the vertices of the original face for a complete
897 //  "patch" or just the surrounding ring -- clearly we ended up with a function for the entire
898 //  patch, but that may change.
899 //      The latter ring of vertices around the face (potentially returned on its own) was
900 //  oriented beginning from the leading CCW boundary edge and ending at the trailing edge.
901 //  The four vertices of the face begin the patch and are oriented similarly to this outer
902 //  ring -- forming an inner ring that begins and ends in the same manner.
903 //
904 //      ---4-----0-----3-----11---
905 //         |     |x   x|     |
906 //         |     |x   x|     |
907 //      ---5-----1-----2-----10---
908 //         |     |v0 v1|     |
909 //         |     |     |     |
910 //      ---6-----7-----8-----9----
911 //         |     |     |     |
912 //
913 int
gatherQuadRegularBoundaryPatchPoints(Index face,Index patchPoints[],int boundaryEdgeInFace,int fvarChannel) const914 Level::gatherQuadRegularBoundaryPatchPoints(
915     Index face, Index patchPoints[], int boundaryEdgeInFace, int fvarChannel) const {
916 
917     Level const& level = *this;
918 
919     int interiorEdgeInFace = fastMod4(boundaryEdgeInFace + 2);
920 
921     //
922     //  V0 and V1 are the two interior vertices (opposite the boundary edge) around
923     //  which we will gather most of the ring:
924     //
925     int intV0InFace = interiorEdgeInFace;
926     int intV1InFace = fastMod4(interiorEdgeInFace + 1);
927 
928     ConstIndexArray faceVerts = level.getFaceVertices(face);
929 
930     Index v0 = faceVerts[intV0InFace];
931     Index v1 = faceVerts[intV1InFace];
932 
933     ConstIndexArray v0Faces = level.getVertexFaces(v0);
934     ConstIndexArray v1Faces = level.getVertexFaces(v1);
935 
936     ConstLocalIndexArray v0InFaces = level.getVertexFaceLocalIndices(v0);
937     ConstLocalIndexArray v1InFaces = level.getVertexFaceLocalIndices(v1);
938 
939     int boundaryFaceInV0Faces = -1;
940     int boundaryFaceInV1Faces = -1;
941     for (int i = 0; i < 4; ++i) {
942         if (face == v0Faces[i]) boundaryFaceInV0Faces = i;
943         if (face == v1Faces[i]) boundaryFaceInV1Faces = i;
944     }
945     assert((boundaryFaceInV0Faces >= 0) && (boundaryFaceInV1Faces >= 0));
946 
947     //  Identify the four faces of interest -- previous to and opposite V0 and
948     //  opposite and next from V1 -- relative to V0 and V1:
949     int prevFaceInV0Faces = fastMod4(boundaryFaceInV0Faces + 1);
950     int intFaceInV0Faces  = fastMod4(boundaryFaceInV0Faces + 2);
951     int intFaceInV1Faces  = fastMod4(boundaryFaceInV1Faces + 2);
952     int nextFaceInV1Faces = fastMod4(boundaryFaceInV1Faces + 3);
953 
954     //  Identify the indices of the four faces:
955     Index prevFace  = v0Faces[prevFaceInV0Faces];
956     Index intV0Face = v0Faces[intFaceInV0Faces];
957     Index intV1Face = v1Faces[intFaceInV1Faces];
958     Index nextFace  = v1Faces[nextFaceInV1Faces];
959 
960     //  Identify V0 and V1 relative to these four faces:
961     LocalIndex v0InPrevFace = v0InFaces[prevFaceInV0Faces];
962     LocalIndex v0InIntFace  = v0InFaces[intFaceInV0Faces];
963     LocalIndex v1InIntFace  = v1InFaces[intFaceInV1Faces];
964     LocalIndex v1InNextFace = v1InFaces[nextFaceInV1Faces];
965 
966     //
967     //  Now that all faces of interest have been found, identify the point
968     //  indices within each face (i.e. the vertex or fvar-value index arrays)
969     //  and copy them into the patch points:
970     //
971     ConstIndexArray thisFacePoints,
972                     prevFacePoints,
973                     intV0FacePoints,
974                     intV1FacePoints,
975                     nextFacePoints;
976 
977     if (fvarChannel < 0) {
978         thisFacePoints  = faceVerts;
979         prevFacePoints  = level.getFaceVertices(prevFace);
980         intV0FacePoints = level.getFaceVertices(intV0Face);
981         intV1FacePoints = level.getFaceVertices(intV1Face);
982         nextFacePoints  = level.getFaceVertices(nextFace);
983     } else {
984         thisFacePoints  = level.getFaceFVarValues(face, fvarChannel);
985         prevFacePoints  = level.getFaceFVarValues(prevFace, fvarChannel);
986         intV0FacePoints = level.getFaceFVarValues(intV0Face, fvarChannel);
987         intV1FacePoints = level.getFaceFVarValues(intV1Face, fvarChannel);
988         nextFacePoints  = level.getFaceFVarValues(nextFace, fvarChannel);
989     }
990 
991     patchPoints[0] = thisFacePoints[fastMod4(boundaryEdgeInFace + 1)];
992     patchPoints[1] = thisFacePoints[fastMod4(boundaryEdgeInFace + 2)];
993     patchPoints[2] = thisFacePoints[fastMod4(boundaryEdgeInFace + 3)];
994     patchPoints[3] = thisFacePoints[         boundaryEdgeInFace];
995 
996     patchPoints[4] = prevFacePoints[fastMod4(v0InPrevFace + 2)];
997 
998     patchPoints[5] = intV0FacePoints[fastMod4(v0InIntFace + 1)];
999     patchPoints[6] = intV0FacePoints[fastMod4(v0InIntFace + 2)];
1000     patchPoints[7] = intV0FacePoints[fastMod4(v0InIntFace + 3)];
1001 
1002     patchPoints[8]  = intV1FacePoints[fastMod4(v1InIntFace + 1)];
1003     patchPoints[9]  = intV1FacePoints[fastMod4(v1InIntFace + 2)];
1004     patchPoints[10] = intV1FacePoints[fastMod4(v1InIntFace + 3)];
1005 
1006     patchPoints[11] = nextFacePoints[fastMod4(v1InNextFace + 2)];
1007 
1008     return 12;
1009 }
1010 
1011 //
1012 //  Gathering the 9 vertices of a quad-regular corner patch:
1013 //      - the neighborhood of the face is assumed to be quad-regular
1014 //      - the single corner vertex is specified
1015 //      - only one vertex of the face is a corner
1016 //
1017 //  Ordering of resulting vertices:
1018 //      It was debatable whether to include the vertices of the original face for a complete
1019 //  "patch" or just the surrounding ring -- clearly we ended up with a function for the entire
1020 //  patch, but that may change.
1021 //      Like the boundary case, the latter ring of vertices around the face was oriented
1022 //  beginning from the leading CCW boundary edge and ending at the trailing edge.  The four
1023 //  face vertices begin the patch, and begin with the corner vertex.
1024 //
1025 //      0-----3-----8---
1026 //      |x   x|     |
1027 //      |x   x|     |
1028 //      1-----2-----7---
1029 //      |     |     |
1030 //      |     |     |
1031 //      4-----5-----6---
1032 //      |     |     |
1033 //
1034 int
gatherQuadRegularCornerPatchPoints(Index face,Index patchPoints[],int cornerVertInFace,int fvarChannel) const1035 Level::gatherQuadRegularCornerPatchPoints(
1036     Index face, Index patchPoints[], int cornerVertInFace, int fvarChannel) const {
1037 
1038     Level const& level = *this;
1039 
1040     int interiorFaceVert = fastMod4(cornerVertInFace + 2);
1041 
1042     ConstIndexArray faceVerts = level.getFaceVertices(face);
1043     Index intVert = faceVerts[interiorFaceVert];
1044 
1045     ConstIndexArray      intVertFaces   = level.getVertexFaces(intVert);
1046     ConstLocalIndexArray intVertInFaces = level.getVertexFaceLocalIndices(intVert);
1047 
1048     int cornerFaceInIntVertFaces = -1;
1049     for (int i = 0; i < intVertFaces.size(); ++i) {
1050         if (face == intVertFaces[i]) {
1051             cornerFaceInIntVertFaces = i;
1052             break;
1053         }
1054     }
1055     assert(cornerFaceInIntVertFaces >= 0);
1056 
1057     //  Identify the three faces relative to the interior vertex:
1058     int prevFaceInIntVertFaces = fastMod4(cornerFaceInIntVertFaces + 1);
1059     int intFaceInIntVertFaces  = fastMod4(cornerFaceInIntVertFaces + 2);
1060     int nextFaceInIntVertFaces = fastMod4(cornerFaceInIntVertFaces + 3);
1061 
1062     //  Identify the indices of the three other faces:
1063     Index prevFace = intVertFaces[prevFaceInIntVertFaces];
1064     Index intFace  = intVertFaces[intFaceInIntVertFaces];
1065     Index nextFace = intVertFaces[nextFaceInIntVertFaces];
1066 
1067     //  Identify the interior vertex relative to these three faces:
1068     LocalIndex intVertInPrevFace = intVertInFaces[prevFaceInIntVertFaces];
1069     LocalIndex intVertInIntFace  = intVertInFaces[intFaceInIntVertFaces];
1070     LocalIndex intVertInNextFace = intVertInFaces[nextFaceInIntVertFaces];
1071 
1072     //
1073     //  Now that all faces of interest have been found, identify the point
1074     //  indices within each face (i.e. the vertex or fvar-value index arrays)
1075     //  and copy them into the patch points:
1076     //
1077     ConstIndexArray thisFacePoints,
1078                     prevFacePoints,
1079                     intFacePoints,
1080                     nextFacePoints;
1081 
1082     if (fvarChannel < 0) {
1083         thisFacePoints = faceVerts;
1084         prevFacePoints = level.getFaceVertices(prevFace);
1085         intFacePoints  = level.getFaceVertices(intFace);
1086         nextFacePoints = level.getFaceVertices(nextFace);
1087     } else {
1088         thisFacePoints = level.getFaceFVarValues(face, fvarChannel);
1089         prevFacePoints = level.getFaceFVarValues(prevFace, fvarChannel);
1090         intFacePoints  = level.getFaceFVarValues(intFace, fvarChannel);
1091         nextFacePoints = level.getFaceFVarValues(nextFace, fvarChannel);
1092     }
1093 
1094     patchPoints[0] = thisFacePoints[         cornerVertInFace];
1095     patchPoints[1] = thisFacePoints[fastMod4(cornerVertInFace + 1)];
1096     patchPoints[2] = thisFacePoints[fastMod4(cornerVertInFace + 2)];
1097     patchPoints[3] = thisFacePoints[fastMod4(cornerVertInFace + 3)];
1098 
1099     patchPoints[4] = prevFacePoints[fastMod4(intVertInPrevFace + 2)];
1100 
1101     patchPoints[5] = intFacePoints[fastMod4(intVertInIntFace + 1)];
1102     patchPoints[6] = intFacePoints[fastMod4(intVertInIntFace + 2)];
1103     patchPoints[7] = intFacePoints[fastMod4(intVertInIntFace + 3)];
1104 
1105     patchPoints[8] = nextFacePoints[fastMod4(intVertInNextFace + 2)];
1106 
1107     return 9;
1108 }
1109 
1110 //
1111 //  Gathering the 12 vertices of a tri-regular interior patch:
1112 //      - the neighborhood of the face is assumed to be tri-regular
1113 //
1114 //  Ordering of resulting vertices:
1115 //      The three vertices of the triangle begin the sequence, followed by counter-clockwise
1116 //  traversal of the outer ring of vertices -- beginning with the vertex incident V0 such
1117 //  that the ring is symmetric about the triangle.
1118 /*
1119 //                   3           11
1120 //                   X - - - - - X
1121 //                 /   \       /   \
1122 //               /       \ 0 /       \
1123 //          4  X - - - - - X - - - - - X 10
1124 //           /   \       / * \       /   \
1125 //         /       \   / * * * \   /       \
1126 //    5  X - - - - - X - - - - - X - - - - - X  9
1127 //         \       / 1 \       / 2 \       /
1128 //           \   /       \   /       \   /
1129 //             X - - - - - X - - - - - X
1130 //             6           7           8
1131 */
1132 int
gatherTriRegularInteriorPatchPoints(Index fIndex,Index points[12],int rotation) const1133 Level::gatherTriRegularInteriorPatchPoints(Index fIndex, Index points[12], int rotation) const
1134 {
1135     ConstIndexArray  fVerts = getFaceVertices(fIndex);
1136     ConstIndexArray  fEdges = getFaceEdges(fIndex);
1137 
1138     int index0 = 0;
1139     int index1 = 1;
1140     int index2 = 2;
1141     if (rotation) {
1142         index0 = rotation % 3;
1143         index1 = (rotation + 1) % 3;
1144         index2 = (rotation + 2) % 3;
1145     }
1146 
1147     Index v0 = fVerts[index0];
1148     Index v1 = fVerts[index1];
1149     Index v2 = fVerts[index2];
1150 
1151     ConstIndexArray  v0Edges = getVertexEdges(v0);
1152     ConstIndexArray  v1Edges = getVertexEdges(v1);
1153     ConstIndexArray  v2Edges = getVertexEdges(v2);
1154 
1155     int e0InV0Edges = v0Edges.FindIndex(fEdges[index0]);
1156     int e1InV1Edges = v1Edges.FindIndex(fEdges[index1]);
1157     int e2InV2Edges = v2Edges.FindIndex(fEdges[index2]);
1158 
1159     points[ 0] = v0;
1160     points[ 1] = v1;
1161     points[ 2] = v2;
1162 
1163     points[11] = otherOfTwo(getEdgeVertices(v0Edges[(e0InV0Edges + 3) % 6]), v0);
1164     points[ 3] = otherOfTwo(getEdgeVertices(v0Edges[(e0InV0Edges + 4) % 6]), v0);
1165     points[ 4] = otherOfTwo(getEdgeVertices(v0Edges[(e0InV0Edges + 5) % 6]), v0);
1166 
1167     points[ 5] = otherOfTwo(getEdgeVertices(v1Edges[(e1InV1Edges + 3) % 6]), v1);
1168     points[ 6] = otherOfTwo(getEdgeVertices(v1Edges[(e1InV1Edges + 4) % 6]), v1);
1169     points[ 7] = otherOfTwo(getEdgeVertices(v1Edges[(e1InV1Edges + 5) % 6]), v1);
1170 
1171     points[ 8] = otherOfTwo(getEdgeVertices(v2Edges[(e2InV2Edges + 3) % 6]), v2);
1172     points[ 9] = otherOfTwo(getEdgeVertices(v2Edges[(e2InV2Edges + 4) % 6]), v2);
1173     points[10] = otherOfTwo(getEdgeVertices(v2Edges[(e2InV2Edges + 5) % 6]), v2);
1174 
1175     return 12;
1176 }
1177 
1178 //
1179 //  Gathering the 9 vertices of a tri-regular "boundary edge" patch:
1180 //      - the neighborhood of the face is assumed to be tri-regular
1181 //      - referred to as "boundary edge" as the boundary occurs on the edge of the triangle
1182 //
1183 //  Boundary edge:
1184 //
1185 /*                   6           5
1186 //                   X - - - - - X
1187 //                 /   \       /   \
1188 //               /       \ 2 /       \
1189 //          7  X - - - - - X - - - - - X  4
1190 //           /   \       / * \       /   \
1191 //         /       \   / * * * \   /       \
1192 //    8  X - - - - - X - - - - - X - - - - - X  3
1193 //                   0           1
1194 */
1195 int
gatherTriRegularBoundaryEdgePatchPoints(Index fIndex,Index points[],int boundaryFaceEdge) const1196 Level::gatherTriRegularBoundaryEdgePatchPoints(Index fIndex, Index points[], int boundaryFaceEdge) const
1197 {
1198     ConstIndexArray  fVerts = getFaceVertices(fIndex);
1199 
1200     Index v0 = fVerts[boundaryFaceEdge];
1201     Index v1 = fVerts[(boundaryFaceEdge + 1) % 3];
1202     Index v2 = fVerts[(boundaryFaceEdge + 2) % 3];
1203 
1204     ConstIndexArray  v0Edges = getVertexEdges(v0);
1205     ConstIndexArray  v1Edges = getVertexEdges(v1);
1206     ConstIndexArray  v2Edges = getVertexEdges(v2);
1207 
1208     int e1InV2Edges = v2Edges.FindIndex(v1Edges[2]);
1209 
1210     points[0] = v0;
1211     points[1] = v1;
1212     points[2] = v2;
1213 
1214     points[3] = otherOfTwo(getEdgeVertices(v1Edges[0]), v1);
1215 
1216     points[4] = otherOfTwo(getEdgeVertices(v2Edges[(e1InV2Edges + 1) % 6]), v2);
1217     points[5] = otherOfTwo(getEdgeVertices(v2Edges[(e1InV2Edges + 2) % 6]), v2);
1218     points[6] = otherOfTwo(getEdgeVertices(v2Edges[(e1InV2Edges + 3) % 6]), v2);
1219     points[7] = otherOfTwo(getEdgeVertices(v2Edges[(e1InV2Edges + 4) % 6]), v2);
1220 
1221     points[8] = otherOfTwo(getEdgeVertices(v0Edges[3]), v0);
1222 
1223     return 9;
1224 }
1225 
1226 //
1227 //  Gathering the 10 vertices of a tri-regular "boundary vertex" patch:
1228 //      - the neighborhood of the face is assumed to be tri-regular
1229 //      - referred to as "boundary vertex" as the boundary occurs on the vertex of the triangle
1230 //
1231 //  Boundary vertex:
1232 /*
1233 //                         0
1234 //          3  X - - - - - X - - - - - X  9
1235 //           /   \       / * \       /   \
1236 //         /       \   / * * * \   /       \
1237 //    4  X - - - - - X - - - - - X - - - - - X  8
1238 //         \       / 1 \       / 2 \       /
1239 //           \   /       \   /       \   /
1240 //             X - - - - - X - - - - - X
1241 //             5           6           7
1242 */
1243 int
gatherTriRegularBoundaryVertexPatchPoints(Index fIndex,Index points[],int boundaryFaceVert) const1244 Level::gatherTriRegularBoundaryVertexPatchPoints(Index fIndex, Index points[], int boundaryFaceVert) const
1245 {
1246     ConstIndexArray  fVerts = getFaceVertices(fIndex);
1247     ConstIndexArray  fEdges = getFaceEdges(fIndex);
1248 
1249     Index v0 = fVerts[boundaryFaceVert];
1250     Index v1 = fVerts[(boundaryFaceVert + 1) % 3];
1251     Index v2 = fVerts[(boundaryFaceVert + 2) % 3];
1252 
1253     Index e1 = fEdges[boundaryFaceVert];
1254     Index e2 = fEdges[(boundaryFaceVert + 2) % 3];
1255 
1256     ConstIndexArray  v1Edges = getVertexEdges(v1);
1257     ConstIndexArray  v2Edges = getVertexEdges(v2);
1258 
1259     int e1InV1Edges = v1Edges.FindIndex(e1);
1260     int e2InV2Edges = v2Edges.FindIndex(e2);
1261 
1262     points[0] = v0;
1263     points[1] = v1;
1264     points[2] = v2;
1265 
1266     points[3] = otherOfTwo(getEdgeVertices(v1Edges[(e1InV1Edges + 1) % 6]), v1);
1267     points[4] = otherOfTwo(getEdgeVertices(v1Edges[(e1InV1Edges + 2) % 6]), v1);
1268     points[5] = otherOfTwo(getEdgeVertices(v1Edges[(e1InV1Edges + 3) % 6]), v1);
1269     points[6] = otherOfTwo(getEdgeVertices(v1Edges[(e1InV1Edges + 4) % 6]), v1);
1270 
1271     points[7] = otherOfTwo(getEdgeVertices(v2Edges[(e2InV2Edges + 3) % 6]), v2);
1272     points[8] = otherOfTwo(getEdgeVertices(v2Edges[(e2InV2Edges + 4) % 6]), v2);
1273     points[9] = otherOfTwo(getEdgeVertices(v2Edges[(e2InV2Edges + 5) % 6]), v2);
1274 
1275     return 10;
1276 }
1277 
1278 //
1279 //  Gathering the 6 vertices of a tri-regular "corner vertex" patch:
1280 //      - the neighborhood of the face is assumed to be tri-regular
1281 //      - referred to as "corner vertex" to disambiguate it from another corner case
1282 //          - another boundary case shares the edge with the corner triangle
1283 //
1284 //  Corner vertex:
1285 /*
1286 //                         0
1287 //                         X
1288 //                       / * \
1289 //                     / * * * \
1290 //                   X - - - - - X
1291 //                 / 1 \       / 2 \
1292 //               /       \   /       \
1293 //             X - - - - - X - - - - - X
1294 //             3           4           5
1295 */
1296 int
gatherTriRegularCornerVertexPatchPoints(Index fIndex,Index points[],int cornerFaceVert) const1297 Level::gatherTriRegularCornerVertexPatchPoints(Index fIndex, Index points[], int cornerFaceVert) const
1298 {
1299     ConstIndexArray  fVerts = getFaceVertices(fIndex);
1300 
1301     Index v0 = fVerts[cornerFaceVert];
1302     Index v1 = fVerts[(cornerFaceVert + 1) % 3];
1303     Index v2 = fVerts[(cornerFaceVert + 2) % 3];
1304 
1305     ConstIndexArray  v1Edges = getVertexEdges(v1);
1306     ConstIndexArray  v2Edges = getVertexEdges(v2);
1307 
1308     points[0] = v0;
1309     points[1] = v1;
1310     points[2] = v2;
1311 
1312     points[3] = otherOfTwo(getEdgeVertices(v1Edges[0]), v1);
1313     points[4] = otherOfTwo(getEdgeVertices(v1Edges[1]), v1);
1314     points[5] = otherOfTwo(getEdgeVertices(v2Edges[3]), v2);
1315 
1316     return 6;
1317 }
1318 
1319 //
1320 //  Gathering the 8 vertices of a tri-regular "corner edge" patch:
1321 //      - the neighborhood of the face is assumed to be tri-regular
1322 //      - referred to as "corner edge" to disambiguate it from the vertex corner case
1323 //          - this faces shares the edge with a corner triangle
1324 //
1325 //  Corner edge:
1326 /*
1327 //                   6           5
1328 //                   X - - - - - X
1329 //                 /   \       /   \
1330 //               /       \ 2 /       \
1331 //          7  X - - - - - X - - - - - X  4
1332 //               \       / * \       /
1333 //                 \   / * * * \   /
1334 //                   X - - - - - X
1335 //                   0 \       / 1
1336 //                       \   /
1337 //                         X
1338 //                         3
1339 */
1340 int
gatherTriRegularCornerEdgePatchPoints(Index fIndex,Index points[],int cornerFaceEdge) const1341 Level::gatherTriRegularCornerEdgePatchPoints(Index fIndex, Index points[], int cornerFaceEdge) const
1342 {
1343     ConstIndexArray  fVerts = getFaceVertices(fIndex);
1344 
1345     Index v0 = fVerts[cornerFaceEdge];
1346     Index v1 = fVerts[(cornerFaceEdge + 1) % 3];
1347     Index v2 = fVerts[(cornerFaceEdge + 2) % 3];
1348 
1349     ConstIndexArray  v0Edges = getVertexEdges(v0);
1350     ConstIndexArray  v1Edges = getVertexEdges(v1);
1351 
1352     points[0] = v0;
1353     points[1] = v1;
1354     points[2] = v2;
1355 
1356     points[3] = otherOfTwo(getEdgeVertices(v1Edges[3]), v1);
1357     points[4] = otherOfTwo(getEdgeVertices(v1Edges[0]), v1);
1358     points[7] = otherOfTwo(getEdgeVertices(v0Edges[3]), v0);
1359 
1360     ConstIndexArray  v4Edges = getVertexEdges(points[4]);
1361     ConstIndexArray  v7Edges = getVertexEdges(points[7]);
1362 
1363     points[5] = otherOfTwo(getEdgeVertices(v4Edges[v4Edges.size() - 3]), v1);
1364     points[6] = otherOfTwo(getEdgeVertices(v7Edges[2]), v1);
1365 
1366     return 8;
1367 }
1368 
1369 bool
isSingleCreasePatch(Index face,float * sharpnessOut,int * sharpEdgeInFaceOut) const1370 Level::isSingleCreasePatch(Index face, float *sharpnessOut, int *sharpEdgeInFaceOut) const {
1371 
1372     //  Using the composite tag for all face vertices, first make sure that some
1373     //  face-vertices are Crease vertices, and quickly reject this case based on the
1374     //  presence of other features.  Ultimately we want a regular interior face with
1375     //  two (adjacent) Crease vertics and two Smooth vertices.  This first test
1376     //  quickly ensures a regular interior face with some number of Crease vertices
1377     //  and any remaining as Smooth.
1378     //
1379     ConstIndexArray fVerts = getFaceVertices(face);
1380 
1381     VTag allCornersTag = getFaceCompositeVTag(fVerts);
1382     if (!(allCornersTag._rule & Sdc::Crease::RULE_CREASE) ||
1383          (allCornersTag._rule & Sdc::Crease::RULE_CORNER) ||
1384          (allCornersTag._rule & Sdc::Crease::RULE_DART) ||
1385           allCornersTag._boundary ||
1386           allCornersTag._xordinary ||
1387           allCornersTag._nonManifold) {
1388         return false;
1389     }
1390 
1391     //  Identify the crease vertices in a 4-bit mask and use it as an index to
1392     //  verify that we have exactly two adjacent crease vertices while identifying
1393     //  the edge between them -- reject any case not returning a valid edge.
1394     //
1395     int creaseCornerMask = ((getVertexTag(fVerts[0])._rule == Sdc::Crease::RULE_CREASE) << 0) |
1396                            ((getVertexTag(fVerts[1])._rule == Sdc::Crease::RULE_CREASE) << 1) |
1397                            ((getVertexTag(fVerts[2])._rule == Sdc::Crease::RULE_CREASE) << 2) |
1398                            ((getVertexTag(fVerts[3])._rule == Sdc::Crease::RULE_CREASE) << 3);
1399     static const int sharpEdgeFromCreaseMask[16] = { -1, -1, -1,  0, -1, -1,  1, -1,
1400                                                      -1,  3, -1, -1,  2, -1, -1, -1 };
1401 
1402     int sharpEdgeInFace = sharpEdgeFromCreaseMask[creaseCornerMask];
1403     if (sharpEdgeInFace < 0) {
1404         return false;
1405     }
1406 
1407     //  Reject if the crease at the two crease vertices A and B is not regular, i.e.
1408     //  any pair of opposing edges does not have the same sharpness value (one pair
1409     //  sharp, the other smooth).  The resulting two regular creases must be "colinear"
1410     //  (sharing the edge between them, and so its common sharpness value) otherwise
1411     //  we would have more than two crease vertices.
1412     //
1413     ConstIndexArray vAEdges = getVertexEdges(fVerts[         sharpEdgeInFace]);
1414     ConstIndexArray vBEdges = getVertexEdges(fVerts[fastMod4(sharpEdgeInFace + 1)]);
1415 
1416     if (!isSharpnessEqual(getEdgeSharpness(vAEdges[0]), getEdgeSharpness(vAEdges[2])) ||
1417         !isSharpnessEqual(getEdgeSharpness(vAEdges[1]), getEdgeSharpness(vAEdges[3])) ||
1418         !isSharpnessEqual(getEdgeSharpness(vBEdges[0]), getEdgeSharpness(vBEdges[2])) ||
1419         !isSharpnessEqual(getEdgeSharpness(vBEdges[1]), getEdgeSharpness(vBEdges[3]))) {
1420         return false;
1421     }
1422     if (sharpnessOut) {
1423         *sharpnessOut = getEdgeSharpness(getFaceEdges(face)[sharpEdgeInFace]);
1424     }
1425     if (sharpEdgeInFaceOut) {
1426         *sharpEdgeInFaceOut = sharpEdgeInFace;
1427     }
1428     return true;
1429 }
1430 
1431 //
1432 //  What follows is an internal/anonymous class and protected methods to complete all
1433 //  topological relations when only the face-vertex relations are defined.
1434 //
1435 //  In keeping with the original idea that Level is just data and relies on other
1436 //  classes to construct it, this functionality may be warranted elsewhere, but we are
1437 //  collectively unclear as to where that should be at present.  In the meantime, the
1438 //  implementation is provided here so that we can test and make use of it.
1439 //
1440 namespace {
1441     //
1442     //  This is an internal helper class to manage the assembly of the topological relations
1443     //  that do not have a predictable size, i.e. faces-per-edge, faces-per-vertex and
1444     //  edges-per-vertex.  Level manages these with two vectors:
1445     //
1446     //      - a vector of integer pairs for the "counts" and "offsets"
1447     //      - a vector of incident members accessed by the "offset" of each
1448     //
1449     //  The "dynamic relation" allocates the latter vector of members based on a typical
1450     //  number of members per component, e.g. we expect valence 4 vertices in a typical
1451     //  quad-mesh, and so an "expected" number might be 6 to accommodate a few x-ordinary
1452     //  vertices.  The member vector is allocated with this number per component and the
1453     //  counts and offsets initialized to refer to them -- but with the counts set to 0.
1454     //  The count will be incremented as members are identified and entered, and if any
1455     //  component "overflows" the expected number of members, the members are moved to a
1456     //  separate vector in an std::map for the component.
1457     //
1458     //  Once all incident members have been added, the main vector is compressed and may
1459     //  need to merge entries from the map in the process.
1460     //
1461     typedef std::map<Index, IndexVector> IrregIndexMap;
1462 
1463     class DynamicRelation {
1464     public:
1465         DynamicRelation(IndexVector& countAndOffsets, IndexVector& indices, int membersPerComp);
~DynamicRelation()1466         ~DynamicRelation() { }
1467 
1468     public:
1469         //  Methods dealing with the members for each component:
1470         IndexArray getCompMembers(Index index);
1471         void       appendCompMember(Index index, Index member);
1472 
1473         //  Methods dealing with the components:
1474         void appendComponent();
1475         int  compressMemberIndices();
1476 
1477     public:
1478         int _compCount;
1479         int _memberCountPerComp;
1480 
1481         IndexVector & _countsAndOffsets;
1482         IndexVector & _regIndices;
1483 
1484         IrregIndexMap _irregIndices;
1485     };
1486 
1487     inline
DynamicRelation(IndexVector & countAndOffsets,IndexVector & indices,int membersPerComp)1488     DynamicRelation::DynamicRelation(IndexVector& countAndOffsets, IndexVector& indices, int membersPerComp) :
1489             _compCount(0),
1490             _memberCountPerComp(membersPerComp),
1491             _countsAndOffsets(countAndOffsets),
1492             _regIndices(indices) {
1493 
1494         _compCount = (int) _countsAndOffsets.size() / 2;
1495 
1496         for (int i = 0; i < _compCount; ++i) {
1497             _countsAndOffsets[2*i]   = 0;
1498             _countsAndOffsets[2*i+1] = i * _memberCountPerComp;
1499         }
1500         _regIndices.resize(_compCount * _memberCountPerComp);
1501     }
1502 
1503     inline IndexArray
getCompMembers(Index compIndex)1504     DynamicRelation::getCompMembers(Index compIndex) {
1505 
1506         int count = _countsAndOffsets[2*compIndex];
1507         if (count > _memberCountPerComp) {
1508             IndexVector & irregMembers = _irregIndices[compIndex];
1509             return IndexArray(&irregMembers[0], (int)irregMembers.size());
1510         } else {
1511             int offset = _countsAndOffsets[2*compIndex+1];
1512             return IndexArray(&_regIndices[offset], count);
1513         }
1514     }
1515     inline void
appendCompMember(Index compIndex,Index memberValue)1516     DynamicRelation::appendCompMember(Index compIndex, Index memberValue) {
1517 
1518         int count  = _countsAndOffsets[2*compIndex];
1519         int offset = _countsAndOffsets[2*compIndex+1];
1520 
1521         if (count < _memberCountPerComp) {
1522             _regIndices[offset + count] = memberValue;
1523         } else {
1524             IndexVector& irregMembers = _irregIndices[compIndex];
1525 
1526             if (count > _memberCountPerComp) {
1527                 irregMembers.push_back(memberValue);
1528             } else {
1529                 irregMembers.resize(_memberCountPerComp + 1);
1530                 std::memcpy(&irregMembers[0], &_regIndices[offset], sizeof(Index) * _memberCountPerComp);
1531                 irregMembers[_memberCountPerComp] = memberValue;
1532             }
1533         }
1534         _countsAndOffsets[2*compIndex] ++;
1535     }
1536     inline void
appendComponent()1537     DynamicRelation::appendComponent() {
1538 
1539         _countsAndOffsets.push_back(0);
1540         _countsAndOffsets.push_back(_compCount * _memberCountPerComp);
1541 
1542         ++ _compCount;
1543         _regIndices.resize(_compCount * _memberCountPerComp);
1544     }
1545     int
compressMemberIndices()1546     DynamicRelation::compressMemberIndices() {
1547 
1548         if (_irregIndices.size() == 0) {
1549             int memberCount = _countsAndOffsets[0];
1550             int memberMax   = _countsAndOffsets[0];
1551             for (int i = 1; i < _compCount; ++i) {
1552                 int count  = _countsAndOffsets[2*i];
1553                 int offset = _countsAndOffsets[2*i + 1];
1554 
1555                 memmove(&_regIndices[memberCount], &_regIndices[offset], count * sizeof(Index));
1556 
1557                 _countsAndOffsets[2*i + 1] = memberCount;
1558                 memberCount += count;
1559                 memberMax    = std::max(memberMax, count);
1560             }
1561             _regIndices.resize(memberCount);
1562             return memberMax;
1563         } else {
1564             //  Assign new offsets-per-component while determining if we can trivially compress in place:
1565             bool cannotBeCompressedInPlace = false;
1566 
1567             int memberCount = _countsAndOffsets[0];
1568             for (int i = 1; i < _compCount; ++i) {
1569                 _countsAndOffsets[2*i + 1] = memberCount;
1570 
1571                 cannotBeCompressedInPlace |= (memberCount > (_memberCountPerComp * i));
1572 
1573                 memberCount += _countsAndOffsets[2*i];
1574             }
1575             cannotBeCompressedInPlace |= (memberCount > (_memberCountPerComp * _compCount));
1576 
1577             //  Copy members into the original or temporary vector accordingly:
1578             IndexVector  tmpIndices;
1579             if (cannotBeCompressedInPlace) {
1580                 tmpIndices.resize(memberCount);
1581             }
1582             IndexVector& dstIndices = cannotBeCompressedInPlace ? tmpIndices : _regIndices;
1583 
1584             int memberMax = _memberCountPerComp;
1585             for (int i = 0; i < _compCount; ++i) {
1586                 int count = _countsAndOffsets[2*i];
1587 
1588                 Index *dstMembers = &dstIndices[0] + _countsAndOffsets[2*i + 1];
1589                 Index *srcMembers = 0;
1590 
1591                 if (count <= _memberCountPerComp) {
1592                      srcMembers = &_regIndices[i * _memberCountPerComp];
1593                 } else {
1594                      srcMembers = &_irregIndices[i][0];
1595                      memberMax = std::max(memberMax, count);
1596                 }
1597                 memmove(dstMembers, srcMembers, count * sizeof(Index));
1598             }
1599             if (cannotBeCompressedInPlace) {
1600                 _regIndices.swap(tmpIndices);
1601             } else {
1602                 _regIndices.resize(memberCount);
1603             }
1604             return memberMax;
1605         }
1606     }
1607 }
1608 
1609 
1610 //
1611 //  Methods to populate the missing topology relations of the Level:
1612 //
1613 inline Index
findEdge(Index v0Index,Index v1Index,ConstIndexArray v0Edges) const1614 Level::findEdge(Index v0Index, Index v1Index, ConstIndexArray v0Edges) const {
1615 
1616     if (v0Index != v1Index) {
1617         for (int j = 0; j < v0Edges.size(); ++j) {
1618             ConstIndexArray eVerts = this->getEdgeVertices(v0Edges[j]);
1619             if ((eVerts[0] == v1Index) || (eVerts[1] == v1Index)) {
1620                 return v0Edges[j];
1621             }
1622         }
1623     } else {
1624         for (int j = 0; j < v0Edges.size(); ++j) {
1625             ConstIndexArray eVerts = this->getEdgeVertices(v0Edges[j]);
1626             if (eVerts[0] == eVerts[1]) {
1627                 return v0Edges[j];
1628             }
1629         }
1630     }
1631     return INDEX_INVALID;
1632 }
1633 
1634 Index
findEdge(Index v0Index,Index v1Index) const1635 Level::findEdge(Index v0Index, Index v1Index) const {
1636     return this->findEdge(v0Index, v1Index, this->getVertexEdges(v0Index));
1637 }
1638 
1639 bool
completeTopologyFromFaceVertices()1640 Level::completeTopologyFromFaceVertices() {
1641 
1642     //
1643     //  It's assumed (a pre-condition) that face-vertices have been fully specified and that we
1644     //  are to construct the remaining relations:  including the edge list.  We may want to
1645     //  support the existence of the edge list too in future:
1646     //
1647     int vCount = this->getNumVertices();
1648     int fCount = this->getNumFaces();
1649     int eCount = this->getNumEdges();
1650     assert((vCount > 0) && (fCount > 0) && (eCount == 0));
1651 
1652     //  May be unnecessary depending on how the vertices and faces were defined, but worth a
1653     //  call to ensure all data related to verts and faces is available -- this will be a
1654     //  harmless call if all has been taken care of.
1655     //
1656     //  Remember to resize edges similarly after the edge list has been assembled...
1657     this->resizeVertices(vCount);
1658     this->resizeFaces(fCount);
1659     this->resizeEdges(0);
1660 
1661     //
1662     //  Resize face-edges to match face-verts and reserve for edges based on an estimate:
1663     //
1664     this->_faceEdgeIndices.resize(this->getNumFaceVerticesTotal());
1665 
1666     int eCountEstimate = (vCount << 1);
1667 
1668     this->_edgeVertIndices.reserve(eCountEstimate * 2);
1669     this->_edgeFaceIndices.reserve(eCountEstimate * 2);
1670 
1671     this->_edgeFaceCountsAndOffsets.reserve(eCountEstimate * 2);
1672 
1673     //
1674     //  Create the dynamic relations to be populated (edge-faces will remain empty as reserved
1675     //  above since there are currently no edges) and iterate through the faces to do so:
1676     //
1677     const int avgSize = 6;
1678 
1679     DynamicRelation dynEdgeFaces(this->_edgeFaceCountsAndOffsets, this->_edgeFaceIndices, 2);
1680     DynamicRelation dynVertFaces(this->_vertFaceCountsAndOffsets, this->_vertFaceIndices, avgSize);
1681     DynamicRelation dynVertEdges(this->_vertEdgeCountsAndOffsets, this->_vertEdgeIndices, avgSize);
1682 
1683     //  Inspect each edge created and identify those that are non-manifold as we go:
1684     IndexVector nonManifoldEdges;
1685 
1686     for (Index fIndex = 0; fIndex < fCount; ++fIndex) {
1687         IndexArray fVerts = this->getFaceVertices(fIndex);
1688         IndexArray fEdges = this->getFaceEdges(fIndex);
1689 
1690         for (int i = 0; i < fVerts.size(); ++i) {
1691             Index v0Index = fVerts[i];
1692             Index v1Index = fVerts[(i+1) % fVerts.size()];
1693 
1694             //
1695             //  If not degenerate, search for a previous occurrence of this edge [v0,v1]
1696             //  in v0's incident edge members.  Otherwise, set the edge index as invalid
1697             //  to trigger creation of a new/unique instance of the degenerate edge:
1698             //
1699             Index eIndex;
1700             if (v0Index != v1Index) {
1701                 eIndex = this->findEdge(v0Index, v1Index, dynVertEdges.getCompMembers(v0Index));
1702             } else {
1703                 eIndex = INDEX_INVALID;
1704                 nonManifoldEdges.push_back(this->_edgeCount);
1705             }
1706 
1707             //
1708             //  If the edge already exists, see if it is non-manifold, i.e. it has already been
1709             //  added to two faces, or this face has the edge in the same orientation as the
1710             //  first face (indicating opposite winding orders between the two faces).
1711             //
1712             //  Otherwise, create a new edge, append the new vertex pair [v0,v1] and update
1713             //  the incidence relations for the edge and its end vertices and this face.
1714             //
1715             //  Regardless of whether or not the edge was new, update the edge-faces, the
1716             //  face-edges and the vertex-faces for this vertex.
1717             //
1718             if (IndexIsValid(eIndex)) {
1719                 IndexArray eFaces = dynEdgeFaces.getCompMembers(eIndex);
1720                 if (eFaces[eFaces.size() - 1] == fIndex) {
1721                     //  If the edge already occurs in this face, create a new instance:
1722                     nonManifoldEdges.push_back(eIndex);
1723                     nonManifoldEdges.push_back(this->_edgeCount);
1724                     eIndex = INDEX_INVALID;
1725                 } else if (eFaces.size() > 1) {
1726                     nonManifoldEdges.push_back(eIndex);
1727                 } else if (v0Index == this->getEdgeVertices(eIndex)[0]) {
1728                     nonManifoldEdges.push_back(eIndex);
1729                 }
1730             }
1731             if (!IndexIsValid(eIndex)) {
1732                 eIndex = (Index) this->_edgeCount;
1733 
1734                 this->_edgeCount ++;
1735                 this->_edgeVertIndices.push_back(v0Index);
1736                 this->_edgeVertIndices.push_back(v1Index);
1737 
1738                 dynEdgeFaces.appendComponent();
1739 
1740                 dynVertEdges.appendCompMember(v0Index, eIndex);
1741                 dynVertEdges.appendCompMember(v1Index, eIndex);
1742             }
1743 
1744             dynEdgeFaces.appendCompMember(eIndex,  fIndex);
1745             dynVertFaces.appendCompMember(v0Index, fIndex);
1746 
1747             fEdges[i] = eIndex;
1748         }
1749     }
1750 
1751     //
1752     //  Compress the incident member vectors while determining the maximum for each.
1753     //  Use these to set maximum relation count members and to test for valence or
1754     //  other incident member overflow:  max edge-faces is simple, but for max-valence,
1755     //  remember it was first initialized with the maximum of face-verts, so use its
1756     //  existing value -- and some non-manifold cases can have #faces > #edges, so be
1757     //  sure to consider both.
1758     //
1759     int maxEdgeFaces = dynEdgeFaces.compressMemberIndices();
1760     int maxVertFaces = dynVertFaces.compressMemberIndices();
1761     int maxVertEdges = dynVertEdges.compressMemberIndices();
1762 
1763     _maxEdgeFaces = maxEdgeFaces;
1764 
1765     assert(_maxValence > 0);
1766     _maxValence = std::max(maxVertFaces, _maxValence);
1767     _maxValence = std::max(maxVertEdges, _maxValence);
1768 
1769     //  If max-edge-faces too large, max-valence must also be, so just need the one:
1770     if (_maxValence > VALENCE_LIMIT) {
1771         return false;
1772     }
1773 
1774     //
1775     //  At this point all incident members are associated with each component.  We still
1776     //  need to populate the "local indices" for each and orient manifold components in
1777     //  counter-clockwise order.  First tag non-manifold edges and their incident
1778     //  vertices so that we can trivially skip orienting these -- though some vertices
1779     //  will be determined non-manifold as a result of a failure to orient them (and
1780     //  will be marked accordingly when so detected).
1781     //
1782     //  Finally, the local indices are assigned.  This is trivial for manifold components
1783     //  as if component V is in component F, V will only occur once in F.  For non-manifold
1784     //  cases V may occur multiple times in F -- we rely on such instances being successive
1785     //  based on their original assignment above, which simplifies the task.
1786     //
1787     //  First resize edges to the new count to ensure anything related to edges is created:
1788     eCount = this->getNumEdges();
1789     this->resizeEdges(eCount);
1790 
1791     for (int i = 0; i < (int)nonManifoldEdges.size(); ++i) {
1792         Index eIndex = nonManifoldEdges[i];
1793 
1794         _edgeTags[eIndex]._nonManifold = true;
1795 
1796         IndexArray eVerts = getEdgeVertices(eIndex);
1797         _vertTags[eVerts[0]]._nonManifold = true;
1798         _vertTags[eVerts[1]]._nonManifold = true;
1799     }
1800 
1801     orientIncidentComponents();
1802 
1803     populateLocalIndices();
1804 
1805 //printf("Vertex topology completed...\n");
1806 //this->print();
1807 //printf("  validating vertex topology...\n");
1808 //this->validateTopology();
1809 //assert(this->validateTopology());
1810     return true;
1811 }
1812 
1813 void
populateLocalIndices()1814 Level::populateLocalIndices() {
1815 
1816     //
1817     //  We have three sets of local indices -- edge-faces, vert-faces and vert-edges:
1818     //
1819     int eCount = this->getNumEdges();
1820     int vCount = this->getNumVertices();
1821 
1822     this->_vertFaceLocalIndices.resize(this->_vertFaceIndices.size());
1823     this->_vertEdgeLocalIndices.resize(this->_vertEdgeIndices.size());
1824     this->_edgeFaceLocalIndices.resize(this->_edgeFaceIndices.size());
1825 
1826     for (Index vIndex = 0; vIndex < vCount; ++vIndex) {
1827         IndexArray      vFaces   = this->getVertexFaces(vIndex);
1828         LocalIndexArray vInFaces = this->getVertexFaceLocalIndices(vIndex);
1829 
1830         //
1831         //  We keep track of the last face during the iteration to detect when two
1832         //  (or more) successive faces are the same -- indicating a degenerate edge
1833         //  or other non-manifold situation.  If so, we continue to search from the
1834         //  point of the last face's local index:
1835         //
1836         Index vFaceLast = INDEX_INVALID;
1837         for (int i = 0; i < vFaces.size(); ++i) {
1838             IndexArray fVerts = this->getFaceVertices(vFaces[i]);
1839 
1840             int vStart = (vFaces[i] == vFaceLast) ? ((int)vInFaces[i-1] + 1) : 0;
1841 
1842             int vInFaceIndex = (int)(std::find(fVerts.begin() + vStart, fVerts.end(), vIndex) - fVerts.begin());
1843             vInFaces[i] = (LocalIndex) vInFaceIndex;
1844 
1845             vFaceLast = vFaces[i];
1846         }
1847     }
1848 
1849     for (Index vIndex = 0; vIndex < vCount; ++vIndex) {
1850         IndexArray      vEdges   = this->getVertexEdges(vIndex);
1851         LocalIndexArray vInEdges = this->getVertexEdgeLocalIndices(vIndex);
1852 
1853         for (int i = 0; i < vEdges.size(); ++i) {
1854             IndexArray eVerts = this->getEdgeVertices(vEdges[i]);
1855 
1856             //
1857             //  For degenerate edges, the first occurrence of the edge (which
1858             //  are presumed successive) will get local index 0, the second 1.
1859             //
1860             if (eVerts[0] != eVerts[1]) {
1861                 vInEdges[i] = (vIndex == eVerts[1]);
1862             } else {
1863                 vInEdges[i] = (i && (vEdges[i] == vEdges[i-1]));
1864             }
1865         }
1866         _maxValence = std::max(_maxValence, vEdges.size());
1867     }
1868 
1869     for (Index eIndex = 0; eIndex < eCount; ++eIndex) {
1870         IndexArray      eFaces   = this->getEdgeFaces(eIndex);
1871         LocalIndexArray eInFaces = this->getEdgeFaceLocalIndices(eIndex);
1872 
1873         //
1874         //  We keep track of the last face during the iteration to detect when two
1875         //  (or more) successive faces are the same -- indicating a degenerate edge
1876         //  or other non-manifold situation.  If so, we continue to search from the
1877         //  point of the last face's local index:
1878         //
1879         Index eFaceLast = INDEX_INVALID;
1880         for (int i = 0; i < eFaces.size(); ++i) {
1881             IndexArray fEdges = this->getFaceEdges(eFaces[i]);
1882 
1883             int eStart = (eFaces[i] == eFaceLast) ? ((int)eInFaces[i-1] + 1) : 0;
1884 
1885             int eInFaceIndex = (int)(std::find(fEdges.begin() + eStart, fEdges.end(), eIndex) - fEdges.begin());
1886             eInFaces[i] = (LocalIndex) eInFaceIndex;
1887 
1888             eFaceLast = eFaces[i];
1889         }
1890     }
1891 }
1892 
1893 void
orientIncidentComponents()1894 Level::orientIncidentComponents() {
1895 
1896     int vCount = getNumVertices();
1897 
1898     for (Index vIndex = 0; vIndex < vCount; ++vIndex) {
1899         Level::VTag & vTag = _vertTags[vIndex];
1900         if (!vTag._nonManifold) {
1901             if (!orderVertexFacesAndEdges(vIndex)) {
1902                 vTag._nonManifold = true;
1903             }
1904         }
1905     }
1906 }
1907 
1908 namespace {
1909     inline int
findInArray(ConstIndexArray array,Index value)1910     findInArray(ConstIndexArray array, Index value) {
1911         return (int)(std::find(array.begin(), array.end(), value) - array.begin());
1912     }
1913 }
1914 
1915 bool
orderVertexFacesAndEdges(Index vIndex,Index * vFacesOrdered,Index * vEdgesOrdered) const1916 Level::orderVertexFacesAndEdges(Index vIndex, Index * vFacesOrdered, Index * vEdgesOrdered) const {
1917 
1918     ConstIndexArray  vEdges = this->getVertexEdges(vIndex);
1919     ConstIndexArray  vFaces = this->getVertexFaces(vIndex);
1920 
1921     int fCount = vFaces.size();
1922     int eCount = vEdges.size();
1923 
1924     if ((fCount == 0) || (eCount < 2) || ((eCount - fCount) > 1)) return false;
1925 
1926     //
1927     //  Note we have already eliminated the possibility of incident degenerate edges
1928     //  and other bad edges earlier -- marking its vertices non-manifold as a result
1929     //  and explicitly avoiding this method:
1930     //
1931     Index fStart  = INDEX_INVALID;
1932     Index eStart  = INDEX_INVALID;
1933     int      fvStart = 0;
1934 
1935     if (eCount == fCount) {
1936         //  Interior case -- start with the first face
1937 
1938         fStart  = vFaces[0];
1939         fvStart = findInArray(this->getFaceVertices(fStart), vIndex);
1940         eStart  = this->getFaceEdges(fStart)[fvStart];
1941     } else {
1942         //  Boundary case -- start with (identify) the leading of two boundary edges:
1943 
1944         for (int i = 0; i < eCount; ++i) {
1945             ConstIndexArray  eFaces = this->getEdgeFaces(vEdges[i]);
1946             if (eFaces.size() == 1) {
1947                 eStart = vEdges[i];
1948                 fStart = eFaces[0];
1949                 fvStart = findInArray(this->getFaceVertices(fStart), vIndex);
1950 
1951                 //  Singular edge -- look for forward edge to this vertex:
1952                 if (eStart == (this->getFaceEdges(fStart)[fvStart])) {
1953                     break;
1954                 }
1955             }
1956         }
1957     }
1958 
1959     //
1960     //  We have identified a starting face, face-vert and leading edge from
1961     //  which to walk counter clockwise to identify manifold neighbors.  If
1962     //  this vertex is really locally manifold, we will end up back at the
1963     //  starting edge or at the other singular edge of a boundary:
1964     //
1965     int eCountOrdered = 1;
1966     int fCountOrdered = 1;
1967 
1968     vFacesOrdered[0] = fStart;
1969     vEdgesOrdered[0] = eStart;
1970 
1971     Index eFirst = eStart;
1972 
1973     while (eCountOrdered < eCount) {
1974         //
1975         //  Find the next edge, i.e. the one counter-clockwise to the last:
1976         //
1977         ConstIndexArray  fVerts = this->getFaceVertices(fStart);
1978         ConstIndexArray  fEdges = this->getFaceEdges(fStart);
1979 
1980         int      feStart = fvStart;
1981         int      feNext  = feStart ? (feStart - 1) : (fVerts.size() - 1);
1982         Index eNext   = fEdges[feNext];
1983 
1984         //  Two non-manifold situations detected:
1985         //      - two subsequent edges the same, i.e. a "repeated edge" in a face
1986         //      - back at the start before all edges processed
1987         if ((eNext == eStart) || (eNext == eFirst)) return false;
1988 
1989         //
1990         //  Add the next edge and if more faces to visit (not at the end of
1991         //  a boundary) look to its opposite face:
1992         //
1993         vEdgesOrdered[eCountOrdered++] = eNext;
1994 
1995         if (fCountOrdered < fCount) {
1996             ConstIndexArray  eFaces = this->getEdgeFaces(eNext);
1997 
1998             if (eFaces.size() == 0) return false;
1999             if ((eFaces.size() == 1) && (eFaces[0] == fStart)) return false;
2000 
2001             fStart  = eFaces[eFaces[0] == fStart];
2002             fvStart = findInArray(this->getFaceEdges(fStart), eNext);
2003 
2004             vFacesOrdered[fCountOrdered++] = fStart;
2005         }
2006         eStart = eNext;
2007     }
2008     assert(eCountOrdered == eCount);
2009     assert(fCountOrdered == fCount);
2010     return true;
2011 }
2012 
2013 bool
orderVertexFacesAndEdges(Index vIndex)2014 Level::orderVertexFacesAndEdges(Index vIndex) {
2015 
2016     IndexArray vFaces = this->getVertexFaces(vIndex);
2017     IndexArray vEdges = this->getVertexEdges(vIndex);
2018 
2019     internal::StackBuffer<Index,32> indexBuffer(vFaces.size() + vEdges.size());
2020 
2021     Index * vFacesOrdered = indexBuffer;
2022     Index * vEdgesOrdered = indexBuffer + vFaces.size();
2023 
2024     if (orderVertexFacesAndEdges(vIndex, vFacesOrdered, vEdgesOrdered)) {
2025         std::memcpy(&vFaces[0], vFacesOrdered, vFaces.size() * sizeof(Index));
2026         std::memcpy(&vEdges[0], vEdgesOrdered, vEdges.size() * sizeof(Index));
2027         return true;
2028     }
2029     return false;
2030 }
2031 
2032 //
2033 //  In development -- methods for accessing face-varying data channels...
2034 //
2035 int
createFVarChannel(int fvarValueCount,Sdc::Options const & fvarOptions)2036 Level::createFVarChannel(int fvarValueCount, Sdc::Options const& fvarOptions) {
2037 
2038     FVarLevel* fvarLevel = new FVarLevel(*this);
2039 
2040     fvarLevel->setOptions(fvarOptions);
2041     fvarLevel->resizeValues(fvarValueCount);
2042     fvarLevel->resizeComponents();
2043 
2044     _fvarChannels.push_back(fvarLevel);
2045     return (int)_fvarChannels.size() - 1;
2046 }
2047 
2048 void
destroyFVarChannel(int channel)2049 Level::destroyFVarChannel(int channel) {
2050 
2051     delete _fvarChannels[channel];
2052     _fvarChannels.erase(_fvarChannels.begin() + channel);
2053 }
2054 
2055 int
getNumFVarValues(int channel) const2056 Level::getNumFVarValues(int channel) const {
2057     return _fvarChannels[channel]->getNumValues();
2058 }
2059 
2060 Sdc::Options
getFVarOptions(int channel) const2061 Level::getFVarOptions(int channel) const {
2062     return _fvarChannels[channel]->getOptions();
2063 }
2064 
2065 ConstIndexArray
getFaceFVarValues(Index faceIndex,int channel) const2066 Level::getFaceFVarValues(Index faceIndex, int channel) const {
2067     return _fvarChannels[channel]->getFaceValues(faceIndex);
2068 }
2069 
2070 IndexArray
getFaceFVarValues(Index faceIndex,int channel)2071 Level::getFaceFVarValues(Index faceIndex, int channel) {
2072     return _fvarChannels[channel]->getFaceValues(faceIndex);
2073 }
2074 
2075 void
completeFVarChannelTopology(int channel,int regBoundaryValence)2076 Level::completeFVarChannelTopology(int channel, int regBoundaryValence) {
2077     return _fvarChannels[channel]->completeTopologyFromFaceValues(regBoundaryValence);
2078 }
2079 
2080 } // end namespace internal
2081 } // end namespace Vtr
2082 
2083 } // end namespace OPENSUBDIV_VERSION
2084 } // end namespace OpenSubdiv
2085