1 //
2 //   Copyright 2013 Pixar
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 "../far/patchTableFactory.h"
25 #include "../far/patchBuilder.h"
26 #include "../far/error.h"
27 #include "../far/ptexIndices.h"
28 #include "../far/topologyRefiner.h"
29 #include "../vtr/level.h"
30 #include "../vtr/fvarLevel.h"
31 #include "../vtr/refinement.h"
32 #include "../vtr/stackBuffer.h"
33 
34 #include <algorithm>
35 #include <cassert>
36 #include <cstring>
37 
38 #include <cstdio>
39 
40 namespace OpenSubdiv {
41 namespace OPENSUBDIV_VERSION {
42 namespace Far {
43 
44 using Vtr::Array;
45 using Vtr::ConstArray;
46 using Vtr::IndexVector;
47 using Vtr::internal::Level;
48 using Vtr::internal::StackBuffer;
49 
50 namespace {
51     //
52     //  Helpers for compiler warnings and floating point equality tests
53     //
54 #ifdef __INTEL_COMPILER
55 #pragma warning (push)
56 #pragma warning disable 1572
57 #endif
isSharpnessEqual(float s1,float s2)58     inline bool isSharpnessEqual(float s1, float s2) { return (s1 == s2); }
59 #ifdef __INTEL_COMPILER
60 #pragma warning (pop)
61 #endif
62 
63     inline int
assignSharpnessIndex(float sharpness,std::vector<float> & sharpnessValues)64     assignSharpnessIndex(float sharpness, std::vector<float> & sharpnessValues) {
65 
66         // linear search
67         for (int i=0; i<(int)sharpnessValues.size(); ++i) {
68             if (isSharpnessEqual(sharpnessValues[i], sharpness)) {
69                 return i;
70             }
71         }
72         sharpnessValues.push_back(sharpness);
73         return (int)sharpnessValues.size()-1;
74     }
75 
76     inline bool
isBoundaryFace(Level const & level,Index face)77     isBoundaryFace(Level const & level, Index face) {
78 
79         return (level.getFaceCompositeVTag(face)._boundary != 0);
80     }
81 
82     inline void
offsetIndices(Index indices[],int size,int offset)83     offsetIndices(Index indices[], int size, int offset) {
84 
85         for (int i = 0; i < size; ++i) {
86             indices[i] += offset;
87         }
88     }
89 } // namespace anon
90 
91 
92 //
93 //  The main PatchTableBuilder class with context
94 //
95 //  Helper class aggregating transient contextual data structures during the
96 //  creation of a patch table.  This helps keeping the factory class stateless.
97 //
98 class PatchTableBuilder {
99 public:
100     //
101     //  Public interface intended for use by the PatchTableFactory -- all
102     //  else is solely for internal use:
103     //
104     typedef PatchTableFactory::Options Options;
105 
106     PatchTableBuilder(TopologyRefiner const & refiner, Options options,
107                       ConstIndexArray selectedFaces);
108     ~PatchTableBuilder();
109 
UniformPolygonsSpecified() const110     bool UniformPolygonsSpecified() const { return _buildUniformLinear; }
111 
112     void BuildUniformPolygons();
113     void BuildPatches();
114 
GetPatchTable() const115     PatchTable * GetPatchTable() const { return _table; };
116 
117 private:
118     typedef PatchTable::StencilTablePtr StencilTablePtr;
119 
120     //  Simple struct to store <face,level> pair for a patch:
121     struct PatchTuple {
PatchTupleOpenSubdiv::OPENSUBDIV_VERSION::Far::PatchTableBuilder::PatchTuple122         PatchTuple(Index face, int level) : faceIndex(face), levelIndex(level) { }
123 
124         Index faceIndex;
125         int   levelIndex;
126     };
127     typedef std::vector<PatchTuple> PatchTupleVector;
128 
129     //  Struct comprising a collection of topological properties for a patch that
130     //  may be shared (between vertex and face-varying patches):
131     struct PatchInfo {
PatchInfoOpenSubdiv::OPENSUBDIV_VERSION::Far::PatchTableBuilder::PatchInfo132         PatchInfo() : isRegular(false), isRegSingleCrease(false),
133                       regBoundaryMask(0), regSharpness(0.0f),
134                       paramBoundaryMask(0) { }
135 
136         bool         isRegular;
137         bool         isRegSingleCrease;
138         int          regBoundaryMask;
139         float        regSharpness;
140         Level::VSpan irregCornerSpans[4];
141         int          paramBoundaryMask;
142 
143         SparseMatrix<float>  fMatrix;
144         SparseMatrix<double> dMatrix;
145     };
146 
147 private:
148     //
149     //  Internal LocalPointHelper class
150     //
151     //  A LocalPointHelper manages the number, sharing of and StencilTable for
152     //  the local points of a patch or one of its face-varying channels.  An
153     //  instance of the helper does not know anything about the properties of
154     //  the Builder classes that use it.  It can combine local points for any
155     //  patch types all in one, so the regular and irregular patch types can
156     //  both be local and differ, e.g. Bezier for regular and Gregory for
157     //  irregular, and points can be effectively shared, appropriate stencils
158     //  created, etc.
159     //
160     //  While not dependent on a particular patch type, some methods do require
161     //  a patch type argument in order to know what can be done with its local
162     //  points, e.g. which points can be shared with adjacent patches.
163     //
164     class LocalPointHelper {
165     public:
166         struct Options {
OptionsOpenSubdiv::OPENSUBDIV_VERSION::Far::PatchTableBuilder::LocalPointHelper::Options167             Options() : shareLocalPoints(false),
168                         reuseSourcePoints(false),
169                         createStencilTable(true),
170                         createVaryingTable(false),
171                         doubleStencilTable(false) { }
172 
173             unsigned int shareLocalPoints   : 1;
174             unsigned int reuseSourcePoints  : 1;
175             unsigned int createStencilTable : 1;
176             unsigned int createVaryingTable : 1;
177             unsigned int doubleStencilTable : 1;
178         };
179 
180     public:
181         LocalPointHelper(TopologyRefiner const & refiner,
182                          Options const & options,
183                          int fvarChannel,
184                          int numLocalPointsExpected);
185         ~LocalPointHelper();
186 
187     public:
GetNumLocalPoints() const188         int GetNumLocalPoints() const { return _numLocalPoints; }
189 
190         template <typename REAL>
191         int AppendLocalPatchPoints(int levelIndex, Index faceIndex,
192                                    SparseMatrix<REAL> const &  conversionMatrix,
193                                    PatchDescriptor::Type       patchType,
194                                    Index const                 sourcePoints[],
195                                    int                         sourcePointOffset,
196                                    Index                       patchPoints[]);
197 
AcquireStencilTable()198         StencilTablePtr AcquireStencilTable() {
199             return _options.doubleStencilTable
200                 ? acquireStencilTable<double>(_stencilTable)
201                 : acquireStencilTable<float>(_stencilTable);
202         }
203 
204     private:
205         //  Internal methods:
206         template <typename REAL>
207         void initializeStencilTable(int numLocalPointsExpected);
208 
209         template <typename REAL>
210         void appendLocalPointStencil(SparseMatrix<REAL> const &  conversionMatrix,
211                                      int                         stencilRow,
212                                      Index const                 sourcePoints[],
213                                      int                         sourcePointOffset);
214 
215         template <typename REAL>
216         void appendLocalPointStencils(SparseMatrix<REAL> const &  conversionMatrix,
217                                       Index const                 sourcePoints[],
218                                       int                         sourcePointOffset);
219 
220         //  Methods for local point Varying stencils
221         //      XXXX -- hope to get rid of these...
222         template <typename REAL>
223         void appendLocalPointVaryingStencil(int const *  varyingIndices,
224                                             int          patchPointIndex,
225                                             Index const  sourcePoints[],
226                                             int          sourcePointOffset);
227 
228         template <typename REAL>
229         StencilTablePtr acquireStencilTable(StencilTablePtr& stencilTableMember);
230 
231         Index findSharedCornerPoint(int levelIndex, Index valueIndex,
232                                     Index newIndex);
233         Index findSharedEdgePoint(int levelIndex, Index edgeIndex, int edgeEnd,
234                                   Index newIndex);
235 
236     private:
237         //  Member variables:
238         TopologyRefiner const& _refiner;
239         Options                _options;
240 
241         int _fvarChannel;
242         int _numLocalPoints;
243         int _localPointOffset;
244 
245         std::vector<IndexVector> _sharedCornerPoints;
246         std::vector<IndexVector> _sharedEdgePoints;
247 
248         StencilTablePtr _stencilTable;
249 
250     //  This was hopefully transitional but will persist -- the should be
251     //  no need for Varying local points or stencils associated with them.
252     public:
AcquireStencilTableVarying()253         StencilTablePtr AcquireStencilTableVarying() {
254             return _options.doubleStencilTable
255                 ? acquireStencilTable<double>(_stencilTableVarying)
256                 : acquireStencilTable<float>(_stencilTableVarying);
257         }
258 
259         StencilTablePtr _stencilTableVarying;
260     };
261 
262 private:
263     //
264     //  Internal LegacyGregoryHelper class
265     //
266     //  This local class helps to populate the arrays in the PatchTable
267     //  associated with legacy-Gregory patches, i.e. the quad-offset and
268     //  vertex-valence tables.  These patches are always associated with
269     //  faces at the last level of refinement, so only the face index in
270     //  that level is required to identify them.
271     //
272     class LegacyGregoryHelper {
273     public:
LegacyGregoryHelper(TopologyRefiner const & ref)274         LegacyGregoryHelper(TopologyRefiner const & ref) : _refiner(ref) { }
~LegacyGregoryHelper()275         ~LegacyGregoryHelper() { }
276 
277     public:
GetNumBoundaryPatches() const278         int GetNumBoundaryPatches() const { return (int)_boundaryFaceIndices.size(); }
GetNumInteriorPatches() const279         int GetNumInteriorPatches() const { return (int)_interiorFaceIndices.size(); }
280 
281         void AddPatchFace(int level, Index face);
282         void FinalizeQuadOffsets(  PatchTable::QuadOffsetsTable & qTable);
283         void FinalizeVertexValence(PatchTable::VertexValenceTable & vTable,
284                                    int lastLevelVertOffset);
285     private:
286         TopologyRefiner const& _refiner;
287         std::vector<Index> _interiorFaceIndices;
288         std::vector<Index> _boundaryFaceIndices;
289     };
290 
291 private:
292     //  Builder methods for internal use:
293 
294     //  Simple queries:
getRefinerFVarChannel(int fvcInTable) const295     int getRefinerFVarChannel(int fvcInTable) const {
296         return (fvcInTable >= 0) ? _fvarChannelIndices[fvcInTable] : -1;
297     }
298 
isFVarChannelLinear(int fvcInTable) const299     bool isFVarChannelLinear(int fvcInTable) const {
300         if (_options.generateFVarLegacyLinearPatches) return true;
301         return (_refiner.GetFVarLinearInterpolation(
302             getRefinerFVarChannel(fvcInTable)) == Sdc::Options::FVAR_LINEAR_ALL);
303     }
304 
doesFVarTopologyMatch(PatchTuple const & patch,int fvcInTable)305     bool doesFVarTopologyMatch(PatchTuple const & patch, int fvcInTable) {
306         return _patchBuilder->DoesFaceVaryingPatchMatch(
307             patch.levelIndex, patch.faceIndex,
308             getRefinerFVarChannel(fvcInTable));
309     }
310 
311     //  Methods for identifying and assigning patch-related data:
312     void identifyPatchTopology(PatchTuple const & patch, PatchInfo & patchInfo,
313                                int fvcInTable = -1);
314 
315     int assignPatchPointsAndStencils(PatchTuple const & patch,
316                                      PatchInfo const & patchInfo,
317                                      Index * patchPoints,
318                                      LocalPointHelper & localHelper,
319                                      int fvcInTable = -1);
320 
321     int assignFacePoints(PatchTuple const & patch,
322                          Index * patchPoints,
323                          int fvcInTable = -1) const;
324 
325     //  High level methods for assembling the table:
326     void identifyPatches();
327     void appendPatch(int levelIndex, Index faceIndex);
328     void findDescendantPatches(int levelIndex, Index faceIndex, int targetLevel);
329     void populatePatches();
330 
331     void allocateVertexTables();
332     void allocateFVarChannels();
333 
334     int estimateLocalPointCount(LocalPointHelper::Options const & options,
335                                 int fvcInTable = -1) const;
336 
337 private:
338     //  Refiner and Options passed on construction:
339     TopologyRefiner const & _refiner;
340     Options const           _options;
341     ConstIndexArray         _selectedFaces;
342 
343     // Flags indicating the need for processing based on provided options
344     unsigned int _requiresLocalPoints          : 1;
345     unsigned int _requiresRegularLocalPoints   : 1;
346     unsigned int _requiresIrregularLocalPoints : 1;
347     unsigned int _requiresSharpnessArray       : 1;
348     unsigned int _requiresFVarPatches          : 1;
349     unsigned int _requiresVaryingPatches       : 1;
350     unsigned int _requiresVaryingLocalPoints   : 1;
351 
352     unsigned int _buildUniformLinear : 1;
353 
354     // The PatchTable being constructed and classes to help its construction:
355     PatchTable * _table;
356 
357     PatchBuilder *    _patchBuilder;
358     PtexIndices const _ptexIndices;
359 
360     // Vector of tuples for each patch identified during topology traversal
361     // and the numbers of irregular and irregular patches identifed:
362     PatchTupleVector _patches;
363 
364     int _numRegularPatches;
365     int _numIrregularPatches;
366 
367     // Vectors for remapping indices of vertices and fvar values as well
368     // as the fvar channels (when a subset is chosen)
369     std::vector<int>                _levelVertOffsets;
370     std::vector< std::vector<int> > _levelFVarValueOffsets;
371     std::vector<int>                _fvarChannelIndices;
372 
373     // State and helpers for legacy features
374     bool                  _requiresLegacyGregoryTables;
375     LegacyGregoryHelper * _legacyGregoryHelper;
376 };
377 
378 // Constructor
PatchTableBuilder(TopologyRefiner const & refiner,Options opts,ConstIndexArray faces)379 PatchTableBuilder::PatchTableBuilder(
380     TopologyRefiner const & refiner, Options opts, ConstIndexArray faces) :
381     _refiner(refiner), _options(opts), _selectedFaces(faces),
382     _table(0), _patchBuilder(0), _ptexIndices(refiner),
383     _numRegularPatches(0), _numIrregularPatches(0),
384     _legacyGregoryHelper(0) {
385 
386     if (_options.generateFVarTables) {
387         // If client-code does not select specific channels, default to all
388         // the channels in the refiner.
389         if (_options.numFVarChannels==-1) {
390             _fvarChannelIndices.resize(_refiner.GetNumFVarChannels());
391             for (int fvc=0;fvc<(int)_fvarChannelIndices.size(); ++fvc) {
392                 _fvarChannelIndices[fvc] = fvc; // std::iota
393             }
394         } else {
395             _fvarChannelIndices.assign(
396                 _options.fvarChannelIndices,
397                 _options.fvarChannelIndices + _options.numFVarChannels);
398         }
399     }
400 
401     //
402     //  Will need to translate PatchTableFactory options to the newer set of
403     //  PatchBuilder options in the near future.  And the state variables are
404     //  a potentially complex combination of options and so are handled after
405     //  the PatchBuilder construction (to potentially help) rather than in
406     //  the initializer list.
407     //
408     PatchBuilder::Options patchOptions;
409 
410     patchOptions.regBasisType = PatchBuilder::BASIS_REGULAR;
411     switch (_options.GetEndCapType()) {
412         case Options::ENDCAP_BILINEAR_BASIS:
413             patchOptions.irregBasisType = PatchBuilder::BASIS_LINEAR;
414             break;
415         case Options::ENDCAP_BSPLINE_BASIS:
416             patchOptions.irregBasisType = PatchBuilder::BASIS_REGULAR;
417             break;
418         case Options::ENDCAP_GREGORY_BASIS:
419             patchOptions.irregBasisType = PatchBuilder::BASIS_GREGORY;
420             break;
421         default:
422             //  The PatchBuilder will infer if left un-specified
423             patchOptions.irregBasisType = PatchBuilder::BASIS_UNSPECIFIED;
424             break;
425     }
426     patchOptions.fillMissingBoundaryPoints   = true;
427     patchOptions.approxInfSharpWithSmooth    = !_options.useInfSharpPatch;
428     patchOptions.approxSmoothCornerWithSharp =
429         _options.generateLegacySharpCornerPatches;
430 
431     _patchBuilder = PatchBuilder::Create(_refiner, patchOptions);
432 
433     //
434     //  Initialize member variables that capture specified options:
435     //
436     _requiresRegularLocalPoints =
437         (patchOptions.regBasisType != PatchBuilder::BASIS_REGULAR);
438     _requiresIrregularLocalPoints =
439         (_options.GetEndCapType() != Options::ENDCAP_LEGACY_GREGORY);
440     _requiresLocalPoints =
441         _requiresIrregularLocalPoints || _requiresRegularLocalPoints;
442 
443     _requiresSharpnessArray = _options.useSingleCreasePatch;
444     _requiresFVarPatches = ! _fvarChannelIndices.empty();
445 
446     _requiresVaryingPatches = _options.generateVaryingTables;
447     _requiresVaryingLocalPoints = _options.generateVaryingTables &&
448                                   _options.generateVaryingLocalPoints;
449 
450     //  Option to be made public in future:
451     bool options_generateNonLinearUniformPatches = false;
452 
453     _buildUniformLinear = _refiner.IsUniform() && !options_generateNonLinearUniformPatches;
454 
455     //
456     //  Create and initialize the new PatchTable instance to be assembled:
457     //
458     _table = new PatchTable(_refiner.GetMaxValence());
459 
460     _table->_numPtexFaces = _ptexIndices.GetNumFaces();
461 
462     _table->_vertexPrecisionIsDouble = _options.patchPrecisionDouble;
463     _table->_varyingPrecisionIsDouble = _options.patchPrecisionDouble;
464     _table->_faceVaryingPrecisionIsDouble = _options.fvarPatchPrecisionDouble;
465 
466     _table->_varyingDesc = PatchDescriptor(_patchBuilder->GetLinearPatchType());
467 
468     //  State and helper to support LegacyGregory arrays in the PatchTable:
469     _requiresLegacyGregoryTables = !_refiner.IsUniform() &&
470         (_options.GetEndCapType() == Options::ENDCAP_LEGACY_GREGORY);
471 
472     if (_requiresLegacyGregoryTables) {
473         _legacyGregoryHelper = new LegacyGregoryHelper(_refiner);
474     }
475 
476 }
477 
~PatchTableBuilder()478 PatchTableBuilder::~PatchTableBuilder() {
479 
480     delete _patchBuilder;
481     delete _legacyGregoryHelper;
482 }
483 
484 
485 void
identifyPatchTopology(PatchTuple const & patch,PatchInfo & patchInfo,int fvarInTable)486 PatchTableBuilder::identifyPatchTopology(PatchTuple const & patch,
487         PatchInfo & patchInfo, int fvarInTable) {
488 
489     int   patchLevel = patch.levelIndex;
490     Index patchFace  = patch.faceIndex;
491 
492     int fvarInRefiner = getRefinerFVarChannel(fvarInTable);
493 
494     patchInfo.isRegular = _patchBuilder->IsPatchRegular(
495         patchLevel, patchFace, fvarInTable);
496 
497     bool useDoubleMatrix = (fvarInRefiner < 0)
498                          ? _options.patchPrecisionDouble
499                          : _options.fvarPatchPrecisionDouble;
500 
501     if (patchInfo.isRegular) {
502         patchInfo.regBoundaryMask = _patchBuilder->GetRegularPatchBoundaryMask(
503             patchLevel, patchFace, fvarInRefiner);
504 
505         patchInfo.isRegSingleCrease = false;
506         patchInfo.regSharpness      = 0.0f;
507         patchInfo.paramBoundaryMask = patchInfo.regBoundaryMask;
508 
509         //  If converting to another basis, get the change-of-basis matrix:
510         if (_requiresRegularLocalPoints) {
511             // _patchBuilder->GetRegularConversionMatrix(...);
512         }
513 
514         //
515         //  Test regular interior patches for a single-crease patch when it
516         //  was specified.
517         //
518         //  Note that the PatchTable clamps the sharpness of single-crease
519         //  patches to that of the maximimu refinement level, so any single-
520         //  crease patches at the last level will be reduced to regular
521         //  patches (maintaining continuity with other semi-sharp patches
522         //  also reduced to regular).
523         //
524         if (_requiresSharpnessArray &&
525                 (patchInfo.regBoundaryMask == 0) && (fvarInRefiner < 0)) {
526             if (patchLevel < (int) _options.maxIsolationLevel) {
527                 PatchBuilder::SingleCreaseInfo creaseInfo;
528 
529                 if (_patchBuilder->IsRegularSingleCreasePatch(
530                         patchLevel, patchFace, creaseInfo)) {
531                     creaseInfo.creaseSharpness =
532                         std::min(creaseInfo.creaseSharpness,
533                              (float)(_options.maxIsolationLevel - patchLevel));
534 
535                     patchInfo.isRegSingleCrease = true;
536                     patchInfo.regSharpness      = creaseInfo.creaseSharpness;
537                     patchInfo.paramBoundaryMask = (1 << creaseInfo.creaseEdgeInFace);
538                 }
539             }
540         }
541     } else if (_requiresIrregularLocalPoints) {
542         _patchBuilder->GetIrregularPatchCornerSpans(
543             patchLevel, patchFace, patchInfo.irregCornerSpans, fvarInRefiner);
544 
545         if (useDoubleMatrix) {
546             _patchBuilder->GetIrregularPatchConversionMatrix(
547                 patchLevel, patchFace, patchInfo.irregCornerSpans, patchInfo.dMatrix);
548         } else {
549             _patchBuilder->GetIrregularPatchConversionMatrix(
550                 patchLevel, patchFace, patchInfo.irregCornerSpans, patchInfo.fMatrix);
551         }
552 
553         patchInfo.paramBoundaryMask = 0;
554     }
555 }
556 
557 int
assignPatchPointsAndStencils(PatchTuple const & patch,PatchInfo const & patchInfo,Index * patchPoints,LocalPointHelper & localHelper,int fvarInTable)558 PatchTableBuilder::assignPatchPointsAndStencils(PatchTuple const & patch,
559         PatchInfo const & patchInfo, Index * patchPoints,
560         LocalPointHelper & localHelper, int fvarInTable) {
561 
562     //
563     //  This is where the interesting/complicated new work will take place
564     //  when a change-of-basis is determined necessary and previously assigned
565     //  to the PatchInfo
566     //
567     //  No change-of-basis means no local points or stencils associated with
568     //  them, which should be trivial but should also only be true in the
569     //  regular case.  (It is also the case that no local points will be
570     //  generated for irregular patches when the LegacyGregory option is
571     //  used -- so that possibility is still accounted for here.)
572     //
573     //  Regarding the return result, it should just be the size of the patch
574     //  associated with the regular/irregular patch type chosen.  This could
575     //  be retrieved from the PatchBuilder or PatchDescriptors -- alternatively
576     //  a return value could be removed and the client left to increment by
577     //  such a fixed step (which is already the case for FVar channels)
578     //
579     //  The more interesting size here is the number of local points/stencils
580     //  added.
581     //
582     int fvarInRefiner = getRefinerFVarChannel(fvarInTable);
583 
584     int sourcePointOffset = (fvarInTable < 0)
585                           ? _levelVertOffsets[patch.levelIndex]
586                           : _levelFVarValueOffsets[fvarInTable][patch.levelIndex];
587 
588     bool useDoubleMatrix = (fvarInTable < 0)
589                          ? _options.patchPrecisionDouble
590                          : _options.fvarPatchPrecisionDouble;
591 
592     int numPatchPoints = 0;
593     if (patchInfo.isRegular) {
594         if (!_requiresRegularLocalPoints) {
595             numPatchPoints = _patchBuilder->GetRegularPatchPoints(
596                     patch.levelIndex, patch.faceIndex,
597                     patchInfo.regBoundaryMask, patchPoints, fvarInRefiner);
598 
599             //  PatchBuilder set to fill missing boundary points so offset all
600             offsetIndices(patchPoints, numPatchPoints, sourcePointOffset);
601         } else {
602             //
603             //  Future support for regular patches converted to another basis.
604             //  Note the "source points" are not returned in the same
605             //  orientation and there may be fewer than expected number in the
606             //  case of boundaries:
607             /*
608             StackBuffer<Index,64,true> sourcePoints(
609                 patchInfo.matrix.GetNumColumns());
610 
611             _patchBuilder->GetRegularPatchSourcePoints(
612                     patch.levelIndex, patch.faceIndex,
613                     patchInfo.regBoundaryMask, sourcePoints, fvarInRefiner);
614 
615             localHelper.AppendLocalPatchPoints(
616                     patch.levelIndex, patch.faceIndex,
617                     patchInfo.matrix, _patchBuilder->GetRegularPatchType(),
618                     sourcePoints, sourcePointOffset, patchPoints);
619 
620             numPatchPoints = patchInfo.matrix.GetNumRows();
621             */
622         }
623     } else if (_requiresIrregularLocalPoints) {
624         int numSourcePoints = 0;
625         if (useDoubleMatrix) {
626             numSourcePoints = patchInfo.dMatrix.GetNumColumns();
627             numPatchPoints  = patchInfo.dMatrix.GetNumRows();
628         } else {
629             numSourcePoints = patchInfo.fMatrix.GetNumColumns();
630             numPatchPoints  = patchInfo.fMatrix.GetNumRows();
631         }
632 
633         StackBuffer<Index,64,true> sourcePoints(numSourcePoints);
634 
635         _patchBuilder->GetIrregularPatchSourcePoints(
636                 patch.levelIndex, patch.faceIndex,
637                 patchInfo.irregCornerSpans, sourcePoints, fvarInRefiner);
638 
639         if (useDoubleMatrix) {
640             localHelper.AppendLocalPatchPoints(
641                     patch.levelIndex, patch.faceIndex,
642                     patchInfo.dMatrix, _patchBuilder->GetIrregularPatchType(),
643                     sourcePoints, sourcePointOffset, patchPoints);
644         } else {
645             localHelper.AppendLocalPatchPoints(
646                     patch.levelIndex, patch.faceIndex,
647                     patchInfo.fMatrix, _patchBuilder->GetIrregularPatchType(),
648                     sourcePoints, sourcePointOffset, patchPoints);
649         }
650     }
651     return numPatchPoints;
652 }
653 
654 int
assignFacePoints(PatchTuple const & patch,Index * patchPoints,int fvarInTable) const655 PatchTableBuilder::assignFacePoints(PatchTuple const & patch,
656                                     Index * patchPoints,
657                                     int fvarInTable) const {
658 
659     Level const & level = _refiner.getLevel(patch.levelIndex);
660 
661     int facePointOffset = (fvarInTable < 0)
662                         ? _levelVertOffsets[patch.levelIndex]
663                         : _levelFVarValueOffsets[fvarInTable][patch.levelIndex];
664 
665     int fvarInRefiner = getRefinerFVarChannel(fvarInTable);
666 
667     ConstIndexArray facePoints = (fvarInRefiner < 0)
668                     ? level.getFaceVertices(patch.faceIndex)
669                     : level.getFaceFVarValues(patch.faceIndex, fvarInRefiner);
670 
671     for (int i = 0; i < facePoints.size(); ++i) {
672         patchPoints[i] = facePoints[i] + facePointOffset;
673     }
674     return facePoints.size();
675 }
676 
677 //
678 //  Reserves tables based on contents of the PatchArrayVector in the PatchTable:
679 //
680 void
allocateVertexTables()681 PatchTableBuilder::allocateVertexTables() {
682 
683     int ncvs = 0, npatches = 0;
684     for (int i=0; i<_table->GetNumPatchArrays(); ++i) {
685         npatches += _table->GetNumPatches(i);
686         ncvs += _table->GetNumControlVertices(i);
687     }
688 
689     if (ncvs==0 || npatches==0)
690         return;
691 
692     _table->_patchVerts.resize( ncvs );
693 
694     _table->_paramTable.resize( npatches );
695 
696     if (_requiresVaryingPatches && !_buildUniformLinear) {
697         _table->allocateVaryingVertices(
698             PatchDescriptor(_patchBuilder->GetLinearPatchType()), npatches);
699     }
700 
701     if (_requiresSharpnessArray) {
702         _table->_sharpnessIndices.resize( npatches, Vtr::INDEX_INVALID );
703     }
704 }
705 
706 //
707 //  Allocate face-varying tables
708 //
709 void
allocateFVarChannels()710 PatchTableBuilder::allocateFVarChannels() {
711 
712     int npatches = _table->GetNumPatchesTotal();
713 
714     _table->allocateFVarPatchChannels((int)_fvarChannelIndices.size());
715 
716     // Initialize each channel
717     for (int fvc=0; fvc<(int)_fvarChannelIndices.size(); ++fvc) {
718         int refinerChannel = _fvarChannelIndices[fvc];
719 
720         Sdc::Options::FVarLinearInterpolation interpolation =
721             _refiner.GetFVarLinearInterpolation(refinerChannel);
722 
723         _table->setFVarPatchChannelLinearInterpolation(interpolation, fvc);
724 
725         PatchDescriptor::Type regPatchType   = _patchBuilder->GetLinearPatchType();
726         PatchDescriptor::Type irregPatchType = regPatchType;
727         if (_buildUniformLinear) {
728             if (_options.triangulateQuads) {
729                 regPatchType   = PatchDescriptor::TRIANGLES;
730                 irregPatchType = regPatchType;
731             }
732         } else {
733             if (!isFVarChannelLinear(fvc)) {
734                 regPatchType   = _patchBuilder->GetRegularPatchType();
735                 irregPatchType = _patchBuilder->GetIrregularPatchType();
736             }
737         }
738         _table->allocateFVarPatchChannelValues(
739                 PatchDescriptor(regPatchType), PatchDescriptor(irregPatchType),
740                 npatches, fvc);
741     }
742 }
743 
744 void
BuildUniformPolygons()745 PatchTableBuilder::BuildUniformPolygons() {
746 
747     // Default behavior is to include base level vertices in the patch vertices
748     // for vertex and varying patches, but not face-varying.  Consider exposing
749     // these as public options in future so that clients can create consistent
750     // behavior:
751 
752     bool includeBaseLevelIndices     = _options.includeBaseLevelIndices;
753     bool includeBaseLevelFVarIndices = _options.includeFVarBaseLevelIndices;
754 
755     // ensure that triangulateQuads is only set for quadrilateral schemes
756     bool triangulateQuads =
757         _options.triangulateQuads && (_patchBuilder->GetRegularFaceSize() == 4);
758 
759     // level=0 may contain n-gons, which are not supported in PatchTable.
760     // even if generateAllLevels = true, we start from level 1.
761 
762     int maxlevel = _refiner.GetMaxLevel(),
763         firstlevel = _options.generateAllLevels ? 1 : maxlevel,
764         nlevels = maxlevel-firstlevel+1;
765 
766     PatchDescriptor::Type ptype = triangulateQuads
767                                 ? PatchDescriptor::TRIANGLES
768                                 : _patchBuilder->GetLinearPatchType();
769 
770     //
771     //  Allocate and initialize the table's members.
772     //
773     _table->_isUniformLinear = true;
774 
775     _table->reservePatchArrays(nlevels);
776 
777     PatchDescriptor desc(ptype);
778 
779     // generate patch arrays
780     for (int level=firstlevel, poffset=0, voffset=0; level<=maxlevel; ++level) {
781 
782         TopologyLevel const & refLevel = _refiner.GetLevel(level);
783 
784         int npatches = refLevel.GetNumFaces();
785         if (_refiner.HasHoles()) {
786             for (int i = npatches - 1; i >= 0; --i) {
787                 npatches -= refLevel.IsFaceHole(i);
788             }
789         }
790         assert(npatches>=0);
791 
792         if (triangulateQuads)
793             npatches *= 2;
794 
795         _table->pushPatchArray(desc, npatches, &voffset, &poffset, 0);
796     }
797 
798     // Allocate various tables
799     allocateVertexTables();
800 
801     if (_requiresFVarPatches) {
802         allocateFVarChannels();
803     }
804 
805     //
806     //  Now populate the patches:
807     //
808 
809     Index          * iptr = &_table->_patchVerts[0];
810     PatchParam     * pptr = &_table->_paramTable[0];
811     Index         ** fptr  = 0;
812     PatchParam    ** fpptr = 0;
813 
814     Index levelVertOffset = includeBaseLevelIndices
815                           ? _refiner.GetLevel(0).GetNumVertices() : 0;
816 
817     Index * levelFVarVertOffsets = 0;
818     if (_requiresFVarPatches) {
819 
820         levelFVarVertOffsets =
821             (Index *)alloca(_fvarChannelIndices.size()*sizeof(Index));
822         memset(levelFVarVertOffsets, 0, _fvarChannelIndices.size()*sizeof(Index));
823 
824         fptr = (Index **)alloca(_fvarChannelIndices.size()*sizeof(Index *));
825         fpptr = (PatchParam **)alloca(_fvarChannelIndices.size()*sizeof(PatchParam *));
826         for (int fvc=0; fvc<(int)_fvarChannelIndices.size(); ++fvc) {
827             fptr[fvc] = _table->getFVarValues(fvc).begin();
828             fpptr[fvc] = _table->getFVarPatchParams(fvc).begin();
829 
830             if (includeBaseLevelFVarIndices) {
831                 int refinerChannel = _fvarChannelIndices[fvc];
832                 levelFVarVertOffsets[fvc] =
833                     _refiner.GetLevel(0).GetNumFVarValues(refinerChannel);
834             }
835         }
836     }
837 
838     for (int level=1; level<=maxlevel; ++level) {
839 
840         TopologyLevel const & refLevel = _refiner.GetLevel(level);
841 
842         int nfaces = refLevel.GetNumFaces();
843         if (level>=firstlevel) {
844             for (int face=0; face<nfaces; ++face) {
845 
846                 if (_refiner.HasHoles() && refLevel.IsFaceHole(face)) {
847                     continue;
848                 }
849 
850                 ConstIndexArray fverts = refLevel.GetFaceVertices(face);
851                 for (int vert=0; vert<fverts.size(); ++vert) {
852                     *iptr++ = levelVertOffset + fverts[vert];
853                 }
854 
855                 PatchParam pparam = _patchBuilder->ComputePatchParam(
856                     level, face, _ptexIndices);
857                 *pptr++ = pparam;
858 
859                 if (_requiresFVarPatches) {
860                     for (int fvc=0; fvc<(int)_fvarChannelIndices.size(); ++fvc) {
861                         int refinerChannel = _fvarChannelIndices[fvc];
862 
863                         ConstIndexArray fvalues =
864                             refLevel.GetFaceFVarValues(face, refinerChannel);
865                         for (int vert=0; vert<fvalues.size(); ++vert) {
866                             assert((levelFVarVertOffsets[fvc] + fvalues[vert])
867                                 < (int)_table->getFVarValues(fvc).size());
868                             fptr[fvc][vert] =
869                                 levelFVarVertOffsets[fvc] + fvalues[vert];
870                         }
871                         fptr[fvc]+=fvalues.size();
872                         *fpptr[fvc]++ = pparam;
873                     }
874                 }
875 
876                 if (triangulateQuads) {
877                     // Triangulate the quadrilateral:
878                     //     {v0,v1,v2,v3} -> {v0,v1,v2},{v3,v0,v2}.
879                     *iptr = *(iptr - 4); // copy v0 index
880                     ++iptr;
881                     *iptr = *(iptr - 3); // copy v2 index
882                     ++iptr;
883 
884                     *pptr++ = pparam;
885 
886                     if (_requiresFVarPatches) {
887                         for (int fvc=0; fvc<(int)_fvarChannelIndices.size(); ++fvc) {
888                             *fptr[fvc] = *(fptr[fvc]-4); // copy fv0 index
889                             ++fptr[fvc];
890                             *fptr[fvc] = *(fptr[fvc]-3); // copy fv2 index
891                             ++fptr[fvc];
892 
893                             *fpptr[fvc]++ = pparam;
894                         }
895                     }
896                 }
897             }
898         }
899 
900         if (_options.generateAllLevels) {
901             levelVertOffset += _refiner.GetLevel(level).GetNumVertices();
902 
903             if (_requiresFVarPatches) {
904                 for (int fvc=0; fvc<(int)_fvarChannelIndices.size(); ++fvc) {
905                     int refinerChannel = _fvarChannelIndices[fvc];
906                     levelFVarVertOffsets[fvc] +=
907                         _refiner.GetLevel(level).GetNumFVarValues(refinerChannel);
908                 }
909             }
910         }
911     }
912 }
913 
914 void
BuildPatches()915 PatchTableBuilder::BuildPatches() {
916 
917     identifyPatches();
918     populatePatches();
919 }
920 
921 //
922 //  Identify all patches required for faces at all levels -- appending the
923 //  <level,face> pairs to identify each patch for later construction, while
924 //  accumulating the number of regular vs irregular patches to size tables.
925 //
926 inline void
appendPatch(int levelIndex,Index faceIndex)927 PatchTableBuilder::appendPatch(int levelIndex, Index faceIndex) {
928 
929     _patches.push_back(PatchTuple(faceIndex, levelIndex));
930 
931     // Count the patches here to simplify subsequent allocation.
932     if (_patchBuilder->IsPatchRegular(levelIndex, faceIndex)) {
933         ++_numRegularPatches;
934     } else {
935         ++_numIrregularPatches;
936 
937         //  LegacyGregory needs to distinguish boundary vs interior
938         if (_requiresLegacyGregoryTables) {
939             _legacyGregoryHelper->AddPatchFace(levelIndex, faceIndex);
940         }
941     }
942 }
943 
944 inline void
findDescendantPatches(int levelIndex,Index faceIndex,int targetLevel)945 PatchTableBuilder::findDescendantPatches(int levelIndex, Index faceIndex, int targetLevel) {
946 
947     //
948     //  If we have reached the target level or a leaf, append the patch (if
949     //  the face qualifies), otherwise recursively search the children:
950     //
951     if ((levelIndex == targetLevel) || _patchBuilder->IsFaceALeaf(levelIndex, faceIndex)) {
952         if (_patchBuilder->IsFaceAPatch(levelIndex, faceIndex)) {
953             appendPatch(levelIndex, faceIndex);
954         }
955     } else {
956         TopologyLevel const & level = _refiner.GetLevel(levelIndex);
957         ConstIndexArray childFaces = level.GetFaceChildFaces(faceIndex);
958         for (int i = 0; i < childFaces.size(); ++i) {
959             if (Vtr::IndexIsValid(childFaces[i])) {
960                 findDescendantPatches(levelIndex + 1, childFaces[i], targetLevel);
961             }
962         }
963     }
964 }
965 
966 void
identifyPatches()967 PatchTableBuilder::identifyPatches() {
968 
969     //
970     //  First initialize the offsets for all levels
971     //
972     _levelVertOffsets.push_back(0);
973     _levelFVarValueOffsets.resize(_fvarChannelIndices.size());
974     for (int fvc=0; fvc<(int)_fvarChannelIndices.size(); ++fvc) {
975         _levelFVarValueOffsets[fvc].push_back(0);
976     }
977 
978     for (int levelIndex=0; levelIndex<_refiner.GetNumLevels(); ++levelIndex) {
979         Level const & level = _refiner.getLevel(levelIndex);
980 
981         _levelVertOffsets.push_back(
982             _levelVertOffsets.back() + level.getNumVertices());
983 
984         for (int fvc=0; fvc<(int)_fvarChannelIndices.size(); ++fvc) {
985             int refinerChannel = _fvarChannelIndices[fvc];
986             _levelFVarValueOffsets[fvc].push_back(
987                 _levelFVarValueOffsets[fvc].back()
988                 + level.getNumFVarValues(refinerChannel));
989         }
990     }
991 
992     //
993     //  If a set of selected base faces is present, identify the patches
994     //  depth first.  Otherwise search breadth first through the levels:
995     //
996     int uniformLevel = _refiner.IsUniform() ? _options.maxIsolationLevel : -1;
997 
998     _patches.reserve(_refiner.GetNumFacesTotal());
999 
1000     if (_selectedFaces.size()) {
1001         for (int i = 0; i < (int)_selectedFaces.size(); ++i) {
1002             findDescendantPatches(0, _selectedFaces[i], uniformLevel);
1003         }
1004     } else if (uniformLevel >= 0) {
1005         int numFaces = _refiner.getLevel(uniformLevel).getNumFaces();
1006 
1007         for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
1008 
1009             if (_patchBuilder->IsFaceAPatch(uniformLevel, faceIndex)) {
1010                 appendPatch(uniformLevel, faceIndex);
1011             }
1012         }
1013     } else {
1014         for (int levelIndex=0; levelIndex<_refiner.GetNumLevels(); ++levelIndex) {
1015             int numFaces = _refiner.getLevel(levelIndex).getNumFaces();
1016 
1017             for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
1018 
1019                 if (_patchBuilder->IsFaceAPatch(levelIndex, faceIndex) &&
1020                     _patchBuilder->IsFaceALeaf(levelIndex, faceIndex)) {
1021                     appendPatch(levelIndex, faceIndex);
1022                 }
1023             }
1024         }
1025     }
1026 }
1027 
1028 //
1029 //  Populate patches that were previously identified.
1030 //
1031 void
populatePatches()1032 PatchTableBuilder::populatePatches() {
1033 
1034     // State needed to populate an array in the patch table.
1035     // Pointers in this structure are initialized after the patch array
1036     // data buffers have been allocated and are then incremented as we
1037     // populate data into the patch table. Currently, we'll have at
1038     // most 3 patch arrays: Regular, Irregular, and IrregularBoundary.
1039     struct PatchArrayBuilder {
1040         PatchArrayBuilder()
1041             : patchType(PatchDescriptor::NON_PATCH), numPatches(0)
1042             , iptr(NULL), pptr(NULL), sptr(NULL), vptr(NULL) { }
1043 
1044         PatchDescriptor::Type patchType;
1045         int numPatches;
1046 
1047         Index      *iptr;
1048         PatchParam *pptr;
1049         Index      *sptr;
1050         Index      *vptr;
1051 
1052         StackBuffer<Index*,1>      fptr;   // fvar indices
1053         StackBuffer<PatchParam*,1> fpptr;  // fvar patch-params
1054 
1055     private:
1056         // Non-copyable
1057         PatchArrayBuilder(PatchArrayBuilder const &) {}
1058         PatchArrayBuilder & operator=(PatchArrayBuilder const &) {return *this;}
1059 
1060     } arrayBuilders[3];
1061 
1062     // Regular patches patches will be packed into the first patch array
1063     // Irregular patches will be packed into arrays according to optional
1064     // specification -- sharing the array with regular patches or packed
1065     // into an array of their own.
1066     int ARRAY_REGULAR   = 0;
1067     int ARRAY_IRREGULAR = 1;
1068     int ARRAY_BOUNDARY  = 2; // only used by LegacyGregory
1069 
1070     arrayBuilders[ARRAY_REGULAR].patchType = _patchBuilder->GetRegularPatchType();
1071     arrayBuilders[ARRAY_REGULAR].numPatches = _numRegularPatches;
1072 
1073     int numPatchArrays = (_numRegularPatches > 0);
1074     if (_numIrregularPatches > 0) {
1075         if (!_requiresLegacyGregoryTables) {
1076             //
1077             //  Pack irregular patches into same array as regular or separately:
1078             //
1079             if (_patchBuilder->GetRegularPatchType() ==
1080                     _patchBuilder->GetIrregularPatchType()) {
1081                 ARRAY_IRREGULAR = ARRAY_REGULAR;
1082                 numPatchArrays = 1;  // needed in case no regular patches
1083             } else {
1084                 ARRAY_IRREGULAR = numPatchArrays;
1085                 numPatchArrays ++;
1086             }
1087             arrayBuilders[ARRAY_IRREGULAR].patchType =
1088                 _patchBuilder->GetIrregularPatchType();
1089             arrayBuilders[ARRAY_IRREGULAR].numPatches += _numIrregularPatches;
1090         } else {
1091             //
1092             // Arrays for Legacy-Gregory tables -- irregular patches are split
1093             // into two arrays for interior and boundary patches
1094             //
1095             ARRAY_IRREGULAR = numPatchArrays;
1096             arrayBuilders[ARRAY_IRREGULAR].patchType =
1097                 PatchDescriptor::GREGORY;
1098             arrayBuilders[ARRAY_IRREGULAR].numPatches =
1099                 _legacyGregoryHelper->GetNumInteriorPatches();
1100             numPatchArrays += (arrayBuilders[ARRAY_IRREGULAR].numPatches > 0);
1101 
1102             ARRAY_BOUNDARY = numPatchArrays;
1103             arrayBuilders[ARRAY_BOUNDARY].patchType =
1104                 PatchDescriptor::GREGORY_BOUNDARY;
1105             arrayBuilders[ARRAY_BOUNDARY].numPatches =
1106                 _legacyGregoryHelper->GetNumBoundaryPatches();
1107             numPatchArrays += (arrayBuilders[ARRAY_BOUNDARY].numPatches > 0);
1108         }
1109     }
1110 
1111     // Create patch arrays
1112     _table->reservePatchArrays(numPatchArrays);
1113 
1114     int voffset=0, poffset=0, qoffset=0;
1115     for (int arrayIndex=0; arrayIndex<numPatchArrays; ++arrayIndex) {
1116         PatchArrayBuilder & arrayBuilder = arrayBuilders[arrayIndex];
1117         _table->pushPatchArray(PatchDescriptor(arrayBuilder.patchType),
1118             arrayBuilder.numPatches, &voffset, &poffset, &qoffset );
1119     }
1120 
1121     // Allocate patch array data buffers
1122     allocateVertexTables();
1123 
1124     if (_requiresFVarPatches) {
1125         allocateFVarChannels();
1126     }
1127 
1128     // Initialize pointers used while populating patch array data buffers
1129     for (int arrayIndex=0; arrayIndex<numPatchArrays; ++arrayIndex) {
1130         PatchArrayBuilder & arrayBuilder = arrayBuilders[arrayIndex];
1131 
1132         arrayBuilder.iptr = _table->getPatchArrayVertices(arrayIndex).begin();
1133         arrayBuilder.pptr = _table->getPatchParams(arrayIndex).begin();
1134         if (_requiresSharpnessArray) {
1135             arrayBuilder.sptr = _table->getSharpnessIndices(arrayIndex);
1136         }
1137         if (_requiresVaryingPatches) {
1138             arrayBuilder.vptr = _table->getPatchArrayVaryingVertices(arrayIndex).begin();
1139         }
1140 
1141         if (_requiresFVarPatches) {
1142             arrayBuilder.fptr.SetSize((int)_fvarChannelIndices.size());
1143             arrayBuilder.fpptr.SetSize((int)_fvarChannelIndices.size());
1144 
1145             for (int fvc=0; fvc<(int)_fvarChannelIndices.size(); ++fvc) {
1146 
1147                 Index pidx = _table->getPatchIndex(arrayIndex, 0);
1148                 int   ofs  = pidx * _table->GetFVarValueStride(fvc);
1149 
1150                 arrayBuilder.fptr[fvc] = &_table->getFVarValues(fvc)[ofs];
1151                 arrayBuilder.fpptr[fvc] = &_table->getFVarPatchParams(fvc)[pidx];
1152             }
1153         }
1154     }
1155 
1156     //
1157     //  Initializing StencilTable and other helpers.  Note Varying local points
1158     //  are managed by the LocalPointHelper for Vertex patches (as Varying local
1159     //  points are tightly coupled to their local points)
1160     //
1161     LocalPointHelper * vertexLocalPointHelper = 0;
1162 
1163     StackBuffer<LocalPointHelper*,4> fvarLocalPointHelpers;
1164 
1165     if (_requiresLocalPoints) {
1166         LocalPointHelper::Options opts;
1167         opts.createStencilTable = true;
1168         opts.createVaryingTable = _requiresVaryingLocalPoints;
1169         opts.doubleStencilTable = _options.patchPrecisionDouble;
1170         opts.shareLocalPoints   = _options.shareEndCapPatchPoints;
1171         opts.reuseSourcePoints  = (_patchBuilder->GetIrregularPatchType() ==
1172                                    _patchBuilder->GetNativePatchType() );
1173 
1174         vertexLocalPointHelper = new LocalPointHelper(
1175                 _refiner, opts, -1, estimateLocalPointCount(opts, -1));
1176 
1177         if (_requiresFVarPatches) {
1178             opts.createStencilTable = true;
1179             opts.createVaryingTable = false;
1180             opts.doubleStencilTable = _options.fvarPatchPrecisionDouble;
1181 
1182             fvarLocalPointHelpers.SetSize((int)_fvarChannelIndices.size());
1183 
1184             for (int fvc = 0; fvc < (int)_fvarChannelIndices.size(); ++fvc) {
1185                 fvarLocalPointHelpers[fvc] = new LocalPointHelper(
1186                         _refiner, opts, getRefinerFVarChannel(fvc),
1187                         estimateLocalPointCount(opts, fvc));
1188             }
1189         }
1190     }
1191 
1192     //  Populate patch data buffers
1193     //
1194     //  Intentionally declare local vairables to contain patch topology info
1195     //  outside the loop to avoid repeated memory de-allocation/re-allocation
1196     //  associated with a change-of-basis.
1197     PatchInfo patchInfo;
1198     PatchInfo fvarPatchInfo;
1199 
1200     bool fvarPrecisionMatches = (_options.patchPrecisionDouble ==
1201                                  _options.fvarPatchPrecisionDouble);
1202 
1203     for (int patchIndex = 0; patchIndex < (int)_patches.size(); ++patchIndex) {
1204 
1205         PatchTuple const & patch = _patches[patchIndex];
1206 
1207         //
1208         //  Identify and assign points, stencils, sharpness, etc. for this patch:
1209         //
1210         identifyPatchTopology(patch, patchInfo);
1211 
1212         PatchArrayBuilder * arrayBuilder = &arrayBuilders[ARRAY_REGULAR];
1213         if (!patchInfo.isRegular) {
1214             arrayBuilder = &arrayBuilders[ARRAY_IRREGULAR];
1215         }
1216 
1217         if (_requiresLegacyGregoryTables && !patchInfo.isRegular) {
1218             if (isBoundaryFace(
1219                     _refiner.getLevel(patch.levelIndex), patch.faceIndex)) {
1220                 arrayBuilder = &arrayBuilders[ARRAY_BOUNDARY];
1221             }
1222             arrayBuilder->iptr += assignFacePoints(patch, arrayBuilder->iptr);
1223         } else {
1224             arrayBuilder->iptr += assignPatchPointsAndStencils(patch,
1225                         patchInfo, arrayBuilder->iptr, *vertexLocalPointHelper);
1226         }
1227         if (_requiresSharpnessArray) {
1228             *arrayBuilder->sptr++ = assignSharpnessIndex(patchInfo.regSharpness,
1229                         _table->_sharpnessValues);
1230         }
1231 
1232         //
1233         //  Identify the PatchParam -- which may vary slightly for face-varying
1234         //  channels but will still be used to initialize them when so to avoid
1235         //  recomputing from scratch
1236         //
1237         PatchParam patchParam =
1238             _patchBuilder->ComputePatchParam(patch.levelIndex, patch.faceIndex,
1239                   _ptexIndices, patchInfo.isRegular, patchInfo.paramBoundaryMask,
1240                   true/* condition to compute transition mask */);
1241         *arrayBuilder->pptr++ = patchParam;
1242 
1243         //
1244         //  Assignment of face-varying patches is split between the comon/trivial
1245         //  case of linear patches and the more complex non-linear cases:
1246         //
1247         assert((_fvarChannelIndices.size() > 0) == _requiresFVarPatches);
1248         for (int fvc = 0; fvc < (int)_fvarChannelIndices.size(); ++fvc) {
1249 
1250             if (isFVarChannelLinear(fvc)) {
1251                 assignFacePoints(patch, arrayBuilder->fptr[fvc], fvc);
1252 
1253                 *arrayBuilder->fpptr[fvc] = patchParam;
1254             } else {
1255                 //
1256                 //  For non-linear patches, reuse patch information when the
1257                 //  topology of the face in face-varying space matches the
1258                 //  original patch:
1259                 //
1260                 bool fvcTopologyMatches = fvarPrecisionMatches &&
1261                                           doesFVarTopologyMatch(patch, fvc);
1262 
1263                 PatchInfo & fvcPatchInfo = fvcTopologyMatches
1264                                          ? patchInfo : fvarPatchInfo;
1265 
1266                 if (!fvcTopologyMatches) {
1267                     identifyPatchTopology(patch, fvcPatchInfo, fvc);
1268                 }
1269                 assignPatchPointsAndStencils(patch, fvcPatchInfo,
1270                         arrayBuilder->fptr[fvc], *fvarLocalPointHelpers[fvc], fvc);
1271 
1272                 //  Initialize and assign the face-varying PatchParam:
1273                 PatchParam & fvcPatchParam = *arrayBuilder->fpptr[fvc];
1274                 fvcPatchParam.Set(
1275                    patchParam.GetFaceId(),
1276                    patchParam.GetU(), patchParam.GetV(),
1277                    patchParam.GetDepth(),
1278                    patchParam.NonQuadRoot(),
1279                    fvcPatchInfo.paramBoundaryMask,
1280                    patchParam.GetTransition(),
1281                    fvcPatchInfo.isRegular);
1282             }
1283             arrayBuilder->fpptr[fvc] ++;
1284             arrayBuilder->fptr[fvc] += _table->GetFVarValueStride(fvc);
1285         }
1286 
1287         if (_requiresVaryingPatches) {
1288             arrayBuilder->vptr += assignFacePoints(patch, arrayBuilder->vptr);
1289         }
1290     }
1291 
1292     //
1293     //  Finalizing and destroying StencilTable and other helpers:
1294     //
1295     if (_requiresLocalPoints) {
1296         _table->_localPointStencils =
1297             vertexLocalPointHelper->AcquireStencilTable();
1298         if (_requiresVaryingLocalPoints) {
1299             _table->_localPointVaryingStencils =
1300                 vertexLocalPointHelper->AcquireStencilTableVarying();
1301         }
1302         delete vertexLocalPointHelper;
1303 
1304         if (_requiresFVarPatches) {
1305             _table->_localPointFaceVaryingStencils.resize(_fvarChannelIndices.size());
1306 
1307             for (int fvc=0; fvc<(int)_fvarChannelIndices.size(); ++fvc) {
1308                 _table->_localPointFaceVaryingStencils[fvc] =
1309                         fvarLocalPointHelpers[fvc]->AcquireStencilTable();
1310                 delete fvarLocalPointHelpers[fvc];
1311             }
1312         }
1313     }
1314     if (_requiresLegacyGregoryTables) {
1315         _legacyGregoryHelper->FinalizeQuadOffsets(_table->_quadOffsetsTable);
1316         _legacyGregoryHelper->FinalizeVertexValence(_table->_vertexValenceTable,
1317                                        _levelVertOffsets[_refiner.GetMaxLevel()]);
1318     }
1319 }
1320 
1321 int
estimateLocalPointCount(LocalPointHelper::Options const & options,int fvarChannel) const1322 PatchTableBuilder::estimateLocalPointCount(
1323         LocalPointHelper::Options const & options,
1324         int fvarChannel) const {
1325 
1326     if ((fvarChannel >= 0) && isFVarChannelLinear(fvarChannel)) return 0;
1327 
1328     //
1329     //  Estimate the local points required for the Vertex topology in all cases
1330     //  as it may be used in the estimates for face-varying channels:
1331     //
1332     int estLocalPoints = 0;
1333 
1334     if (_requiresRegularLocalPoints) {
1335         //
1336         //  Either all regular patches are being converted to a non-native
1337         //  basis, or boundary points are being extrapolated in the regular
1338         //  basis.  The latter case typically involves a small fraction of
1339         //  patches and points, so we don't estimate any local points and
1340         //  leave it up to incremental allocation later to account for them.
1341         //
1342         int numPointsPerPatch = PatchDescriptor(
1343                 _patchBuilder->GetRegularPatchType()).GetNumControlVertices();
1344 
1345         if (_patchBuilder->GetRegularPatchType() !=
1346                 _patchBuilder->GetNativePatchType()) {
1347             estLocalPoints += _numRegularPatches * numPointsPerPatch;
1348         }
1349     }
1350     if (_requiresIrregularLocalPoints) {
1351         bool oldEstimate = false;
1352         int numIrregularPatches = oldEstimate ?
1353             _refiner.GetLevel(_refiner.GetMaxLevel()).GetNumFaces() :
1354             _numIrregularPatches;
1355 
1356         //
1357         //  If converting to a basis other than regular, its difficult to
1358         //  predict the degree of point-sharing that may occur, and in general,
1359         //  the maximal benefit is small so we don't attempt to compensate for
1360         //  it here.  If converting to the same basis as regular, roughly half
1361         //  of the points of the patch are involved in approximating the
1362         //  irregularity (and cannot be shared) so don't include the source
1363         //  points that will be used in such patches.
1364         //
1365         int numPointsPerPatch = PatchDescriptor(
1366             _patchBuilder->GetIrregularPatchType()).GetNumControlVertices();
1367 
1368         if (options.reuseSourcePoints && (_patchBuilder->GetIrregularPatchType() ==
1369                                           _patchBuilder->GetNativePatchType())) {
1370             numPointsPerPatch /= 2;
1371         }
1372         estLocalPoints += numIrregularPatches * numPointsPerPatch;
1373     }
1374 
1375     //
1376     //  Its difficult to estimate the differences in number of irregularities
1377     //  between the vertex topology and a face-varying channel without more
1378     //  detailed inspection.
1379     //
1380     //  A much higher number of fvar-values than vertices is an indication that
1381     //  the number of differences increases, and that generally lowers the
1382     //  number of irregular patches due to more regular patches on face-varying
1383     //  boundaries, but not always.  The use of some interpolation types, e.g.
1384     //  LINEAR_BOUNDARIES, combined with inf-sharp patches can increase the
1385     //  number of irregularities significantly.
1386     //
1387     if ((fvarChannel >= 0) && (_refiner.GetNumLevels() > 1)) {
1388         //
1389         //  We're seeing face-varying stencil table sizes about 1/4 the size of
1390         //  the vertex stencil table for what seem like typical cases...
1391         //
1392         //  Identify the ratio of fvar-values to vertices that typically leads
1393         //  to these reductions and reduce the number of expected local points
1394         //  proportionally.  Use the number of fvar-values at level 1:  level 0
1395         //  can be misleading as there can be many FEWER than the number of
1396         //  vertices, but subsequent levels will have at least one unique
1397         //  fvar-value per vertex, and later levels will have a much higher
1398         //  percentage shared as a result of refinement.
1399         //
1400         int fvc = getRefinerFVarChannel(fvarChannel);
1401         if (_refiner.GetLevel(1).GetNumFVarValues(fvc) >
1402                 _refiner.GetLevel(1).GetNumVertices()) {
1403             //  Scale this based on ratio of fvar-values to vertices...
1404             float fvarReduction = 0.5;
1405 
1406             estLocalPoints = (int) ((float)estLocalPoints * fvarReduction);
1407         }
1408     }
1409     return estLocalPoints;
1410 }
1411 
1412 
1413 //
1414 //  Member function definitions for the LocalPointHelper class:
1415 //
LocalPointHelper(TopologyRefiner const & refiner,Options const & options,int fvarChannel,int numLocalPointsExpected)1416 PatchTableBuilder::LocalPointHelper::LocalPointHelper(
1417         TopologyRefiner const & refiner, Options const & options,
1418         int fvarChannel, int numLocalPointsExpected) :
1419             _refiner(refiner), _options(options), _fvarChannel(fvarChannel),
1420             _numLocalPoints(0), _stencilTable(), _stencilTableVarying() {
1421 
1422     _localPointOffset = (_fvarChannel < 0)
1423                       ? _refiner.GetNumVerticesTotal()
1424                       : _refiner.GetNumFVarValuesTotal(_fvarChannel);
1425 
1426     if (_options.createStencilTable) {
1427         if (_options.doubleStencilTable) {
1428             initializeStencilTable<double>(numLocalPointsExpected);
1429         } else {
1430             initializeStencilTable<float>(numLocalPointsExpected);
1431         }
1432     }
1433 }
1434 
1435 template <typename REAL>
1436 void
initializeStencilTable(int numLocalPointsExpected)1437 PatchTableBuilder::LocalPointHelper::initializeStencilTable(int numLocalPointsExpected) {
1438 
1439     //
1440     //  Reserving space for the local-point stencils has been a source of
1441     //  problems in the past so we rely on the PatchTableBuilder to provide
1442     //  a reasonable estimate to the LocalPointHelper on construction.  For
1443     //  large meshes a limit on the size initially reserve is capped.
1444     //
1445     //  The average number of entries per stencil has been historically set
1446     //  at 16, which seemed high and was reduced on further investigation.
1447     //
1448     StencilTableReal<REAL> * stencilTable = new StencilTableReal<REAL>(0);
1449     StencilTableReal<REAL> * varyingTable = _options.createVaryingTable
1450                                           ? new StencilTableReal<REAL>(0) : 0;
1451 
1452     //  Historic note:  limits to 100M (=800M bytes) entries for reserved size
1453     size_t const MaxEntriesToReserve  = 100 * 1024 * 1024;
1454     size_t const AvgEntriesPerStencil = 9;  // originally 16
1455 
1456     size_t numStencilsExpected       = numLocalPointsExpected;
1457     size_t numStencilEntriesExpected = numStencilsExpected * AvgEntriesPerStencil;
1458 
1459     size_t numEntriesToReserve = std::min(numStencilEntriesExpected,
1460                                           MaxEntriesToReserve);
1461     if (numEntriesToReserve) {
1462         stencilTable->reserve(
1463                 (int)numStencilsExpected, (int)numEntriesToReserve);
1464 
1465         if (varyingTable) {
1466             //  Varying stencils have only one entry per point
1467             varyingTable->reserve(
1468                     (int)numStencilsExpected, (int)numStencilsExpected);
1469         }
1470     }
1471 
1472     _stencilTable.Set(stencilTable);
1473     _stencilTableVarying.Set(varyingTable);
1474 }
1475 
1476 template <typename REAL>
1477 PatchTableBuilder::StencilTablePtr
acquireStencilTable(StencilTablePtr & stencilTableMember)1478 PatchTableBuilder::LocalPointHelper::acquireStencilTable(
1479         StencilTablePtr& stencilTableMember) {
1480 
1481     StencilTableReal<REAL> * stencilTable = stencilTableMember.Get<REAL>();
1482 
1483     if (stencilTable) {
1484         if (stencilTable->GetNumStencils() > 0) {
1485             stencilTable->finalize();
1486         } else {
1487             delete stencilTable;
1488             stencilTable = 0;
1489         }
1490     }
1491 
1492     stencilTableMember.Set();
1493     return StencilTablePtr(stencilTable);
1494 }
1495 
~LocalPointHelper()1496 PatchTableBuilder::LocalPointHelper::~LocalPointHelper() {
1497 
1498     if (_options.doubleStencilTable) {
1499         delete _stencilTable.Get<double>();
1500         delete _stencilTableVarying.Get<double>();
1501     } else {
1502         delete _stencilTable.Get<float>();
1503         delete _stencilTableVarying.Get<float>();
1504     }
1505 }
1506 
1507 Index
findSharedCornerPoint(int levelIndex,Index vertIndex,Index localPointIndex)1508 PatchTableBuilder::LocalPointHelper::findSharedCornerPoint(int levelIndex,
1509         Index vertIndex, Index localPointIndex) {
1510 
1511     if (_sharedCornerPoints.empty()) {
1512         _sharedCornerPoints.resize(_refiner.GetNumLevels());
1513     }
1514 
1515     IndexVector & vertexPoints = _sharedCornerPoints[levelIndex];
1516     if (vertexPoints.empty()) {
1517         Level const & level = _refiner.getLevel(levelIndex);
1518 
1519         if (_fvarChannel < 0) {
1520             vertexPoints.resize(level.getNumVertices(), INDEX_INVALID);
1521         } else {
1522             vertexPoints.resize(level.getNumFVarValues(_fvarChannel), INDEX_INVALID);
1523         }
1524     }
1525 
1526     Index & assignedIndex = vertexPoints[vertIndex];
1527     if (!IndexIsValid(assignedIndex)) {
1528         assignedIndex = localPointIndex;
1529     }
1530     return assignedIndex;
1531 }
1532 
1533 Index
findSharedEdgePoint(int levelIndex,Index edgeIndex,int edgeEnd,Index localPointIndex)1534 PatchTableBuilder::LocalPointHelper::findSharedEdgePoint(int levelIndex,
1535          Index edgeIndex, int edgeEnd, Index localPointIndex) {
1536 
1537     if (_sharedEdgePoints.empty()) {
1538         _sharedEdgePoints.resize(_refiner.GetNumLevels());
1539     }
1540 
1541     IndexVector & edgePoints = _sharedEdgePoints[levelIndex];
1542     if (edgePoints.empty()) {
1543         edgePoints.resize(
1544                 2 * _refiner.GetLevel(levelIndex).GetNumEdges(), INDEX_INVALID);
1545     }
1546 
1547     Index & assignedIndex = edgePoints[2 * edgeIndex + edgeEnd];
1548     if (!IndexIsValid(assignedIndex)) {
1549         assignedIndex = localPointIndex;
1550     } else {
1551     }
1552     return assignedIndex;
1553 }
1554 
1555 template <typename REAL>
1556 void
appendLocalPointStencil(SparseMatrix<REAL> const & conversionMatrix,int stencilRow,Index const sourcePoints[],int sourcePointOffset)1557 PatchTableBuilder::LocalPointHelper::appendLocalPointStencil(
1558     SparseMatrix<REAL> const &  conversionMatrix,
1559     int                         stencilRow,
1560     Index const                 sourcePoints[],
1561     int                         sourcePointOffset) {
1562 
1563     int               stencilSize   = conversionMatrix.GetRowSize(stencilRow);
1564     ConstArray<int>   matrixColumns = conversionMatrix.GetRowColumns(stencilRow);
1565     ConstArray<REAL>  matrixWeights = conversionMatrix.GetRowElements(stencilRow);
1566 
1567     StencilTableReal<REAL>* stencilTable = _stencilTable.Get<REAL>();
1568 
1569     stencilTable->_sizes.push_back(stencilSize);
1570     for (int i = 0; i < stencilSize; ++i) {
1571         stencilTable->_weights.push_back(matrixWeights[i]);
1572         stencilTable->_indices.push_back(
1573                 sourcePoints[matrixColumns[i]] + sourcePointOffset);
1574     }
1575 }
1576 
1577 template <typename REAL>
1578 void
appendLocalPointStencils(SparseMatrix<REAL> const & conversionMatrix,Index const sourcePoints[],int sourcePointOffset)1579 PatchTableBuilder::LocalPointHelper::appendLocalPointStencils(
1580     SparseMatrix<REAL> const &  conversionMatrix,
1581     Index const                 sourcePoints[],
1582     int                         sourcePointOffset) {
1583 
1584     //
1585     //  Resize the StencilTable members to accomodate all rows and elements from
1586     //  the given set of points represented by the matrix
1587     //
1588     StencilTableReal<REAL>* stencilTable = _stencilTable.Get<REAL>();
1589 
1590     int numNewStencils = conversionMatrix.GetNumRows();
1591     int numNewElements = conversionMatrix.GetNumElements();
1592 
1593     size_t numOldStencils = stencilTable->_sizes.size();
1594     size_t numOldElements = stencilTable->_indices.size();
1595 
1596     //  Assign the sizes for the new stencils:
1597     stencilTable->_sizes.resize(numOldStencils + numNewStencils);
1598 
1599     int * newSizes = &stencilTable->_sizes[numOldStencils];
1600     for (int i = 0; i < numNewStencils; ++i) {
1601         newSizes[i] = conversionMatrix.GetRowSize(i);
1602     }
1603 
1604     //  Assign remapped indices for the stencils:
1605     stencilTable->_indices.resize(numOldElements + numNewElements);
1606 
1607     int const * mtxIndices = &conversionMatrix.GetColumns()[0];
1608     int *       newIndices = &stencilTable->_indices[numOldElements];
1609 
1610     for (int i = 0; i < numNewElements; ++i) {
1611         newIndices[i] = sourcePoints[mtxIndices[i]] + sourcePointOffset;
1612     }
1613 
1614     //  Copy the stencil weights direct from the matrix elements:
1615     stencilTable->_weights.resize(numOldElements + numNewElements);
1616 
1617     REAL const * mtxWeights = &conversionMatrix.GetElements()[0];
1618     REAL *       newWeights = &stencilTable->_weights[numOldElements];
1619 
1620     std::memcpy(newWeights, mtxWeights, numNewElements * sizeof(REAL));
1621 }
1622 
1623 
1624 //
1625 //  Its unfortunate that varying stencils for local points were ever created
1626 //  and external dependency on them forces a certain coordination here.  Each
1627 //  patch type is expected to have a varying value computed for each patch
1628 //  point and shaders retrieve the varying value associated with particular
1629 //  points.  So we need to store that mapping from control point to varying
1630 //  point (or corner of the patch) somewhere.  We are trying to avoid adding
1631 //  more to the PatchDescriptor interface, so we'll keep it here for now in
1632 //  the hope we may be able to eliminate the need for it.
1633 //
1634 namespace {
1635     inline int const *
GetVaryingIndicesPerType(PatchDescriptor::Type type)1636     GetVaryingIndicesPerType(PatchDescriptor::Type type) {
1637 
1638         //  Note that we can use the linear and gregory vectors here for
1639         //  both quads and tris
1640         static int const linearIndices[4] = { 0, 1, 2, 3 };
1641         static int const bsplineIndices[] =
1642                 { 0, 0, 1, 1, 0, 0, 1, 1, 3, 3, 2, 2, 3, 3, 2, 2 };
1643         static int const boxsplineIndices[] =
1644                 { 0, 0, 1, 0, 0, 1, 1, 2, 2, 1, 2, 2 };
1645         static int const gregoryIndices[] =
1646                 { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3 };
1647         static int const gregoryTriIndices[] =
1648                 { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0, 1, 2 };
1649 
1650         if (type == PatchDescriptor::GREGORY_BASIS) {
1651             return gregoryIndices;
1652         } else if (type == PatchDescriptor::GREGORY_TRIANGLE) {
1653             return gregoryTriIndices;
1654         } else if (type == PatchDescriptor::REGULAR) {
1655             return bsplineIndices;
1656         } else if (type == PatchDescriptor::LOOP) {
1657             return boxsplineIndices;
1658         } else if (type == PatchDescriptor::QUADS) {
1659             return linearIndices;
1660         } else if (type == PatchDescriptor::TRIANGLES) {
1661             return linearIndices;
1662         }
1663         return 0;
1664     }
1665 }
1666 
1667 template <typename REAL>
1668 void
appendLocalPointVaryingStencil(int const * varyingIndices,int patchPointIndex,Index const sourcePoints[],int sourcePointOffset)1669 PatchTableBuilder::LocalPointHelper::appendLocalPointVaryingStencil(
1670     int const * varyingIndices, int patchPointIndex,
1671     Index const sourcePoints[], int sourcePointOffset) {
1672 
1673     Index varyingPoint =
1674         sourcePoints[varyingIndices[patchPointIndex]] + sourcePointOffset;
1675 
1676     StencilTableReal<REAL>* t = _stencilTableVarying.Get<REAL>();
1677 
1678     t->_sizes.push_back(1);
1679     t->_indices.push_back(varyingPoint);
1680     t->_weights.push_back((REAL) 1.0);
1681 }
1682 
1683 namespace {
1684     typedef short ShareBits;
1685 
1686     static ShareBits const SHARE_CORNER     = 0x10;
1687     static ShareBits const SHARE_EDGE_BEGIN = 0x20;
1688     static ShareBits const SHARE_EDGE_END   = 0x40;
1689     static ShareBits const SHARE_EDGE       = SHARE_EDGE_BEGIN | SHARE_EDGE_END;
1690     static ShareBits const SHARE_INDEX_MASK = 0x0f;
1691 
1692     inline ShareBits const *
GetShareBitsPerType(PatchDescriptor::Type type)1693     GetShareBitsPerType(PatchDescriptor::Type type) {
1694 
1695         static ShareBits const linearQuadBits[5] = { 0x10, 0x11, 0x12, 0x13,
1696                                                      SHARE_CORNER };
1697         static ShareBits const gregoryQuadBits[21] = { 0x10, 0x20, 0x43, 0, 0,
1698                                                        0x11, 0x21, 0x40, 0, 0,
1699                                                        0x12, 0x22, 0x41, 0, 0,
1700                                                        0x13, 0x23, 0x42, 0, 0,
1701                                                        SHARE_CORNER | SHARE_EDGE };
1702 
1703         if (type == PatchDescriptor::QUADS) {
1704             return linearQuadBits;
1705         } else if (type == PatchDescriptor::GREGORY_BASIS) {
1706             return gregoryQuadBits;
1707         }
1708         return 0;
1709     }
1710 }
1711 
1712 template <typename REAL>
1713 int
AppendLocalPatchPoints(int levelIndex,Index faceIndex,SparseMatrix<REAL> const & matrix,PatchDescriptor::Type patchType,Index const sourcePoints[],int sourcePointOffset,Index patchPoints[])1714 PatchTableBuilder::LocalPointHelper::AppendLocalPatchPoints(
1715     int levelIndex, Index faceIndex,
1716     SparseMatrix<REAL> const &  matrix,
1717     PatchDescriptor::Type       patchType,
1718     Index const                 sourcePoints[],
1719     int                         sourcePointOffset,
1720     Index                       patchPoints[]) {
1721 
1722     //
1723     //  If sharing local points, verify the type of this patch supports
1724     //  sharing and disable it if not:
1725     //
1726     int numPatchPoints  = matrix.GetNumRows();
1727 
1728     int firstNewLocalPoint = _localPointOffset + _numLocalPoints;
1729     int nextNewLocalPoint  = firstNewLocalPoint;
1730 
1731     ShareBits const* shareBitsPerPoint = _options.shareLocalPoints ?
1732                         GetShareBitsPerType(patchType) : 0;
1733 
1734     bool shareLocalPointsForThisPatch = (shareBitsPerPoint != 0);
1735 
1736     int const * varyingIndices = 0;
1737     if (_stencilTableVarying) {
1738         varyingIndices = GetVaryingIndicesPerType(patchType);
1739     }
1740 
1741     bool applyVertexStencils  = (_stencilTable.Get<REAL>() != 0);
1742     bool applyVaryingStencils = (varyingIndices != 0);
1743 
1744     //
1745     //  When point-sharing is not enabled, all patch points are generally
1746     //  new local points -- the exception to this occurs when "re-using"
1747     //  source points, i.e. the resulting patch can be a mixture of source
1748     //  and local points (typically when the irregular patch type is the
1749     //  same as the regular patch type native to the scheme).
1750     //
1751     if (!shareLocalPointsForThisPatch) {
1752         if (!_options.reuseSourcePoints) {
1753             if (applyVertexStencils) {
1754                 appendLocalPointStencils(
1755                     matrix, sourcePoints, sourcePointOffset);
1756                 if (applyVaryingStencils) {
1757                     for (int i = 0; i < numPatchPoints; ++i) {
1758                         appendLocalPointVaryingStencil<REAL>(
1759                             varyingIndices, i, sourcePoints, sourcePointOffset);
1760                     }
1761                 }
1762             }
1763             for (int i = 0; i < numPatchPoints; ++i) {
1764                 patchPoints[i] = nextNewLocalPoint ++;
1765             }
1766         } else {
1767             for (int i = 0; i < numPatchPoints; ++i) {
1768                 if (_options.reuseSourcePoints && (matrix.GetRowSize(i) == 1)) {
1769                     patchPoints[i] = sourcePoints[matrix.GetRowColumns(i)[0]]
1770                                    + sourcePointOffset;
1771                     continue;
1772                 }
1773                 if (applyVertexStencils) {
1774                     appendLocalPointStencil(
1775                         matrix, i, sourcePoints, sourcePointOffset);
1776                     if (applyVaryingStencils) {
1777                         appendLocalPointVaryingStencil<REAL>(
1778                             varyingIndices, i, sourcePoints, sourcePointOffset);
1779                     }
1780                 }
1781                 patchPoints[i] = nextNewLocalPoint ++;
1782             }
1783         }
1784     } else {
1785         //  Gather topology info according to the sharing for this patch type
1786         //
1787         Level const & level = _refiner.getLevel(levelIndex);
1788 
1789         ConstIndexArray fCorners;
1790         ConstIndexArray fVerts;
1791         ConstIndexArray fEdges;
1792         bool            fEdgeReversed[4];
1793         bool            fEdgeBoundary[4];
1794 
1795         ShareBits const shareBitsForType = shareBitsPerPoint[numPatchPoints];
1796         if (shareBitsForType) {
1797             if (shareBitsForType & SHARE_CORNER) {
1798                 fCorners = (_fvarChannel < 0)
1799                          ? level.getFaceVertices(faceIndex)
1800                          : level.getFaceFVarValues(faceIndex, _fvarChannel);
1801             }
1802             if (shareBitsForType & SHARE_EDGE) {
1803                 fEdges = level.getFaceEdges(faceIndex);
1804                 fVerts = (_fvarChannel < 0) ? fCorners
1805                                             : level.getFaceVertices(faceIndex);
1806 
1807                 Level::ETag fEdgeTags[4];
1808                 level.getFaceETags(faceIndex, fEdgeTags, _fvarChannel);
1809 
1810                 for (int i = 0; i < fEdges.size(); ++i) {
1811                     fEdgeReversed[i] = level.getEdgeVertices(fEdges[i])[0] != fVerts[i];
1812                     fEdgeBoundary[i] = fEdgeTags[i]._boundary;
1813                 }
1814             }
1815         }
1816 
1817         //  Inspect the sharing bits for each point -- if set, see if a local
1818         //  point for the corresponding vertex/fvar-value or edge was
1819         //  previously used:
1820         //
1821         for (int i = 0; i < numPatchPoints; ++i) {
1822             if (_options.reuseSourcePoints && (matrix.GetRowSize(i) == 1)) {
1823                 patchPoints[i] = sourcePoints[matrix.GetRowColumns(i)[0]]
1824                                + sourcePointOffset;
1825                 continue;
1826             }
1827 
1828             int patchPoint = nextNewLocalPoint;
1829 
1830             if (shareBitsPerPoint[i]) {
1831                 int index = shareBitsPerPoint[i] & SHARE_INDEX_MASK;
1832 
1833                 if (shareBitsPerPoint[i] & SHARE_CORNER) {
1834                     patchPoint = findSharedCornerPoint(
1835                         levelIndex, fCorners[index], nextNewLocalPoint);
1836                 } else if (!fEdgeBoundary[index]) {
1837                     int edgeEnd = (((shareBitsPerPoint[i] & SHARE_EDGE_END) > 0) !=
1838                                    fEdgeReversed[index]);
1839                     patchPoint = findSharedEdgePoint(
1840                         levelIndex, fEdges[index], edgeEnd, nextNewLocalPoint);
1841                 }
1842             }
1843             if (patchPoint == nextNewLocalPoint) {
1844                 if (applyVertexStencils) {
1845                     appendLocalPointStencil(
1846                         matrix, i, sourcePoints, sourcePointOffset);
1847                     if (applyVaryingStencils) {
1848                         appendLocalPointVaryingStencil<REAL>(
1849                             varyingIndices, i, sourcePoints, sourcePointOffset);
1850                     }
1851                 }
1852                 nextNewLocalPoint ++;
1853             }
1854             patchPoints[i] = patchPoint;
1855         }
1856     }
1857 
1858     int numNewLocalPoints = nextNewLocalPoint - firstNewLocalPoint;
1859     _numLocalPoints += numNewLocalPoints;
1860     return numNewLocalPoints;
1861 }
1862 
1863 
1864 //
1865 //  Member function definitions for the LegacyGregoryHelper class:
1866 //
1867 void
AddPatchFace(int level,Index face)1868 PatchTableBuilder::LegacyGregoryHelper::AddPatchFace(int level, Index face) {
1869 
1870     if (_refiner.getLevel(level).getFaceCompositeVTag(face)._boundary) {
1871         _boundaryFaceIndices.push_back(face);
1872     } else {
1873         _interiorFaceIndices.push_back(face);
1874     }
1875 }
1876 
1877 void
FinalizeQuadOffsets(PatchTable::QuadOffsetsTable & qTable)1878 PatchTableBuilder::LegacyGregoryHelper::FinalizeQuadOffsets(
1879         PatchTable::QuadOffsetsTable & qTable) {
1880 
1881     size_t numInteriorPatches = _interiorFaceIndices.size();
1882     size_t numBoundaryPatches = _boundaryFaceIndices.size();
1883     size_t numTotalPatches    = numInteriorPatches + numBoundaryPatches;
1884 
1885     struct QuadOffset {
1886         static int Assign(Level const& level, Index faceIndex,
1887                           unsigned int offsets[]) {
1888             ConstIndexArray fVerts = level.getFaceVertices(faceIndex);
1889 
1890             for (int i = 0; i < 4; ++i) {
1891                 ConstIndexArray vFaces = level.getVertexFaces(fVerts[i]);
1892                 int faceInVFaces = vFaces.FindIndex(faceIndex);
1893 
1894                 // we have to use number of incident edges to modulo the local
1895                 // index as there could be 2 consecutive edges in the face
1896                 // belonging to the patch
1897                 int vOffset0 = faceInVFaces;
1898                 int vOffset1 = (faceInVFaces + 1) %
1899                                     level.getVertexEdges(fVerts[i]).size();
1900                 offsets[i] = vOffset0 | (vOffset1 << 8);
1901             }
1902             return 4;
1903         }
1904     };
1905 
1906     if (numTotalPatches > 0) {
1907         qTable.resize(numTotalPatches*4);
1908 
1909         // all patches assumed to be at the last level
1910         Level const &maxLevel = _refiner.getLevel(_refiner.GetMaxLevel());
1911 
1912         PatchTable::QuadOffsetsTable::value_type *p = &(qTable[0]);
1913         for (size_t i = 0; i < numInteriorPatches; ++i) {
1914             p += QuadOffset::Assign(maxLevel, _interiorFaceIndices[i], p);
1915         }
1916         for (size_t i = 0; i < numBoundaryPatches; ++i) {
1917             p += QuadOffset::Assign(maxLevel, _boundaryFaceIndices[i], p);
1918         }
1919     }
1920 }
1921 
1922 void
FinalizeVertexValence(PatchTable::VertexValenceTable & vTable,int lastLevelOffset)1923 PatchTableBuilder::LegacyGregoryHelper::FinalizeVertexValence(
1924         PatchTable::VertexValenceTable & vTable, int lastLevelOffset) {
1925 
1926     //  Populate the "vertex valence" table for Gregory patches -- this table
1927     //  contains the one-ring of vertices around each vertex.  Currently it is
1928     //  extremely wasteful for the following reasons:
1929     //      - it allocates 2*maxvalence+1 for ALL vertices
1930     //      - it initializes the one-ring for ALL vertices
1931     //  We use the full size expected (not sure what else relies on that) but
1932     //  we avoid initializing the vast majority of vertices that are not
1933     //  associated with gregory patches -- only populating those in the last
1934     //  level (an older version attempted to avoid vertices not involved with
1935     //  Gregory patches)
1936     //
1937     int vWidth = 2*_refiner.GetMaxValence() + 1;
1938 
1939     vTable.resize((long)_refiner.GetNumVerticesTotal() * vWidth);
1940 
1941     Level const & lastLevel = _refiner.getLevel(_refiner.GetMaxLevel());
1942 
1943     int * vTableEntry = &vTable[lastLevelOffset * vWidth];
1944 
1945     for (int vIndex = 0; vIndex < lastLevel.getNumVertices(); ++vIndex) {
1946         //  Gather the one-ring around the vertex and set its resulting size
1947         //  (note negative size used to distinguish between boundary/interior):
1948         //
1949         int *ringDest = vTableEntry + 1;
1950         int  ringSize =
1951                 lastLevel.gatherQuadRegularRingAroundVertex(vIndex, ringDest);
1952 
1953         for (int j = 0; j < ringSize; ++j) {
1954             ringDest[j] += lastLevelOffset;
1955         }
1956         if (ringSize & 1) {
1957             // boundary: duplicate end vertex index and store negative valence
1958             ringSize++;
1959             vTableEntry[ringSize]=vTableEntry[ringSize-1];
1960             vTableEntry[0] = -ringSize/2;
1961         } else {
1962             vTableEntry[0] = ringSize/2;
1963         }
1964         vTableEntry += vWidth;
1965     }
1966 }
1967 
1968 
1969 //
1970 //  The sole public PatchTableFactory method to create a PatchTable -- deferring
1971 //  to the PatchTableBuilder implementation
1972 //
1973 PatchTable *
Create(TopologyRefiner const & refiner,Options options,ConstIndexArray selectedFaces)1974 PatchTableFactory::Create(TopologyRefiner const & refiner,
1975                           Options options,
1976                           ConstIndexArray selectedFaces) {
1977 
1978     PatchTableBuilder builder(refiner, options, selectedFaces);
1979 
1980     if (builder.UniformPolygonsSpecified()) {
1981         builder.BuildUniformPolygons();
1982     } else {
1983         builder.BuildPatches();
1984     }
1985     return builder.GetPatchTable();
1986 }
1987 
1988 
1989 //
1990 //  Implementation of PatchTableFactory::PatchFaceTag -- unintentionally
1991 //  exposed to the public interface, no longer internally used and so
1992 //  planned for deprecation
1993 //
1994 void
clear()1995 PatchTableFactory::PatchFaceTag::clear() {
1996     std::memset(this, 0, sizeof(*this));
1997 }
1998 
1999 void
assignTransitionPropertiesFromEdgeMask(int tMask)2000 PatchTableFactory::PatchFaceTag::assignTransitionPropertiesFromEdgeMask(
2001         int tMask) {
2002 
2003     _transitionMask = tMask;
2004 }
2005 
2006 void
assignBoundaryPropertiesFromEdgeMask(int eMask)2007 PatchTableFactory::PatchFaceTag::assignBoundaryPropertiesFromEdgeMask(
2008         int eMask) {
2009 
2010     static int const edgeMaskToCount[16] =
2011         { 0, 1, 1, 2, 1, -1, 2, -1, 1, 2, -1, -1, 2, -1, -1, -1 };
2012     static int const edgeMaskToIndex[16] =
2013         { -1, 0, 1, 1, 2, -1, 2, -1, 3, 0, -1, -1, 3, -1, -1,-1 };
2014 
2015     assert(edgeMaskToCount[eMask] != -1);
2016     assert(edgeMaskToIndex[eMask] != -1);
2017 
2018     _boundaryMask    = eMask;
2019     _hasBoundaryEdge = (eMask > 0);
2020 
2021     _boundaryCount = edgeMaskToCount[eMask];
2022     _boundaryIndex = edgeMaskToIndex[eMask];
2023 }
2024 
2025 void
assignBoundaryPropertiesFromVertexMask(int vMask)2026 PatchTableFactory::PatchFaceTag::assignBoundaryPropertiesFromVertexMask(
2027         int vMask) {
2028 
2029     // This is only intended to support the case of a single boundary vertex
2030     // with no boundary edges, which can only occur with an irregular vertex
2031 
2032     static int const singleBitVertexMaskToCount[16] =
2033         { 0, 1, 1, -1, 1, -1 , -1, -1, 1, -1 , -1, -1, -1, -1 , -1, -1 };
2034     static int const singleBitVertexMaskToIndex[16] =
2035         { 0, 0, 1, -1, 2, -1 , -1, -1, 3, -1 , -1, -1, -1, -1 , -1, -1 };
2036 
2037     assert(_hasBoundaryEdge == false);
2038     assert(singleBitVertexMaskToCount[vMask] != -1);
2039     assert(singleBitVertexMaskToIndex[vMask] != -1);
2040 
2041     _boundaryMask = vMask;
2042 
2043     _boundaryCount = singleBitVertexMaskToCount[vMask];
2044     _boundaryIndex = singleBitVertexMaskToIndex[vMask];
2045 }
2046 
2047 } // end namespace Far
2048 
2049 } // end namespace OPENSUBDIV_VERSION
2050 } // end namespace OpenSubdiv
2051