OpenSubdiv/opensubdiv/hbr/face.h
manuelk ea1a87441f Add support for hierarchical hole edits.
- add tag parsing for h-hole in shape_utils
- re-create Renderman's test shape from the documentation (catmark_square_hedit.h)
- fix Hbr to correctly pass the hole tag from parent to child face
- fix FarSubdivisionTables to handle disconnected face-vertices without crashing

fixes #75
2013-03-01 18:27:19 -08:00

1062 lines
34 KiB
C++

//
// 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 <assert.h>
#include <cstdio>
#include <functional>
#include <iostream>
#include <algorithm>
#include <vector>
#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 T> class HbrVertex;
template <class T> class HbrHalfedge;
template <class T> class HbrFace;
template <class T> class HbrMesh;
template <class T> class HbrHierarchicalEdit;
template <class T> std::ostream& operator<<(std::ostream& out, const HbrFace<T>& face);
// A descriptor for a path to a face
struct HbrFacePath {
void Print() const {
printf("%d", topface);
for (std::vector<int>::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<int> 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<int>::const_reverse_iterator i = x.remainder.rbegin();
std::vector<int>::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 T>
class HbrFaceChildren {
public:
HbrFace<T> *& operator[](const int index) {
return children[index];
}
const HbrFace<T> *& operator[](const int index) const {
return children[index];
}
private:
friend class HbrAllocator<HbrFaceChildren<T> >;
// Used by block allocator
HbrFaceChildren<T>*& GetNext() { return (HbrFaceChildren<T>*&) children; }
HbrFaceChildren() {}
~HbrFaceChildren() {}
HbrFace<T> *children[4];
};
template <class T> class HbrFace {
private:
friend class HbrAllocator<HbrFace<T> >;
friend class HbrHalfedge<T>;
HbrFace();
~HbrFace();
public:
void Initialize(HbrMesh<T>* mesh, HbrFace<T>* parent, int childindex, int id, int uindex, int nvertices, HbrVertex<T>** vertices, int fvarwidth = 0, int depth = 0);
void Destroy();
// Returns the mesh to which this face belongs
HbrMesh<T>* 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<T>* GetFirstEdge() const {
if (nvertices > 4) {
return (HbrHalfedge<T>*)(extraedges);
} else {
return const_cast<HbrHalfedge<T>*>(&edges[0]);
}
}
// Return the halfedge which originates at the vertex with the
// indicated origin index
HbrHalfedge<T>* GetEdge(int index) const;
// Return the vertex with the indicated index
HbrVertex<T>* 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<T>* GetParent() const {
if (parent == -1) return NULL;
return mesh->GetFace(parent);
}
// Set the child
void SetChild(int index, HbrFace<T>* face);
// Return the child with the indicated index
HbrFace<T>* 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<T>* Subdivide();
bool HasChildVertex() const { return vchild!=-1; }
// 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(bool h=1) { hole = h; }
// 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<T>& 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<T>** edits);
// Return the list of hierarchical edits associated with this face
HbrHierarchicalEdit<T>** 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<int>(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<T>*& GetNext() { return (HbrFace<T>*&) mesh; }
HbrFacePath GetPath() const {
HbrFacePath path;
path.remainder.reserve(GetDepth());
const HbrFace<T>* 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<int>(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<int> &support);
private:
// Mesh to which this face belongs
HbrMesh<T>* 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<T> 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<T>* children;
HbrFace<T>** 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<nv; ++i) {
if (GetVertex(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 <class T>
HbrFace<T>::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 <class T>
void
HbrFace<T>::Initialize(HbrMesh<T>* m, HbrFace<T>* _parent, int childindex, int fid, int _uindex, int nv, HbrVertex<T>** 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 = static_cast<unsigned char>(_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<T>) + sizeof(HbrFace<T>*);
extraedges = (char *) malloc(nv * edgesize);
for (i = 0; i < nv; ++i) {
HbrHalfedge<T>* edge = (HbrHalfedge<T>*)(extraedges + i * edgesize);
new (edge) HbrHalfedge<T>();
}
} 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<T>* edge;
size_t edgesize;
if (nv > 4) {
edge = (HbrHalfedge<T>*)(extraedges);
edgesize = sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*);
} else {
edge = edges;
edgesize = sizeof(HbrHalfedge<T>);
}
for (i = 0, next = 1; i < nv; ++i, ++next) {
if (next == nv) next = 0;
HbrHalfedge<T>* 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<T>*)((char *) edge + edgesize);
}
if (nv > 4) {
edge = (HbrHalfedge<T>*)(extraedges);
} else {
edge = edges;
}
for (i = 0; i < nv; ++i) {
vertices[i]->AddIncidentEdge(edge);
edge = (HbrHalfedge<T>*)((char *) edge + edgesize);
}
}
template <class T>
HbrFace<T>::~HbrFace() {
Destroy();
}
template <class T>
void
HbrFace<T>::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<T>* edge;
size_t edgesize;
if (nvertices > 4) {
edge = (HbrHalfedge<T>*)(extraedges);
edgesize = sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*);
} else {
edge = edges;
edgesize = sizeof(HbrHalfedge<T>);
}
for (i = 0; i < nvertices; ++i) {
#ifdef HBRSTITCH
edge->DestroyStitchEdges(stitchCount);
#endif
HbrVertex<T>* vertex = mesh->GetVertex(edge->GetOrgVertexID());
if (fvarbits) {
HbrFVarData<T>& fvt = vertex->GetFVarData(this);
if (fvt.GetFaceID() == GetID()) {
fvt.SetFaceID(-1);
}
}
vertex->RemoveIncidentEdge(edge);
vertex->UnGuaranteeNeighbors();
edge = (HbrHalfedge<T>*)((char *) edge + edgesize);
}
if (extraedges) {
edge = (HbrHalfedge<T>*)(extraedges);
for (i = 0; i < nvertices; ++i) {
edge->~HbrHalfedge<T>();
edge = (HbrHalfedge<T>*)((char *) edge + edgesize);
}
free(extraedges);
extraedges = 0;
}
// Remove parent's reference to self
HbrFace<T> *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<T> *vchildVert = mesh->GetVertex(vchild);
vchildVert->SetParent(static_cast<HbrFace*>(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 <class T>
HbrHalfedge<T>*
HbrFace<T>::GetEdge(int index) const {
assert(index >= 0 && index < nvertices);
if (nvertices > 4) {
const size_t edgesize = sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*);
return (HbrHalfedge<T>*)(extraedges + index * edgesize);
} else {
return const_cast<HbrHalfedge<T>*>(edges + index);
}
}
template <class T>
HbrVertex<T>*
HbrFace<T>::GetVertex(int index) const {
assert(index >= 0 && index < nvertices);
if (nvertices > 4) {
const size_t edgesize = sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*);
HbrHalfedge<T>* edge = (HbrHalfedge<T>*)(extraedges +
index * edgesize);
return mesh->GetVertex(edge->GetOrgVertexID());
} else {
return mesh->GetVertex(edges[index].GetOrgVertexID());
}
}
template <class T>
int
HbrFace<T>::GetVertexID(int index) const {
assert(index >= 0 && index < nvertices);
if (nvertices > 4) {
const size_t edgesize = sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*);
HbrHalfedge<T>* edge = (HbrHalfedge<T>*)(extraedges +
index * edgesize);
return edge->GetOrgVertexID();
} else {
return edges[index].GetOrgVertexID();
}
}
template <class T>
void
HbrFace<T>::SetChild(int index, HbrFace<T>* 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<T>*[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 <class T>
HbrVertex<T>*
HbrFace<T>::Subdivide() {
if (vchild != -1) return mesh->GetVertex(vchild);
HbrVertex<T>* vchildVert = mesh->GetSubdivision()->Subdivide(mesh, this);
vchild = vchildVert->GetID();
vchildVert->SetParent(this);
return vchildVert;
}
template <class T>
void
HbrFace<T>::Refine() {
mesh->GetSubdivision()->Refine(mesh, this);
}
template <class T>
void
HbrFace<T>::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 <class T>
bool
HbrFace<T>::HasLimit() {
return mesh->GetSubdivision()->HasLimit(mesh, this);
}
template <class T>
unsigned long
HbrFace<T>::GetMemStats() const {
return sizeof(HbrFace<T>);
}
template <class T>
void
HbrFace<T>::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<T>* v;
HbrHalfedge<T>* e, *ee, *eee, *start;
size_t edgesize, eedgesize;
if (nvertices > 4) {
e = (HbrHalfedge<T>*)(extraedges);
edgesize = sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*);
} else {
e = edges;
edgesize = sizeof(HbrHalfedge<T>);
}
for (int i = 0; i < nvertices; ++i) {
v = mesh->GetVertex(e->GetOrgVertexID());
v->GuaranteeNeighbors();
start = v->GetIncidentEdge();
ee = start;
do {
HbrFace<T>* f = ee->GetLeftFace();
int nv = f->GetNumVertices();
if (nv > 4) {
eee = (HbrHalfedge<T>*)(f->extraedges);
eedgesize = sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*);
} else {
eee = f->edges;
eedgesize = sizeof(HbrHalfedge<T>);
}
for (int j = 0; j < nv; ++j) {
mesh->GetVertex(eee->GetOrgVertexID())->IncrementUsage();
eee = (HbrHalfedge<T>*)((char *) eee + eedgesize);
}
ee = v->GetNextEdge(ee);
if (ee == start) break;
} while (ee);
e = (HbrHalfedge<T>*)((char *) e + edgesize);
}
}
template <class T>
void
HbrFace<T>::ClearUsage() {
bool gc = false;
// Must mark all vertices which may affect this face
HbrVertex<T>* v, *vv;
HbrHalfedge<T>* e, *ee, *eee, *start;
size_t edgesize, eedgesize;
if (nvertices > 4) {
e = (HbrHalfedge<T>*)(extraedges);
edgesize = sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*);
} else {
e = edges;
edgesize = sizeof(HbrHalfedge<T>);
}
for (int i = 0; i < nvertices; ++i) {
v = mesh->GetVertex(e->GetOrgVertexID());
start = v->GetIncidentEdge();
ee = start;
do {
HbrFace<T>* f = ee->GetLeftFace();
int nv = f->GetNumVertices();
if (nv > 4) {
eee = (HbrHalfedge<T>*)(f->extraedges);
eedgesize = sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*);
} else {
eee = f->edges;
eedgesize = sizeof(HbrHalfedge<T>);
}
for (int j = 0; j < nv; ++j) {
HbrVertex<T>* vert = mesh->GetVertex(eee->GetOrgVertexID());
vert->DecrementUsage();
if (!vert->IsUsed()) {
mesh->AddGarbageCollectableVertex(vert);
gc = true;
}
eee = (HbrHalfedge<T>*)((char *) eee + eedgesize);
}
ee = v->GetNextEdge(ee);
if (ee == start) break;
} while (ee);
e = (HbrHalfedge<T>*)((char *) e + edgesize);
}
if (gc) mesh->GarbageCollect();
}
template <class T>
bool
HbrFace<T>::GarbageCollectable() const {
if (children.children || protect) return false;
for (int i = 0; i < nvertices; ++i) {
HbrHalfedge<T>* edge = GetEdge(i);
HbrVertex<T>* vertex = edge->GetOrgVertex(mesh);
if (vertex->IsUsed()) return false;
if (!GetParent() && vertex->EdgeRemovalWillMakeSingular(edge)) {
return false;
}
}
return true;
}
template <class T>
void
HbrFace<T>::SetHierarchicalEdits(HbrHierarchicalEdit<T>** edits) {
HbrHierarchicalEdit<T>** faceedits = edits;
HbrHierarchicalEdit<T>** baseedit = mesh->GetHierarchicalEditsAtOffset(0);
editOffset = int(faceedits - baseedit);
// Walk the list of edits and look for any which apply locally.
while (HbrHierarchicalEdit<T>* edit = *faceedits) {
if (!edit->IsRelevantToFace(this)) break;
edit->ApplyEditToFace(this);
faceedits++;
}
}
template <class T>
void
HbrFace<T>::GetSupportingVertices(std::vector<int> &support) {
support.reserve(16);
HbrVertex<T>* v;
HbrHalfedge<T>* e, *ee, *eee, *start;
size_t edgesize, eedgesize;
if (nvertices > 4) {
e = (HbrHalfedge<T>*)(extraedges);
edgesize = sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*);
} else {
e = edges;
edgesize = sizeof(HbrHalfedge<T>);
}
for (int i = 0; i < nvertices; ++i) {
v = mesh->GetVertex(e->GetOrgVertexID());
v->GuaranteeNeighbors();
start = v->GetIncidentEdge();
ee = start;
do {
HbrFace<T>* f = ee->GetLeftFace();
int nv = f->GetNumVertices();
if (nv > 4) {
eee = (HbrHalfedge<T>*)(f->extraedges);
eedgesize = sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*);
} else {
eee = f->edges;
eedgesize = sizeof(HbrHalfedge<T>);
}
for (int j = 0; j < nv; ++j) {
int id = eee->GetOrgVertexID();
std::vector<int>::iterator vi =
std::lower_bound(support.begin(), support.end(), id);
if (vi == support.end() || *vi != id) {
support.insert(vi, id);
}
eee = (HbrHalfedge<T>*)((char *) eee + eedgesize);
}
ee = v->GetNextEdge(ee);
if (ee == start) break;
} while (ee);
e = (HbrHalfedge<T>*)((char *) e + edgesize);
}
}
template <class T>
std::ostream& operator<<(std::ostream& out, const HbrFace<T>& face) {
out << "face " << face.GetID() << ", " << face.GetNumVertices() << " vertices (";
for (int i = 0; i < face.GetNumVertices(); ++i) {
HbrHalfedge<T>* e = face.GetEdge(i);
out << *(e->GetOrgVertex());
if (e->IsBoundary()) {
out << " -/-> ";
} else {
out << " ---> ";
}
}
out << ")";
return out;
}
template <class T>
class HbrFaceOperator {
public:
virtual void operator() (HbrFace<T> &face) = 0;
virtual ~HbrFaceOperator() {}
};
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* HBRFACE_H */