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
25 #ifndef OPENSUBDIV3_HBRMESH_H
26 #define OPENSUBDIV3_HBRMESH_H
27
28 #ifdef PRMAN
29 #include "libtarget/TgMalloc.h" // only for alloca
30 #include "libtarget/TgThread.h"
31 #ifdef HBRSTITCH
32 #include "libtarget/TgHashMap.h"
33 #endif
34 #endif
35
36 #include <algorithm>
37 #include <cstring>
38 #include <iterator>
39 #include <vector>
40 #include <set>
41 #include <iostream>
42
43 #include "../hbr/vertex.h"
44 #include "../hbr/face.h"
45 #include "../hbr/hierarchicalEdit.h"
46 #include "../hbr/vertexEdit.h"
47 #include "../hbr/creaseEdit.h"
48 #include "../hbr/allocator.h"
49
50 #include "../version.h"
51
52 namespace OpenSubdiv {
53 namespace OPENSUBDIV_VERSION {
54
55 template <class T> class HbrSubdivision;
56 template <class T> class HbrHalfedge;
57
58 template <class T> class HbrMesh {
59 public:
60 HbrMesh(HbrSubdivision<T>* subdivision = 0, int fvarcount = 0, const int *fvarindices = 0, const int *fvarwidths = 0, int totalfvarwidth = 0
61 #ifdef HBRSTITCH
62 , int stitchCount = 0
63 #endif
64 );
65 ~HbrMesh();
66
67 // Create vertex with the indicated ID and data
68 HbrVertex<T>* NewVertex(int id, const T &data);
69
70 // Create vertex with the indicated data. The ID will be assigned
71 // by the mesh.
72 HbrVertex<T>* NewVertex(const T &data);
73
74 // Create vertex without an ID - one will be assigned by the mesh,
75 // and the data implicitly created will share the same id
76 HbrVertex<T>* NewVertex();
77
78 // Ask for vertex with the indicated ID
GetVertex(int id)79 HbrVertex<T>* GetVertex(int id) const {
80 if (id >= nvertices) {
81 return 0;
82 } else {
83 return vertices[id];
84 }
85 }
86
87 // Ask for client data associated with the vertex with the indicated ID
GetVertexClientData(int id)88 void* GetVertexClientData(int id) const {
89 if (id >= vertexClientData.size()) {
90 return 0;
91 } else {
92 return vertexClientData[id];
93 }
94 }
95
96 // Set client data associated with the vertex with the indicated ID
SetVertexClientData(int id,void * data)97 void SetVertexClientData(int id, void *data) {
98 if (id >= vertexClientData.size()) {
99 size_t oldsize = vertexClientData.size();
100 vertexClientData.resize(nvertices);
101 if (s_memStatsIncrement) {
102 s_memStatsIncrement((vertexClientData.size() - oldsize) * sizeof(void*));
103 }
104 }
105 vertexClientData[id] = data;
106 }
107
108 // Create face from a list of vertex IDs
109 HbrFace<T>* NewFace(int nvertices, const int *vtx, int uindex);
110
111 // Create face from a list of vertices
112 HbrFace<T>* NewFace(int nvertices, HbrVertex<T>** vtx, HbrFace<T>* parent, int childindex);
113
114 // "Create" a new uniform index
NewUniformIndex()115 int NewUniformIndex() { return ++maxUniformIndex; }
116
117 // Finishes initialization of the mesh
118 void Finish();
119
120 // Remove the indicated face from the mesh
121 void DeleteFace(HbrFace<T>* face);
122
123 // Remove the indicated vertex from the mesh
124 void DeleteVertex(HbrVertex<T>* vertex);
125
126 // Returns number of vertices in the mesh
127 int GetNumVertices() const;
128
129 // Returns number of disconnected vertices in the mesh
130 int GetNumDisconnectedVertices() const;
131
132 // Returns number of faces in the mesh
133 int GetNumFaces() const;
134
135 // Returns number of coarse faces in the mesh
136 int GetNumCoarseFaces() const;
137
138 // Ask for face with the indicated ID
139 HbrFace<T>* GetFace(int id) const;
140
141 // Ask for client data associated with the face with the indicated ID
GetFaceClientData(int id)142 void* GetFaceClientData(int id) const {
143 if (id >= faceClientData.size()) {
144 return 0;
145 } else {
146 return faceClientData[id];
147 }
148 }
149
150 // Set client data associated with the face with the indicated ID
SetFaceClientData(int id,void * data)151 void SetFaceClientData(int id, void *data) {
152 if (id >= faceClientData.size()) {
153 size_t oldsize = faceClientData.size();
154 faceClientData.resize(nfaces);
155 if (s_memStatsIncrement) {
156 s_memStatsIncrement((faceClientData.size() - oldsize) * sizeof(void*));
157 }
158 }
159 faceClientData[id] = data;
160 }
161
162 // Returns a collection of all vertices in the mesh. This function
163 // requires an output iterator; to get the vertices into a
164 // std::vector, use GetVertices(std::back_inserter(myvector))
165 template <typename OutputIterator>
166 void GetVertices(OutputIterator vertices) const;
167
168 // Applies operator to all vertices
169 void ApplyOperatorAllVertices(HbrVertexOperator<T> &op) const;
170
171 // Returns a collection of all faces in the mesh. This function
172 // requires an output iterator; to get the faces into a
173 // std::vector, use GetFaces(std::back_inserter(myvector))
174 template <typename OutputIterator>
175 void GetFaces(OutputIterator faces) const;
176
177 // Returns the subdivision method
GetSubdivision()178 HbrSubdivision<T>* GetSubdivision() const { return subdivision; }
179
180 // Return the number of facevarying variables
GetFVarCount()181 int GetFVarCount() const { return fvarcount; }
182
183 // Return a table of the start index of each facevarying variable
GetFVarIndices()184 const int *GetFVarIndices() const { return fvarindices; }
185
186 // Return a table of the size of each facevarying variable
GetFVarWidths()187 const int *GetFVarWidths() const { return fvarwidths; }
188
189 // Return the sum size of facevarying variables per vertex
GetTotalFVarWidth()190 int GetTotalFVarWidth() const { return totalfvarwidth; }
191
192 #ifdef HBRSTITCH
GetStitchCount()193 int GetStitchCount() const { return stitchCount; }
194 #endif
195
196 void PrintStats(std::ostream& out);
197
198 // Returns memory statistics
GetMemStats()199 size_t GetMemStats() const { return m_memory; }
200
201 // Interpolate boundary management
202 enum InterpolateBoundaryMethod {
203 k_InterpolateBoundaryNone,
204 k_InterpolateBoundaryEdgeOnly,
205 k_InterpolateBoundaryEdgeAndCorner,
206 k_InterpolateBoundaryAlwaysSharp
207 };
208
GetInterpolateBoundaryMethod()209 InterpolateBoundaryMethod GetInterpolateBoundaryMethod() const { return interpboundarymethod; }
SetInterpolateBoundaryMethod(InterpolateBoundaryMethod method)210 void SetInterpolateBoundaryMethod(InterpolateBoundaryMethod method) { interpboundarymethod = method; }
GetFVarInterpolateBoundaryMethod()211 InterpolateBoundaryMethod GetFVarInterpolateBoundaryMethod() const { return fvarinterpboundarymethod; }
SetFVarInterpolateBoundaryMethod(InterpolateBoundaryMethod method)212 void SetFVarInterpolateBoundaryMethod(InterpolateBoundaryMethod method) { fvarinterpboundarymethod = method; }
213
GetFVarPropagateCorners()214 bool GetFVarPropagateCorners() const { return fvarpropagatecorners; }
SetFVarPropagateCorners(bool p)215 void SetFVarPropagateCorners(bool p) { fvarpropagatecorners = p; }
216
217 // Register routines for keeping track of memory usage
RegisterMemoryRoutines(void (* increment)(unsigned long bytes),void (* decrement)(unsigned long bytes))218 void RegisterMemoryRoutines(void (*increment)(unsigned long bytes), void (*decrement)(unsigned long bytes)) {
219 m_faceAllocator.SetMemStatsIncrement(increment);
220 m_faceAllocator.SetMemStatsDecrement(decrement);
221 m_vertexAllocator.SetMemStatsIncrement(increment);
222 m_vertexAllocator.SetMemStatsDecrement(decrement);
223 s_memStatsIncrement = increment;
224 s_memStatsDecrement = decrement;
225 }
226
227 // Add a vertex to consider for garbage collection. All
228 // neighboring faces of that vertex will be examined to see if
229 // they can be deleted
AddGarbageCollectableVertex(HbrVertex<T> * vertex)230 void AddGarbageCollectableVertex(HbrVertex<T>* vertex) {
231 if (!m_transientMode) {
232 assert(vertex);
233 if (!vertex->IsCollected()) {
234 gcVertices.push_back(vertex); vertex->SetCollected();
235 }
236 }
237 }
238
239 // Apply garbage collection to the mesh
240 void GarbageCollect();
241
242 // Add a new hierarchical edit to the mesh
243 void AddHierarchicalEdit(HbrHierarchicalEdit<T>* edit);
244
245 // Return the hierarchical edits associated with the mesh
GetHierarchicalEdits()246 const std::vector<HbrHierarchicalEdit<T>*> &GetHierarchicalEdits() const {
247 return hierarchicalEdits;
248 }
249
250 // Return the hierarchical edits associated with the mesh at an
251 // offset
GetHierarchicalEditsAtOffset(int offset)252 HbrHierarchicalEdit<T>** GetHierarchicalEditsAtOffset(int offset) {
253 return &hierarchicalEdits[offset];
254 }
255
256 // Whether the mesh has certain types of edits
HasVertexEdits()257 bool HasVertexEdits() const { return hasVertexEdits; }
HasCreaseEdits()258 bool HasCreaseEdits() const { return hasCreaseEdits; }
259
Unrefine(int numCoarseVerts,int numCoarseFaces)260 void Unrefine(int numCoarseVerts, int numCoarseFaces) {
261
262 for (int i = numCoarseFaces; i < maxFaceID; ++i) {
263 HbrFace<T>* f = GetFace(i);
264 if(f and not f->IsCoarse())
265 DeleteFace(f);
266 }
267
268 maxFaceID = numCoarseFaces;
269
270 for(int i=numCoarseVerts; i<(int)vertices.size(); ++i ) {
271 HbrVertex<T>* v = GetVertex(i);
272 if(v and not v->IsReferenced())
273 DeleteVertex(v);
274 }
275 }
276
277 // When mode is true, the mesh is put in a "transient" mode,
278 // i.e. all subsequent intermediate vertices/faces that are
279 // created by subdivision are deemed temporary. This transient
280 // data can be entirely freed by a subsequent call to
281 // FreeTransientData(). Essentially, the mesh is checkpointed and
282 // restored. This is useful when space is at a premium and
283 // subdivided results are cached elsewhere. On the other hand,
284 // repeatedly putting the mesh in and out of transient mode and
285 // performing the same evaluations comes at a significant compute
286 // cost.
SetTransientMode(bool mode)287 void SetTransientMode(bool mode) {
288 m_transientMode = mode;
289 }
290
291 // Frees transient subdivision data; returns the mesh to a
292 // checkpointed state prior to a call to SetTransientMode.
293 void FreeTransientData();
294
295 // Create new face children block for use by HbrFace
NewFaceChildren()296 HbrFaceChildren<T>* NewFaceChildren() {
297 return m_faceChildrenAllocator.Allocate();
298 }
299
300 // Recycle face children block used by HbrFace
DeleteFaceChildren(HbrFaceChildren<T> * facechildren)301 void DeleteFaceChildren(HbrFaceChildren<T>* facechildren) {
302 m_faceChildrenAllocator.Deallocate(facechildren);
303 }
304
305 #ifdef HBRSTITCH
GetStitchData(const HbrHalfedge<T> * edge)306 void * GetStitchData(const HbrHalfedge<T>* edge) const {
307 typename TgHashMap<const HbrHalfedge<T>*, void *>::const_iterator i =
308 stitchData.find(edge);
309 if (i != stitchData.end()) {
310 return i->second;
311 } else {
312 return NULL;
313 }
314 }
315
SetStitchData(const HbrHalfedge<T> * edge,void * data)316 void SetStitchData(const HbrHalfedge<T>* edge, void *data) {
317 stitchData[edge] = data;
318 }
319 #endif
320
321 private:
322
323 // Subdivision method used in this mesh
324 HbrSubdivision<T>* subdivision;
325
326 // Number of facevarying datums
327 int fvarcount;
328
329 // Start indices of the facevarying data we want to store
330 const int *fvarindices;
331
332 // Individual widths of the facevarying data we want to store
333 const int *fvarwidths;
334
335 // Total widths of the facevarying data
336 const int totalfvarwidth;
337
338 #ifdef HBRSTITCH
339 // Number of stitch edges per halfedge
340 const int stitchCount;
341
342 // Client (sparse) data used on some halfedges
343 TgHashMap<const HbrHalfedge<T>*, void *> stitchData;
344 #endif
345
346 // Vertices which comprise this mesh
347 std::vector<HbrVertex<T> *> vertices;
348 int nvertices;
349
350 // Client data associated with each face
351 std::vector<void *> vertexClientData;
352
353 // Faces which comprise this mesh
354 std::vector<HbrFace<T> *> faces;
355 int nfaces;
356
357 // Client data associated with each face
358 std::vector<void *> faceClientData;
359
360 // Maximum vertex ID - may be needed when generating a unique
361 // vertex ID
362 int maxVertexID;
363
364 // Maximum face ID - needed when generating a unique face ID
365 int maxFaceID;
366
367 // Maximum uniform index - needed to generate a new uniform index
368 int maxUniformIndex;
369
370 // Boundary interpolation method
371 InterpolateBoundaryMethod interpboundarymethod;
372
373 // Facevarying boundary interpolation method
374 InterpolateBoundaryMethod fvarinterpboundarymethod;
375
376 // Whether facevarying corners propagate their sharpness
377 bool fvarpropagatecorners;
378
379 // Memory statistics tracking routines
380 HbrMemStatFunction s_memStatsIncrement;
381 HbrMemStatFunction s_memStatsDecrement;
382
383 // Vertices which may be garbage collected
384 std::vector<HbrVertex<T>*> gcVertices;
385
386 // List of vertex IDs which may be recycled
387 std::set<int> recycleIDs;
388
389 // Hierarchical edits. This vector is left unsorted until Finish()
390 // is called, at which point it is sorted. After that point,
391 // HbrFaces have pointers directly into this array so manipulation
392 // of it should be avoided.
393 std::vector<HbrHierarchicalEdit<T>*> hierarchicalEdits;
394
395 // Size of faces (including 4 facevarying bits and stitch edges)
396 const size_t m_faceSize;
397 HbrAllocator<HbrFace<T> > m_faceAllocator;
398
399 // Size of vertices (includes storage for one piece of facevarying data)
400 const size_t m_vertexSize;
401 HbrAllocator<HbrVertex<T> > m_vertexAllocator;
402
403 // Allocator for face children blocks used by HbrFace
404 HbrAllocator<HbrFaceChildren<T> > m_faceChildrenAllocator;
405
406 // Memory used by this mesh alone, plus all its faces and vertices
407 size_t m_memory;
408
409 // Number of coarse faces. Initialized at Finish()
410 int m_numCoarseFaces;
411
412 // Flags which indicate whether the mesh has certain types of
413 // edits
414 unsigned hasVertexEdits:1;
415 unsigned hasCreaseEdits:1;
416
417 // True if the mesh is in "transient" mode, meaning all
418 // vertices/faces that are created via NewVertex/NewFace should be
419 // deemed temporary
420 bool m_transientMode;
421
422 // Vertices which are transient
423 std::vector<HbrVertex<T>*> m_transientVertices;
424
425 // Faces which are transient
426 std::vector<HbrFace<T>*> m_transientFaces;
427
428 #ifdef HBR_ADAPTIVE
429 public:
GetSplitVertices()430 std::vector<std::pair<int, int> > const & GetSplitVertices() const {
431 return m_splitVertices;
432 }
433
434 protected:
435 friend class HbrVertex<T>;
436
addSplitVertex(int splitIdx,int orgIdx)437 void addSplitVertex(int splitIdx, int orgIdx) {
438 m_splitVertices.push_back(std::pair<int,int>(splitIdx, orgIdx));
439 }
440
441 private:
442 std::vector<std::pair<int, int> > m_splitVertices;
443 #endif
444 };
445
446 } // end namespace OPENSUBDIV_VERSION
447 using namespace OPENSUBDIV_VERSION;
448
449 } // end namespace OpenSubdiv
450
451 #include <algorithm>
452 #include "../hbr/mesh.h"
453 #include "../hbr/halfedge.h"
454
455 namespace OpenSubdiv {
456 namespace OPENSUBDIV_VERSION {
457
458 template <class T>
HbrMesh(HbrSubdivision<T> * s,int _fvarcount,const int * _fvarindices,const int * _fvarwidths,int _totalfvarwidth,int _stitchCount)459 HbrMesh<T>::HbrMesh(HbrSubdivision<T>* s, int _fvarcount, const int *_fvarindices, const int *_fvarwidths, int _totalfvarwidth
460 #ifdef HBRSTITCH
461 , int _stitchCount
462 #endif
463 )
464 : subdivision(s), fvarcount(_fvarcount), fvarindices(_fvarindices),
465 fvarwidths(_fvarwidths), totalfvarwidth(_totalfvarwidth),
466 #ifdef HBRSTITCH
467 stitchCount(_stitchCount),
468 #endif
469 nvertices(0), nfaces(0), maxVertexID(0), maxFaceID(0), maxUniformIndex(0),
470 interpboundarymethod(k_InterpolateBoundaryNone),
471 fvarinterpboundarymethod(k_InterpolateBoundaryNone),
472 fvarpropagatecorners(false),
473 s_memStatsIncrement(0), s_memStatsDecrement(0),
474 m_faceSize(sizeof(HbrFace<T>) + 4 *
475 ((fvarcount + 15) / 16 * sizeof(unsigned int)
476 #ifdef HBRSTITCH
477 + stitchCount * sizeof(StitchEdge*)
478 #endif
479 )),
480 m_faceAllocator(&m_memory, 512, 0, 0, m_faceSize),
481 m_vertexSize(sizeof(HbrVertex<T>) +
482 (totalfvarwidth ? (sizeof(HbrFVarData<T>) + (totalfvarwidth - 1) * sizeof(float)) : 0)),
483 m_vertexAllocator(&m_memory, 512, 0, 0, m_vertexSize),
484 m_faceChildrenAllocator(&m_memory, 512, 0, 0),
485 m_memory(0),
486 m_numCoarseFaces(-1),
487 hasVertexEdits(0),
488 hasCreaseEdits(0),
489 m_transientMode(false) {
490 }
491
492 template <class T>
~HbrMesh()493 HbrMesh<T>::~HbrMesh() {
494 GarbageCollect();
495
496 int i;
497 if (!faces.empty()) {
498 for (i = 0; i < nfaces; ++i) {
499 if (faces[i]) {
500 faces[i]->Destroy();
501 m_faceAllocator.Deallocate(faces[i]);
502 }
503 }
504 if (s_memStatsDecrement) {
505 s_memStatsDecrement(faces.size() * sizeof(HbrFace<T>*));
506 }
507 }
508 if (!vertices.empty()) {
509 for (i = 0; i < nvertices; ++i) {
510 if (vertices[i]) {
511 vertices[i]->Destroy(this);
512 m_vertexAllocator.Deallocate(vertices[i]);
513 }
514 }
515 if (s_memStatsDecrement) {
516 s_memStatsDecrement(vertices.size() * sizeof(HbrVertex<T>*));
517 }
518 }
519 if (!vertexClientData.empty() && s_memStatsDecrement) {
520 s_memStatsDecrement(vertexClientData.size() * sizeof(void*));
521 }
522 if (!faceClientData.empty() && s_memStatsDecrement) {
523 s_memStatsDecrement(faceClientData.size() * sizeof(void*));
524 }
525 for (typename std::vector<HbrHierarchicalEdit<T>* >::iterator hi =
526 hierarchicalEdits.begin(); hi != hierarchicalEdits.end(); ++hi) {
527 delete *hi;
528 }
529 }
530
531 template <class T>
532 HbrVertex<T>*
NewVertex(int id,const T & data)533 HbrMesh<T>::NewVertex(int id, const T &data) {
534 HbrVertex<T>* v = 0;
535 if (nvertices <= id) {
536 while (nvertices <= maxVertexID) {
537 nvertices *= 2;
538 if (nvertices < 1) nvertices = 1;
539 }
540 size_t oldsize = vertices.size();
541 vertices.resize(nvertices);
542 if (s_memStatsIncrement) {
543 s_memStatsIncrement((vertices.size() - oldsize) * sizeof(HbrVertex<T>*));
544 }
545 }
546 v = vertices[id];
547 if (v) {
548 v->Destroy(this);
549 } else {
550 v = m_vertexAllocator.Allocate();
551 }
552 v->Initialize(id, data, GetTotalFVarWidth());
553 vertices[id] = v;
554
555 if (id >= maxVertexID) {
556 maxVertexID = id + 1;
557 }
558
559 // Newly created vertices are always candidates for garbage
560 // collection, until they get "owned" by someone who
561 // IncrementsUsage on the vertex.
562 AddGarbageCollectableVertex(v);
563
564 // If mesh is in transient mode, add vertex to transient list
565 if (m_transientMode) {
566 m_transientVertices.push_back(v);
567 }
568 return v;
569 }
570
571 template <class T>
572 HbrVertex<T>*
NewVertex(const T & data)573 HbrMesh<T>::NewVertex(const T &data) {
574 // Pick an ID - either the maximum vertex ID or a recycled ID if
575 // we can
576 int id = maxVertexID;
577 if (!recycleIDs.empty()) {
578 id = *recycleIDs.begin();
579 recycleIDs.erase(recycleIDs.begin());
580 }
581 if (id >= maxVertexID) {
582 maxVertexID = id + 1;
583 }
584 return NewVertex(id, data);
585 }
586
587 template <class T>
588 HbrVertex<T>*
NewVertex()589 HbrMesh<T>::NewVertex() {
590 // Pick an ID - either the maximum vertex ID or a recycled ID if
591 // we can
592 int id = maxVertexID;
593 if (!recycleIDs.empty()) {
594 id = *recycleIDs.begin();
595 recycleIDs.erase(recycleIDs.begin());
596 }
597 if (id >= maxVertexID) {
598 maxVertexID = id + 1;
599 }
600 T data(id);
601 data.Clear();
602 return NewVertex(id, data);
603 }
604
605 template <class T>
606 HbrFace<T>*
NewFace(int nv,const int * vtx,int uindex)607 HbrMesh<T>::NewFace(int nv, const int *vtx, int uindex) {
608 HbrVertex<T>** facevertices = reinterpret_cast<HbrVertex<T>**>(alloca(sizeof(HbrVertex<T>*) * nv));
609 int i;
610 for (i = 0; i < nv; ++i) {
611 facevertices[i] = GetVertex(vtx[i]);
612 if (!facevertices[i]) {
613 return 0;
614 }
615 }
616 HbrFace<T> *f = 0;
617 // Resize if needed
618 if (nfaces <= maxFaceID) {
619 while (nfaces <= maxFaceID) {
620 nfaces *= 2;
621 if (nfaces < 1) nfaces = 1;
622 }
623 size_t oldsize = faces.size();
624 faces.resize(nfaces);
625 if (s_memStatsIncrement) {
626 s_memStatsIncrement((faces.size() - oldsize) * sizeof(HbrVertex<T>*));
627 }
628 }
629 f = faces[maxFaceID];
630 if (f) {
631 f->Destroy();
632 } else {
633 f = m_faceAllocator.Allocate();
634 }
635 f->Initialize(this, NULL, -1, maxFaceID, uindex, nv, facevertices, totalfvarwidth, 0);
636 faces[maxFaceID] = f;
637 maxFaceID++;
638 // Update the maximum encountered uniform index
639 if (uindex > maxUniformIndex) maxUniformIndex = uindex;
640
641 // If mesh is in transient mode, add face to transient list
642 if (m_transientMode) {
643 m_transientFaces.push_back(f);
644 }
645 return f;
646 }
647
648 template <class T>
649 HbrFace<T>*
NewFace(int nv,HbrVertex<T> ** vtx,HbrFace<T> * parent,int childindex)650 HbrMesh<T>::NewFace(int nv, HbrVertex<T> **vtx, HbrFace<T>* parent, int childindex) {
651 HbrFace<T> *f = 0;
652 // Resize if needed
653 if (nfaces <= maxFaceID) {
654 while (nfaces <= maxFaceID) {
655 nfaces *= 2;
656 if (nfaces < 1) nfaces = 1;
657 }
658 size_t oldsize = faces.size();
659 faces.resize(nfaces);
660 if (s_memStatsIncrement) {
661 s_memStatsIncrement((faces.size() - oldsize) * sizeof(HbrVertex<T>*));
662 }
663 }
664 f = faces[maxFaceID];
665 if (f) {
666 f->Destroy();
667 } else {
668 f = m_faceAllocator.Allocate();
669 }
670 f->Initialize(this, parent, childindex, maxFaceID, parent ? parent->GetUniformIndex() : 0, nv, vtx, totalfvarwidth, parent ? parent->GetDepth() + 1 : 0);
671 if (parent) {
672 f->SetPtexIndex(parent->GetPtexIndex());
673 }
674 faces[maxFaceID] = f;
675 maxFaceID++;
676
677 // If mesh is in transient mode, add face to transient list
678 if (m_transientMode) {
679 m_transientFaces.push_back(f);
680 }
681 return f;
682 }
683
684 template <class T>
685 void
Finish()686 HbrMesh<T>::Finish() {
687 int i, j;
688 m_numCoarseFaces = 0;
689 for (i = 0; i < nfaces; ++i) {
690 if (faces[i]) {
691 faces[i]->SetCoarse();
692 m_numCoarseFaces++;
693 }
694 }
695
696 std::vector<HbrVertex<T>*> vertexlist;
697 GetVertices(std::back_inserter(vertexlist));
698 for (typename std::vector<HbrVertex<T>*>::iterator vi = vertexlist.begin();
699 vi != vertexlist.end(); ++vi) {
700 HbrVertex<T>* vertex = *vi;
701 if (vertex->IsConnected()) vertex->Finish();
702 }
703 // Finish may have added new vertices
704 vertexlist.clear();
705 GetVertices(std::back_inserter(vertexlist));
706
707 // If interpolateboundary is on, process boundary edges
708 if (interpboundarymethod == k_InterpolateBoundaryEdgeOnly || interpboundarymethod == k_InterpolateBoundaryEdgeAndCorner) {
709 for (i = 0; i < nfaces; ++i) {
710 if (HbrFace<T>* face = faces[i]) {
711 int nv = face->GetNumVertices();
712 for (int k = 0; k < nv; ++k) {
713 HbrHalfedge<T>* edge = face->GetEdge(k);
714 if (edge->IsBoundary()) {
715 edge->SetSharpness(HbrHalfedge<T>::k_InfinitelySharp);
716 }
717 }
718 }
719 }
720 }
721 // Process corners
722 if (interpboundarymethod == k_InterpolateBoundaryEdgeAndCorner) {
723 for (typename std::vector<HbrVertex<T>*>::iterator vi = vertexlist.begin();
724 vi != vertexlist.end(); ++vi) {
725 HbrVertex<T>* vertex = *vi;
726 if (vertex && vertex->IsConnected() && vertex->OnBoundary() && vertex->GetCoarseValence() == 2) {
727 vertex->SetSharpness(HbrVertex<T>::k_InfinitelySharp);
728 }
729 }
730 }
731
732 // Sort the hierarchical edits
733 if (!hierarchicalEdits.empty()) {
734 HbrHierarchicalEditComparator<T> cmp;
735 int nHierarchicalEdits = (int)hierarchicalEdits.size();
736 std::sort(hierarchicalEdits.begin(), hierarchicalEdits.end(), cmp);
737 // Push a sentinel null value - we rely upon this sentinel to
738 // ensure face->GetHierarchicalEdits knows when to terminate
739 hierarchicalEdits.push_back(0);
740 j = 0;
741 // Link faces to hierarchical edits
742 for (i = 0; i < nfaces; ++i) {
743 if (faces[i]) {
744 while (j < nHierarchicalEdits && hierarchicalEdits[j]->GetFaceID() < i) {
745 ++j;
746 }
747 if (j < nHierarchicalEdits && hierarchicalEdits[j]->GetFaceID() == i) {
748 faces[i]->SetHierarchicalEdits(&hierarchicalEdits[j]);
749 }
750 }
751 }
752 }
753 }
754
755 template <class T>
756 void
DeleteFace(HbrFace<T> * face)757 HbrMesh<T>::DeleteFace(HbrFace<T>* face) {
758 if (face->GetID() < nfaces) {
759 HbrFace<T>* f = faces[face->GetID()];
760 if (f == face) {
761 faces[face->GetID()] = 0;
762 face->Destroy();
763 m_faceAllocator.Deallocate(face);
764 }
765 }
766 }
767
768 template <class T>
769 void
DeleteVertex(HbrVertex<T> * vertex)770 HbrMesh<T>::DeleteVertex(HbrVertex<T>* vertex) {
771 HbrVertex<T> *v = GetVertex(vertex->GetID());
772 if (v == vertex) {
773 recycleIDs.insert(vertex->GetID());
774 int id = vertex->GetID();
775 vertices[id] = 0;
776 vertex->Destroy(this);
777 m_vertexAllocator.Deallocate(vertex);
778 }
779 }
780
781 template <class T>
782 int
GetNumVertices()783 HbrMesh<T>::GetNumVertices() const {
784 int count = 0;
785 for (int i = 0; i < nvertices; ++i) {
786 if (vertices[i]) count++;
787 }
788 return count;
789 }
790
791 template <class T>
792 int
GetNumDisconnectedVertices()793 HbrMesh<T>::GetNumDisconnectedVertices() const {
794 int disconnected = 0;
795 for (int i = 0; i < nvertices; ++i) {
796 if (HbrVertex<T>* v = vertices[i]) {
797 if (!v->IsConnected()) {
798 disconnected++;
799 }
800 }
801 }
802 return disconnected;
803 }
804
805 template <class T>
806 int
GetNumFaces()807 HbrMesh<T>::GetNumFaces() const {
808 int count = 0;
809 for (int i = 0; i < nfaces; ++i) {
810 if (faces[i]) count++;
811 }
812 return count;
813 }
814
815 template <class T>
816 int
GetNumCoarseFaces()817 HbrMesh<T>::GetNumCoarseFaces() const {
818 // Use the value computed by Finish() if it exists
819 if (m_numCoarseFaces >= 0) return m_numCoarseFaces;
820 // Otherwise we have to just count it up now
821 int count = 0;
822 for (int i = 0; i < nfaces; ++i) {
823 if (faces[i] && faces[i]->IsCoarse()) count++;
824 }
825 return count;
826 }
827
828 template <class T>
829 HbrFace<T>*
GetFace(int id)830 HbrMesh<T>::GetFace(int id) const {
831 if (id < nfaces) {
832 return faces[id];
833 }
834 return 0;
835 }
836
837 template <class T>
838 template <typename OutputIterator>
839 void
GetVertices(OutputIterator lvertices)840 HbrMesh<T>::GetVertices(OutputIterator lvertices) const {
841 for (int i = 0; i < nvertices; ++i) {
842 if (vertices[i]) *lvertices++ = vertices[i];
843 }
844 }
845
846 template <class T>
847 void
ApplyOperatorAllVertices(HbrVertexOperator<T> & op)848 HbrMesh<T>::ApplyOperatorAllVertices(HbrVertexOperator<T> &op) const {
849 for (int i = 0; i < nvertices; ++i) {
850 if (vertices[i]) op(*vertices[i]);
851 }
852 }
853
854 template <class T>
855 template <typename OutputIterator>
856 void
GetFaces(OutputIterator lfaces)857 HbrMesh<T>::GetFaces(OutputIterator lfaces) const {
858 for (int i = 0; i < nfaces; ++i) {
859 if (faces[i]) *lfaces++ = faces[i];
860 }
861 }
862
863 template <class T>
864 void
PrintStats(std::ostream & out)865 HbrMesh<T>::PrintStats(std::ostream &out) {
866 int singular = 0;
867 int sumvalence = 0;
868 int i, nv = 0;
869 int disconnected = 0;
870 int extraordinary = 0;
871 for (i = 0; i < nvertices; ++i) {
872 if (HbrVertex<T>* v = vertices[i]) {
873 nv++;
874 if (v->IsSingular()) {
875 out << " singular: " << *v << "\n";
876 singular++;
877 } else if (!v->IsConnected()) {
878 out << " disconnected: " << *v << "\n";
879 disconnected++;
880 } else {
881 if (v->IsExtraordinary()) {
882 extraordinary++;
883 }
884 sumvalence += v->GetValence();
885 }
886 }
887 }
888 out << "Mesh has " << nv << " vertices\n";
889 out << "Total singular vertices " << singular << "\n";
890 out << "Total disconnected vertices " << disconnected << "\n";
891 out << "Total extraordinary vertices " << extraordinary << "\n";
892 out << "Average valence " << (float) sumvalence / nv << "\n";
893
894 int sumsides = 0;
895 int numfaces = 0;
896 for (i = 0; i < nfaces; ++i) {
897 if (HbrFace<T>* f = faces[i]) {
898 numfaces++;
899 sumsides += f->GetNumVertices();
900 }
901 }
902 out << "Mesh has " << nfaces << " faces\n";
903 out << "Average sidedness " << (float) sumsides / nfaces << "\n";
904 }
905
906 template <class T>
907 void
GarbageCollect()908 HbrMesh<T>::GarbageCollect() {
909 if (gcVertices.empty()) return;
910
911 static const size_t gcthreshold = 4096;
912
913 if (gcVertices.size() <= gcthreshold) return;
914 // Go through the list of garbage collectable vertices and gather
915 // up the neighboring faces of those vertices which can be garbage
916 // collected.
917 std::vector<HbrFace<T>*> killlist;
918 std::vector<HbrVertex<T>*> vlist;
919
920 // Process the vertices in the same order as they were collected
921 // (gcVertices used to be declared as a std::deque, but that was
922 // causing unnecessary heap traffic).
923 int numprocessed = (int)gcVertices.size() - gcthreshold / 2;
924 for (int i = 0; i < numprocessed; ++i) {
925 HbrVertex<T>* v = gcVertices[i];
926 v->ClearCollected();
927 if (v->IsUsed()) continue;
928 vlist.push_back(v);
929 HbrHalfedge<T>* start = v->GetIncidentEdge(), *edge;
930 edge = start;
931 while (edge) {
932 HbrFace<T>* f = edge->GetLeftFace();
933 if (!f->IsCollected()) {
934 f->SetCollected();
935 killlist.push_back(f);
936 }
937 edge = v->GetNextEdge(edge);
938 if (edge == start) break;
939 }
940 }
941
942 gcVertices.erase(gcVertices.begin(), gcVertices.begin() + numprocessed);
943
944 // Delete those faces
945 for (typename std::vector<HbrFace<T>*>::iterator fi = killlist.begin(); fi != killlist.end(); ++fi) {
946 if ((*fi)->GarbageCollectable()) {
947 DeleteFace(*fi);
948 } else {
949 (*fi)->ClearCollected();
950 }
951 }
952
953 // Delete as many vertices as we can
954 for (typename std::vector<HbrVertex<T>*>::iterator vi = vlist.begin(); vi != vlist.end(); ++vi) {
955 HbrVertex<T>* v = *vi;
956 if (!v->IsReferenced()) {
957 DeleteVertex(v);
958 }
959 }
960 }
961
962 template <class T>
963 void
AddHierarchicalEdit(HbrHierarchicalEdit<T> * edit)964 HbrMesh<T>::AddHierarchicalEdit(HbrHierarchicalEdit<T>* edit) {
965 hierarchicalEdits.push_back(edit);
966 if (dynamic_cast<HbrVertexEdit<T>*>(edit) ||
967 dynamic_cast<HbrMovingVertexEdit<T>*>(edit)) {
968 hasVertexEdits = 1;
969 } else if (dynamic_cast<HbrCreaseEdit<T>*>(edit)) {
970 hasCreaseEdits = 1;
971 }
972 }
973
974 template <class T>
975 void
FreeTransientData()976 HbrMesh<T>::FreeTransientData() {
977 // When purging transient data, we must clear the faces first
978 for (typename std::vector<HbrFace<T>*>::iterator fi = m_transientFaces.begin();
979 fi != m_transientFaces.end(); ++fi) {
980 DeleteFace(*fi);
981 }
982 // The vertices should now be trivial to purge after the transient
983 // faces have been cleared
984 for (typename std::vector<HbrVertex<T>*>::iterator vi = m_transientVertices.begin();
985 vi != m_transientVertices.end(); ++vi) {
986 DeleteVertex(*vi);
987 }
988 m_transientVertices.clear();
989 m_transientFaces.clear();
990 // Reset max face ID
991 int i;
992 for (i = nfaces - 1; i >= 0; --i) {
993 if (faces[i]) {
994 maxFaceID = i + 1;
995 break;
996 }
997 }
998 // Reset max vertex ID
999 for (i = nvertices - 1; i >= 0; --i) {
1000 if (vertices[i]) {
1001 maxVertexID = i + 1;
1002 break;
1003 }
1004 }
1005 }
1006
1007 } // end namespace OPENSUBDIV_VERSION
1008 using namespace OPENSUBDIV_VERSION;
1009
1010 } // end namespace OpenSubdiv
1011
1012 #endif /* OPENSUBDIV3_HBRMESH_H */
1013