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