OpenSubdiv/opensubdiv/hbr/vertex.h
jcowles 392e5e8bed Remove #pragma once
While this may be worth revisiting, we should first quantify the benefits and
identify the compilers that support it. Ultimately, we may never use pragma
once in favor of strictly using standard C++.
2015-05-20 09:59:18 -07:00

1559 lines
49 KiB
C++

//
// Copyright 2013 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
// compliance with the Apache License and the following modification to it:
// Section 6. Trademarks. is deleted and replaced with:
//
// 6. Trademarks. This License does not grant permission to use the trade
// names, trademarks, service marks, or product names of the Licensor
// and its affiliates, except as required to comply with Section 4(c) of
// the License and to reproduce the content of the NOTICE file.
//
// You may obtain a copy of the Apache License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//
#ifndef OPENSUBDIV3_HBRVERTEX_H
#define OPENSUBDIV3_HBRVERTEX_H
#include <assert.h>
#include <iostream>
#include <iterator>
#include <vector>
#include "../hbr/fvarData.h"
#include "../hbr/face.h"
#include "../version.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
template <class T> class HbrHalfedge;
template <class T> class HbrHalfedgeCompare;
template <class T> class HbrVertex;
template <class T> class HbrVertexOperator;
template <class T> class HbrFaceOperator;
template <class T> class HbrHalfedgeOperator;
template <class T> class HbrVertex {
public:
HbrVertex();
HbrVertex(int vid, const T &data, int fvarwidth) {
Initialize(vid, data, fvarwidth);
}
void Initialize(int vid, const T &data, int fvarwidth);
~HbrVertex();
void Destroy(HbrMesh<T> *mesh = 0);
// Registers an incident edge with the vertex
void AddIncidentEdge(HbrHalfedge<T>* edge);
// Unregister an incident edge with the vertex
void RemoveIncidentEdge(HbrHalfedge<T>* edge);
// Checks if removal of the indicated incident edge will result
// in a singular vertex
bool EdgeRemovalWillMakeSingular(HbrHalfedge<T>* edge) const;
// Sets up vertex flags after the vertex has been bound to a mesh
void Finish();
// Compute the valence of this vertex
int GetValence() const;
// Compute the valence of this vertex including only edges which
// are "coarse" (highest level edges)
int GetCoarseValence() const;
// Return vertex ID
int GetID() const { return id; }
// Return vertex data
T& GetData() { return data; }
// Return vertex data
const T& GetData() const { return data; }
// Returns the facevarying data which is matched to the face.
// This may either be the "generic" facevarying item (fvardata, so
// data.GetFace() == face) or one specifically registered to the
// face (in the middle of morefvardata, so data.GetFace() ==
// face). If we require storage for a facevarying data designed to
// store discontinuous values for this face, we must have called
// NewFVarData before GetFVarData will give it to us.
HbrFVarData<T>& GetFVarData(const HbrFace<T>* face);
// Returns new facevarying data matched to the face
HbrFVarData<T>& NewFVarData(const HbrFace<T>* face);
// Return any incident face attached to the vertex
HbrFace<T>* GetFace() const;
// Return the mesh to which this vertex belongs
HbrMesh<T>* GetMesh() const;
// Return an edge connected to dest
HbrHalfedge<T>* GetEdge(const HbrVertex<T>* dest) const;
// Return an edge connected to vertex with id dest
HbrHalfedge<T>* GetEdge(int dest) const;
// Given an edge, returns the next edge in counterclockwise order
// around this vertex. Note well: this is only the next halfedge,
// which means that all edges returned by this function are
// guaranteed to have the same origin vertex (ie this vertex). In
// boundary cases if you are interested in all edges you will not
// get the last edge with this function. For that reason,
// GetSurroundingEdges is preferred.
HbrHalfedge<T>* GetNextEdge(const HbrHalfedge<T>* edge) const;
// Given an edge, returns the previous edge (ie going clockwise)
// around this vertex
HbrHalfedge<T>* GetPreviousEdge(const HbrHalfedge<T>* edge) const;
// Quadedge-like algebra subset. Since we are dealing with
// halfedges and not symmetric edges, these functions accept a
// destination vertex which indicates the (possibly imaginary)
// halfedge we are considering, and return the destination vertex
// of the desired (also possibly imaginary) halfedge. Also,
// currently they are potentially very inefficient and should be
// avoided.
HbrVertex<T>* GetQEONext(const HbrVertex<T>* dest) const;
HbrVertex<T>* GetQEONext(const HbrHalfedge<T>* edge) const;
HbrVertex<T>* GetQEOPrev(const HbrHalfedge<T>* edge) const;
HbrVertex<T>* GetQEOPrev(const HbrVertex<T>* dest) const;
HbrVertex<T>* GetQELNext(const HbrVertex<T>* dest) const;
// Returns true if the vertex is on a boundary edge
bool OnBoundary() const;
// Returns true if the vertex has a facevarying mask which is
// smooth (0).
bool IsFVarSmooth(int datum);
// Returns true if all facevarying data has facevarying mask which
// is smooth
bool IsFVarAllSmooth();
// Returns true if the vertex has a facevarying mask which is dart
// (1).
bool IsFVarDart(int datum);
// Returns true if the vertex is a facevarying corner for any
// incident face, where "cornerness" is defined as having two
// incident edges that make up a face both being facevarying
// edges.
bool IsFVarCorner(int datum);
// Returns the sharpness of the vertex
float GetSharpness() const { return sharpness; }
// Sets the sharpness of the vertex
void SetSharpness(float sharp) { sharpness = sharp; ClearMask(); }
// Returns whether the corner is sharp at the current level of
// subdivision (next = false) or at the next level of subdivision
// (next = true).
bool IsSharp(bool next) const { return (next ? (sharpness > 0.0f) : (sharpness >= 1.0f)); }
// Sets the vertex mask if the vertex is sharp to reflect that
// it's a corner
void ClearMask() {
mask0 = mask1 = 0; validmask = 0; volatil = 0;
}
// Returns the integer mask of the vertex at the current level of
// subdivision (next = false) or at the next level of subdivision
// (next = true)
unsigned char GetMask(bool next);
// Returns the facevarying integer mask of the vertex
unsigned char GetFVarMask(int datum);
// Computes the "fractional mask" of the vertex at the current
// subdivision level, based on the fractional sharpnesses of any
// adjacent sharp edges. The fractional mask is a value between 0
// and 1
float GetFractionalMask() const;
// Returns whether the vertex is singular (has two separate
// incident halfedge cycles)
bool IsSingular() const { return nIncidentEdges > 1; }
// Collect the ring of edges around this vertex. Note well: not
// all edges in this list will have an orientation where the
// origin of the edge is this vertex! This function requires an
// output iterator; to get the edges into a std::vector, use
// GetSurroundingEdges(std::back_inserter(myvector))
template <typename OutputIterator>
void GetSurroundingEdges(OutputIterator edges) const;
// Apply an edge operator to each edge in the ring of edges
// around this vertex
void ApplyOperatorSurroundingEdges(HbrHalfedgeOperator<T> &op) const;
// Collect the ring of vertices around this vertex (the ones that
// share an edge with this vertex). This function requires an
// output iterator; to get the vertices into a std::vector, use
// GetSurroundingVertices(std::back_inserter(myvector))
template <typename OutputIterator>
void GetSurroundingVertices(OutputIterator vertices) const;
// Apply a vertex operator to each vertex in the ring of vertices
// around this vertex
void ApplyOperatorSurroundingVertices(HbrVertexOperator<T> &op) const;
// Applys an operator to the ring of faces around this vertex
void ApplyOperatorSurroundingFaces(HbrFaceOperator<T> &op) const;
// Returns the parent, which can be a edge, face, or vertex
HbrHalfedge<T>* GetParentEdge() const { return (parentType == k_ParentEdge ? parent.edge : 0); }
HbrFace<T>* GetParentFace() const { return (parentType == k_ParentFace ? parent.face : 0); }
HbrVertex<T>* GetParentVertex() const { return (parentType == k_ParentVertex ? parent.vertex : 0); }
// Set the parent pointer
void SetParent(HbrHalfedge<T>* edge) { assert(!edge || !parent.vertex); parentType = k_ParentEdge; parent.edge = edge; }
void SetParent(HbrFace<T>* face) { assert(!face || !parent.vertex); parentType = k_ParentFace; parent.face = face; }
void SetParent(HbrVertex<T>* vertex) { assert(!vertex || !parent.vertex); parentType = k_ParentVertex; parent.vertex = vertex; }
// Subdivides the vertex and returns the child vertex
HbrVertex<T>* Subdivide();
// Refines the ring of faces around this vertex
void Refine();
// Make sure the vertex has all faces in the ring around it
void GuaranteeNeighbors();
// Indicates that the vertex may have a missing face neighbor and
// may need to guarantee its neighbors in the future
void UnGuaranteeNeighbors() {
neighborsguaranteed = 0;
// Its mask is also invalidated
validmask = 0;
}
// True if the edge has a subdivided child vertex
bool HasChild() const { return vchild!=-1; }
// Remove the reference to subdivided vertex
void RemoveChild() { vchild = -1; }
// Returns true if the vertex still has an incident edge (in other
// words, it belongs to a face)
bool IsReferenced() const { return references != 0; }
// Returns true if the vertex is extraordinary
bool IsExtraordinary() const { return extraordinary; }
// Tag the vertex as being extraordinary
void SetExtraordinary() { extraordinary = 1; }
// Returns whether the vertex is volatile (incident to a semisharp
// edge or semisharp corner)
bool IsVolatile() { if (!validmask) GetMask(false); return volatil; }
// Simple bookkeeping needed for garbage collection by HbrMesh
bool IsCollected() const { return collected; }
void SetCollected() { collected = 1; }
void ClearCollected() { collected = 0; }
// Bookkeeping to see if a vertex edit exists for this vertex
bool HasVertexEdit() const { return hasvertexedit; }
void SetVertexEdit() { hasvertexedit = 1; }
void ClearVertexEdit() { hasvertexedit = 0; }
// Returns memory statistics
unsigned long GetMemStats() const;
// Returns true if the vertex is connected. This means that it has
// an incident edge
bool IsConnected() const { return nIncidentEdges > 0; }
// Return an incident edge to this vertex, which happens to be the
// first halfedge of the cycles.
HbrHalfedge<T>* GetIncidentEdge() const {
if (nIncidentEdges > 1) {
return incident.edges[0];
} else if (nIncidentEdges == 1) {
return incident.edge;
} else {
return 0;
}
}
// Sharpness and mask constants
enum Mask {
k_Smooth = 0,
k_Dart = 1,
k_Crease = 2,
k_Corner = 3,
k_InfinitelySharp = 10
};
// Increment the usage counter on the vertex
void IncrementUsage() { used++; }
// Decrement the usage counter on the vertex
void DecrementUsage() { used--; }
// Check the usage counter on the vertex
bool IsUsed() const { return used || (vchild != -1); }
// Used by block allocator
HbrVertex<T>*& GetNext() { return parent.vertex; }
// Returns the blind pointer to client data
void *GetClientData(HbrMesh<T>* mesh) const {
return mesh->GetVertexClientData(id);
}
// Sets the blind pointer to client data
void SetClientData(HbrMesh<T> *mesh, void *data) {
mesh->SetVertexClientData(id, data);
}
enum ParentType {
k_ParentNone, k_ParentFace, k_ParentEdge, k_ParentVertex
};
private:
// Splits a singular vertex into multiple nonsingular vertices
void splitSingular();
// Data
T data;
// Pointer to extra facevarying data. Space for this is allocated
// by NewFVarData. This struct is actually overpadded.
struct morefvardata {
int count;
} *morefvar;
// Unique ID of this vertex
int id;
// The number of halfedges which have this vertex as the incident
// edge. When references == 0, the vertex is safe to delete
int references;
// The number of faces marked "used" which share this vertex. May
// not be the same as references!
int used;
// Sharpness
float sharpness;
// Index of child vertex
int vchild;
// Size of incident array
unsigned short nIncidentEdges;
// Vertex masks, at this level of subdivision and at the next
// level of subdivision. Valid only when validmask = 1.
unsigned short mask0:3;
unsigned short mask1:3;
// Extraordinary bit
unsigned short extraordinary:1;
// Whether the current mask value is correct or should be recalculated
unsigned short validmask:1;
// Whether the vertex is "volatile" (is incident to a semisharp edge,
// or is a semisharp corner)
unsigned short volatil:1;
// Whether we can guarantee the existence of neighboring faces on
// this vertex
unsigned short neighborsguaranteed:1;
// Bookkeeping for HbrMesh
unsigned short collected:1;
// Whether the vertex has an edit. The edit is owned by a face
// so this is just a tag that indicates we need to search the
// vertex's neighboring faces for an edit
unsigned short hasvertexedit:1;
// Whether the vertex edit (if any) has been applied
unsigned short editsapplied:1;
// Whether Destroy() has been called
unsigned short destroyed:1;
// Parent type - can be face, edge, or vertex
unsigned short parentType:2;
// List of edge cycles. For "singular" vertices, the corresponding
// set of adjacent halfedges may consist of several cycles, and we
// need to account for all of them here. In cases where
// nIncidentEdges is 1, the edge field of the union points
// directly at the edge which starts the only incident cycle. If
// nIncidnetEdges is 2 or more, the edges field of the union is a
// separate allocated array and edge member of the array points at
// separate cycles.
union {
HbrHalfedge<T>* edge;
HbrHalfedge<T>** edges;
} incident;
union {
HbrFace<T>* face;
HbrHalfedge<T>* edge;
HbrVertex<T>* vertex;
} parent;
#ifdef HBR_ADAPTIVE
public:
struct adaptiveFlags {
unsigned isTagged:1;
unsigned wasTagged:1;
adaptiveFlags() : isTagged(0), wasTagged(0) { }
};
adaptiveFlags _adaptiveFlags;
#endif
};
template <class T>
HbrVertex<T>::HbrVertex() :
morefvar(0), id(-1), references(0), used(0),
sharpness(0.0f), vchild(-1), nIncidentEdges(0), extraordinary(0), validmask(0),
volatil(0), neighborsguaranteed(0), collected(0), hasvertexedit(0),
editsapplied(0), destroyed(0), parentType(k_ParentNone) {
ClearMask();
parent.vertex = 0;
incident.edge = 0;
}
template <class T>
void
HbrVertex<T>::Initialize(int vid, const T &vdata, int fvarwidth) {
data = vdata;
morefvar = 0 ;
id = vid;
references = 0;
used = 0;
extraordinary = 0;
ClearMask();
neighborsguaranteed = 0;
collected = 0;
hasvertexedit = 0;
editsapplied = 0;
destroyed = 0;
sharpness = 0.0f;
nIncidentEdges = 0;
vchild = -1;
assert(!parent.vertex);
parentType = k_ParentVertex;
parent.vertex = 0;
if (fvarwidth) {
// Upstream allocator ensured the class was padded by the
// appropriate size. GetFVarData will return a pointer to this
// memory, but it needs to be properly initialized.
// Run placement new to initialize datum
char *buffer = ((char*) this + sizeof(*this));
new (buffer) HbrFVarData<T>();
}
}
template <class T>
HbrVertex<T>::~HbrVertex() {
Destroy();
}
template <class T>
void
HbrVertex<T>::Destroy(HbrMesh<T> *mesh) {
if (!destroyed) {
// Vertices are only safe for deletion if the number of incident
// edges is exactly zero.
assert(references == 0);
// Delete parent reference to self
if (parentType == k_ParentEdge && parent.edge) {
parent.edge->RemoveChild();
parent.edge = 0;
} else if (parentType == k_ParentFace && parent.face) {
parent.face->RemoveChild();
parent.face = 0;
} else if (parentType == k_ParentVertex && parent.vertex) {
parent.vertex->RemoveChild();
parent.vertex = 0;
}
// Orphan the child vertex
if (vchild != -1) {
if (mesh) {
HbrVertex<T> *vchildVert = mesh->GetVertex(vchild);
vchildVert->SetParent(static_cast<HbrVertex*>(0));
}
vchild = -1;
}
// We're skipping the placement destructors here, in the
// assumption that HbrFVarData's destructor doesn't actually do
// anything much
if (morefvar) {
free(morefvar);
}
destroyed = 1;
}
}
template <class T>
void
HbrVertex<T>::AddIncidentEdge(HbrHalfedge<T>* edge) {
assert(edge->GetOrgVertex() == this);
// First, maintain the property that all of the incident edges
// will always be a boundary edge if possible. If any of the
// incident edges are no longer boundaries at this point then they
// can be immediately removed.
int i;
unsigned short newEdgeCount = 0;
bool edgeFound = false;
HbrHalfedge<T>** incidentEdges =
(nIncidentEdges > 1) ? incident.edges : &incident.edge;
for (i = 0; i < nIncidentEdges; ++i) {
if (incidentEdges[i] == edge) {
edgeFound = true;
}
if (incidentEdges[i]->IsBoundary()) {
incidentEdges[newEdgeCount++] = incidentEdges[i];
} else {
// Did this edge suddenly stop being a boundary because
// the newly introduced edge (or something close to it)
// closed a cycle? If so, we don't want to lose a pointer
// to this edge cycle! So check to see if this cycle is
// complete, and if so, keep it.
HbrHalfedge<T>* start = incidentEdges[i];
HbrHalfedge<T>* edge = start;
bool prevmatch = false;
do {
edge = GetNextEdge(edge);
// Check all previous incident edges, if already
// encountered then we have an edge to this cycle and
// don't need to proceed further with this check
for (int j = 0; j < i; ++j) {
if (incidentEdges[j] == edge) {
prevmatch = true;
break;
}
}
} while (!prevmatch && edge && edge != start);
if (!prevmatch && edge && edge == start) {
incidentEdges[newEdgeCount++] = incidentEdges[i];
}
}
}
// If we are now left with no incident edges, then this edge
// becomes the sole incident edge (since we always need somewhere
// to start, even if it's a uninterrupted cycle [ie it doesn't
// matter whether the edge is a boundary]). Restore incidentEdges
// array to point to the end of the object.
if (newEdgeCount == 0) {
if (!(edgeFound && nIncidentEdges == 1)) {
if (nIncidentEdges > 1) {
delete [] incidentEdges;
}
incidentEdges = &incident.edge;
incidentEdges[0] = edge;
nIncidentEdges = 1;
}
}
// Otherwise, we already have a set of incident edges - we only
// add this edge if it's a boundary edge, which would begin a new
// cycle.
else if (edge->IsBoundary()) {
if (!edgeFound) {
// Must add the new edge. May need to reallocate here.
if (newEdgeCount + 1 != nIncidentEdges) {
HbrHalfedge<T>** newIncidentEdges = 0;
if (newEdgeCount + 1 > 1) {
newIncidentEdges = new HbrHalfedge<T>*[newEdgeCount + 1];
} else {
newIncidentEdges = &incident.edge;
}
for (i = 0; i < newEdgeCount; ++i) {
newIncidentEdges[i] = incidentEdges[i];
}
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
nIncidentEdges = newEdgeCount + 1;
incidentEdges = newIncidentEdges;
if (nIncidentEdges > 1) {
incident.edges = newIncidentEdges;
}
}
incidentEdges[newEdgeCount] = edge;
} else {
// Edge is already in our list, so we don't need to add it
// again. However, we may need to reallocate due to above
// cleaning of nonboundary edges
if (newEdgeCount != nIncidentEdges) {
HbrHalfedge<T>** newIncidentEdges = 0;
if (newEdgeCount > 1) {
newIncidentEdges = new HbrHalfedge<T>*[newEdgeCount];
} else {
newIncidentEdges = &incident.edge;
}
for (i = 0; i < newEdgeCount; ++i) {
newIncidentEdges[i] = incidentEdges[i];
}
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
nIncidentEdges = newEdgeCount;
incidentEdges = newIncidentEdges;
if (nIncidentEdges > 1) {
incident.edges = newIncidentEdges;
}
}
}
}
else {
// Again, we may need to reallocate due to above cleaning of
// nonboundary edges
if (newEdgeCount != nIncidentEdges) {
HbrHalfedge<T>** newIncidentEdges = 0;
if (newEdgeCount > 1) {
newIncidentEdges = new HbrHalfedge<T>*[newEdgeCount];
} else {
newIncidentEdges = &incident.edge;
}
for (i = 0; i < newEdgeCount; ++i) {
newIncidentEdges[i] = incidentEdges[i];
}
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
nIncidentEdges = newEdgeCount;
incidentEdges = newIncidentEdges;
if (nIncidentEdges > 1) {
incident.edges = newIncidentEdges;
}
}
}
// For non-boundary edges, ensure that the incident edge starting
// the cycle is the lowest possible edge. By doing this,
// operations like GetSurroundingEdges will be guaranteed to
// return the same order of edges/faces through multi-threading.
if (!incidentEdges[0]->IsBoundary()) {
HbrHalfedge<T>* start = GetIncidentEdge();
incidentEdges[0] = start;
HbrFacePath incidentEdgePath = incidentEdges[0]->GetFace()->GetPath();
HbrHalfedge<T>* e = GetNextEdge(start);
while (e) {
if (e == start) break;
HbrFacePath ePath = e->GetFace()->GetPath();
if (ePath < incidentEdgePath) {
incidentEdges[0] = e;
incidentEdgePath = ePath;
}
HbrHalfedge<T>* next = GetNextEdge(e);
if (!next) {
e = e->GetPrev();
if (e->GetFace()->GetPath() < incidentEdges[0]->GetFace()->GetPath()) {
incidentEdges[0] = e;
}
break;
} else {
e = next;
}
}
}
references++;
}
template <class T>
void
HbrVertex<T>::RemoveIncidentEdge(HbrHalfedge<T>* edge) {
int i, j;
HbrHalfedge<T>** incidentEdges =
(nIncidentEdges > 1) ? incident.edges : &incident.edge;
references--;
if (references) {
HbrHalfedge<T>* next;
// We may need to shuffle our halfedge cycles. First we check
// whether the edge being erased begins any edge cycles
bool edgeFound = false;
next = GetNextEdge(edge);
for (i = 0; i < nIncidentEdges; ++i) {
if (incidentEdges[i] == edge) {
// Edge cycle found. Replace the edge with the next edge
// in the cycle if possible.
if (next) {
incidentEdges[i] = next;
// We are done.
return;
}
// If no next edge is found it means the entire cycle
// has gone away.
edgeFound = true;
break;
}
}
// The edge cycle needs to disappear
if (edgeFound) {
assert(nIncidentEdges > 1);
HbrHalfedge<T>** newIncidentEdges = 0;
if (nIncidentEdges - 1 > 1) {
newIncidentEdges = new HbrHalfedge<T>*[nIncidentEdges - 1];
} else {
newIncidentEdges = &incident.edge;
}
j = 0;
for (i = 0; i < nIncidentEdges; ++i) {
if (incidentEdges[i] != edge) {
newIncidentEdges[j++] = incidentEdges[i];
}
}
assert(j == nIncidentEdges - 1);
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
nIncidentEdges--;
if (nIncidentEdges > 1) {
incident.edges = newIncidentEdges;
}
return;
}
// Now deal with the case where we remove an edge
// which did not begin a boundary edge cycle. If this
// happens then the resulting unbroken cycle does
// get broken; in that case we replace the incident
// edge with the next one after this.
else if (nIncidentEdges == 1 && !incidentEdges[0]->IsBoundary()) {
if (next) {
incidentEdges[0] = next;
} else {
// hm, what does this mean for us? Not sure at the
// moment.
std::cout << "Could not split cycle!\n";
assert(0);
}
}
// (Is this another case or a specialization of the above?)
// When an edge in the middle of a boundary cycle goes away we
// need to mark a new cycle.
//
// If there is no next edge, it means that we didn't
// actually split the cycle, we just deleted the last edge
// in the cycle. As such nothing needs to occur because
// the "split" is already present.
else if (!edge->IsBoundary() && next) {
HbrHalfedge<T>** newIncidentEdges = 0;
if (nIncidentEdges + 1 > 1) {
newIncidentEdges = new HbrHalfedge<T>*[nIncidentEdges + 1];
} else {
newIncidentEdges = &incident.edge;
}
for (i = 0; i < nIncidentEdges; ++i) {
newIncidentEdges[i] = incidentEdges[i];
}
newIncidentEdges[nIncidentEdges] = next;
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
nIncidentEdges++;
if (nIncidentEdges > 1) {
incident.edges = newIncidentEdges;
}
}
} else {
// No references left, we can just clear all the cycles
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
nIncidentEdges = 0;
}
}
template <class T>
bool
HbrVertex<T>::EdgeRemovalWillMakeSingular(HbrHalfedge<T>* edge) const {
// Only edge left, or no incident edges at all (how?)
if (references <= 1 || nIncidentEdges <= 0) {
return false;
}
// There are at least two existing cycles. We could maybe consider
// the case where removal of this edge will actually make one of
// the edge cycles go away, possibly leaving behind just one, but
// we'll ignore that possibility for now
else if (nIncidentEdges > 1) {
return true;
}
// This is the incident edge starting a single cycle. Removal of
// the edge will replace the start of the cycle with the next
// edge, and we keep a single cycle.
else if (nIncidentEdges == 1 && incident.edge == edge) {
return false;
}
// Check the single cycle: was it interrupted? (i.e. a
// boundary). If not interrupted, then deletion of any edge still
// leaves a single cycle. Otherwise: if the edge is the *last*
// edge in the cycle, we still don't need to split the any further
// cycle. Otherwise we must split the cycle, which would result in
// a singular vertex
else if (!GetIncidentEdge()->IsBoundary()) {
return false;
} else if (GetNextEdge(edge)) {
return true;
} else {
return false;
}
}
template <class T>
void
HbrVertex<T>::Finish() {
extraordinary = false;
if (HbrMesh<T>* mesh = GetMesh()) {
if (IsSingular()) splitSingular();
assert(!IsSingular());
if (mesh->GetSubdivision()) {
extraordinary = mesh->GetSubdivision()->VertexIsExtraordinary(mesh, this);
}
}
}
template <class T>
int
HbrVertex<T>::GetValence() const {
int valence = 0;
assert(!IsSingular());
HbrHalfedge<T>* start =
(nIncidentEdges > 1) ? incident.edges[0] : incident.edge;
HbrHalfedge<T>* edge = start;
if (edge) do {
valence++;
edge = GetNextEdge(edge);
} while (edge && edge != start);
// In boundary cases, we increment the valence count by
// one more
if (!edge) valence++;
return valence;
}
template <class T>
int
HbrVertex<T>::GetCoarseValence() const {
int valence = 0;
assert(!IsSingular());
HbrHalfedge<T>* start =
(nIncidentEdges > 1) ? incident.edges[0] : incident.edge;
HbrHalfedge<T>* edge = start;
if (edge) do {
if (edge->IsCoarse()) {
valence++;
}
edge = GetNextEdge(edge);
} while (edge && edge != start);
// In boundary cases, we increment the valence count by one more
// (this assumes the last edge is coarse, which it had better be
// in the boundary case!)
if (!edge) valence++;
return valence;
}
template <class T>
HbrFVarData<T>&
HbrVertex<T>::GetFVarData(const HbrFace<T>* face) {
// See if there are any extra facevarying datum associated with
// this vertex, and whether any of them match the face.
if (morefvar) {
size_t fvtsize = sizeof(HbrFVarData<T>) + sizeof(float) * (GetMesh()->GetTotalFVarWidth() - 1);
HbrFVarData<T> *fvt = (HbrFVarData<T> *)((char *) morefvar + sizeof(int));
for (int i = 0; i < morefvar->count; ++i) {
if (fvt->GetFaceID() == face->GetID()) {
return *fvt;
}
fvt = (HbrFVarData<T>*)((char*) fvt + fvtsize);
}
}
// Otherwise, return the default facevarying datum, which lives
// in the overallocated space after the end of this object
return *((HbrFVarData<T>*) ((char*) this + sizeof(*this)));
}
template <class T>
HbrFVarData<T>&
HbrVertex<T>::NewFVarData(const HbrFace<T>* face) {
const int fvarwidth = GetMesh()->GetTotalFVarWidth();
size_t fvtsize = sizeof(HbrFVarData<T>) + (fvarwidth - 1) * sizeof(float);
if (morefvar) {
struct morefvardata *newmorefvar =
(struct morefvardata *) malloc(sizeof(int) + (morefvar->count + 1) * fvtsize);
HbrFVarData<T> *newfvt = (HbrFVarData<T> *)((char *) newmorefvar + sizeof(int));
HbrFVarData<T> *oldfvt = (HbrFVarData<T> *)((char *) morefvar + sizeof(int));
for (int i = 0; i < morefvar->count; ++i) {
new (newfvt) HbrFVarData<T>();
newfvt->SetAllData(fvarwidth, oldfvt->GetData(0));
newfvt->SetFaceID(oldfvt->GetFaceID());
oldfvt = (HbrFVarData<T>*)((char*) oldfvt + fvtsize);
newfvt = (HbrFVarData<T>*)((char*) newfvt + fvtsize);
}
new (newfvt) HbrFVarData<T>();
newfvt->SetFaceID(face->GetID());
newmorefvar->count = morefvar->count + 1;
free(morefvar);
morefvar = newmorefvar;
return *newfvt;
} else {
morefvar = (struct morefvardata *) malloc(sizeof(int) + fvtsize);
HbrFVarData<T> *newfvt = (HbrFVarData<T> *)((char *) morefvar + sizeof(int));
new (newfvt) HbrFVarData<T>();
newfvt->SetFaceID(face->GetID());
morefvar->count = 1;
return *newfvt;
}
}
template <class T>
HbrFace<T>*
HbrVertex<T>::GetFace() const {
return GetIncidentEdge()->GetFace();
}
template <class T>
HbrMesh<T>*
HbrVertex<T>::GetMesh() const {
return GetFace()->GetMesh();
}
template <class T>
HbrHalfedge<T>*
HbrVertex<T>::GetEdge(const HbrVertex<T>* dest) const {
// Here, we generally want to go through all halfedge cycles
for (int i = 0; i < nIncidentEdges; ++i) {
HbrHalfedge<T>* cycle =
(nIncidentEdges > 1) ? incident.edges[i] : incident.edge;
HbrHalfedge<T>* edge = cycle;
if (edge) do {
if (edge->GetDestVertex() == dest) {
return edge;
}
edge = GetNextEdge(edge);
} while (edge && edge != cycle);
}
return 0;
}
template <class T>
HbrHalfedge<T>*
HbrVertex<T>::GetEdge(int dest) const {
// Here, we generally want to go through all halfedge cycles
for (int i = 0; i < nIncidentEdges; ++i) {
HbrHalfedge<T>* cycle =
(nIncidentEdges > 1) ? incident.edges[i] : incident.edge;
HbrHalfedge<T>* edge = cycle;
if (edge) do {
if (edge->GetDestVertexID() == dest) {
return edge;
}
edge = GetNextEdge(edge);
} while (edge && edge != cycle);
}
return 0;
}
template <class T>
HbrHalfedge<T>*
HbrVertex<T>::GetNextEdge(const HbrHalfedge<T>* edge) const {
// Paranoia:
// if (edge->GetOrgVertex() != this) return 0;
return edge->GetPrev()->GetOpposite();
}
template <class T>
HbrHalfedge<T>*
HbrVertex<T>::GetPreviousEdge(const HbrHalfedge<T>* edge) const {
// Paranoia:
// if (edge->GetOrgVertex() != this) return 0;
return edge->GetOpposite()->GetNext();
}
template <class T>
HbrVertex<T>*
HbrVertex<T>::GetQEONext(const HbrVertex<T>* dest) const {
HbrHalfedge<T>* edge = GetEdge(dest);
if (edge) {
return edge->GetPrev()->GetOrgVertex();
}
HbrHalfedge<T>* start = GetIncidentEdge(), *next;
edge = start;
while (edge) {
next = GetNextEdge(edge);
if (edge->GetDestVertex() == dest) {
if (!next) {
return edge->GetPrev()->GetOrgVertex();
} else {
return next->GetDestVertex();
}
}
if (next == start) {
return 0;
} else if (!next) {
if (edge->GetPrev()->GetOrgVertex() == dest) {
return start->GetDestVertex();
} else {
return 0;
}
} else {
edge = next;
}
}
// Shouldn't get here
return 0;
}
template <class T>
HbrVertex<T>*
HbrVertex<T>::GetQEONext(const HbrHalfedge<T>* edge) const {
assert(edge->GetOrgVertex() == this);
return edge->GetPrev()->GetOrgVertex();
}
template <class T>
HbrVertex<T>*
HbrVertex<T>::GetQEOPrev(const HbrVertex<T>* dest) const {
HbrHalfedge<T>* edge = GetEdge(dest);
if (edge) {
if (edge->GetOpposite()) {
return edge->GetOpposite()->GetNext()->GetDestVertex();
} else {
HbrHalfedge<T>* start = GetIncidentEdge(), *next;
edge = start;
while (edge) {
next = GetNextEdge(edge);
if (next == start) {
if (next->GetDestVertex() == dest) {
return edge->GetDestVertex();
} else {
return 0;
}
} else if (!next) {
if (edge->GetPrev()->GetOrgVertex() == dest) {
return edge->GetDestVertex();
} else if (start->GetDestVertex() == dest) {
return edge->GetPrev()->GetOrgVertex();
} else {
return 0;
}
} else if (next->GetDestVertex() == dest) {
return edge->GetDestVertex();
} else {
edge = next;
}
}
return 0;
}
}
edge = dest->GetEdge(this);
if (edge) {
return edge->GetNext()->GetDestVertex();
}
return 0;
}
template <class T>
HbrVertex<T>*
HbrVertex<T>::GetQEOPrev(const HbrHalfedge<T>* edge) const {
assert(edge->GetOrgVertex() == this);
if (edge->GetOpposite()) {
return edge->GetOpposite()->GetNext()->GetDestVertex();
} else {
return GetQEOPrev(edge->GetDestVertex());
}
}
template <class T>
HbrVertex<T>*
HbrVertex<T>::GetQELNext(const HbrVertex<T>* dest) const {
HbrHalfedge<T>* edge = GetEdge(dest);
if (edge) {
return edge->GetNext()->GetDestVertex();
}
edge = dest->GetEdge(this);
if (edge) {
return edge->GetPrev()->GetOrgVertex();
}
return 0;
}
template <class T>
bool
HbrVertex<T>::OnBoundary() const {
// We really only need to check the first incident edge, since
// singular vertices by definition are on the boundary
return GetIncidentEdge()->IsBoundary();
}
template <class T>
bool
HbrVertex<T>::IsFVarSmooth(int datum) {
return (GetFVarMask(datum) == k_Smooth);
}
template <class T>
bool
HbrVertex<T>::IsFVarAllSmooth() {
for (int i = 0; i < GetMesh()->GetFVarCount(); ++i) {
if (!IsFVarSmooth(i)) return false;
}
return true;
}
template <class T>
bool
HbrVertex<T>::IsFVarDart(int datum) {
return (GetFVarMask(datum) == k_Dart);
}
template <class T>
bool
HbrVertex<T>::IsFVarCorner(int datum) {
// If it's a dart, it's a corner
if (IsFVarDart(datum)) return true;
// Run through surrounding edges, looking for two adjacent
// facevarying boundary edges
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *nextedge;
edge = start;
bool lastedgewassharp = false;
while (edge) {
if (edge->GetFVarSharpness(datum)) {
if (lastedgewassharp) {
return true;
} else {
lastedgewassharp = true;
}
} else {
lastedgewassharp = false;
}
nextedge = GetNextEdge(edge);
if (nextedge == start) {
return start->GetFVarSharpness(datum) && lastedgewassharp;
} else if (!nextedge) {
// Special case for the last edge in a cycle.
edge = edge->GetPrev();
return edge->GetFVarSharpness(datum) && lastedgewassharp;
} else {
edge = nextedge;
}
}
return false;
}
template <class T>
unsigned char
HbrVertex<T>::GetMask(bool next) {
if (validmask) {
return (unsigned char)(next ? mask1 : mask0);
}
mask0 = mask1 = 0;
// Mark volatility
if (sharpness > k_Smooth && sharpness < k_InfinitelySharp)
volatil = 1;
// If the vertex is tagged as sharp immediately promote its mask
// to corner
if (IsSharp(false)) {
mask0 += k_Corner;
}
if (IsSharp(true)) {
mask1 += k_Corner;
}
// Count the number of surrounding sharp edges
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *nextedge;
edge = start;
while (edge) {
float esharp = edge->GetSharpness();
if (edge->IsSharp(false)) {
if (mask0 < k_Corner) {
mask0++;
}
}
if (edge->IsSharp(true)) {
if (mask1 < k_Corner) {
mask1++;
}
}
// If any incident edge is semisharp, mark the vertex as volatile
if (esharp > HbrHalfedge<T>::k_Smooth && esharp < HbrHalfedge<T>::k_InfinitelySharp) {
volatil = 1;
}
nextedge = GetNextEdge(edge);
if (nextedge == start) {
break;
} else if (!nextedge) {
// Special case for the last edge in a cycle.
edge = edge->GetPrev();
esharp = edge->GetSharpness();
if (edge->IsSharp(false)) {
if (mask0 < k_Corner) {
mask0++;
}
}
if (edge->IsSharp(true)) {
if (mask1 < k_Corner) {
mask1++;
}
}
if (esharp > HbrHalfedge<T>::k_Smooth && esharp < HbrHalfedge<T>::k_InfinitelySharp) {
volatil = 1;
}
break;
} else {
edge = nextedge;
}
}
validmask = 1;
return (unsigned char)(next ? mask1 : mask0);
}
template <class T>
unsigned char
HbrVertex<T>::GetFVarMask(int datum) {
unsigned char mask = 0;
// If the vertex is tagged as sharp immediately promote its mask
// to corner
if (IsSharp(false)) {
mask += k_Corner;
}
// Count the number of surrounding facevarying boundary edges
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *nextedge;
edge = start;
while (edge) {
if (edge->GetFVarSharpness(datum)) {
if (mask < k_Corner) {
mask++;
} else {
// Can't get any sharper, so give up early
break;
}
}
nextedge = GetNextEdge(edge);
if (nextedge == start) {
break;
} else if (!nextedge) {
// Special case for the last edge in a cycle.
edge = edge->GetPrev();
if (edge->GetFVarSharpness(datum)) {
if (mask < k_Corner) {
mask++;
}
}
break;
} else {
edge = nextedge;
}
}
return mask;
}
template <class T>
float
HbrVertex<T>::GetFractionalMask() const {
float mask = 0;
float n = 0;
if (sharpness > k_Smooth && sharpness < k_Dart) {
mask += sharpness; ++n;
}
// Add up the strengths of surrounding fractional sharp edges
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *next;
edge = start;
while (edge) {
float esharp = edge->GetSharpness();
if (esharp > HbrHalfedge<T>::k_Smooth && esharp < HbrHalfedge<T>::k_Sharp) {
mask += esharp; ++n;
}
next = GetNextEdge(edge);
if (next == start) {
break;
} else if (!next) {
// Special case for the last edge in a cycle.
esharp = edge->GetPrev()->GetSharpness();
if (esharp > HbrHalfedge<T>::k_Smooth && esharp < HbrHalfedge<T>::k_Sharp) {
mask += esharp; ++n;
}
break;
} else {
edge = next;
}
}
assert (n > 0.0f && mask < n);
return (mask / n);
}
template <class T>
template <typename OutputIterator>
void
HbrVertex<T>::GetSurroundingEdges(OutputIterator edges) const {
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *next;
edge = start;
while (edge) {
*edges++ = edge;
next = GetNextEdge(edge);
if (next == start) {
break;
} else if (!next) {
// Special case for the last edge in a cycle.
*edges++ = edge->GetPrev();
break;
} else {
edge = next;
}
}
}
template <class T>
void
HbrVertex<T>::ApplyOperatorSurroundingEdges(HbrHalfedgeOperator<T> &op) const {
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *next;
edge = start;
while (edge) {
op(*edge);
next = GetNextEdge(edge);
if (next == start) {
break;
} else if (!next) {
op(*edge->GetPrev());
break;
} else {
edge = next;
}
}
}
template <class T>
template <typename OutputIterator>
void
HbrVertex<T>::GetSurroundingVertices(OutputIterator vertices) const {
HbrMesh<T>* mesh = GetMesh();
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *next;
edge = start;
while (edge) {
*vertices++ = edge->GetDestVertex(mesh);
next = GetNextEdge(edge);
if (next == start) {
break;
} else if (!next) {
// Special case for the last edge in a cycle: the last
// vertex on that cycle is not the destination of an
// outgoing halfedge
*vertices++ = edge->GetPrev()->GetOrgVertex(mesh);
break;
} else {
edge = next;
}
}
}
template <class T>
void
HbrVertex<T>::ApplyOperatorSurroundingVertices(HbrVertexOperator<T> &op) const {
HbrMesh<T>* mesh = GetMesh();
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *next;
edge = start;
while (edge) {
op(*edge->GetDestVertex(mesh));
next = GetNextEdge(edge);
if (next == start) return;
else if (!next) {
op(*edge->GetPrev()->GetOrgVertex(mesh));
return;
} else {
edge = next;
}
}
}
template <class T>
void
HbrVertex<T>::ApplyOperatorSurroundingFaces(HbrFaceOperator<T> &op) const {
HbrHalfedge<T>* start = GetIncidentEdge(), *edge;
edge = start;
while (edge) {
op(*edge->GetLeftFace());
edge = GetNextEdge(edge);
if (edge == start) break;
}
}
template <class T>
HbrVertex<T>*
HbrVertex<T>::Subdivide() {
HbrMesh<T>* mesh = GetMesh();
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
HbrVertex<T>::Refine() {
HbrMesh<T>* mesh = GetMesh();
mesh->GetSubdivision()->RefineAtVertex(mesh, this);
}
template <class T>
void
HbrVertex<T>::GuaranteeNeighbors() {
if (!neighborsguaranteed) {
HbrMesh<T>* mesh = GetMesh();
mesh->GetSubdivision()->GuaranteeNeighbors(mesh, this);
neighborsguaranteed = 1;
// At this point we can apply vertex edits because we have all
// surrounding faces, and know whether any of them has
// necessary edit information (they would have set our
// hasvertexedit bit)
if (hasvertexedit && !editsapplied) {
HbrHalfedge<T>* start = GetIncidentEdge(), *edge;
edge = start;
while (edge) {
HbrFace<T>* face = edge->GetLeftFace();
if (HbrHierarchicalEdit<T>** edits = face->GetHierarchicalEdits()) {
while (HbrHierarchicalEdit<T>* edit = *edits) {
if (!edit->IsRelevantToFace(face)) break;
edit->ApplyEditToVertex(face, this);
edits++;
}
}
edge = GetNextEdge(edge);
if (edge == start) break;
}
editsapplied = 1;
}
}
}
template <class T>
unsigned long
HbrVertex<T>::GetMemStats() const {
return sizeof(HbrVertex<T>);
}
template <class T>
void
HbrVertex<T>::splitSingular() {
HbrMesh<T>* mesh = GetMesh();
HbrHalfedge<T>* e;
HbrHalfedge<T>** incidentEdges =
(nIncidentEdges > 1) ? incident.edges : &incident.edge;
// Go through each edge cycle after the first
std::vector<HbrHalfedge<T>*> edges;
for (int i = 1; i < nIncidentEdges; ++i) {
// Create duplicate vertex
HbrVertex<T>* w = mesh->NewVertex();
w->GetData().AddWithWeight(GetData(), 1.0);
w->SetSharpness(GetSharpness());
// Walk all edges in this cycle and reattach them to duplicate
// vertex
HbrHalfedge<T>* start = incidentEdges[i];
e = start;
edges.clear();
do {
edges.push_back(e);
e = GetNextEdge(e);
} while (e && e != start);
for (typename std::vector<HbrHalfedge<T>*>::iterator ei = edges.begin(); ei != edges.end(); ++ei) {
e = *ei;
if (e->GetOpposite()) {
HbrHalfedge<T>* next = e->GetOpposite()->GetNext();
if (next->GetOrgVertex() == this) {
references--;
next->SetOrgVertex(w);
w->AddIncidentEdge(next);
}
}
// Check again, because sometimes it's been relinked by
// previous clause already
if (e->GetOrgVertex() == this) {
references--;
e->SetOrgVertex(w);
w->AddIncidentEdge(e);
}
}
w->Finish();
#ifdef HBR_ADAPTIVE
mesh->addSplitVertex(w->GetID(), this->GetID());
#endif
}
e = incidentEdges[0];
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
nIncidentEdges = 1;
incident.edge = e;
}
template <class T>
std::ostream&
operator<<(std::ostream& out, const HbrVertex<T>& vertex) {
return out << "vertex " << vertex.GetID();
}
template <class T>
class HbrVertexOperator {
public:
virtual void operator() (HbrVertex<T> &vertex) = 0;
virtual ~HbrVertexOperator() {}
};
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* OPENSUBDIV3_HBRVERTEX_H */