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