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/stackBuffer.h"
28 #include "../vtr/level.h"
29 
30 #include "../vtr/fvarLevel.h"
31 
32 #include <cassert>
33 #include <cstdio>
34 #include <cstring>
35 #include <algorithm>
36 
37 
38 //
39 //  FVarLevel:
40 //      Simple container of face-varying topology, associated with a particular
41 //  level.  It is typically constructed and initialized similarly to levels -- the
42 //  base level in a Factory and subsequent levels by refinement.
43 //
44 namespace OpenSubdiv {
45 namespace OPENSUBDIV_VERSION {
46 
47 namespace Vtr {
48 namespace internal {
49 
50 
51 //
52 //  Information about the "span" for a face-varying value -- the set of faces
53 //  that share face-varying continuous edges around their common vertex.
54 //
55 //  This is intended for transient internal use only when analyzing the base
56 //  level topology.  Information gathered for a single span is translated into
57 //  topology tags for the value (ValueTag) which classify the value and persist
58 //  in the FVarLevel for later refinement and analysis.  The ValueSpan exists
59 //  solely to derive the ValueTag and is not intended (or capable) of capturing
60 //  the full topological extent of many spans.
61 //
62 struct FVarLevel::ValueSpan {
63     LocalIndex _size;
64     LocalIndex _start;
65     LocalIndex _disctsEdgeCount;
66     LocalIndex _semiSharpEdgeCount;
67     LocalIndex _infSharpEdgeCount;
68 };
69 
70 
71 //
72 //  Simple (for now) constructor and destructor:
73 //
FVarLevel(Level const & level)74 FVarLevel::FVarLevel(Level const& level) :
75     _level(level),
76     _isLinear(false),
77     _hasLinearBoundaries(false),
78     _hasDependentSharpness(false),
79     _valueCount(0) {
80 }
81 
~FVarLevel()82 FVarLevel::~FVarLevel() {
83 }
84 
85 //
86 //  Initialization and sizing methods to allocate space:
87 //
88 void
setOptions(Sdc::Options const & options)89 FVarLevel::setOptions(Sdc::Options const& options) {
90     _options = options;
91 }
92 
93 void
resizeComponents()94 FVarLevel::resizeComponents() {
95 
96     //  Per-face members:
97     _faceVertValues.resize(_level.getNumFaceVerticesTotal());
98 
99     //  Per-edge members:
100     ETag edgeTagMatch;
101     edgeTagMatch.clear();
102     _edgeTags.resize(_level.getNumEdges(), edgeTagMatch);
103 
104     //  Per-vertex members:
105     _vertSiblingCounts.resize(_level.getNumVertices());
106     _vertSiblingOffsets.resize(_level.getNumVertices());
107 
108     _vertFaceSiblings.resize(_level.getNumVertexFacesTotal(), 0);
109 }
110 
111 void
resizeVertexValues(int vertexValueCount)112 FVarLevel::resizeVertexValues(int vertexValueCount) {
113 
114     _vertValueIndices.resize(vertexValueCount);
115 
116     ValueTag valueTagMatch;
117     valueTagMatch.clear();
118     _vertValueTags.resize(vertexValueCount, valueTagMatch);
119 
120     if (hasCreaseEnds()) {
121         _vertValueCreaseEnds.resize(vertexValueCount);
122     }
123 }
124 
125 void
resizeValues(int valueCount)126 FVarLevel::resizeValues(int valueCount) {
127     _valueCount = valueCount;
128 }
129 
130 
131 //
132 //  Initialize the component tags once all face-values have been assigned...
133 //
134 //  Constructing the mapping between vertices and their face-varying values involves:
135 //
136 //      - iteration through all vertices to mark edge discontinuities and classify
137 //      - allocation of vectors mapping vertices to their multiple (sibling) values
138 //      - iteration through all vertices and their distinct values to tag topologically
139 //
140 //  Once values have been identified for each vertex and tagged, refinement propagates
141 //  the tags to child values using more simplified logic (child values inherit the
142 //  topology of their parent) and no further analysis is required.
143 //
144 void
completeTopologyFromFaceValues(int regularBoundaryValence)145 FVarLevel::completeTopologyFromFaceValues(int regularBoundaryValence) {
146 
147     //
148     //  Assign some members and local variables based on the interpolation options (the
149     //  members support queries that are expected later):
150     //
151     //  Given the growing number of options and behaviors to support, this is likely going
152     //  to get another pass.  It may be worth identifying the behavior for each "feature",
153     //  i.e. determine smooth or sharp for corners, creases and darts, but the fact that
154     //  the rule for one value may be dependent on that of another complicates this.
155     //
156     using Sdc::Options;
157 
158     Options::VtxBoundaryInterpolation geomOptions = _options.GetVtxBoundaryInterpolation();
159     Options::FVarLinearInterpolation  fvarOptions = _options.GetFVarLinearInterpolation();
160 
161     _isLinear = (fvarOptions == Options::FVAR_LINEAR_ALL);
162 
163     _hasLinearBoundaries = (fvarOptions == Options::FVAR_LINEAR_ALL) ||
164                            (fvarOptions == Options::FVAR_LINEAR_BOUNDARIES);
165 
166     _hasDependentSharpness = (fvarOptions == Options::FVAR_LINEAR_CORNERS_PLUS1) ||
167                              (fvarOptions == Options::FVAR_LINEAR_CORNERS_PLUS2);
168 
169     bool geomCornersAreSmooth = (geomOptions != Options::VTX_BOUNDARY_EDGE_AND_CORNER);
170     bool fvarCornersAreSharp  = (fvarOptions != Options::FVAR_LINEAR_NONE);
171 
172     bool makeSmoothCornersSharp = geomCornersAreSmooth && fvarCornersAreSharp;
173 
174     bool sharpenBothIfOneCorner  = (fvarOptions == Options::FVAR_LINEAR_CORNERS_PLUS2);
175 
176     bool sharpenDarts = sharpenBothIfOneCorner || _hasLinearBoundaries;
177 
178 
179     //
180     //  It's awkward and potentially inefficient to try and accomplish everything in one
181     //  pass over the vertices...
182     //
183     //  Make a first pass through the vertices to identify discts edges and to determine
184     //  the number of values-per-vertex for subsequent allocation.  The presence of a
185     //  discts edge warrants marking vertices at BOTH ends as having mismatched topology
186     //  wrt the vertices (part of why full topological analysis is deferred).
187     //
188     //  So this first pass will allocate/initialize the overall structure of the topology.
189     //  Given N vertices and M (as yet unknown) sibling values, the first pass achieves
190     //  the following:
191     //
192     //      - assigns a local vector indicating which of the N vertices "match"
193     //          - requires a single value but must also have no discts incident edges
194     //      - determines the number of values associated with each of the N vertices
195     //      - assigns an offset to the first value for each of the N vertices
196     //      - initializes the vert-face "siblings" for all N vertices
197     //  and
198     //      - tags any incident edges as discts
199     //
200     //  The second pass initializes remaining members based on the total number of siblings
201     //  M after allocating appropriate vectors dependent on M.
202     //
203     std::vector<LocalIndex> vertexMismatch(_level.getNumVertices(), 0);
204 
205     _vertFaceSiblings.resize(_level.getNumVertexFacesTotal(), 0);
206 
207     int const maxValence = _level.getMaxValence();
208 
209     internal::StackBuffer<Index,16>     indexBuffer(maxValence);
210     internal::StackBuffer<int,16>       valueBuffer(maxValence);
211     internal::StackBuffer<Sibling,16>   siblingBuffer(maxValence);
212     internal::StackBuffer<ValueSpan,16> spanBuffer(maxValence);
213 
214     int *     uniqueValues   = valueBuffer;
215     Sibling * vValueSiblings = siblingBuffer;
216 
217     int totalValueCount = 0;
218     for (int vIndex = 0; vIndex < _level.getNumVertices(); ++vIndex) {
219         //
220         //  Retrieve the FVar values from each incident face and store locally for
221         //  use -- we will identify the index of its corresponding "sibling" as we
222         //  inspect them more closely later:
223         //
224         ConstIndexArray       vFaces  = _level.getVertexFaces(vIndex);
225         ConstLocalIndexArray  vInFace = _level.getVertexFaceLocalIndices(vIndex);
226 
227         Index * vValues = indexBuffer;
228 
229         for (int i = 0; i < vFaces.size(); ++i) {
230             vValues[i] = _faceVertValues[_level.getOffsetOfFaceVertices(vFaces[i]) + vInFace[i]];
231         }
232 
233         //
234         //  Inspect the incident edges of the vertex and tag those whose FVar values are
235         //  discts between the two (or more) faces sharing that edge.  When manifold, we
236         //  know an edge is discts when two successive fvar-values differ -- so we will
237         //  make use of the local buffer of values.  Unfortunately we can't infer anything
238         //  about the edges for a non-manifold vertex, so that case will be more complex.
239         //
240         ConstIndexArray       vEdges  = _level.getVertexEdges(vIndex);
241         ConstLocalIndexArray  vInEdge = _level.getVertexEdgeLocalIndices(vIndex);
242 
243         bool vIsManifold = !_level.getVertexTag(vIndex)._nonManifold;
244         bool vIsBoundary = _level.getVertexTag(vIndex)._boundary;
245 
246         if (vIsManifold) {
247             //
248             //  We want to use face indices here as we are accessing the fvar-values per
249             //  face.  The indexing range here maps to the interior edges for boundary
250             //  and interior verts:
251             //
252             for (int i = vIsBoundary; i < vFaces.size(); ++i) {
253                 int vFaceNext = i;
254                 int vFacePrev = i ? (i - 1) : (vFaces.size() - 1);
255 
256                 if (vValues[vFaceNext] != vValues[vFacePrev]) {
257                     Index eIndex = vEdges[i];
258 
259                     //  Tag both end vertices as not matching topology:
260                     ConstIndexArray eVerts = _level.getEdgeVertices(eIndex);
261                     vertexMismatch[eVerts[0]] = true;
262                     vertexMismatch[eVerts[1]] = true;
263 
264                     //  Tag the corresponding edge as discts:
265                     ETag& eTag = _edgeTags[eIndex];
266 
267                     eTag._disctsV0 = (eVerts[0] == vIndex);
268                     eTag._disctsV1 = (eVerts[1] == vIndex);
269                     eTag._mismatch = true;
270                     eTag._linear = (ETag::ETagSize) _hasLinearBoundaries;
271                 }
272             }
273         } else if (vFaces.size() > 0) {
274             //
275             //  Unfortunately for non-manifold cases we can't make as much use of the
276             //  retrieved face-values as there is no correlation between the incident
277             //  edge and face lists.  So inspect each edge for continuity between its
278             //  faces in general -- which is awkward (and what we were hoping to avoid
279             //  by doing the overall vertex traversal to begin with):
280             //
281             for (int i = 0; i < vEdges.size(); ++i) {
282                 Index eIndex = vEdges[i];
283 
284                 ConstIndexArray eFaces  = _level.getEdgeFaces(eIndex);
285                 if (eFaces.size() < 2) continue;
286 
287                 ConstLocalIndexArray eInFace = _level.getEdgeFaceLocalIndices(eIndex);
288                 ConstIndexArray      eVerts  = _level.getEdgeVertices(eIndex);
289 
290                 int   vertInEdge = vInEdge[i];
291                 bool  markEdgeDiscts = false;
292                 Index valueIndexInFace0 = 0;
293                 for (int j = 0; !markEdgeDiscts && (j < eFaces.size()); ++j) {
294                     Index           fIndex  = eFaces[j];
295                     ConstIndexArray fVerts  = _level.getFaceVertices(fIndex);
296                     ConstIndexArray fValues = getFaceValues(fIndex);
297 
298                     int edgeInFace   = eInFace[j];
299                     int edgeReversed = (eVerts[0] != fVerts[edgeInFace]);
300                     int vertInFace   = edgeInFace + (vertInEdge != edgeReversed);
301                     if (vertInFace == fVerts.size()) vertInFace = 0;
302 
303                     if (j == 0) {
304                         valueIndexInFace0 = fValues[vertInFace];
305                     } else {
306                         markEdgeDiscts = (fValues[vertInFace] != valueIndexInFace0);
307                     }
308                 }
309                 if (markEdgeDiscts) {
310                     //  Tag both end vertices as not matching topology:
311                     vertexMismatch[eVerts[0]] = true;
312                     vertexMismatch[eVerts[1]] = true;
313 
314                     //  Tag the corresponding edge as discts:
315                     ETag& eTag = _edgeTags[eIndex];
316 
317                     eTag._disctsV0 = (eVerts[0] == vIndex);
318                     eTag._disctsV1 = (eVerts[1] == vIndex);
319                     eTag._mismatch = true;
320                     eTag._linear = (ETag::ETagSize) _hasLinearBoundaries;
321                 }
322             }
323         }
324 
325         //
326         //  While we've tagged the vertex as having mismatched FVar topology in the presence of
327         //  any discts edges, we also need to account for different treatment of vertices along
328         //  geometric boundaries if the FVar interpolation rules affect them.  So inspect all
329         //  boundary vertices that have not already been tagged.
330         //
331         if (vIsBoundary && !vertexMismatch[vIndex]) {
332             if (_hasLinearBoundaries && (vFaces.size() > 0)) {
333                 vertexMismatch[vIndex] = true;
334 
335                 if (vIsManifold) {
336                     _edgeTags[vEdges[0]]._linear = true;
337                     _edgeTags[vEdges[vEdges.size()-1]]._linear = true;
338                 } else {
339                     for (int i = 0; i < vEdges.size(); ++i) {
340                         if (_level.getEdgeTag(vEdges[i])._boundary) {
341                             _edgeTags[vEdges[i]]._linear = true;
342                         }
343                     }
344                 }
345             } else if (vFaces.size() == 1) {
346                 if (makeSmoothCornersSharp) {
347                     vertexMismatch[vIndex] = true;
348                 }
349             }
350         }
351 
352         //
353         //  Inspect the set of fvar-values around the vertex to identify the number of
354         //  unique values.  While doing so, associate a "sibling index" (over the range
355         //  of unique values) with each value around the vertex (this latter need makes
356         //  it harder to make simple use of std::sort() and uniq() on the set of values)
357         //
358         int uniqueValueCount = 1;
359 
360         uniqueValues[0] = vValues[0];
361         vValueSiblings[0] = 0;
362 
363         for (int i = 1; i < vFaces.size(); ++i) {
364             if (vValues[i] == vValues[i-1]) {
365                 vValueSiblings[i] = vValueSiblings[i-1];
366             } else {
367                 //  Add the "new" value if not already present -- unless found, the
368                 //  sibling index will be for the next/new unique value:
369                 vValueSiblings[i] = (Sibling) uniqueValueCount;
370 
371                 if (uniqueValueCount == 1) {
372                     uniqueValues[uniqueValueCount++] = vValues[i];
373                 } else if ((uniqueValueCount == 2) && (uniqueValues[0] != vValues[i])) {
374                     uniqueValues[uniqueValueCount++] = vValues[i];
375                 } else {
376                     int* uniqueBegin = uniqueValues;
377                     int* uniqueEnd   = uniqueValues + uniqueValueCount;
378                     int* uniqueFound = std::find(uniqueBegin, uniqueEnd, vValues[i]);
379                     if (uniqueFound == uniqueEnd) {
380                         uniqueValues[uniqueValueCount++] = vValues[i];
381                     } else {
382                         vValueSiblings[i] = (Sibling) (uniqueFound - uniqueBegin);
383                     }
384                 }
385             }
386         }
387 
388         //
389         //  Some non-manifold cases can have multiple fvar-values but without any discts
390         //  edges that would previously have identified mismatch (e.g. two faces meeting
391         //  at a common vertex), so deal with that case now that we've counted values:
392         //
393         if (!vIsManifold && !vertexMismatch[vIndex]) {
394             vertexMismatch[vIndex] = (uniqueValueCount > 1);
395         }
396 
397         //
398         //  Update the value count and offset for this vertex and cumulative totals:
399         //
400         _vertSiblingCounts[vIndex]  = (LocalIndex) uniqueValueCount;
401         _vertSiblingOffsets[vIndex] = totalValueCount;
402 
403         totalValueCount += uniqueValueCount;
404 
405         //  Update the vert-face siblings from the local array above:
406         if (uniqueValueCount > 1) {
407             SiblingArray vFaceSiblings = getVertexFaceSiblings(vIndex);
408             for (int i = 0; i < vFaces.size(); ++i) {
409                 vFaceSiblings[i] = vValueSiblings[i];
410             }
411         }
412     }
413 
414     //
415     //  Now that we know the total number of additional sibling values (M values in addition
416     //  to the N vertex values) allocate space to accommodate all N + M vertex values.
417     //
418     //  Then make the second pass through the vertices to identify the values associated with
419     //  each and to inspect and tag local face-varying topology for those that don't match:
420     //
421     resizeVertexValues(totalValueCount);
422 
423     for (int vIndex = 0; vIndex < _level.getNumVertices(); ++vIndex) {
424         ConstIndexArray       vFaces  = _level.getVertexFaces(vIndex);
425         ConstLocalIndexArray  vInFace = _level.getVertexFaceLocalIndices(vIndex);
426 
427         //
428         //  First step is to assign the values associated with the faces by retrieving them
429         //  from the faces.  If the face-varying topology around this vertex matches the vertex
430         //  topology, there is little more to do as other members were bulk-initialized to
431         //  match, so we can continue immediately:
432         //
433         IndexArray vValues = getVertexValues(vIndex);
434 
435         if (vFaces.size() > 0) {
436             vValues[0] = _faceVertValues[_level.getOffsetOfFaceVertices(vFaces[0]) + vInFace[0]];
437         } else {
438             vValues[0] = 0;
439         }
440         if (!vertexMismatch[vIndex]) {
441             continue;
442         }
443         if (vValues.size() > 1) {
444             ConstSiblingArray vFaceSiblings = getVertexFaceSiblings(vIndex);
445 
446             for (int i = 1, nextSibling = 1; i < vFaces.size(); ++i) {
447                 if (vFaceSiblings[i] == nextSibling) {
448                     vValues[nextSibling++] = _faceVertValues[_level.getOffsetOfFaceVertices(vFaces[i]) + vInFace[i]];
449                 }
450             }
451         }
452 
453         //  XXXX (barfowl) -- this pre-emptive sharpening of values will need to be
454         //  revisited soon.  This intentionally avoids the overhead of identifying the
455         //  local topology of the values along its boundaries -- necessary for smooth
456         //  boundary values but not for sharp as far as refining and limiting the
457         //  values is concerned.  But ultimately we need more information than just
458         //  the sharp tag when it comes to identifying and gathering FVar patches.
459         //
460         //  Currently values for non-manifold vertices are sharpened, and that may
461         //  also need to be revisited.
462         //
463         //  Until then...
464         //
465         //  If all values for this vertex are to be designated as sharp, the value tags
466         //  have already been initialized for this by default, so we can continue.  On
467         //  further inspection there may be other cases where all are determined to be
468         //  sharp, but use what information we can now to avoid that inspection:
469         //
470         //  Regarding sharpness of the vertex itself, its vertex tags reflect the inf-
471         //  or semi-sharp nature of the vertex and edges around it, so be careful not
472         //  to assume too much from say, the presence of an incident inf-sharp edge.
473         //  We can make clear decisions based on the sharpness of the vertex itself.
474         //
475         ValueTagArray vValueTags = getVertexValueTags(vIndex);
476 
477         Level::VTag const vTag = _level.getVertexTag(vIndex);
478 
479         bool allCornersAreSharp = _hasLinearBoundaries || vTag._infSharp || vTag._nonManifold ||
480                                   (_hasDependentSharpness && (vValues.size() > 2)) ||
481                                   (sharpenDarts && (vValues.size() == 1) && !vTag._boundary);
482 
483         //
484         //  Values may be a mix of sharp corners and smooth boundaries -- start by
485         //  gathering information about the "span" of faces for each value.
486         //
487         //  Note that the term "span" presumes sequential and continuous, but the
488         //  result for a span may include multiple disconnected regions sharing the
489         //  common value -- think of a familiar non-manifold "bowtie" vertex in FVar
490         //  space.  Such spans are locally non-manifold but are marked as "disjoint"
491         //  to avoid overloading "non-manifold" here.
492         //
493         ValueSpan * vValueSpans = spanBuffer;
494         memset(vValueSpans, 0, vValues.size() * sizeof(ValueSpan));
495 
496         gatherValueSpans(vIndex, vValueSpans);
497 
498         //
499         //  Spans are identified as sharp or smooth based on their own local topology,
500         //  but the sharpness of one span may be dependent on the sharpness of another
501         //  if certain linear-interpolation options were specified.  Mark both as
502         //  infinitely sharp where possible (rather than semi-sharp) to avoid
503         //  re-assessing this dependency as sharpness is reduced during refinement.
504         //
505         bool hasDependentValuesToSharpen = false;
506         if (!allCornersAreSharp) {
507             if (_hasDependentSharpness && (vValues.size() == 2)) {
508                 //  Detect interior inf-sharp or discts edges:
509                 allCornersAreSharp = vValueSpans[0]._infSharpEdgeCount || vValueSpans[1]._infSharpEdgeCount ||
510                                      vValueSpans[0]._disctsEdgeCount   || vValueSpans[1]._disctsEdgeCount;
511 
512                 //  Detect a sharp corner, making both sharp:
513                 if (sharpenBothIfOneCorner) {
514                     allCornersAreSharp |= (vValueSpans[0]._size == 1) || (vValueSpans[1]._size == 1);
515                 }
516 
517                 //  If only one semi-sharp, need to mark the other as dependent on it:
518                 hasDependentValuesToSharpen = (vValueSpans[0]._semiSharpEdgeCount > 0) !=
519                                               (vValueSpans[1]._semiSharpEdgeCount > 0);
520             }
521         }
522 
523         //
524         //  Inspect each vertex value to determine if it is a smooth boundary (crease) and tag
525         //  it accordingly.  If not semi-sharp, be sure to consider those values sharpened by
526         //  the topology of other values.
527         //
528         for (int i = 0; i < vValues.size(); ++i) {
529             ValueTag & valueTag = vValueTags[i];
530 
531             valueTag.clear();
532             valueTag._mismatch = true;
533 
534             ValueSpan const & vSpan = vValueSpans[i];
535             if (vSpan._disctsEdgeCount) {
536                 valueTag._nonManifold = true;
537                 continue;
538             }
539             assert(vSpan._size != 0);
540 
541             bool isInfSharp = allCornersAreSharp || vSpan._infSharpEdgeCount ||
542                               ((vSpan._size == 1) && fvarCornersAreSharp);
543 
544             if (vSpan._size == 1) {
545                 valueTag._xordinary = !isInfSharp;
546             } else {
547                 valueTag._xordinary = (vSpan._size != regularBoundaryValence);
548             }
549 
550             valueTag._infSharpEdges = (vSpan._infSharpEdgeCount > 0);
551             valueTag._infIrregular = vSpan._infSharpEdgeCount ? ((vSpan._size - vSpan._infSharpEdgeCount) > 1)
552                                    : (isInfSharp ? (vSpan._size > 1) : valueTag._xordinary);
553 
554             if (!isInfSharp) {
555                 //
556                 //  Remember that a semi-sharp value (or one dependent on one) needs to be
557                 //  treated as a corner (at least three sharp edges or one sharp vertex)
558                 //  until the sharpness has decayed, so don't tag them as creases here.
559                 //  But do initialize and maintain the ends of the crease until needed.
560                 //
561                 if (vSpan._semiSharpEdgeCount || vTag._semiSharp) {
562                     valueTag._semiSharp = true;
563                 } else if (hasDependentValuesToSharpen) {
564                     valueTag._semiSharp = true;
565                     valueTag._depSharp = true;
566                 } else {
567                     valueTag._crease = true;
568                 }
569 
570                 if (hasCreaseEnds()) {
571                     CreaseEndPair & valueCrease = getVertexValueCreaseEnds(vIndex)[i];
572 
573                     valueCrease._startFace = vSpan._start;
574                     if ((i == 0) && (vSpan._start != 0)) {
575                         valueCrease._endFace = (LocalIndex) (vSpan._start + vSpan._size - 1 - vFaces.size());
576                     } else {
577                         valueCrease._endFace = (LocalIndex) (vSpan._start + vSpan._size - 1);
578                     }
579                 }
580             }
581         }
582     }
583     //printf("completed fvar topology...\n");
584     //print();
585     //printf("validating...\n");
586     //assert(validate());
587 }
588 
589 //
590 //  Values tagged as creases have their two "end values" identified relative to the incident
591 //  faces of the vertex for compact storage and quick retrieval.  This method identifies the
592 //  values for the two ends of such a crease value:
593 //
594 void
getVertexCreaseEndValues(Index vIndex,Sibling vSibling,Index endValues[2]) const595 FVarLevel::getVertexCreaseEndValues(Index vIndex, Sibling vSibling, Index endValues[2]) const {
596 
597     ConstCreaseEndPairArray vValueCreaseEnds = getVertexValueCreaseEnds(vIndex);
598 
599     ConstIndexArray      vFaces  = _level.getVertexFaces(vIndex);
600     ConstLocalIndexArray vInFace = _level.getVertexFaceLocalIndices(vIndex);
601 
602     LocalIndex vertFace0 = vValueCreaseEnds[vSibling]._startFace;
603     LocalIndex vertFace1 = vValueCreaseEnds[vSibling]._endFace;
604 
605     ConstIndexArray face0Values = getFaceValues(vFaces[vertFace0]);
606     ConstIndexArray face1Values = getFaceValues(vFaces[vertFace1]);
607 
608     int endInFace0 = vInFace[vertFace0];
609     int endInFace1 = vInFace[vertFace1];
610 
611     endInFace0 = (endInFace0 == (face0Values.size() - 1)) ? 0 : (endInFace0 + 1);
612     endInFace1 = (endInFace1 ? endInFace1 : face1Values.size()) - 1;
613 
614     endValues[0] = face0Values[endInFace0];
615     endValues[1] = face1Values[endInFace1];
616 }
617 
618 //
619 //  Debugging aids...
620 //
621 bool
validate() const622 FVarLevel::validate() const {
623 
624     //
625     //  Verify that member sizes match sizes for the associated level:
626     //
627     if ((int)_vertSiblingCounts.size() != _level.getNumVertices()) {
628         printf("Error:  vertex count mismatch\n");
629         return false;
630     }
631     if ((int)_edgeTags.size() != _level.getNumEdges()) {
632         printf("Error:  edge count mismatch\n");
633         return false;
634     }
635     if ((int)_faceVertValues.size() != _level.getNumFaceVerticesTotal()) {
636         printf("Error:  face-value/face-vert count mismatch\n");
637         return false;
638     }
639     if (_level.getDepth() > 0) {
640         if (_valueCount != (int)_vertValueIndices.size()) {
641             printf("Error:  value/vertex-value count mismatch\n");
642             return false;
643         }
644     }
645 
646     //
647     //  Verify that face-verts and (locally computed) face-vert siblings yield the
648     //  expected face-vert values:
649     //
650     std::vector<Sibling> fvSiblingVector;
651     buildFaceVertexSiblingsFromVertexFaceSiblings(fvSiblingVector);
652 
653     for (int fIndex = 0; fIndex < _level.getNumFaces(); ++fIndex) {
654         ConstIndexArray     fVerts = _level.getFaceVertices(fIndex);
655         ConstIndexArray    fValues = getFaceValues(fIndex);
656         Sibling const  * fSiblings = &fvSiblingVector[_level.getOffsetOfFaceVertices(fIndex)];
657 
658         for (int fvIndex = 0; fvIndex < fVerts.size(); ++fvIndex) {
659             Index vIndex = fVerts[fvIndex];
660 
661             Index   fvValue   = fValues[fvIndex];
662             Sibling fvSibling = fSiblings[fvIndex];
663             if (fvSibling >= getNumVertexValues(vIndex)) {
664                 printf("Error:  invalid sibling %d for face-vert %d.%d = %d\n", fvSibling, fIndex, fvIndex, vIndex);
665                 return false;
666             }
667 
668             Index testValue = getVertexValue(vIndex, fvSibling);
669             if (testValue != fvValue) {
670                 printf("Error:  unexpected value %d for sibling %d of face-vert %d.%d = %d (expecting %d)\n",
671                         testValue, fvSibling, fIndex, fvIndex, vIndex, fvValue);
672                 return false;
673             }
674         }
675     }
676 
677     //
678     //  Verify that the vert-face siblings yield the expected value:
679     //
680     for (int vIndex = 0; vIndex < _level.getNumVertices(); ++vIndex) {
681         ConstIndexArray      vFaces    = _level.getVertexFaces(vIndex);
682         ConstLocalIndexArray vInFace   = _level.getVertexFaceLocalIndices(vIndex);
683         ConstSiblingArray    vSiblings = getVertexFaceSiblings(vIndex);
684 
685         for (int j = 0; j < vFaces.size(); ++j) {
686             Sibling vSibling = vSiblings[j];
687             if (vSibling >= getNumVertexValues(vIndex)) {
688                 printf("Error:  invalid sibling %d at vert-face %d.%d\n", vSibling, vIndex, j);
689                 return false;
690             }
691 
692             Index fIndex  = vFaces[j];
693             int   fvIndex = vInFace[j];
694             Index fvValue = getFaceValues(fIndex)[fvIndex];
695 
696             Index vValue = getVertexValue(vIndex, vSibling);
697             if (vValue != fvValue) {
698                 printf("Error:  value mismatch between face-vert %d.%d and vert-face %d.%d (%d != %d)\n",
699                         fIndex, fvIndex, vIndex, j, fvValue, vValue);
700                 return false;
701             }
702         }
703     }
704     return true;
705 }
706 
707 void
print() const708 FVarLevel::print() const {
709 
710     std::vector<Sibling> fvSiblingVector;
711     buildFaceVertexSiblingsFromVertexFaceSiblings(fvSiblingVector);
712 
713     printf("Face-varying data channel:\n");
714     printf("  Inventory:\n");
715     printf("    vertex count       = %d\n", _level.getNumVertices());
716     printf("    source value count = %d\n", _valueCount);
717     printf("    vertex value count = %d\n", (int)_vertValueIndices.size());
718 
719     printf("  Face values:\n");
720     for (int i = 0; i < _level.getNumFaces(); ++i) {
721         ConstIndexArray  fVerts    = _level.getFaceVertices(i);
722         ConstIndexArray  fValues   = getFaceValues(i);
723         Sibling const  * fSiblings = &fvSiblingVector[_level.getOffsetOfFaceVertices(i)];
724 
725         printf("    face%4d:  ", i);
726 
727         printf("verts =");
728         for (int j = 0; j < fVerts.size(); ++j) {
729             printf("%4d", fVerts[j]);
730         }
731         printf(",  values =");
732         for (int j = 0; j < fValues.size(); ++j) {
733             printf("%4d", fValues[j]);
734         }
735         printf(",  siblings =");
736         for (int j = 0; j < fVerts.size(); ++j) {
737             printf("%4d", (int)fSiblings[j]);
738         }
739         printf("\n");
740     }
741 
742     printf("  Vertex values:\n");
743     for (int i = 0; i < _level.getNumVertices(); ++i) {
744         int vCount  = getNumVertexValues(i);
745         int vOffset = getVertexValueOffset(i);
746 
747         printf("    vert%4d:  vcount = %1d, voffset =%4d, ", i, vCount, vOffset);
748 
749         ConstIndexArray vValues = getVertexValues(i);
750 
751         printf("values =");
752         for (int j = 0; j < vValues.size(); ++j) {
753             printf("%4d", vValues[j]);
754         }
755         if (vCount > 1) {
756             ConstValueTagArray vValueTags = getVertexValueTags(i);
757 
758             printf(", crease =");
759             for (int j = 0; j < vValueTags.size(); ++j) {
760                 printf("%4d", vValueTags[j]._crease);
761             }
762             printf(", semi-sharp =");
763             for (int j = 0; j < vValueTags.size(); ++j) {
764                 printf("%2d", vValueTags[j]._semiSharp);
765             }
766         }
767         printf("\n");
768     }
769 
770     printf("  Edge discontinuities:\n");
771     for (int i = 0; i < _level.getNumEdges(); ++i) {
772         ETag const eTag = getEdgeTag(i);
773         if (eTag._mismatch) {
774             ConstIndexArray eVerts = _level.getEdgeVertices(i);
775             printf("    edge%4d:  verts = [%4d%4d], discts = [%d,%d]\n", i, eVerts[0], eVerts[1],
776                     eTag._disctsV0, eTag._disctsV1);
777         }
778     }
779 }
780 
781 
782 
783 void
initializeFaceValuesFromFaceVertices()784 FVarLevel::initializeFaceValuesFromFaceVertices() {
785 
786     ConstIndexArray srcFaceVerts = _level.getFaceVertices();
787     Index *         dstFaceValues = &_faceVertValues[0];
788 
789     std::memcpy(dstFaceValues, &srcFaceVerts[0], srcFaceVerts.size() * sizeof(Index));
790 }
791 
792 
793 void
initializeFaceValuesFromVertexFaceSiblings()794 FVarLevel::initializeFaceValuesFromVertexFaceSiblings() {
795     //
796     //  Iterate through all face-values first and initialize them with the first value
797     //  associated with each face-vertex.  Then make a second sparse pass through the
798     //  vertex-faces to offset those with multiple values.  This turns out to be much
799     //  more efficient than a single iteration through the vertex-faces since the first
800     //  pass is much more memory coherent.
801     //
802     ConstIndexArray fvIndices = _level.getFaceVertices();
803     for (int i = 0; i < fvIndices.size(); ++i) {
804         _faceVertValues[i] = getVertexValueOffset(fvIndices[i]);
805     }
806 
807     //
808     //  Now use the vert-face-siblings to populate the face-vert-values:
809     //
810     for (int vIndex = 0; vIndex < _level.getNumVertices(); ++vIndex) {
811         if (getNumVertexValues(vIndex) > 1) {
812             ConstIndexArray      vFaces    = _level.getVertexFaces(vIndex);
813             ConstLocalIndexArray vInFace   = _level.getVertexFaceLocalIndices(vIndex);
814             ConstSiblingArray    vSiblings = getVertexFaceSiblings(vIndex);
815 
816             for (int j = 0; j < vFaces.size(); ++j) {
817                 if (vSiblings[j]) {
818                     int fvOffset = _level.getOffsetOfFaceVertices(vFaces[j]);
819 
820                     _faceVertValues[fvOffset + vInFace[j]] += vSiblings[j];
821                 }
822             }
823         }
824     }
825 }
826 
827 void
buildFaceVertexSiblingsFromVertexFaceSiblings(std::vector<Sibling> & fvSiblings) const828 FVarLevel::buildFaceVertexSiblingsFromVertexFaceSiblings(std::vector<Sibling>& fvSiblings) const {
829 
830     fvSiblings.resize(_level.getNumFaceVerticesTotal());
831     std::memset(&fvSiblings[0], 0, _level.getNumFaceVerticesTotal() * sizeof(Sibling));
832 
833     for (int vIndex = 0; vIndex < _level.getNumVertices(); ++vIndex) {
834         //  We can skip cases of one sibling as we initialized to 0...
835         if (getNumVertexValues(vIndex) > 1) {
836             ConstIndexArray      vFaces    = _level.getVertexFaces(vIndex);
837             ConstLocalIndexArray vInFace   = _level.getVertexFaceLocalIndices(vIndex);
838             ConstSiblingArray    vSiblings = getVertexFaceSiblings(vIndex);
839 
840             for (int j = 0; j < vFaces.size(); ++j) {
841                 if (vSiblings[j] > 0) {
842                     fvSiblings[_level.getOffsetOfFaceVertices(vFaces[j]) + vInFace[j]] = vSiblings[j];
843                 }
844             }
845         }
846     }
847 }
848 
849 
850 //
851 //  Higher-level topological queries, i.e. values in a neighborhood:
852 //    - given an edge, return values corresponding to its vertices within a given face
853 //    - given a vertex, return values corresponding to verts at the ends of its edges
854 //
855 void
getEdgeFaceValues(Index eIndex,int fIncToEdge,Index valuesPerVert[2]) const856 FVarLevel::getEdgeFaceValues(Index eIndex, int fIncToEdge, Index valuesPerVert[2]) const {
857 
858     ConstIndexArray eVerts = _level.getEdgeVertices(eIndex);
859 
860     if ((getNumVertexValues(eVerts[0]) + getNumVertexValues(eVerts[1])) > 2) {
861         Index eFace   = _level.getEdgeFaces(eIndex)[fIncToEdge];
862         int   eInFace = _level.getEdgeFaceLocalIndices(eIndex)[fIncToEdge];
863 
864         ConstIndexArray fValues = getFaceValues(eFace);
865 
866         valuesPerVert[0] = fValues[eInFace];
867         valuesPerVert[1] = fValues[((eInFace + 1) < fValues.size()) ? (eInFace + 1) : 0];
868 
869         //  Given the way these two end-values are used (both weights the same) we really
870         //  don't need to ensure the value pair matches the vertex pair...
871         if (eVerts[0] != _level.getFaceVertices(eFace)[eInFace]) {
872             std::swap(valuesPerVert[0], valuesPerVert[1]);
873         }
874     } else {
875         //  Remember the extra level of indirection at level 0 -- avoid it here:
876         if (_level.getDepth() > 0) {
877             valuesPerVert[0] = getVertexValueOffset(eVerts[0]);
878             valuesPerVert[1] = getVertexValueOffset(eVerts[1]);
879         } else {
880             valuesPerVert[0] = getVertexValue(eVerts[0]);
881             valuesPerVert[1] = getVertexValue(eVerts[1]);
882         }
883     }
884 }
885 
886 void
getVertexEdgeValues(Index vIndex,Index valuesPerEdge[]) const887 FVarLevel::getVertexEdgeValues(Index vIndex, Index valuesPerEdge[]) const {
888 
889     ConstIndexArray      vEdges  = _level.getVertexEdges(vIndex);
890     ConstLocalIndexArray vInEdge = _level.getVertexEdgeLocalIndices(vIndex);
891 
892     ConstIndexArray      vFaces  = _level.getVertexFaces(vIndex);
893     ConstLocalIndexArray vInFace = _level.getVertexFaceLocalIndices(vIndex);
894 
895     bool vIsBoundary = _level.getVertexTag(vIndex)._boundary;
896     bool vIsManifold = ! _level.getVertexTag(vIndex)._nonManifold;
897 
898     bool isBaseLevel = (_level.getDepth() == 0);
899 
900     for (int i = 0; i < vEdges.size(); ++i) {
901         Index           eIndex = vEdges[i];
902         ConstIndexArray eVerts = _level.getEdgeVertices(eIndex);
903 
904         //  Remember this method is for presumed continuous edges around the vertex:
905         assert(edgeTopologyMatches(eIndex));
906 
907         Index vOther = eVerts[!vInEdge[i]];
908         if (getNumVertexValues(vOther) == 1) {
909             valuesPerEdge[i] = isBaseLevel ? getVertexValue(vOther) : getVertexValueOffset(vOther);
910         } else if (vIsManifold) {
911             if (vIsBoundary && (i == (vEdges.size() - 1))) {
912                 ConstIndexArray fValues = getFaceValues(vFaces[i-1]);
913 
914                 int prevInFace = vInFace[i-1] ? (vInFace[i-1] - 1) : (fValues.size() - 1);
915                 valuesPerEdge[i] = fValues[prevInFace];
916             } else {
917                 ConstIndexArray fValues = getFaceValues(vFaces[i]);
918 
919                 int nextInFace = (vInFace[i] == (fValues.size() - 1)) ? 0 : (vInFace[i] + 1);
920                 valuesPerEdge[i] = fValues[nextInFace];
921             }
922         } else {
923             Index eFace0   = _level.getEdgeFaces(eIndex)[0];
924             int   eInFace0 = _level.getEdgeFaceLocalIndices(eIndex)[0];
925 
926             ConstIndexArray fVerts  = _level.getFaceVertices(eFace0);
927             ConstIndexArray fValues = getFaceValues(eFace0);
928             if (vOther == fVerts[eInFace0]) {
929                 valuesPerEdge[i] = fValues[eInFace0];
930             } else {
931                 int valueInFace = (eInFace0 == (fValues.size() - 1)) ? 0 : (eInFace0 + 1);
932                 valuesPerEdge[i] = fValues[valueInFace];
933             }
934         }
935     }
936 }
937 
938 //
939 //  Gather information about the "span" of faces for each value:
940 //
941 //  The "size" (number of faces in which each value occurs), is most immediately useful
942 //  in determining whether a value is a corner or smooth boundary, while other properties
943 //  such as the first face and whether or not the span is interrupted by discts, semi-
944 //  sharp or infinite edges, are useful to fully qualify smooth boundaries by the caller.
945 //
946 void
gatherValueSpans(Index vIndex,ValueSpan * vValueSpans) const947 FVarLevel::gatherValueSpans(Index vIndex, ValueSpan * vValueSpans) const {
948 
949     ConstIndexArray vEdges = _level.getVertexEdges(vIndex);
950     ConstIndexArray vFaces = _level.getVertexFaces(vIndex);
951 
952     ConstSiblingArray vFaceSiblings = getVertexFaceSiblings(vIndex);
953 
954     bool vHasSingleValue = (getNumVertexValues(vIndex) == 1);
955     bool vIsBoundary = vEdges.size() > vFaces.size();
956     bool vIsNonManifold = _level.getVertexTag(vIndex)._nonManifold;
957 
958     if (vIsNonManifold) {
959         //  This needs more work as spans around a non-manifold vertex may themselves be
960         //  manifold.  Just mark all spans with a discts edge for now to trigger them
961         //  non-manifold
962 
963         ConstIndexArray vValues = getVertexValues(vIndex);
964         for (int i = 0; i < vValues.size(); ++i) {
965             vValueSpans[i]._size = 0;
966             vValueSpans[i]._disctsEdgeCount = 1;
967         }
968     } else if (vHasSingleValue && !vIsBoundary) {
969         //  Mark an interior dart disjoint if more than one discts edge:
970         vValueSpans[0]._size  = 0;
971         vValueSpans[0]._start = 0;
972         for (int i = 0; i < vEdges.size(); ++i) {
973             if (_edgeTags[vEdges[i]]._mismatch) {
974                 if (vValueSpans[0]._size > 0) {
975                     vValueSpans[0]._disctsEdgeCount = 1;
976                     break;
977                 } else {
978                     vValueSpans[0]._size  = (LocalIndex) vFaces.size();
979                     vValueSpans[0]._start = (LocalIndex) i;
980                 }
981             } else if (_level.getEdgeTag(vEdges[i])._infSharp) {
982                 ++ vValueSpans[0]._infSharpEdgeCount;
983             } else if (_level.getEdgeTag(vEdges[i])._semiSharp) {
984                 ++ vValueSpans[0]._semiSharpEdgeCount;
985             }
986         }
987         vValueSpans[0]._size = (LocalIndex) vFaces.size();
988     } else {
989         //  Walk around the vertex and accumulate span info for each value -- be
990         //  careful about the span for the first value "wrapping" around:
991         vValueSpans[0]._size  = 1;
992         vValueSpans[0]._start = 0;
993         if (!vIsBoundary && (vFaceSiblings[vFaces.size() - 1] == 0)) {
994             if (_edgeTags[vEdges[0]]._mismatch) {
995                 ++ vValueSpans[0]._disctsEdgeCount;
996             } else if (_level.getEdgeTag(vEdges[0])._infSharp) {
997                 ++ vValueSpans[0]._infSharpEdgeCount;
998             } else if (_level.getEdgeTag(vEdges[0])._semiSharp) {
999                 ++ vValueSpans[0]._semiSharpEdgeCount;
1000             }
1001         }
1002         for (int i = 1; i < vFaces.size(); ++i) {
1003             if (vFaceSiblings[i] == vFaceSiblings[i-1]) {
1004                 if (_edgeTags[vEdges[i]]._mismatch) {
1005                     ++ vValueSpans[vFaceSiblings[i]]._disctsEdgeCount;
1006                 } else if (_level.getEdgeTag(vEdges[i])._infSharp) {
1007                     ++ vValueSpans[vFaceSiblings[i]]._infSharpEdgeCount;
1008                 } else if (_level.getEdgeTag(vEdges[i])._semiSharp) {
1009                     ++ vValueSpans[vFaceSiblings[i]]._semiSharpEdgeCount;
1010                 }
1011             } else {
1012                 //  If we have already set the span for this value, mark disjoint
1013                 if (vValueSpans[vFaceSiblings[i]]._size > 0) {
1014                     ++ vValueSpans[vFaceSiblings[i]]._disctsEdgeCount;
1015                 }
1016                 vValueSpans[vFaceSiblings[i]]._start = (LocalIndex) i;
1017             }
1018             ++ vValueSpans[vFaceSiblings[i]]._size;
1019         }
1020         //  If the span for value 0 has wrapped around, decrement the disjoint added
1021         //  at the interior edge where it started the closing part of the span:
1022         if ((vFaceSiblings[vFaces.size() - 1] == 0) && !vIsBoundary) {
1023             -- vValueSpans[0]._disctsEdgeCount;
1024         }
1025     }
1026 }
1027 
1028 //
1029 //  Methods to retrieve and combine value and vertex tags:
1030 //
1031 void
getFaceValueTags(Index faceIndex,ValueTag valueTags[]) const1032 FVarLevel::getFaceValueTags(Index faceIndex, ValueTag valueTags[]) const {
1033 
1034     ConstIndexArray faceValues = getFaceValues(faceIndex);
1035     ConstIndexArray faceVerts  = _level.getFaceVertices(faceIndex);
1036 
1037     for (int i = 0; i < faceValues.size(); ++i) {
1038         Index srcValueIndex = findVertexValueIndex(faceVerts[i], faceValues[i]);
1039         assert(_vertValueIndices[srcValueIndex] == faceValues[i]);
1040 
1041         valueTags[i] = _vertValueTags[srcValueIndex];
1042     }
1043 }
1044 
1045 FVarLevel::ValueTag
getFaceCompositeValueTag(Index faceIndex) const1046 FVarLevel::getFaceCompositeValueTag(Index faceIndex) const {
1047 
1048     ConstIndexArray faceValues = getFaceValues(faceIndex);
1049     ConstIndexArray faceVerts  = _level.getFaceVertices(faceIndex);
1050 
1051     typedef ValueTag::ValueTagSize ValueTagSize;
1052 
1053     ValueTagSize compInt = 0;
1054     for (int i = 0; i < faceValues.size(); ++i) {
1055         Index srcValueIndex = findVertexValueIndex(faceVerts[i], faceValues[i]);
1056         assert(_vertValueIndices[srcValueIndex] == faceValues[i]);
1057 
1058         ValueTag const &   srcTag = _vertValueTags[srcValueIndex];
1059         ValueTagSize const srcInt = srcTag.getBits();
1060 
1061         compInt |= srcInt;
1062     }
1063     return ValueTag(compInt);
1064 }
1065 
1066 } // end namespace internal
1067 } // end namespace Vtr
1068 
1069 } // end namespace OPENSUBDIV_VERSION
1070 } // end namespace OpenSubdiv
1071