1 //
2 //   Copyright 2017 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 
25 #ifndef OPENSUBDIV3_FAR_PATCH_BUILDER_H
26 #define OPENSUBDIV3_FAR_PATCH_BUILDER_H
27 
28 #include "../version.h"
29 
30 #include "../sdc/types.h"
31 #include "../far/types.h"
32 #include "../far/topologyRefiner.h"
33 #include "../far/patchDescriptor.h"
34 #include "../far/patchParam.h"
35 #include "../far/ptexIndices.h"
36 #include "../far/sparseMatrix.h"
37 
38 
39 namespace OpenSubdiv {
40 namespace OPENSUBDIV_VERSION {
41 
42 namespace Far {
43 
44 //
45 //  SourcePatch
46 //
47 //  This is a local utility class that captures the full local topology of an
48 //  arbitrarily irregular patch, i.e. a patch which may have one or all corners
49 //  irregular.  Given the topology at each corner the entire collection of
50 //  points involved is identified and oriented consistently.
51 //
52 //  Note (barfowl):
53 //      This was originally a class internal to PatchBuilder, but there is some
54 //  redundancy between it and the Level::VSpan used more publicly to identify
55 //  irregular corner topology.   Replacing VSpan with SourcePatch is now under
56 //  consideration, and doing so will impact its public/private interface (which
57 //  was left public to give PatchBuilder access).
58 //      A simpler constructor to initialize an instance given a set of Corners
59 //  would also be preferable if made more public (i.e. public for use within
60 //  the library, not exported to clients) -- eliminating the need for the
61 //  explicit initialization and required call to the Finalize() method that
62 //  the PatchBuilder currently performs internally.
63 //
64 class SourcePatch {
65 public:
66     struct Corner {
CornerCorner67         Corner() { std::memset(this, 0, sizeof(Corner)); }
68 
69         LocalIndex _numFaces;   // valence of corner vertex
70         LocalIndex _patchFace;  // location of patch within incident faces
71 
72         unsigned short _boundary : 1;
73         unsigned short _sharp    : 1;
74         unsigned short _dart     : 1;
75 
76         //  For internal bookkeeping -- consider hiding or moving elsewhere
77         unsigned short _sharesWithPrev : 1;
78         unsigned short _sharesWithNext : 1;
79         unsigned short _val2Interior   : 1;
80         unsigned short _val2Adjacent   : 1;
81     };
82 
83 public:
SourcePatch()84     SourcePatch() { std::memset(this, 0, sizeof(SourcePatch)); }
~SourcePatch()85     ~SourcePatch() { }
86 
87     //  To be called after all Corners have been initialized (hope to
88     //  replace this with alternative constructor at some point)
89     void Finalize(int size3or4);
90 
GetNumSourcePoints()91     int GetNumSourcePoints() const { return _numSourcePoints; }
GetMaxValence()92     int GetMaxValence() const { return _maxValence; }
GetMaxRingSize()93     int GetMaxRingSize() const { return _maxRingSize; }
94 
GetCornerRingSize(int corner)95     int GetCornerRingSize(int corner) const { return _ringSizes[corner]; }
96     int GetCornerRingPoints(int corner, int points[]) const;
97 
98 //  public/private access needs to be reviewed when/if used more publicly
99 //private:
100 public:
101     //  The SourcePatch is fully defined by its Corner members
102     Corner _corners[4];
103     int    _numCorners;
104 
105     //  Additional members (derived from Corners) to help assemble corner rings:
106     int _numSourcePoints;
107     int _maxValence;
108     int _maxRingSize;
109 
110     int _ringSizes[4];
111     int _localRingSizes[4];
112     int _localRingOffsets[4];
113 };
114 
115 
116 //
117 //  PatchBuilder
118 //
119 //  This is the main class to assist the identification of limit surface
120 //  patches from faces in a TopologyRefiner for assembly into other, larger
121 //  datatypes.
122 //
123 //  The PatchBuilder takes a const reference to a refiner and supports
124 //  arbitrarily refined hierarchies, i.e. it is not restricted to uniform or
125 //  adaptive refinement strategies and does not include any logic relating
126 //  to the origin of the hierarchy.  It can associate a patch with any face
127 //  in the hierarchy (subject to a few minimum requirements) -- leaving the
128 //  decision as to which faces/patches are appropriate to its client.
129 //
130 //  PatchBuilder is an abstract base class with a subclass derived to support
131 //  each subdivision scheme -- as such, construction relies on a factory
132 //  method to create an instance of the appropriate subclass.  Only two pure
133 //  virtual methods are required (other than the required destructor):
134 //
135 //      - determine the patch type for a subdivision scheme given a more
136 //        general basis specification (e.g. Bezier, Gregory, Linear, etc)
137 //
138 //      - convert the vertices in the subdivision hierarchy into points of a
139 //        specified patch type, using computations specific to that scheme
140 //
141 //  The base class handles the more general topological analysis that
142 //  determines the nature of a patch associated with each face -- providing
143 //  both queries to the client, along with more involved methods to extract
144 //  or convert data associated with the patches.  There is no concrete "Patch"
145 //  class to which all clients would be required to conform.  The queries and
146 //  data returned are provided for clients to assemble into patches or other
147 //  aggregates as they see fit.
148 //
149 //  This is intended as an internal/private class for use within the library
150 //  for now -- possibly to be exported for use by clients when/if its
151 //  interface is appropriate and stable.
152 //
153 class PatchBuilder {
154 public:
155     //
156     //  A PatchBuilder is constructed given a patch "basis" rather than a
157     //  "type" to use with the subdivision scheme involved.  The relevant
158     //  explicit patch types will be determined from the basis and scheme:
159     //
160     enum BasisType {
161         BASIS_UNSPECIFIED,
162         BASIS_REGULAR,
163         BASIS_GREGORY,
164         BASIS_LINEAR,
165         BASIS_BEZIER   // to be supported in future
166     };
167 
168     //
169     //  Required Options specify a patch basis to use for both regular and
170     //  irregular patches -- sparing the client the need to repeatedly
171     //  specify these for each face considered.  Other options are included
172     //  to support legacy approximations:
173     //
174     struct Options {
OptionsOptions175         Options() : regBasisType(BASIS_UNSPECIFIED),
176                     irregBasisType(BASIS_UNSPECIFIED),
177                     fillMissingBoundaryPoints(false),
178                     approxInfSharpWithSmooth(false),
179                     approxSmoothCornerWithSharp(false) { }
180 
181         BasisType regBasisType;
182         BasisType irregBasisType;
183         bool      fillMissingBoundaryPoints;
184         bool      approxInfSharpWithSmooth;
185         bool      approxSmoothCornerWithSharp;
186     };
187 
188 public:
189     //
190     //  Public construction (via factory method) and destruction:
191     //
192     static PatchBuilder* Create(TopologyRefiner const& refiner,
193                                 Options const& options);
194     virtual ~PatchBuilder();
195 
196     //
197     //  High-level queries related to the subdivision scheme of the refiner, the
198     //  patch types associated with it and those chosen to represent its faces:
199     //
GetRegularFaceSize()200     int GetRegularFaceSize() const { return _schemeRegFaceSize; }
201 
GetRegularBasisType()202     BasisType GetRegularBasisType() const { return _options.regBasisType; }
GetIrregularBasisType()203     BasisType GetIrregularBasisType() const { return _options.irregBasisType; }
204 
GetRegularPatchType()205     PatchDescriptor::Type GetRegularPatchType() const { return _regPatchType; }
GetIrregularPatchType()206     PatchDescriptor::Type GetIrregularPatchType() const { return _irregPatchType; }
207 
GetNativePatchType()208     PatchDescriptor::Type GetNativePatchType() const { return _nativePatchType; }
GetLinearPatchType()209     PatchDescriptor::Type GetLinearPatchType() const { return _linearPatchType; }
210 
211     //
212     //  Face-level queries to determine presence of patches:
213     //
214     bool IsFaceAPatch(int level, Index face) const;
215     bool IsFaceALeaf(int level, Index face) const;
216 
217     //
218     //  Patch-level topological queries:
219     //
220     bool IsPatchRegular(int level, Index face, int fvc = -1) const;
221 
222     int GetRegularPatchBoundaryMask(int level, Index face, int fvc = -1) const;
223 
224     void GetIrregularPatchCornerSpans(int level, Index face,
225             Vtr::internal::Level::VSpan cornerSpans[4], int fvc = -1) const;
226 
DoesFaceVaryingPatchMatch(int level,Index face,int fvc)227     bool DoesFaceVaryingPatchMatch(int level, Index face, int fvc) const {
228         return _refiner.getLevel(level).doesFaceFVarTopologyMatch(face, fvc);
229     }
230 
231     //
232     //  Patch-level control point retrieval and methods for converting source
233     //  points to a set of local points in a different basis
234     //
235     int GetRegularPatchPoints(int level, Index face,
236             int regBoundaryMask, // compute internally when < 0
237             Index patchPoints[],
238             int fvc = -1) const;
239 
240     template <typename REAL>
241     int GetIrregularPatchConversionMatrix(int level, Index face,
242             Vtr::internal::Level::VSpan const cornerSpans[],
243             SparseMatrix<REAL> &              matrix) const;
244 
245     int GetIrregularPatchSourcePoints(int level, Index face,
246             Vtr::internal::Level::VSpan const cornerSpans[],
247             Index                             sourcePoints[],
248             int                               fvc = -1) const;
249     //
250     //  Queries related to "single-crease" patches -- currently a subset of
251     //  regular interior patches:
252     //
253     struct SingleCreaseInfo {
254         int   creaseEdgeInFace;
255         float creaseSharpness;
256     };
257     bool IsRegularSingleCreasePatch(int level, Index face,
258             SingleCreaseInfo & info) const;
259 
260     //
261     //  Computing the PatchParam -- note the regrettable dependency on
262     //  PtexIndices but PatchParam is essentially tied to it indefinitely.
263     //  Better to pass it in than have the PatchBuilder build its own
264     //  PtexIndices.
265     //
266     //  Consider creating a PatchParamFactory which can manage the PtexIndices
267     //  along with this method.  It will then be able to generate additional
268     //  data to accelerate these computations.
269     //
270     PatchParam ComputePatchParam(int level, Index face,
271             PtexIndices const& ptexIndices, bool isRegular = true,
272             int boundaryMask = 0, bool computeTransitionMask = false) const;
273 
274 protected:
275     PatchBuilder(TopologyRefiner const& refiner, Options const& options);
276 
277     //  Internal methods supporting topology queries:
278     int getRegularFacePoints(int level, Index face,
279             Index patchPoints[], int fvc) const;
280 
281     int getQuadRegularPatchPoints(int level, Index face,
282             int regBoundaryMask, Index patchPoints[], int fvc) const;
283 
284     int getTriRegularPatchPoints(int level, Index face,
285             int regBoundaryMask, Index patchPoints[], int fvc) const;
286 
287     //  Internal methods using the SourcePatch:
288     int assembleIrregularSourcePatch(int level, Index face,
289             Vtr::internal::Level::VSpan const cornerSpans[],
290             SourcePatch & sourcePatch) const;
291 
292     int gatherIrregularSourcePoints(int level, Index face,
293             Vtr::internal::Level::VSpan const cornerSpans[],
294             SourcePatch &  sourcePatch,
295             Index patchPoints[], int fvc) const;
296 
297 protected:
298     //
299     //  Virtual methods to be provided by subclass for each scheme:
300     //
301     virtual PatchDescriptor::Type patchTypeFromBasis(BasisType basis) const = 0;
302 
303     //  Note overloading of the conversion for SparseMatrix<REAL>:
304     virtual int convertToPatchType(SourcePatch const &   sourcePatch,
305                                    PatchDescriptor::Type patchType,
306                                    SparseMatrix<float> & matrix) const = 0;
307     virtual int convertToPatchType(SourcePatch const &    sourcePatch,
308                                    PatchDescriptor::Type  patchType,
309                                    SparseMatrix<double> & matrix) const = 0;
310 
311 protected:
312     TopologyRefiner const& _refiner;
313     Options const          _options;
314 
315     Sdc::SchemeType _schemeType;
316     int             _schemeRegFaceSize;
317     bool            _schemeIsLinear;
318 
319     PatchDescriptor::Type _regPatchType;
320     PatchDescriptor::Type _irregPatchType;
321     PatchDescriptor::Type _nativePatchType;
322     PatchDescriptor::Type _linearPatchType;
323 };
324 
325 } // end namespace Far
326 
327 } // end namespace OPENSUBDIV_VERSION
328 using namespace OPENSUBDIV_VERSION;
329 
330 } // end namespace OpenSubdiv
331 
332 #endif /* OPENSUBDIV3_FAR_PATCH_BUILDER_H */
333