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 #ifndef OPENSUBDIV3_VTR_FVAR_LEVEL_H
25 #define OPENSUBDIV3_VTR_FVAR_LEVEL_H
26 
27 #include "../version.h"
28 
29 #include "../sdc/types.h"
30 #include "../sdc/crease.h"
31 #include "../sdc/options.h"
32 #include "../vtr/types.h"
33 #include "../vtr/level.h"
34 
35 #include <vector>
36 #include <cassert>
37 #include <cstring>
38 
39 
40 namespace OpenSubdiv {
41 namespace OPENSUBDIV_VERSION {
42 
43 namespace Vtr {
44 namespace internal {
45 
46 //
47 //  FVarLevel:
48 //      A "face-varying channel" includes the topology for a set of face-varying
49 //  data, relative to the topology of the Level with which it is associated.
50 //
51 //  Analogous to a set of vertices and face-vertices that define the topology for
52 //  the geometry, a channel requires a set of "values" and "face-values".  The
53 //  "values" are indices of entries in a set of face-varying data, just as vertices
54 //  are indices into a set of vertex data.  The face-values identify a value for
55 //  each vertex of the face, and so define topology for the values that may be
56 //  unique to each channel.
57 //
58 //  In addition to the value size and the vector of face-values (which matches the
59 //  size of the geometry's face-vertices), tags are associated with each component
60 //  to identify deviations of the face-varying topology from the vertex topology.
61 //  And since there may be a one-to-many mapping between vertices and face-varying
62 //  values, that mapping is also allocated.
63 //
64 //  It turns out that the mapping used is able to completely encode the set of
65 //  face-values and is more amenable to refinement.  Currently the face-values
66 //  take up almost half the memory of this representation, so if memory does
67 //  become a concern, we do not need to store them.  The only reason we do so now
68 //  is that the face-value interface for specifying base topology and inspecting
69 //  subsequent levels is very familiar to that of face-vertices for clients.  So
70 //  having them available for such access is convenient.
71 //
72 //  Regarding scope and access...
73 //      Unclear at this early state, but leaning towards nesting this class within
74 //  Level, given the intimate dependency between the two.
75 //      Everything is being declared public for now to facilitate access until it's
76 //  clearer how this functionality will be provided.
77 //
78 class FVarLevel {
79 public:
80     //
81     //  Component tags -- trying to minimize the types needed here:
82     //
83     //  Tag per Edge:
84     //      - facilitates topological analysis around each vertex
85     //      - required during refinement to spawn one or more edge-values
86     //
87     struct ETag {
ETagETag88         ETag() { }
89 
clearETag90         void clear() { std::memset(this, 0, sizeof(ETag)); }
91 
92         typedef unsigned char ETagSize;
93 
94         ETagSize _mismatch : 1;  // local FVar topology does not match
95         ETagSize _disctsV0 : 1;  // discontinuous at vertex 0
96         ETagSize _disctsV1 : 1;  // discontinuous at vertex 1
97         ETagSize _linear   : 1;  // linear boundary constraints
98 
99         Level::ETag combineWithLevelETag(Level::ETag) const;
100     };
101 
102     //
103     //  Tag per Value:
104     //      - informs both refinement and interpolation
105     //          - every value spawns a child value in refinement
106     //      - includes a subset of Level::VTag to be later combined with a VTag
107     //
108     struct ValueTag {
ValueTagValueTag109         ValueTag() { }
110 
clearValueTag111         void clear() { std::memset(this, 0, sizeof(ValueTag)); }
112 
isMismatchValueTag113         bool isMismatch() const    { return _mismatch; }
isCreaseValueTag114         bool isCrease() const      { return _crease; }
isCornerValueTag115         bool isCorner() const      { return !_crease; }
isSemiSharpValueTag116         bool isSemiSharp() const   { return _semiSharp; }
isInfSharpValueTag117         bool isInfSharp() const    { return !_semiSharp && !_crease; }
isDepSharpValueTag118         bool isDepSharp() const    { return _depSharp; }
hasCreaseEndsValueTag119         bool hasCreaseEnds() const { return _crease || _semiSharp; }
120 
hasInfSharpEdgesValueTag121         bool hasInfSharpEdges() const   { return _infSharpEdges; }
hasInfIrregularityValueTag122         bool hasInfIrregularity() const { return _infIrregular; }
123 
124         typedef unsigned char ValueTagSize;
125 
126         //  If there is no mismatch, no other members should be inspected
127         ValueTagSize _mismatch    : 1;  // local FVar topology does not match
128         ValueTagSize _xordinary   : 1;  // local FVar topology is extra-ordinary
129         ValueTagSize _nonManifold : 1;  // local FVar topology is non-manifold
130         ValueTagSize _crease      : 1;  // value is a crease, otherwise a corner
131         ValueTagSize _semiSharp   : 1;  // value is a corner decaying to crease
132         ValueTagSize _depSharp    : 1;  // value is a corner by dependency on another
133 
134         ValueTagSize _infSharpEdges : 1;  // value is a corner by inf-sharp features
135         ValueTagSize _infIrregular  : 1;  // value span includes inf-sharp irregularity
136 
137         Level::VTag combineWithLevelVTag(Level::VTag) const;
138 
139         //  Alternate constructor and accessor for dealing with integer bits directly:
ValueTagValueTag140         explicit ValueTag(ValueTagSize bits) {
141             std::memcpy(this, &bits, sizeof(bits));
142         }
getBitsValueTag143         ValueTagSize getBits() const {
144             ValueTagSize bits;
145             std::memcpy(&bits, this, sizeof(bits));
146             return bits;
147         }
148     };
149 
150     typedef Vtr::ConstArray<ValueTag> ConstValueTagArray;
151     typedef Vtr::Array<ValueTag> ValueTagArray;
152 
153     //
154     //  Simple struct containing the "end faces" of a crease, i.e. the faces which
155     //  contain the FVar values to be used when interpolating the crease.  (Prefer
156     //  the struct over std::pair for its member names)
157     //
158     struct CreaseEndPair {
159         LocalIndex _startFace;
160         LocalIndex _endFace;
161     };
162 
163     typedef Vtr::ConstArray<CreaseEndPair> ConstCreaseEndPairArray;
164     typedef Vtr::Array<CreaseEndPair> CreaseEndPairArray;
165 
166     typedef LocalIndex      Sibling;
167 
168     typedef ConstLocalIndexArray ConstSiblingArray;
169     typedef LocalIndexArray SiblingArray;
170 
171 public:
172     FVarLevel(Level const& level);
173     ~FVarLevel();
174 
175     //  Queries for the entire channel:
getLevel()176     Level const& getLevel() const { return _level; }
177 
getNumValues()178     int getNumValues() const          { return _valueCount; }
getNumFaceValuesTotal()179     int getNumFaceValuesTotal() const { return (int) _faceVertValues.size(); }
180 
isLinear()181     bool isLinear() const            { return _isLinear; }
hasLinearBoundaries()182     bool hasLinearBoundaries() const { return _hasLinearBoundaries; }
hasSmoothBoundaries()183     bool hasSmoothBoundaries() const { return ! _hasLinearBoundaries; }
hasCreaseEnds()184     bool hasCreaseEnds() const       { return hasSmoothBoundaries(); }
185 
getOptions()186     Sdc::Options getOptions() const { return _options; }
187 
188     //  Queries per face:
189     ConstIndexArray  getFaceValues(Index fIndex) const;
190     IndexArray       getFaceValues(Index fIndex);
191 
192     //  Queries per edge:
getEdgeTag(Index eIndex)193     ETag getEdgeTag(Index eIndex) const          { return _edgeTags[eIndex]; }
edgeTopologyMatches(Index eIndex)194     bool edgeTopologyMatches(Index eIndex) const { return !getEdgeTag(eIndex)._mismatch; }
195 
196     //  Queries per vertex (and its potential sibling values):
getNumVertexValues(Index v)197     int   getNumVertexValues(Index v) const                  { return _vertSiblingCounts[v]; }
198     Index getVertexValueOffset(Index v, Sibling i = 0) const { return _vertSiblingOffsets[v] + i; }
199 
200     Index getVertexValue(Index v, Sibling i = 0) const { return _vertValueIndices[getVertexValueOffset(v,i)]; }
201 
202     Index findVertexValueIndex(Index vertexIndex, Index valueIndex) const;
203 
204     //  Methods to access/modify array properties per vertex:
205     ConstIndexArray  getVertexValues(Index vIndex) const;
206     IndexArray       getVertexValues(Index vIndex);
207 
208     ConstValueTagArray  getVertexValueTags(Index vIndex) const;
209     ValueTagArray       getVertexValueTags(Index vIndex);
210 
211     ConstCreaseEndPairArray  getVertexValueCreaseEnds(Index vIndex) const;
212     CreaseEndPairArray       getVertexValueCreaseEnds(Index vIndex);
213 
214     ConstSiblingArray  getVertexFaceSiblings(Index vIndex) const;
215     SiblingArray       getVertexFaceSiblings(Index vIndex);
216 
217     //  Queries per value:
getValueTag(Index valueIndex)218     ValueTag getValueTag(Index valueIndex) const          { return _vertValueTags[valueIndex]; }
valueTopologyMatches(Index valueIndex)219     bool     valueTopologyMatches(Index valueIndex) const { return !getValueTag(valueIndex)._mismatch; }
220 
getValueCreaseEndPair(Index valueIndex)221     CreaseEndPair getValueCreaseEndPair(Index valueIndex) const { return _vertValueCreaseEnds[valueIndex]; }
222 
223     //  Tag queries related to faces (use Level methods for those returning Level::VTag/ETag)
224     void getFaceValueTags(Index faceIndex, ValueTag valueTags[]) const;
225 
226     ValueTag getFaceCompositeValueTag(Index faceIndex) const;
227 
228     //  Higher-level topological queries, i.e. values in a neighborhood:
229     void getEdgeFaceValues(Index eIndex, int fIncToEdge, Index valuesPerVert[2]) const;
230     void getVertexEdgeValues(Index vIndex, Index valuesPerEdge[]) const;
231     void getVertexCreaseEndValues(Index vIndex, Sibling sibling, Index endValues[2]) const;
232 
233     //  Initialization and allocation helpers:
234     void setOptions(Sdc::Options const& options);
235     void resizeVertexValues(int numVertexValues);
236     void resizeValues(int numValues);
237     void resizeComponents();
238 
239     //  Topological analysis methods -- tagging and face-value population:
240     void completeTopologyFromFaceValues(int regBoundaryValence);
241     void initializeFaceValuesFromFaceVertices();
242     void initializeFaceValuesFromVertexFaceSiblings();
243 
244     struct ValueSpan;
245     void gatherValueSpans(Index vIndex, ValueSpan * vValueSpans) const;
246 
247     //  Debugging methods:
248     bool validate() const;
249     void print() const;
250     void buildFaceVertexSiblingsFromVertexFaceSiblings(std::vector<Sibling>& fvSiblings) const;
251 
252 private:
253     //  Just as Refinements build Levels, FVarRefinements build FVarLevels...
254     friend class FVarRefinement;
255 
256     Level const & _level;
257 
258     //  Linear interpolation options vary between channels:
259     Sdc::Options _options;
260 
261     bool _isLinear;
262     bool _hasLinearBoundaries;
263     bool _hasDependentSharpness;
264     int  _valueCount;
265 
266     //
267     //  Vectors recording face-varying topology including tags that help propagate
268     //  data through the refinement hierarchy.  Vectors are not sparse but most use
269     //  8-bit values relative to the local topology.
270     //
271     //  The vector of face-values is actually redundant here, but is constructed as
272     //  it is most convenient for clients.  It represents almost half the memory of
273     //  the topology (4 32-bit integers per face) and not surprisingly, populating
274     //  it takes a considerable amount of the refinement time (1/3).  We can reduce
275     //  both if we are willing to compute these on demand for clients.
276     //
277     //  Per-face (matches face-verts of corresponding level):
278     std::vector<Index> _faceVertValues;
279 
280     //  Per-edge:
281     std::vector<ETag> _edgeTags;
282 
283     //  Per-vertex:
284     std::vector<Sibling>  _vertSiblingCounts;
285     std::vector<int>      _vertSiblingOffsets;
286     std::vector<Sibling>  _vertFaceSiblings;
287 
288     //  Per-value:
289     std::vector<Index>         _vertValueIndices;
290     std::vector<ValueTag>      _vertValueTags;
291     std::vector<CreaseEndPair> _vertValueCreaseEnds;
292 };
293 
294 //
295 //  Access/modify the values associated with each face:
296 //
297 inline ConstIndexArray
getFaceValues(Index fIndex)298 FVarLevel::getFaceValues(Index fIndex) const {
299 
300     int vCount  = _level.getNumFaceVertices(fIndex);
301     int vOffset = _level.getOffsetOfFaceVertices(fIndex);
302     return ConstIndexArray(&_faceVertValues[vOffset], vCount);
303 }
304 inline IndexArray
getFaceValues(Index fIndex)305 FVarLevel::getFaceValues(Index fIndex) {
306 
307     int vCount  = _level.getNumFaceVertices(fIndex);
308     int vOffset = _level.getOffsetOfFaceVertices(fIndex);
309     return IndexArray(&_faceVertValues[vOffset], vCount);
310 }
311 
312 inline FVarLevel::ConstSiblingArray
getVertexFaceSiblings(Index vIndex)313 FVarLevel::getVertexFaceSiblings(Index vIndex) const {
314 
315     int vCount  = _level.getNumVertexFaces(vIndex);
316     int vOffset = _level.getOffsetOfVertexFaces(vIndex);
317     return ConstSiblingArray(&_vertFaceSiblings[vOffset], vCount);
318 }
319 inline FVarLevel::SiblingArray
getVertexFaceSiblings(Index vIndex)320 FVarLevel::getVertexFaceSiblings(Index vIndex) {
321 
322     int vCount  = _level.getNumVertexFaces(vIndex);
323     int vOffset = _level.getOffsetOfVertexFaces(vIndex);
324     return SiblingArray(&_vertFaceSiblings[vOffset], vCount);
325 }
326 
327 inline ConstIndexArray
getVertexValues(Index vIndex)328 FVarLevel::getVertexValues(Index vIndex) const
329 {
330     int vCount  = getNumVertexValues(vIndex);
331     int vOffset = getVertexValueOffset(vIndex);
332     return ConstIndexArray(&_vertValueIndices[vOffset], vCount);
333 }
334 inline IndexArray
getVertexValues(Index vIndex)335 FVarLevel::getVertexValues(Index vIndex)
336 {
337     int vCount  = getNumVertexValues(vIndex);
338     int vOffset = getVertexValueOffset(vIndex);
339     return IndexArray(&_vertValueIndices[vOffset], vCount);
340 }
341 
342 inline FVarLevel::ConstValueTagArray
getVertexValueTags(Index vIndex)343 FVarLevel::getVertexValueTags(Index vIndex) const
344 {
345     int vCount  = getNumVertexValues(vIndex);
346     int vOffset = getVertexValueOffset(vIndex);
347     return ConstValueTagArray(&_vertValueTags[vOffset], vCount);
348 }
349 inline FVarLevel::ValueTagArray
getVertexValueTags(Index vIndex)350 FVarLevel::getVertexValueTags(Index vIndex)
351 {
352     int vCount  = getNumVertexValues(vIndex);
353     int vOffset = getVertexValueOffset(vIndex);
354     return ValueTagArray(&_vertValueTags[vOffset], vCount);
355 }
356 
357 inline FVarLevel::ConstCreaseEndPairArray
getVertexValueCreaseEnds(Index vIndex)358 FVarLevel::getVertexValueCreaseEnds(Index vIndex) const
359 {
360     int vCount  = getNumVertexValues(vIndex);
361     int vOffset = getVertexValueOffset(vIndex);
362     return ConstCreaseEndPairArray(&_vertValueCreaseEnds[vOffset], vCount);
363 }
364 inline FVarLevel::CreaseEndPairArray
getVertexValueCreaseEnds(Index vIndex)365 FVarLevel::getVertexValueCreaseEnds(Index vIndex)
366 {
367     int vCount  = getNumVertexValues(vIndex);
368     int vOffset = getVertexValueOffset(vIndex);
369     return CreaseEndPairArray(&_vertValueCreaseEnds[vOffset], vCount);
370 }
371 
372 inline Index
findVertexValueIndex(Index vertexIndex,Index valueIndex)373 FVarLevel::findVertexValueIndex(Index vertexIndex, Index valueIndex) const {
374 
375     if (_level.getDepth() > 0) return valueIndex;
376 
377     Index vvIndex = getVertexValueOffset(vertexIndex);
378     while (_vertValueIndices[vvIndex] != valueIndex) {
379         ++ vvIndex;
380     }
381     return vvIndex;
382 }
383 
384 //
385 //  Methods related to tagging:
386 //
387 inline Level::ETag
combineWithLevelETag(Level::ETag levelTag)388 FVarLevel::ETag::combineWithLevelETag(Level::ETag levelTag) const
389 {
390     if (this->_mismatch) {
391         levelTag._boundary = true;
392         levelTag._infSharp = true;
393     }
394     return levelTag;
395 }
396 inline Level::VTag
combineWithLevelVTag(Level::VTag levelTag)397 FVarLevel::ValueTag::combineWithLevelVTag(Level::VTag levelTag) const
398 {
399     if (this->_mismatch) {
400         //
401         //  Semi-sharp FVar values are always tagged and treated as corners
402         //  (at least three sharp edges (two boundary edges and one interior
403         //  semi-sharp) and/or vertex is semi-sharp) until the sharpness has
404         //  decayed, but they ultimately lie on the inf-sharp crease of the
405         //  FVar boundary.  Consider this when tagging inf-sharp features.
406         //
407         if (this->isCorner()) {
408             levelTag._rule = (Level::VTag::VTagSize) Sdc::Crease::RULE_CORNER;
409         } else {
410             levelTag._rule = (Level::VTag::VTagSize) Sdc::Crease::RULE_CREASE;
411         }
412         if (this->isCrease() || this->isSemiSharp()) {
413             levelTag._infSharp = false;
414             levelTag._infSharpCrease = true;
415             levelTag._corner = false;
416         } else {
417             levelTag._infSharp = true;
418             levelTag._infSharpCrease = false;
419             levelTag._corner = !this->_infIrregular && !this->_infSharpEdges;
420         }
421         levelTag._infSharpEdges = true;
422         levelTag._infIrregular = this->_infIrregular;
423 
424         levelTag._boundary = true;
425         levelTag._xordinary = this->_xordinary;
426 
427         levelTag._nonManifold |= this->_nonManifold;
428     }
429     return levelTag;
430 }
431 
432 } // end namespace internal
433 } // end namespace Vtr
434 
435 } // end namespace OPENSUBDIV_VERSION
436 using namespace OPENSUBDIV_VERSION;
437 } // end namespace OpenSubdiv
438 
439 #endif /* OPENSUBDIV3_VTR_FVAR_LEVEL_H */
440