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