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