// // Copyright (C) Pixar. All rights reserved. // // This license governs use of the accompanying software. If you // use the software, you accept this license. If you do not accept // the license, do not use the software. // // 1. Definitions // The terms "reproduce," "reproduction," "derivative works," and // "distribution" have the same meaning here as under U.S. // copyright law. A "contribution" is the original software, or // any additions or changes to the software. // A "contributor" is any person or entity that distributes its // contribution under this license. // "Licensed patents" are a contributor's patent claims that read // directly on its contribution. // // 2. Grant of Rights // (A) Copyright Grant- Subject to the terms of this license, // including the license conditions and limitations in section 3, // each contributor grants you a non-exclusive, worldwide, // royalty-free copyright license to reproduce its contribution, // prepare derivative works of its contribution, and distribute // its contribution or any derivative works that you create. // (B) Patent Grant- Subject to the terms of this license, // including the license conditions and limitations in section 3, // each contributor grants you a non-exclusive, worldwide, // royalty-free license under its licensed patents to make, have // made, use, sell, offer for sale, import, and/or otherwise // dispose of its contribution in the software or derivative works // of the contribution in the software. // // 3. Conditions and Limitations // (A) No Trademark License- This license does not grant you // rights to use any contributor's name, logo, or trademarks. // (B) If you bring a patent claim against any contributor over // patents that you claim are infringed by the software, your // patent license from such contributor to the software ends // automatically. // (C) If you distribute any portion of the software, you must // retain all copyright, patent, trademark, and attribution // notices that are present in the software. // (D) If you distribute any portion of the software in source // code form, you may do so only under this license by including a // complete copy of this license with your distribution. If you // distribute any portion of the software in compiled or object // code form, you may only do so under a license that complies // with this license. // (E) The software is licensed "as-is." You bear the risk of // using it. The contributors give no express warranties, // guarantees or conditions. You may have additional consumer // rights under your local laws which this license cannot change. // To the extent permitted under your local laws, the contributors // exclude the implied warranties of merchantability, fitness for // a particular purpose and non-infringement. // #ifndef HBRFACE_H #define HBRFACE_H #include #include #include #include #include #include #include "../hbr/fvarData.h" #include "../hbr/allocator.h" #ifdef HBRSTITCH #include "libgprims/stitch.h" #include "libgprims/stitchInternal.h" #endif #include "../version.h" namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { template class HbrVertex; template class HbrHalfedge; template class HbrFace; template class HbrMesh; template class HbrHierarchicalEdit; template std::ostream& operator<<(std::ostream& out, const HbrFace& face); // A descriptor for a path to a face struct HbrFacePath { void Print() const { printf("%d", topface); for (std::vector::const_reverse_iterator i = remainder.rbegin(); i != remainder.rend(); ++i) { printf(" %d", *i); } printf("\n"); } int topface; // Note that the elements in remainder are stored in reverse order. std::vector remainder; friend bool operator< (const HbrFacePath& x, const HbrFacePath& y); }; inline bool operator< (const HbrFacePath& x, const HbrFacePath& y) { if (x.topface != y.topface) { return x.topface < y.topface; } else if (x.remainder.size() != y.remainder.size()) { return x.remainder.size() < y.remainder.size(); } else { std::vector::const_reverse_iterator i = x.remainder.rbegin(); std::vector::const_reverse_iterator j = y.remainder.rbegin(); for ( ; i != x.remainder.rend(); ++i, ++j) { if (*i != *j) return (*i < *j); } return true; } } // A simple wrapper around an array of four children. Used to block // allocate pointers to children of HbrFace in the common case template class HbrFaceChildren { public: HbrFace *& operator[](const int index) { return children[index]; } const HbrFace *& operator[](const int index) const { return children[index]; } private: friend class HbrAllocator >; // Used by block allocator HbrFaceChildren*& GetNext() { return (HbrFaceChildren*&) children; } HbrFaceChildren() {} ~HbrFaceChildren() {} HbrFace *children[4]; }; template class HbrFace { private: friend class HbrAllocator >; friend class HbrHalfedge; HbrFace(); ~HbrFace(); public: void Initialize(HbrMesh* mesh, HbrFace* parent, int childindex, int id, int uindex, int nvertices, HbrVertex** vertices, int fvarwidth = 0, int depth = 0); void Destroy(); // Returns the mesh to which this face belongs HbrMesh* GetMesh() const { return mesh; } // Return number of vertices int GetNumVertices() const { return nvertices; } // Return face ID int GetID() const { return id; } // Return the first halfedge of the face HbrHalfedge* GetFirstEdge() const { if (nvertices > 4) { return (HbrHalfedge*)(extraedges); } else { return const_cast*>(&edges[0]); } } // Return the halfedge which originates at the vertex with the // indicated origin index HbrHalfedge* GetEdge(int index) const; // Return the vertex with the indicated index HbrVertex* GetVertex(int index) const; // Return the ID of the vertex with the indicated index int GetVertexID(int index) const; // Return the parent of this face HbrFace* GetParent() const { if (parent == -1) return NULL; return mesh->GetFace(parent); } // Set the child void SetChild(int index, HbrFace* face); // Return the child with the indicated index HbrFace* GetChild(int index) const { int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(nvertices); if (!children.children || index < 0 || index >= nchildren) return 0; if (nchildren > 4) { return children.extrachildren[index]; } else { return (*children.children)[index]; } } // Subdivide the face into a vertex if needed and return HbrVertex* Subdivide(); // Remove the reference to subdivided vertex void RemoveChild() { vchild = -1; } // "Hole" flags used by subdivision to drop faces bool IsHole() const { return hole; } void SetHole() { hole = 1; } // Coarse faces are the top level faces of a mesh. This will be // set by mesh->Finish() bool IsCoarse() const { return coarse; } void SetCoarse() { coarse = 1; } // Protected faces cannot be garbage collected; this may be set on // coarse level faces if the mesh is shared bool IsProtected() const { return protect; } void SetProtected() { protect = 1; } void ClearProtected() { protect = 0; } // Simple bookkeeping needed for garbage collection by HbrMesh bool IsCollected() const { return collected; } void SetCollected() { collected = 1; } void ClearCollected() { collected = 0; } // Refine the face void Refine(); // Unrefine the face void Unrefine(); // Returns true if the face has a limit surface bool HasLimit(); // Returns memory statistics unsigned long GetMemStats() const; // Return facevarying data from the appropriate vertex index // registered to this face. Note that this may either be "generic" // facevarying item (data.GetFace() == 0) or one specifically // registered to the face (data.GetFace() == this) - this is // important when trying to figure out whether the vertex has // created some storage for the item designed to store // discontinuous values for this face. HbrFVarData& GetFVarData(int index) { return GetVertex(index)->GetFVarData(this); } // Mark this face as being used, which in turn increments the // usage counter of all vertices in the support for the face. A // used face can not be garbage collected void MarkUsage(); // Clears the usage of this face, which in turn decrements the // usage counter of all vertices in the support for the face and // marks the face as a candidate for garbage collection void ClearUsage(); // A face can be cleaned if all of its vertices are not being // used; has no children; and (for top level faces) deletion of // its edges will not leave singular vertices bool GarbageCollectable() const; // Connect this face to a list of hierarchical edits void SetHierarchicalEdits(HbrHierarchicalEdit** edits); // Return the list of hierarchical edits associated with this face HbrHierarchicalEdit** GetHierarchicalEdits() const { if (editOffset == -1) { return NULL; } return mesh->GetHierarchicalEditsAtOffset(editOffset); } // Whether the face has certain types of edits (not necessarily // local - could apply to a subface) bool HasVertexEdits() const { return hasVertexEdits; } void MarkVertexEdits() { hasVertexEdits = 1; } // Return the depth of the face int GetDepth() const { return static_cast(depth); } // Return the uniform index of the face. This is different // from the ID because it may be shared with other faces int GetUniformIndex() const { return uindex; } // Set the uniform index of the face void SetUniformIndex(int i) { uindex = i; } // Return the ptex index int GetPtexIndex() const { return ptexindex; } // Set the ptex index of the face void SetPtexIndex(int i) { ptexindex = i; } // Used by block allocator HbrFace*& GetNext() { return (HbrFace*&) mesh; } HbrFacePath GetPath() const { HbrFacePath path; path.remainder.reserve(GetDepth()); const HbrFace* f = this, *p = GetParent(); while (p) { int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(p->nvertices); if (nchildren > 4) { for (int i = 0; i < nchildren; ++i) { if (p->children.extrachildren[i] == f) { path.remainder.push_back(i); break; } } } else { for (int i = 0; i < nchildren; ++i) { if ((*p->children.children)[i] == f) { path.remainder.push_back(i); break; } } } f = p; p = f->GetParent(); } path.topface = f->GetID(); assert(GetDepth() == 0 || static_cast(path.remainder.size()) == GetDepth()); return path; } void PrintPath() const { GetPath().Print(); } // Returns the blind pointer to client data void *GetClientData() const { return mesh->GetFaceClientData(id); } // Sets the blind pointer to client data void SetClientData(void *data) { mesh->SetFaceClientData(id, data); } // Gets the list of vertices which are in the support for the face. void GetSupportingVertices(std::vector &support); private: // Mesh to which this face belongs HbrMesh* mesh; // Unique id for this face int id; // Uniform index int uindex; // Ptex index int ptexindex; // Number of vertices (and number of edges) int nvertices; // Halfedge array for this face HbrHalfedge edges[4]; // Edge storage if this face is not a triangle or quad char* extraedges; // Pointer to children array. If there are four children or less, // we use the HbrFaceChildren pointer, otherwise we use // extrachildren union { HbrFaceChildren* children; HbrFace** extrachildren; } children; // Bits used by halfedges to track facevarying sharpnesses unsigned int *fvarbits; #ifdef HBRSTITCH // Pointers to stitch edges used by the half edges. StitchEdge **stitchEdges; #endif // Index of parent face int parent; // Index of subdivided vertex child int vchild; // Offset to the mesh' list of hierarchical edits applicable to this face int editOffset; // Depth of the face in the mesh hierarchy - coarse faces are // level 0. (Hmmm.. is it safe to assume that we'll never // subdivide to greater than 255?) unsigned char depth; unsigned short hole:1; unsigned short coarse:1; unsigned short protect:1; unsigned short collected:1; unsigned short hasVertexEdits:1; unsigned short initialized:1; unsigned short destroyed:1; #ifdef HBR_ADAPTIVE public: enum PatchType { kUnknown=0, kFull=1, kEnd=2, kGregory=3 }; enum TransitionType { kTransition0=0, kTransition1=1, kTransition2=2, kTransition3=3, kTransition4=4, kNone=5 }; struct AdaptiveFlags { unsigned patchType:2; unsigned transitionType:3; unsigned rots:2; unsigned brots:2; unsigned bverts:2; unsigned isCritical:1; unsigned isExtraordinary:1; unsigned isTagged:1; AdaptiveFlags() : patchType(0), transitionType(5), rots(0), brots(0), bverts(0), isCritical(0), isExtraordinary(0), isTagged(0) { } }; AdaptiveFlags _adaptiveFlags; bool isTransitionPatch() const { return (_adaptiveFlags.transitionType!=kNone); } bool hasTaggedVertices() { int nv = GetNumVertices(); for (int i=0; i_adaptiveFlags.wasTagged) return true; } return false; } #endif }; } // end namespace OPENSUBDIV_VERSION using namespace OPENSUBDIV_VERSION; } // end namespace OpenSubdiv #include "../hbr/mesh.h" namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { template HbrFace::HbrFace() : mesh(0), id(-1), uindex(-1), ptexindex(-1), nvertices(0), extraedges(0), fvarbits(0), parent(-1), vchild(-1), #ifdef HBRSTITCH stitchEdges(0), #endif editOffset(-1), depth(0), hole(0), coarse(0), protect(0), collected(0), hasVertexEdits(0), initialized(0), destroyed(0) { children.children = 0; } template void HbrFace::Initialize(HbrMesh* m, HbrFace* _parent, int childindex, int fid, int _uindex, int nv, HbrVertex** vertices, int /* fvarwidth */, int _depth) { mesh = m; id = fid; uindex = _uindex; ptexindex = -1; nvertices = nv; extraedges = 0; children.children = 0; vchild = -1; fvarbits = 0; #ifdef HBRSTITCH stitchEdges = 0; #endif editOffset = -1; depth = _depth; hole = 0; coarse = 0; protect = 0; collected = 0; hasVertexEdits = 0; initialized = 1; destroyed = 0; int i; const int fvarcount = mesh->GetFVarCount(); int fvarbitsSizePerEdge = ((fvarcount + 15) / 16); if (nv > 4) { // If we have more than four vertices, we ignore the // overallocation and allocate our own buffers for stitch // edges and facevarying data. #ifdef HBRSTITCH if (mesh->GetStitchCount()) { const size_t buffersize = nv * (mesh->GetStitchCount() * sizeof(StitchEdge*)); char *buffer = (char *) malloc(buffersize); memset(buffer, 0, buffersize); stitchEdges = (StitchEdge**) buffer; } #endif if (fvarcount) { // We allocate fvarbits in one chunk. // fvarbits needs capacity for two bits per fvardatum per edge, // minimum size one integer per edge const size_t fvarbitsSize = nv * (fvarbitsSizePerEdge * sizeof(unsigned int)); char *buffer = (char*) malloc(fvarbitsSize); fvarbits = (unsigned int*) buffer; } // We also ignore the edge array and allocate extra storage - // this simplifies GetNext and GetPrev math in HbrHalfedge const size_t edgesize = sizeof(HbrHalfedge) + sizeof(HbrFace*); extraedges = (char *) malloc(nv * edgesize); for (i = 0; i < nv; ++i) { HbrHalfedge* edge = (HbrHalfedge*)(extraedges + i * edgesize); new (edge) HbrHalfedge(); } } else { // Under four vertices: upstream allocation for the class has // been over allocated to include storage for stitchEdges // and fvarbits. Just point our pointers at it. char *buffer = ((char *) this + sizeof(*this)); #ifdef HBRSTITCH if (mesh->GetStitchCount()) { const size_t buffersize = 4 * (mesh->GetStitchCount() * sizeof(StitchEdge*)); memset(buffer, 0, buffersize); stitchEdges = (StitchEdge**) buffer; buffer += buffersize; } #endif if (fvarcount) { fvarbits = (unsigned int*) buffer; } } // Must do this before we create edges if (_parent) { _parent->SetChild(childindex, this); } // Edges must be constructed in this two part approach: we must // ensure that opposite/next/previous ptrs are all set up // correctly, before we can begin adding incident edges to // vertices. int next; unsigned int *curfvarbits = fvarbits; HbrHalfedge* edge; size_t edgesize; if (nv > 4) { edge = (HbrHalfedge*)(extraedges); edgesize = sizeof(HbrHalfedge) + sizeof(HbrFace*); } else { edge = edges; edgesize = sizeof(HbrHalfedge); } for (i = 0, next = 1; i < nv; ++i, ++next) { if (next == nv) next = 0; HbrHalfedge* opposite = vertices[next]->GetEdge(vertices[i]->GetID()); edge->Initialize(opposite, i, vertices[i], curfvarbits, this); if (opposite) opposite->SetOpposite(edge); if (fvarbits) { curfvarbits = curfvarbits + fvarbitsSizePerEdge; } edge = (HbrHalfedge*)((char *) edge + edgesize); } if (nv > 4) { edge = (HbrHalfedge*)(extraedges); } else { edge = edges; } for (i = 0; i < nv; ++i) { vertices[i]->AddIncidentEdge(edge); edge = (HbrHalfedge*)((char *) edge + edgesize); } } template HbrFace::~HbrFace() { Destroy(); } template void HbrFace::Destroy() { if (initialized && !destroyed) { int i; #ifdef HBRSTITCH const int stitchCount = mesh->GetStitchCount(); #endif // Remove children's references to self if (children.children) { int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(nvertices); if (nchildren > 4) { for (i = 0; i < nchildren; ++i) { if (children.extrachildren[i]) { children.extrachildren[i]->parent = -1; children.extrachildren[i] = 0; } } delete[] children.extrachildren; children.extrachildren = 0; } else { for (i = 0; i < nchildren; ++i) { if ((*children.children)[i]) { (*children.children)[i]->parent = -1; (*children.children)[i] = 0; } } mesh->DeleteFaceChildren(children.children); children.children = 0; } } // Deleting the incident edges from the vertices in this way is // the safest way of doing things. Doing it in the halfedge // destructor will not work well because it disrupts cycle // finding/incident edge replacement in the vertex code. // We also take this time to clean up any orphaned stitches // still belonging to the edges. HbrHalfedge* edge; size_t edgesize; if (nvertices > 4) { edge = (HbrHalfedge*)(extraedges); edgesize = sizeof(HbrHalfedge) + sizeof(HbrFace*); } else { edge = edges; edgesize = sizeof(HbrHalfedge); } for (i = 0; i < nvertices; ++i) { #ifdef HBRSTITCH edge->DestroyStitchEdges(stitchCount); #endif HbrVertex* vertex = mesh->GetVertex(edge->GetOrgVertexID()); if (fvarbits) { HbrFVarData& fvt = vertex->GetFVarData(this); if (fvt.GetFaceID() == GetID()) { fvt.SetFaceID(-1); } } vertex->RemoveIncidentEdge(edge); vertex->UnGuaranteeNeighbors(); edge = (HbrHalfedge*)((char *) edge + edgesize); } if (extraedges) { edge = (HbrHalfedge*)(extraedges); for (i = 0; i < nvertices; ++i) { edge->~HbrHalfedge(); edge = (HbrHalfedge*)((char *) edge + edgesize); } free(extraedges); extraedges = 0; } // Remove parent's reference to self HbrFace *parentFace = GetParent(); if (parentFace) { bool parentHasOtherKids = false; int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(parentFace->nvertices); if (nchildren > 4) { for (i = 0; i < nchildren; ++i) { if (parentFace->children.extrachildren[i] == this) { parentFace->children.extrachildren[i] = 0; } else if (parentFace->children.extrachildren[i]) parentHasOtherKids = true; } // After cleaning the parent's reference to self, the parent // may be able to clean itself up if (!parentHasOtherKids) { delete[] parentFace->children.extrachildren; parentFace->children.extrachildren = 0; if (parentFace->GarbageCollectable()) { mesh->DeleteFace(parentFace); } } } else { for (i = 0; i < nchildren; ++i) { if ((*parentFace->children.children)[i] == this) { (*parentFace->children.children)[i] = 0; } else if ((*parentFace->children.children)[i]) parentHasOtherKids = true; } // After cleaning the parent's reference to self, the parent // may be able to clean itself up if (!parentHasOtherKids) { mesh->DeleteFaceChildren(parentFace->children.children); parentFace->children.children = 0; if (parentFace->GarbageCollectable()) { mesh->DeleteFace(parentFace); } } } parent = -1; } // Orphan the child vertex if (vchild != -1) { HbrVertex *vchildVert = mesh->GetVertex(vchild); vchildVert->SetParent(static_cast(0)); vchild = -1; } if (nvertices > 4 && fvarbits) { free(fvarbits); #ifdef HBRSTITCH if (stitchEdges) { free(stitchEdges); } #endif } fvarbits = 0; #ifdef HBRSTITCH stitchEdges = 0; #endif // Make sure the four edges intrinsic to face are properly cleared // if they were used if (nvertices <= 4) { for (i = 0; i < nvertices; ++i) { edges[i].Clear(); } } nvertices = 0; initialized = 0; mesh = 0; destroyed = 1; } } template HbrHalfedge* HbrFace::GetEdge(int index) const { assert(index >= 0 && index < nvertices); if (nvertices > 4) { const size_t edgesize = sizeof(HbrHalfedge) + sizeof(HbrFace*); return (HbrHalfedge*)(extraedges + index * edgesize); } else { return const_cast*>(edges + index); } } template HbrVertex* HbrFace::GetVertex(int index) const { assert(index >= 0 && index < nvertices); if (nvertices > 4) { const size_t edgesize = sizeof(HbrHalfedge) + sizeof(HbrFace*); HbrHalfedge* edge = (HbrHalfedge*)(extraedges + index * edgesize); return mesh->GetVertex(edge->GetOrgVertexID()); } else { return mesh->GetVertex(edges[index].GetOrgVertexID()); } } template int HbrFace::GetVertexID(int index) const { assert(index >= 0 && index < nvertices); if (nvertices > 4) { const size_t edgesize = sizeof(HbrHalfedge) + sizeof(HbrFace*); HbrHalfedge* edge = (HbrHalfedge*)(extraedges + index * edgesize); return edge->GetOrgVertexID(); } else { return edges[index].GetOrgVertexID(); } } template void HbrFace::SetChild(int index, HbrFace* face) { assert(id != -1); int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(nvertices); // Construct the children array if it doesn't already exist if (!children.children) { int i; if (nchildren > 4) { children.extrachildren = new HbrFace*[nchildren]; for (i = 0; i < nchildren; ++i) { children.extrachildren[i] = 0; } } else { children.children = mesh->NewFaceChildren(); for (i = 0; i < nchildren; ++i) { (*children.children)[i] = 0; } } } if (nchildren > 4) { children.extrachildren[index] = face; } else { (*children.children)[index] = face; } face->parent = this->id; } template HbrVertex* HbrFace::Subdivide() { if (vchild != -1) return mesh->GetVertex(vchild); HbrVertex* vchildVert = mesh->GetSubdivision()->Subdivide(mesh, this); vchild = vchildVert->GetID(); vchildVert->SetParent(this); return vchildVert; } template void HbrFace::Refine() { mesh->GetSubdivision()->Refine(mesh, this); } template void HbrFace::Unrefine() { // Delete the children, via the mesh (so that the mesh loses // references to the children) if (children.children) { int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(nvertices); if (nchildren > 4) { for (int i = 0; i < nchildren; ++i) { if (children.extrachildren[i]) mesh->DeleteFace(children.extrachildren[i]); } delete[] children.extrachildren; children.extrachildren = 0; } else { for (int i = 0; i < nchildren; ++i) { if ((*children.children)[i]) mesh->DeleteFace((*children.children)[i]); } mesh->DeleteFaceChildren(children.children); children.children = 0; } } } template bool HbrFace::HasLimit() { return mesh->GetSubdivision()->HasLimit(mesh, this); } template unsigned long HbrFace::GetMemStats() const { return sizeof(HbrFace); } template void HbrFace::MarkUsage() { // Must increment the usage on all vertices which are in the // support for this face. Note well: this will increment vertices // more than once. This doesn't really matter as long as // ClearUsage also does the same number of decrements. If we // really were concerned about ensuring single increments, we can // use GetSupportingVertices, but that's slower. HbrVertex* v; HbrHalfedge* e, *ee, *eee, *start; size_t edgesize, eedgesize; if (nvertices > 4) { e = (HbrHalfedge*)(extraedges); edgesize = sizeof(HbrHalfedge) + sizeof(HbrFace*); } else { e = edges; edgesize = sizeof(HbrHalfedge); } for (int i = 0; i < nvertices; ++i) { v = mesh->GetVertex(e->GetOrgVertexID()); v->GuaranteeNeighbors(); start = v->GetIncidentEdge(); ee = start; do { HbrFace* f = ee->GetLeftFace(); int nv = f->GetNumVertices(); if (nv > 4) { eee = (HbrHalfedge*)(f->extraedges); eedgesize = sizeof(HbrHalfedge) + sizeof(HbrFace*); } else { eee = f->edges; eedgesize = sizeof(HbrHalfedge); } for (int j = 0; j < nv; ++j) { mesh->GetVertex(eee->GetOrgVertexID())->IncrementUsage(); eee = (HbrHalfedge*)((char *) eee + eedgesize); } ee = v->GetNextEdge(ee); if (ee == start) break; } while (ee); e = (HbrHalfedge*)((char *) e + edgesize); } } template void HbrFace::ClearUsage() { bool gc = false; // Must mark all vertices which may affect this face HbrVertex* v, *vv; HbrHalfedge* e, *ee, *eee, *start; size_t edgesize, eedgesize; if (nvertices > 4) { e = (HbrHalfedge*)(extraedges); edgesize = sizeof(HbrHalfedge) + sizeof(HbrFace*); } else { e = edges; edgesize = sizeof(HbrHalfedge); } for (int i = 0; i < nvertices; ++i) { v = mesh->GetVertex(e->GetOrgVertexID()); start = v->GetIncidentEdge(); ee = start; do { HbrFace* f = ee->GetLeftFace(); int nv = f->GetNumVertices(); if (nv > 4) { eee = (HbrHalfedge*)(f->extraedges); eedgesize = sizeof(HbrHalfedge) + sizeof(HbrFace*); } else { eee = f->edges; eedgesize = sizeof(HbrHalfedge); } for (int j = 0; j < nv; ++j) { HbrVertex* vert = mesh->GetVertex(eee->GetOrgVertexID()); vert->DecrementUsage(); if (!vert->IsUsed()) { mesh->AddGarbageCollectableVertex(vert); gc = true; } eee = (HbrHalfedge*)((char *) eee + eedgesize); } ee = v->GetNextEdge(ee); if (ee == start) break; } while (ee); e = (HbrHalfedge*)((char *) e + edgesize); } if (gc) mesh->GarbageCollect(); } template bool HbrFace::GarbageCollectable() const { if (children.children || protect) return false; for (int i = 0; i < nvertices; ++i) { HbrHalfedge* edge = GetEdge(i); HbrVertex* vertex = edge->GetOrgVertex(mesh); if (vertex->IsUsed()) return false; if (!GetParent() && vertex->EdgeRemovalWillMakeSingular(edge)) { return false; } } return true; } template void HbrFace::SetHierarchicalEdits(HbrHierarchicalEdit** edits) { HbrHierarchicalEdit** faceedits = edits; HbrHierarchicalEdit** baseedit = mesh->GetHierarchicalEditsAtOffset(0); editOffset = int(faceedits - baseedit); // Walk the list of edits and look for any which apply locally. while (HbrHierarchicalEdit* edit = *faceedits) { if (!edit->IsRelevantToFace(this)) break; edit->ApplyEditToFace(this); faceedits++; } } template void HbrFace::GetSupportingVertices(std::vector &support) { support.reserve(16); HbrVertex* v; HbrHalfedge* e, *ee, *eee, *start; size_t edgesize, eedgesize; if (nvertices > 4) { e = (HbrHalfedge*)(extraedges); edgesize = sizeof(HbrHalfedge) + sizeof(HbrFace*); } else { e = edges; edgesize = sizeof(HbrHalfedge); } for (int i = 0; i < nvertices; ++i) { v = mesh->GetVertex(e->GetOrgVertexID()); v->GuaranteeNeighbors(); start = v->GetIncidentEdge(); ee = start; do { HbrFace* f = ee->GetLeftFace(); int nv = f->GetNumVertices(); if (nv > 4) { eee = (HbrHalfedge*)(f->extraedges); eedgesize = sizeof(HbrHalfedge) + sizeof(HbrFace*); } else { eee = f->edges; eedgesize = sizeof(HbrHalfedge); } for (int j = 0; j < nv; ++j) { int id = eee->GetOrgVertexID(); std::vector::iterator vi = std::lower_bound(support.begin(), support.end(), id); if (vi == support.end() || *vi != id) { support.insert(vi, id); } eee = (HbrHalfedge*)((char *) eee + eedgesize); } ee = v->GetNextEdge(ee); if (ee == start) break; } while (ee); e = (HbrHalfedge*)((char *) e + edgesize); } } template std::ostream& operator<<(std::ostream& out, const HbrFace& face) { out << "face " << face.GetID() << ", " << face.GetNumVertices() << " vertices ("; for (int i = 0; i < face.GetNumVertices(); ++i) { HbrHalfedge* e = face.GetEdge(i); out << *(e->GetOrgVertex()); if (e->IsBoundary()) { out << " -/-> "; } else { out << " ---> "; } } out << ")"; return out; } template class HbrFaceOperator { public: virtual void operator() (HbrFace &face) = 0; virtual ~HbrFaceOperator() {} }; } // end namespace OPENSUBDIV_VERSION using namespace OPENSUBDIV_VERSION; } // end namespace OpenSubdiv #endif /* HBRFACE_H */