Add Chromium-only Blender WebEngine parity work
This commit is contained in:
41
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/CMakeLists.txt
vendored
Normal file
41
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
# https://opensubdiv.org/license.
|
||||
#
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
set(PUBLIC_HEADER_FILES
|
||||
allocator.h
|
||||
bilinear.h
|
||||
catmark.h
|
||||
cornerEdit.h
|
||||
creaseEdit.h
|
||||
faceEdit.h
|
||||
face.h
|
||||
fvarData.h
|
||||
fvarEdit.h
|
||||
halfedge.h
|
||||
hierarchicalEdit.h
|
||||
holeEdit.h
|
||||
loop.h
|
||||
mesh.h
|
||||
subdivision.h
|
||||
vertexEdit.h
|
||||
vertex.h
|
||||
)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
install(
|
||||
FILES
|
||||
${PUBLIC_HEADER_FILES}
|
||||
DESTINATION
|
||||
"${CMAKE_INCDIR_BASE}/hbr"
|
||||
PERMISSIONS
|
||||
OWNER_READ
|
||||
GROUP_READ
|
||||
WORLD_READ )
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
155
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/allocator.h
vendored
Normal file
155
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/allocator.h
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRALLOCATOR_H
|
||||
#define OPENSUBDIV3_HBRALLOCATOR_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
typedef void (*HbrMemStatFunction)(size_t bytes);
|
||||
|
||||
/**
|
||||
* HbrAllocator - derived from UtBlockAllocator.h, but embedded in
|
||||
* libhbrep.
|
||||
*/
|
||||
template <typename T> class HbrAllocator {
|
||||
|
||||
public:
|
||||
|
||||
/// Constructor
|
||||
HbrAllocator(size_t *memorystat, int blocksize, void (*increment)(size_t bytes), void (*decrement)(size_t bytes), size_t elemsize = sizeof(T));
|
||||
|
||||
/// Destructor
|
||||
~HbrAllocator();
|
||||
|
||||
/// Create an allocated object
|
||||
T * Allocate();
|
||||
|
||||
/// Return an allocated object to the block allocator
|
||||
void Deallocate(T *);
|
||||
|
||||
/// Clear the allocator, deleting all allocated objects.
|
||||
void Clear();
|
||||
|
||||
void SetMemStatsIncrement(void (*increment)(size_t bytes)) { m_increment = increment; }
|
||||
|
||||
void SetMemStatsDecrement(void (*decrement)(size_t bytes)) { m_decrement = decrement; }
|
||||
|
||||
private:
|
||||
size_t *m_memorystat;
|
||||
const int m_blocksize;
|
||||
int m_elemsize;
|
||||
T** m_blocks;
|
||||
|
||||
// Number of actually allocated blocks
|
||||
int m_nblocks;
|
||||
|
||||
// Size of the m_blocks array (which is NOT the number of actually
|
||||
// allocated blocks)
|
||||
int m_blockCapacity;
|
||||
|
||||
int m_freecount;
|
||||
T * m_freelist;
|
||||
|
||||
// Memory statistics tracking routines
|
||||
HbrMemStatFunction m_increment;
|
||||
HbrMemStatFunction m_decrement;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
HbrAllocator<T>::HbrAllocator(size_t *memorystat, int blocksize, void (*increment)(size_t bytes), void (*decrement)(size_t bytes), size_t elemsize)
|
||||
: m_memorystat(memorystat), m_blocksize(blocksize), m_elemsize((int)elemsize), m_blocks(0), m_nblocks(0), m_blockCapacity(0), m_freecount(0), m_increment(increment), m_decrement(decrement) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
HbrAllocator<T>::~HbrAllocator() {
|
||||
Clear();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void HbrAllocator<T>::Clear() {
|
||||
for (int i = 0; i < m_nblocks; ++i) {
|
||||
// Run the destructors (placement)
|
||||
T* blockptr = m_blocks[i];
|
||||
T* startblock = blockptr;
|
||||
for (int j = 0; j < m_blocksize; ++j) {
|
||||
blockptr->~T();
|
||||
blockptr = (T*) ((char*) blockptr + m_elemsize);
|
||||
}
|
||||
free(startblock);
|
||||
if (m_decrement) m_decrement(m_blocksize * m_elemsize);
|
||||
*m_memorystat -= m_blocksize * m_elemsize;
|
||||
}
|
||||
free(m_blocks);
|
||||
m_blocks = 0;
|
||||
m_nblocks = 0;
|
||||
m_blockCapacity = 0;
|
||||
m_freecount = 0;
|
||||
m_freelist = NULL;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T*
|
||||
HbrAllocator<T>::Allocate() {
|
||||
if (!m_freecount) {
|
||||
|
||||
// Allocate a new block
|
||||
T* block = (T*) malloc(m_blocksize * m_elemsize);
|
||||
T* blockptr = block;
|
||||
// Run the constructors on each element using placement new
|
||||
for (int i = 0; i < m_blocksize; ++i) {
|
||||
new (blockptr) T();
|
||||
blockptr = (T*) ((char*) blockptr + m_elemsize);
|
||||
}
|
||||
if (m_increment) m_increment(m_blocksize * m_elemsize);
|
||||
*m_memorystat += m_blocksize * m_elemsize;
|
||||
|
||||
// Put the block's entries on the free list
|
||||
blockptr = block;
|
||||
for (int i = 0; i < m_blocksize - 1; ++i) {
|
||||
T* next = (T*) ((char*) blockptr + m_elemsize);
|
||||
blockptr->GetNext() = next;
|
||||
blockptr = next;
|
||||
}
|
||||
blockptr->GetNext() = 0;
|
||||
m_freelist = block;
|
||||
|
||||
// Keep track of the newly allocated block
|
||||
if (m_nblocks + 1 >= m_blockCapacity) {
|
||||
m_blockCapacity = m_blockCapacity * 2;
|
||||
if (m_blockCapacity < 1) m_blockCapacity = 1;
|
||||
m_blocks = (T**) realloc(m_blocks, m_blockCapacity * sizeof(T*));
|
||||
}
|
||||
m_blocks[m_nblocks] = block;
|
||||
m_nblocks++;
|
||||
m_freecount += m_blocksize;
|
||||
}
|
||||
T* obj = m_freelist;
|
||||
m_freelist = obj->GetNext();
|
||||
obj->GetNext() = 0;
|
||||
m_freecount--;
|
||||
return obj;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
HbrAllocator<T>::Deallocate(T * obj) {
|
||||
assert(!obj->GetNext());
|
||||
obj->GetNext() = m_freelist;
|
||||
m_freelist = obj;
|
||||
m_freecount++;
|
||||
}
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRALLOCATOR_H */
|
||||
892
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/bilinear.h
vendored
Normal file
892
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/bilinear.h
vendored
Normal file
@@ -0,0 +1,892 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRBILINEAR_H
|
||||
#define OPENSUBDIV3_HBRBILINEAR_H
|
||||
|
||||
/*#define HBR_DEBUG */
|
||||
#include "../hbr/subdivision.h"
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T>
|
||||
class HbrBilinearSubdivision : public HbrSubdivision<T> {
|
||||
public:
|
||||
HbrBilinearSubdivision<T>()
|
||||
: HbrSubdivision<T>() {}
|
||||
|
||||
virtual HbrSubdivision<T>* Clone() const {
|
||||
return new HbrBilinearSubdivision<T>();
|
||||
}
|
||||
|
||||
virtual void Refine(HbrMesh<T>* mesh, HbrFace<T>* face);
|
||||
virtual HbrFace<T>* RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, HbrVertex<T>* vertex);
|
||||
virtual void GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
|
||||
virtual void GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
|
||||
|
||||
virtual bool HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face);
|
||||
virtual bool HasLimit(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
|
||||
virtual bool HasLimit(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
|
||||
|
||||
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face);
|
||||
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
|
||||
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
|
||||
|
||||
virtual bool VertexIsExtraordinary(HbrMesh<T> const * /* mesh */, HbrVertex<T>* vertex) { return vertex->GetValence() != 4; }
|
||||
virtual bool FaceIsExtraordinary(HbrMesh<T> const * /* mesh */, HbrFace<T>* face) { return face->GetNumVertices() != 4; }
|
||||
|
||||
virtual int GetFaceChildrenCount(int nvertices) const { return nvertices; }
|
||||
|
||||
private:
|
||||
|
||||
// Transfers facevarying data from a parent face to a child face
|
||||
void transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, HbrFace<T>* child, int index);
|
||||
|
||||
// Transfers vertex and edge edits from a parent face to a child face
|
||||
void transferEditsToChild(HbrFace<T>* face, HbrFace<T>* child, int index);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrBilinearSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, HbrFace<T>* child, int index) {
|
||||
|
||||
typename HbrMesh<T>::InterpolateBoundaryMethod fvarinterp = mesh->GetFVarInterpolateBoundaryMethod();
|
||||
const int fvarcount = mesh->GetFVarCount();
|
||||
int fvarindex = 0;
|
||||
const int nv = face->GetNumVertices();
|
||||
bool extraordinary = (nv != 4);
|
||||
HbrVertex<T> *v = face->GetVertex(index), *childVertex;
|
||||
HbrHalfedge<T>* edge;
|
||||
|
||||
// We do the face subdivision rule first, because we may reuse the
|
||||
// result (stored in fv2) for the other subdivisions.
|
||||
float weight = 1.0f / nv;
|
||||
|
||||
// For the face center vertex, the facevarying data can be cleared
|
||||
// and averaged en masse, since the subdivision rules don't change
|
||||
// for any of the data - we use the smooth rule for all of it.
|
||||
// And since we know that the fvardata for this particular vertex
|
||||
// is smooth and therefore shareable amongst all incident faces,
|
||||
// we don't have to allocate extra storage for it. We also don't
|
||||
// have to compute it if some other face got to it first (as
|
||||
// indicated by the IsInitialized() flag).
|
||||
HbrFVarData<T>& fv2 = child->GetFVarData(extraordinary ? 2 : (index+2)%4);
|
||||
if (!fv2.IsInitialized()) {
|
||||
const int totalfvarwidth = mesh->GetTotalFVarWidth();
|
||||
fv2.ClearAll(totalfvarwidth);
|
||||
for (int j = 0; j < nv; ++j) {
|
||||
fv2.AddWithWeightAll(face->GetFVarData(j), totalfvarwidth, weight);
|
||||
}
|
||||
}
|
||||
assert(fv2.IsInitialized());
|
||||
|
||||
v->GuaranteeNeighbors();
|
||||
|
||||
// Make sure that that each of the vertices of the child face have
|
||||
// the appropriate facevarying storage as needed. If there are
|
||||
// discontinuities in any facevarying datum, the vertex must
|
||||
// allocate a new block of facevarying storage specific to the
|
||||
// child face.
|
||||
bool fv0IsSmooth, fv1IsSmooth, fv3IsSmooth;
|
||||
|
||||
childVertex = child->GetVertex(extraordinary ? 0 : (index+0)%4);
|
||||
fv0IsSmooth = v->IsFVarAllSmooth();
|
||||
if (!fv0IsSmooth) {
|
||||
childVertex->NewFVarData(child);
|
||||
}
|
||||
HbrFVarData<T>& fv0 = childVertex->GetFVarData(child);
|
||||
|
||||
edge = face->GetEdge(index);
|
||||
GuaranteeNeighbor(mesh, edge);
|
||||
assert(edge->GetOrgVertex() == v);
|
||||
childVertex = child->GetVertex(extraordinary ? 1 : (index+1)%4);
|
||||
fv1IsSmooth = !edge->IsFVarInfiniteSharpAnywhere();
|
||||
if (!fv1IsSmooth) {
|
||||
childVertex->NewFVarData(child);
|
||||
}
|
||||
HbrFVarData<T>& fv1 = childVertex->GetFVarData(child);
|
||||
|
||||
edge = edge->GetPrev();
|
||||
GuaranteeNeighbor(mesh, edge);
|
||||
assert(edge == face->GetEdge((index + nv - 1) % nv));
|
||||
assert(edge->GetDestVertex() == v);
|
||||
childVertex = child->GetVertex(extraordinary ? 3 : (index+3)%4);
|
||||
fv3IsSmooth = !edge->IsFVarInfiniteSharpAnywhere();
|
||||
if (!fv3IsSmooth) {
|
||||
childVertex->NewFVarData(child);
|
||||
}
|
||||
HbrFVarData<T>& fv3 = childVertex->GetFVarData(child);
|
||||
fvarindex = 0;
|
||||
for (int fvaritem = 0; fvaritem < fvarcount; ++fvaritem) {
|
||||
// Vertex subdivision rule. Analyze whether the vertex is on the
|
||||
// boundary and whether it's an infinitely sharp corner. We
|
||||
// determine the last by checking the propagate corners flag on
|
||||
// the mesh; if it's off, we check the two edges of this face
|
||||
// incident to that vertex and determining whether they are
|
||||
// facevarying boundary edges - this is analogous to what goes on
|
||||
// for the interpolateboundary tag (which when set to
|
||||
// EDGEANDCORNER marks vertices with a valence of two as being
|
||||
// sharp corners). If propagate corners is on, we check *all*
|
||||
// faces to see if two edges side by side are facevarying boundary
|
||||
// edges. The facevarying boundary check ignores geometric
|
||||
// sharpness, otherwise we may swim at geometric creases which
|
||||
// aren't actually discontinuous.
|
||||
bool infcorner = false;
|
||||
const int fvarwidth = mesh->GetFVarWidths()[fvaritem];
|
||||
const unsigned char fvarmask = v->GetFVarMask(fvaritem);
|
||||
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryEdgeAndCorner) {
|
||||
if (fvarmask >= HbrVertex<T>::k_Corner) {
|
||||
infcorner = true;
|
||||
} else if (mesh->GetFVarPropagateCorners()) {
|
||||
if (v->IsFVarCorner(fvaritem)) {
|
||||
infcorner = true;
|
||||
}
|
||||
} else {
|
||||
if (face->GetEdge(index)->GetFVarSharpness(fvaritem, true) && face->GetEdge(index)->GetPrev()->GetFVarSharpness(fvaritem, true)) {
|
||||
infcorner = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Infinitely sharp vertex rule. Applied if the vertex is:
|
||||
// - undergoing no facevarying boundary interpolation;
|
||||
// - at a geometric crease, in either boundary interpolation case; or
|
||||
// - is an infinitely sharp facevarying vertex, in the EDGEANDCORNER case; or
|
||||
// - has a mask equal or greater than one, in the "always
|
||||
// sharp" interpolate boundary case
|
||||
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
|
||||
(fvarinterp == HbrMesh<T>::k_InterpolateBoundaryAlwaysSharp &&
|
||||
fvarmask >= 1) ||
|
||||
v->GetSharpness() > HbrVertex<T>::k_Smooth ||
|
||||
infcorner) {
|
||||
fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 1.0f);
|
||||
}
|
||||
// Dart rule: unlike geometric creases, because there's two
|
||||
// discontinuous values for the one incident edge, we use the
|
||||
// boundary rule and not the smooth rule
|
||||
else if (fvarmask == 1) {
|
||||
assert(!v->OnBoundary());
|
||||
|
||||
// Use 0.75 of the current vert
|
||||
fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.75f);
|
||||
|
||||
// 0.125 of "two adjacent edge vertices", which in actuality
|
||||
// are the facevarying values of the same vertex but on each
|
||||
// side of the single incident facevarying sharp edge
|
||||
HbrHalfedge<T>* start = v->GetIncidentEdge(), *nextedge;
|
||||
edge = start;
|
||||
while (edge) {
|
||||
if (edge->GetFVarSharpness(fvaritem)) {
|
||||
break;
|
||||
}
|
||||
nextedge = v->GetNextEdge(edge);
|
||||
if (nextedge == start) {
|
||||
assert(0); // we should have found it by now
|
||||
break;
|
||||
} else if (!nextedge) {
|
||||
// should never get into this case - if the vertex is
|
||||
// on a boundary, it can never be a facevarying dart
|
||||
// vertex
|
||||
assert(0);
|
||||
edge = edge->GetPrev();
|
||||
break;
|
||||
} else {
|
||||
edge = nextedge;
|
||||
}
|
||||
}
|
||||
HbrVertex<T>* w = edge->GetDestVertex();
|
||||
HbrFace<T>* bestface = edge->GetLeftFace();
|
||||
int j;
|
||||
for (j = 0; j < bestface->GetNumVertices(); ++j) {
|
||||
if (bestface->GetVertex(j) == w) break;
|
||||
}
|
||||
assert(j != bestface->GetNumVertices());
|
||||
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
|
||||
bestface = edge->GetRightFace();
|
||||
for (j = 0; j < bestface->GetNumVertices(); ++j) {
|
||||
if (bestface->GetVertex(j) == w) break;
|
||||
}
|
||||
assert(j != bestface->GetNumVertices());
|
||||
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
|
||||
}
|
||||
// Boundary vertex rule
|
||||
else if (fvarmask != 0) {
|
||||
|
||||
// Use 0.75 of the current vert
|
||||
fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.75f);
|
||||
|
||||
// Compute 0.125 of two adjacent edge vertices. However the
|
||||
// two adjacent edge vertices we use must be part of the
|
||||
// facevarying "boundary". To find the first edge we cycle
|
||||
// counterclockwise around the current vertex v and look for
|
||||
// the first boundary edge
|
||||
|
||||
HbrFace<T>* bestface = face;
|
||||
HbrHalfedge<T>* bestedge = face->GetEdge(index)->GetPrev();
|
||||
HbrHalfedge<T>* starte = bestedge->GetOpposite();
|
||||
HbrVertex<T>* w = 0;
|
||||
if (!starte) {
|
||||
w = face->GetEdge(index)->GetPrev()->GetOrgVertex();
|
||||
} else {
|
||||
HbrHalfedge<T>* e = starte, *next;
|
||||
assert(starte->GetOrgVertex() == v);
|
||||
do {
|
||||
if (e->GetFVarSharpness(fvaritem) || !e->GetLeftFace()) {
|
||||
bestface = e->GetRightFace();
|
||||
bestedge = e;
|
||||
break;
|
||||
}
|
||||
next = v->GetNextEdge(e);
|
||||
if (!next) {
|
||||
bestface = e->GetLeftFace();
|
||||
w = e->GetPrev()->GetOrgVertex();
|
||||
break;
|
||||
}
|
||||
e = next;
|
||||
} while (e && e != starte);
|
||||
}
|
||||
if (!w) w = bestedge->GetDestVertex();
|
||||
int j;
|
||||
for (j = 0; j < bestface->GetNumVertices(); ++j) {
|
||||
if (bestface->GetVertex(j) == w) break;
|
||||
}
|
||||
assert(j != bestface->GetNumVertices());
|
||||
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
|
||||
|
||||
// Look for the other edge by cycling clockwise around v
|
||||
bestface = face;
|
||||
bestedge = face->GetEdge(index);
|
||||
starte = bestedge;
|
||||
w = 0;
|
||||
if (HbrHalfedge<T>* e = starte) {
|
||||
assert(starte->GetOrgVertex() == v);
|
||||
do {
|
||||
if (e->GetFVarSharpness(fvaritem) || !e->GetRightFace()) {
|
||||
bestface = e->GetLeftFace();
|
||||
bestedge = e;
|
||||
break;
|
||||
}
|
||||
assert(e->GetOpposite());
|
||||
e = v->GetPreviousEdge(e);
|
||||
} while (e && e != starte);
|
||||
}
|
||||
if (!w) w = bestedge->GetDestVertex();
|
||||
for (j = 0; j < bestface->GetNumVertices(); ++j) {
|
||||
if (bestface->GetVertex(j) == w) break;
|
||||
}
|
||||
assert(j != bestface->GetNumVertices());
|
||||
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
|
||||
|
||||
}
|
||||
// Smooth rule. Here, we can take a shortcut if we know that
|
||||
// the vertex is smooth and some other vertex has completely
|
||||
// computed the facevarying values
|
||||
else if (!fv0IsSmooth || !fv0.IsInitialized()) {
|
||||
int valence = v->GetValence();
|
||||
float invvalencesquared = 1.0f / (valence * valence);
|
||||
|
||||
// Use n-2/n of the current vertex value
|
||||
fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, invvalencesquared * valence * (valence - 2));
|
||||
|
||||
// Add 1/n^2 of surrounding edge vertices and surrounding face
|
||||
// averages. We loop over all surrounding faces..
|
||||
HbrHalfedge<T>* start = v->GetIncidentEdge(), *edge;
|
||||
edge = start;
|
||||
while (edge) {
|
||||
HbrFace<T>* g = edge->GetLeftFace();
|
||||
weight = invvalencesquared / g->GetNumVertices();
|
||||
// .. and compute the average of each face. At the same
|
||||
// time, we look for the edge on that face whose origin is
|
||||
// the same as v, and add a contribution from its
|
||||
// destination vertex value; this takes care of the
|
||||
// surrounding edge vertex addition.
|
||||
for (int j = 0; j < g->GetNumVertices(); ++j) {
|
||||
fv0.AddWithWeight(g->GetFVarData(j), fvarindex, fvarwidth, weight);
|
||||
if (g->GetEdge(j)->GetOrgVertex() == v) {
|
||||
fv0.AddWithWeight(g->GetFVarData((j + 1) % g->GetNumVertices()), fvarindex, fvarwidth, invvalencesquared);
|
||||
}
|
||||
}
|
||||
edge = v->GetNextEdge(edge);
|
||||
if (edge == start) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Edge subdivision rule
|
||||
edge = face->GetEdge(index);
|
||||
|
||||
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
|
||||
edge->GetFVarSharpness(fvaritem) || edge->IsBoundary()) {
|
||||
|
||||
// Sharp edge rule
|
||||
fv1.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.5f);
|
||||
fv1.AddWithWeight(face->GetFVarData((index + 1) % nv), fvarindex, fvarwidth, 0.5f);
|
||||
} else if (!fv1IsSmooth || !fv1.IsInitialized()) {
|
||||
// Smooth edge subdivision. Add 0.25 of adjacent vertices
|
||||
fv1.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.25f);
|
||||
fv1.AddWithWeight(face->GetFVarData((index + 1) % nv), fvarindex, fvarwidth, 0.25f);
|
||||
// Local subdivided face vertex
|
||||
fv1.AddWithWeight(fv2, fvarindex, fvarwidth, 0.25f);
|
||||
// Add 0.25 * average of neighboring face vertices
|
||||
HbrFace<T>* oppFace = edge->GetRightFace();
|
||||
weight = 0.25f / oppFace->GetNumVertices();
|
||||
for (int j = 0; j < oppFace->GetNumVertices(); ++j) {
|
||||
fv1.AddWithWeight(oppFace->GetFVarData(j), fvarindex, fvarwidth, weight);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Edge subdivision rule
|
||||
edge = edge->GetPrev();
|
||||
|
||||
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
|
||||
edge->GetFVarSharpness(fvaritem) || edge->IsBoundary()) {
|
||||
|
||||
// Sharp edge rule
|
||||
fv3.SetWithWeight(face->GetFVarData((index + nv - 1) % nv), fvarindex, fvarwidth, 0.5f);
|
||||
fv3.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.5f);
|
||||
} else if (!fv3IsSmooth || !fv3.IsInitialized()) {
|
||||
// Smooth edge subdivision. Add 0.25 of adjacent vertices
|
||||
fv3.SetWithWeight(face->GetFVarData((index + nv - 1) % nv), fvarindex, fvarwidth, 0.25f);
|
||||
fv3.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.25f);
|
||||
// Local subdivided face vertex
|
||||
fv3.AddWithWeight(fv2, fvarindex, fvarwidth, 0.25f);
|
||||
// Add 0.25 * average of neighboring face vertices
|
||||
HbrFace<T>* oppFace = edge->GetRightFace();
|
||||
weight = 0.25f / oppFace->GetNumVertices();
|
||||
for (int j = 0; j < oppFace->GetNumVertices(); ++j) {
|
||||
fv3.AddWithWeight(oppFace->GetFVarData(j), fvarindex, fvarwidth, weight);
|
||||
}
|
||||
}
|
||||
|
||||
fvarindex += fvarwidth;
|
||||
}
|
||||
fv0.SetInitialized();
|
||||
fv1.SetInitialized();
|
||||
fv3.SetInitialized();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrBilinearSubdivision<T>::transferEditsToChild(HbrFace<T>* face, HbrFace<T>* child, int index) {
|
||||
|
||||
// Hand down hole tag
|
||||
child->SetHole(face->IsHole());
|
||||
|
||||
// Hand down pointers to hierarchical edits
|
||||
if (HbrHierarchicalEdit<T>** edits = face->GetHierarchicalEdits()) {
|
||||
while (HbrHierarchicalEdit<T>* edit = *edits) {
|
||||
if (!edit->IsRelevantToFace(face)) break;
|
||||
if (edit->GetNSubfaces() > face->GetDepth() &&
|
||||
(edit->GetSubface(face->GetDepth()) == index)) {
|
||||
child->SetHierarchicalEdits(edits);
|
||||
break;
|
||||
}
|
||||
edits++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrBilinearSubdivision<T>::Refine(HbrMesh<T>* mesh, HbrFace<T>* face) {
|
||||
|
||||
// Create new quadrilateral children faces from this face
|
||||
HbrFace<T>* child;
|
||||
HbrVertex<T>* vertices[4];
|
||||
HbrHalfedge<T>* edge = face->GetFirstEdge();
|
||||
HbrHalfedge<T>* prevedge = edge->GetPrev();
|
||||
HbrHalfedge<T>* childedge;
|
||||
int nv = face->GetNumVertices();
|
||||
float sharpness;
|
||||
bool extraordinary = (nv != 4);
|
||||
// The funny indexing on vertices is done only for
|
||||
// non-extraordinary faces in order to correctly preserve
|
||||
// parametric space through the refinement. If we split an
|
||||
// extraordinary face then it doesn't matter.
|
||||
for (int i = 0; i < nv; ++i) {
|
||||
if (!face->GetChild(i)) {
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Kid " << i << "\n";
|
||||
#endif
|
||||
HbrVertex<T>* vertex = edge->GetOrgVertex();
|
||||
if (extraordinary) {
|
||||
vertices[0] = vertex->Subdivide();
|
||||
vertices[1] = edge->Subdivide();
|
||||
vertices[2] = face->Subdivide();
|
||||
vertices[3] = prevedge->Subdivide();
|
||||
} else {
|
||||
vertices[i] = vertex->Subdivide();
|
||||
vertices[(i+1)%4] = edge->Subdivide();
|
||||
vertices[(i+2)%4] = face->Subdivide();
|
||||
vertices[(i+3)%4] = prevedge->Subdivide();
|
||||
}
|
||||
child = mesh->NewFace(4, vertices, face, i);
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Creating face " << *child << " during refine\n";
|
||||
#endif
|
||||
|
||||
// Hand down edge sharpnesses
|
||||
childedge = vertex->Subdivide()->GetEdge(edge->Subdivide());
|
||||
assert(childedge);
|
||||
if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
|
||||
HbrSubdivision<T>::SubdivideCreaseWeight(edge, edge->GetOrgVertex(), childedge);
|
||||
}
|
||||
childedge->CopyFVarInfiniteSharpness(edge);
|
||||
|
||||
childedge = prevedge->Subdivide()->GetEdge(vertex->Subdivide());
|
||||
assert(childedge);
|
||||
if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
|
||||
HbrSubdivision<T>::SubdivideCreaseWeight(prevedge, prevedge->GetDestVertex(), childedge);
|
||||
}
|
||||
childedge->CopyFVarInfiniteSharpness(prevedge);
|
||||
|
||||
if (mesh->GetTotalFVarWidth()) {
|
||||
transferFVarToChild(mesh, face, child, i);
|
||||
}
|
||||
|
||||
// Special handling of ptex index for extraordinary faces: make
|
||||
// sure the children get their indices reassigned to be
|
||||
// consecutive within the block reserved for the parent.
|
||||
if (face->GetNumVertices() != 4 && face->GetPtexIndex() != -1) {
|
||||
child->SetPtexIndex(face->GetPtexIndex() + i);
|
||||
}
|
||||
|
||||
transferEditsToChild(face, child, i);
|
||||
}
|
||||
prevedge = edge;
|
||||
edge = edge->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrFace<T>*
|
||||
HbrBilinearSubdivision<T>::RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, HbrVertex<T>* vertex) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << " forcing refine on " << *face << " at " << *vertex << '\n';
|
||||
#endif
|
||||
|
||||
// Create new quadrilateral children faces from this face
|
||||
HbrHalfedge<T>* edge = face->GetFirstEdge();
|
||||
HbrHalfedge<T>* prevedge = edge->GetPrev();
|
||||
HbrHalfedge<T>* childedge;
|
||||
int nv = face->GetNumVertices();
|
||||
float sharpness;
|
||||
bool extraordinary = (nv != 4);
|
||||
// The funny indexing on vertices is done only for
|
||||
// non-extraordinary faces in order to correctly preserve
|
||||
// parametric space through the refinement. If we split an
|
||||
// extraordinary face then it doesn't matter.
|
||||
for (int i = 0; i < nv; ++i) {
|
||||
if (edge->GetOrgVertex() == vertex) {
|
||||
if (!face->GetChild(i)) {
|
||||
HbrFace<T>* child;
|
||||
HbrVertex<T>* vertices[4];
|
||||
if (extraordinary) {
|
||||
vertices[0] = vertex->Subdivide();
|
||||
vertices[1] = edge->Subdivide();
|
||||
vertices[2] = face->Subdivide();
|
||||
vertices[3] = prevedge->Subdivide();
|
||||
} else {
|
||||
vertices[i] = vertex->Subdivide();
|
||||
vertices[(i+1)%4] = edge->Subdivide();
|
||||
vertices[(i+2)%4] = face->Subdivide();
|
||||
vertices[(i+3)%4] = prevedge->Subdivide();
|
||||
}
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Kid " << i << "\n";
|
||||
std::cerr << " subdivision created " << *vertices[0] << '\n';
|
||||
std::cerr << " subdivision created " << *vertices[1] << '\n';
|
||||
std::cerr << " subdivision created " << *vertices[2] << '\n';
|
||||
std::cerr << " subdivision created " << *vertices[3] << '\n';
|
||||
#endif
|
||||
child = mesh->NewFace(4, vertices, face, i);
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Creating face " << *child << " during refine\n";
|
||||
#endif
|
||||
// Hand down edge sharpness
|
||||
childedge = vertex->Subdivide()->GetEdge(edge->Subdivide());
|
||||
assert(childedge);
|
||||
if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
|
||||
HbrSubdivision<T>::SubdivideCreaseWeight(edge, edge->GetOrgVertex(), childedge);
|
||||
}
|
||||
childedge->CopyFVarInfiniteSharpness(edge);
|
||||
|
||||
childedge = prevedge->Subdivide()->GetEdge(vertex->Subdivide());
|
||||
assert(childedge);
|
||||
if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
|
||||
HbrSubdivision<T>::SubdivideCreaseWeight(prevedge, prevedge->GetDestVertex(), childedge);
|
||||
}
|
||||
childedge->CopyFVarInfiniteSharpness(prevedge);
|
||||
|
||||
if (mesh->GetTotalFVarWidth()) {
|
||||
transferFVarToChild(mesh, face, child, i);
|
||||
}
|
||||
|
||||
// Special handling of ptex index for extraordinary faces: make
|
||||
// sure the children get their indices reassigned to be
|
||||
// consecutive within the block reserved for the parent.
|
||||
if (face->GetNumVertices() != 4 && face->GetPtexIndex() != -1) {
|
||||
child->SetPtexIndex(face->GetPtexIndex() + i);
|
||||
}
|
||||
|
||||
transferEditsToChild(face, child, i);
|
||||
return child;
|
||||
} else {
|
||||
return face->GetChild(i);
|
||||
}
|
||||
}
|
||||
prevedge = edge;
|
||||
edge = edge->GetNext();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrBilinearSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
|
||||
if (edge->GetOpposite()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For the given edge: if the parent of either of its incident
|
||||
// vertices is itself a _face_, then ensuring that this parent
|
||||
// face has refined at a particular vertex is sufficient to
|
||||
// ensure that both of the faces on each side of the edge have
|
||||
// been created.
|
||||
bool destParentWasEdge = true;
|
||||
HbrFace<T>* parentFace = edge->GetOrgVertex()->GetParentFace();
|
||||
HbrHalfedge<T>* parentEdge = edge->GetDestVertex()->GetParentEdge();
|
||||
if (!parentFace) {
|
||||
destParentWasEdge = false;
|
||||
parentFace = edge->GetDestVertex()->GetParentFace();
|
||||
parentEdge = edge->GetOrgVertex()->GetParentEdge();
|
||||
}
|
||||
|
||||
if (parentFace) {
|
||||
|
||||
// Make sure we deal with a parent halfedge which is
|
||||
// associated with the parent face
|
||||
if (parentEdge->GetFace() != parentFace) {
|
||||
parentEdge = parentEdge->GetOpposite();
|
||||
}
|
||||
// If one of the vertices had a parent face, the other one MUST
|
||||
// have been a child of an edge
|
||||
assert(parentEdge && parentEdge->GetFace() == parentFace);
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "\nparent edge is " << *parentEdge << "\n";
|
||||
#endif
|
||||
|
||||
// The vertex to refine at depends on whether the
|
||||
// destination or origin vertex of this edge had a parent
|
||||
// edge
|
||||
if (destParentWasEdge) {
|
||||
RefineFaceAtVertex(mesh, parentFace, parentEdge->GetOrgVertex());
|
||||
} else {
|
||||
RefineFaceAtVertex(mesh, parentFace, parentEdge->GetDestVertex());
|
||||
}
|
||||
|
||||
// It should always be the case that the opposite now exists -
|
||||
// we can't have a boundary case here
|
||||
assert(edge->GetOpposite());
|
||||
} else {
|
||||
HbrVertex<T>* parentVertex = edge->GetOrgVertex()->GetParentVertex();
|
||||
parentEdge = edge->GetDestVertex()->GetParentEdge();
|
||||
if (!parentVertex) {
|
||||
parentVertex = edge->GetDestVertex()->GetParentVertex();
|
||||
parentEdge = edge->GetOrgVertex()->GetParentEdge();
|
||||
}
|
||||
|
||||
if (parentVertex) {
|
||||
|
||||
assert(parentEdge);
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "\nparent edge is " << *parentEdge << "\n";
|
||||
#endif
|
||||
|
||||
// 1. Go up to the parent of my face
|
||||
|
||||
parentFace = edge->GetFace()->GetParent();
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "\nparent face is " << *parentFace << "\n";
|
||||
#endif
|
||||
|
||||
// 2. Ask the opposite face (if it exists) to refine
|
||||
if (parentFace) {
|
||||
|
||||
// A vertex can be associated with either of two
|
||||
// parent halfedges. If the parent edge that we're
|
||||
// interested in doesn't match then we should look at
|
||||
// its opposite
|
||||
if (parentEdge->GetFace() != parentFace)
|
||||
parentEdge = parentEdge->GetOpposite();
|
||||
assert(parentEdge->GetFace() == parentFace);
|
||||
|
||||
// Make sure the parent edge has its neighbor as well
|
||||
GuaranteeNeighbor(mesh, parentEdge);
|
||||
|
||||
// Now access that neighbor and refine it
|
||||
if (parentEdge->GetRightFace()) {
|
||||
RefineFaceAtVertex(mesh, parentEdge->GetRightFace(), parentVertex);
|
||||
|
||||
// FIXME: assertion?
|
||||
assert(edge->GetOpposite());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrBilinearSubdivision<T>::GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "\n\nneighbor guarantee at " << *vertex << " invoked\n";
|
||||
#endif
|
||||
|
||||
// If the vertex is a child of a face, guaranteeing the neighbors
|
||||
// of the vertex is simply a matter of ensuring the parent face
|
||||
// has refined.
|
||||
HbrFace<T>* parentFace = vertex->GetParentFace();
|
||||
if (parentFace) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << " forcing full refine on parent face\n";
|
||||
#endif
|
||||
Refine(mesh, parentFace);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise if the vertex is a child of an edge, we need to
|
||||
// ensure that the parent faces on either side of the parent edge
|
||||
// 1) exist, and 2) have refined at both vertices of the parent
|
||||
// edge
|
||||
HbrHalfedge<T>* parentEdge = vertex->GetParentEdge();
|
||||
if (parentEdge) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << " forcing full refine on adjacent faces of parent edge\n";
|
||||
#endif
|
||||
HbrVertex<T>* dest = parentEdge->GetDestVertex();
|
||||
HbrVertex<T>* org = parentEdge->GetOrgVertex();
|
||||
GuaranteeNeighbor(mesh, parentEdge);
|
||||
parentFace = parentEdge->GetLeftFace();
|
||||
RefineFaceAtVertex(mesh, parentFace, dest);
|
||||
RefineFaceAtVertex(mesh, parentFace, org);
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << " on the right face?\n";
|
||||
#endif
|
||||
parentFace = parentEdge->GetRightFace();
|
||||
// The right face may not necessarily exist even after
|
||||
// GuaranteeNeighbor
|
||||
if (parentFace) {
|
||||
RefineFaceAtVertex(mesh, parentFace, dest);
|
||||
RefineFaceAtVertex(mesh, parentFace, org);
|
||||
}
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << " end force\n";
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
// The last case: the vertex is a child of a vertex. In this case
|
||||
// we have to first recursively guarantee that the parent's
|
||||
// adjacent faces also exist.
|
||||
HbrVertex<T>* parentVertex = vertex->GetParentVertex();
|
||||
if (parentVertex) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << " recursive parent vertex guarantee call\n";
|
||||
#endif
|
||||
parentVertex->GuaranteeNeighbors();
|
||||
|
||||
// And then we refine all the face neighbors of the
|
||||
// parentVertex
|
||||
HbrHalfedge<T>* start = parentVertex->GetIncidentEdge(), *edge;
|
||||
edge = start;
|
||||
while (edge) {
|
||||
HbrFace<T>* f = edge->GetLeftFace();
|
||||
RefineFaceAtVertex(mesh, f, parentVertex);
|
||||
edge = parentVertex->GetNextEdge(edge);
|
||||
if (edge == start) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
HbrBilinearSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face) {
|
||||
|
||||
if (face->IsHole()) return false;
|
||||
// A limit face exists if all the bounding edges have limit curves
|
||||
for (int i = 0; i < face->GetNumVertices(); ++i) {
|
||||
if (!HasLimit(mesh, face->GetEdge(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
HbrBilinearSubdivision<T>::HasLimit(HbrMesh<T>* /* mesh */, HbrHalfedge<T>* /* edge */) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
HbrBilinearSubdivision<T>::HasLimit(HbrMesh<T>* /* mesh */, HbrVertex<T>* vertex) {
|
||||
vertex->GuaranteeNeighbors();
|
||||
switch (vertex->GetMask(false)) {
|
||||
case HbrVertex<T>::k_Smooth:
|
||||
case HbrVertex<T>::k_Dart:
|
||||
return !vertex->OnBoundary();
|
||||
break;
|
||||
case HbrVertex<T>::k_Crease:
|
||||
case HbrVertex<T>::k_Corner:
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrVertex<T>*
|
||||
HbrBilinearSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face) {
|
||||
|
||||
// Face rule: simply average all vertices on the face
|
||||
HbrVertex<T>* v = mesh->NewVertex();
|
||||
T& data = v->GetData();
|
||||
int nv = face->GetNumVertices();
|
||||
float weight = 1.0f / nv;
|
||||
|
||||
HbrHalfedge<T>* edge = face->GetFirstEdge();
|
||||
for (int i = 0; i < face->GetNumVertices(); ++i) {
|
||||
HbrVertex<T>* w = edge->GetOrgVertex();
|
||||
// If there are vertex edits we have to make sure the edit
|
||||
// has been applied
|
||||
if (mesh->HasVertexEdits()) {
|
||||
w->GuaranteeNeighbors();
|
||||
}
|
||||
data.AddWithWeight(w->GetData(), weight);
|
||||
data.AddVaryingWithWeight(w->GetData(), weight);
|
||||
edge = edge->GetNext();
|
||||
}
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Subdividing at " << *face << "\n";
|
||||
#endif
|
||||
|
||||
// Set the extraordinary flag if the face had anything other than
|
||||
// 4 vertices
|
||||
if (nv != 4) v->SetExtraordinary();
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << " created " << *v << "\n";
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrVertex<T>*
|
||||
HbrBilinearSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
float esharp = edge->GetSharpness();
|
||||
std::cerr << "Subdividing at " << *edge << " (sharpness = " << esharp << ")";
|
||||
#endif
|
||||
|
||||
HbrVertex<T>* v = mesh->NewVertex();
|
||||
T& data = v->GetData();
|
||||
|
||||
|
||||
// If there's the possibility of a crease edits, make sure the
|
||||
// edit has been applied
|
||||
if (mesh->HasCreaseEdits()) {
|
||||
edge->GuaranteeNeighbor();
|
||||
}
|
||||
|
||||
// If there's the possibility of vertex edits on either vertex, we
|
||||
// have to make sure the edit has been applied
|
||||
if (mesh->HasVertexEdits()) {
|
||||
edge->GetOrgVertex()->GuaranteeNeighbors();
|
||||
edge->GetDestVertex()->GuaranteeNeighbors();
|
||||
}
|
||||
|
||||
// Average the two end points
|
||||
data.AddWithWeight(edge->GetOrgVertex()->GetData(), 0.5f);
|
||||
data.AddWithWeight(edge->GetDestVertex()->GetData(), 0.5f);
|
||||
|
||||
// Varying data is always the average of two end points
|
||||
data.AddVaryingWithWeight(edge->GetOrgVertex()->GetData(), 0.5f);
|
||||
data.AddVaryingWithWeight(edge->GetDestVertex()->GetData(), 0.5f);
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << " created " << *v << "\n";
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrVertex<T>*
|
||||
HbrBilinearSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
|
||||
|
||||
HbrVertex<T>* v;
|
||||
|
||||
// If there are vertex edits we have to make sure the edit has
|
||||
// been applied by guaranteeing the neighbors of the
|
||||
// vertex. Unfortunately in this case, we can't share the data
|
||||
// with the parent
|
||||
if (mesh->HasVertexEdits()) {
|
||||
vertex->GuaranteeNeighbors();
|
||||
|
||||
v = mesh->NewVertex();
|
||||
T& data = v->GetData();
|
||||
|
||||
// Just copy the old value
|
||||
data.AddWithWeight(vertex->GetData(), 1.0f);
|
||||
|
||||
// Varying data is always just propagated down
|
||||
data.AddVaryingWithWeight(vertex->GetData(), 1.0f);
|
||||
|
||||
} else {
|
||||
// Create a new vertex that just shares the same data
|
||||
v = mesh->NewVertex(vertex->GetData());
|
||||
}
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Subdividing at " << *vertex << "\n";
|
||||
std::cerr << " created " << *v << "\n";
|
||||
#endif
|
||||
// Inherit extraordinary flag and sharpness
|
||||
if (vertex->IsExtraordinary()) v->SetExtraordinary();
|
||||
float sharp = vertex->GetSharpness();
|
||||
if (sharp >= HbrVertex<T>::k_InfinitelySharp) {
|
||||
v->SetSharpness(HbrVertex<T>::k_InfinitelySharp);
|
||||
} else if (sharp > HbrVertex<T>::k_Smooth) {
|
||||
sharp -= 1.0f;
|
||||
if (sharp < (float) HbrVertex<T>::k_Smooth) {
|
||||
sharp = (float) HbrVertex<T>::k_Smooth;
|
||||
}
|
||||
v->SetSharpness(sharp);
|
||||
} else {
|
||||
v->SetSharpness(HbrVertex<T>::k_Smooth);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRBILINEAR_H */
|
||||
1114
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/catmark.h
vendored
Normal file
1114
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/catmark.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
81
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/cornerEdit.h
vendored
Normal file
81
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/cornerEdit.h
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRCORNEREDIT_H
|
||||
#define OPENSUBDIV3_HBRCORNEREDIT_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrCornerEdit;
|
||||
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& out, const HbrCornerEdit<T>& path) {
|
||||
out << "vertex path = (" << path.faceid << ' ';
|
||||
for (int i = 0; i < path.nsubfaces; ++i) {
|
||||
out << static_cast<int>(path.subfaces[i]) << ' ';
|
||||
}
|
||||
return out << static_cast<int>(path.vertexid) << "), sharpness = " << path.sharpness;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class HbrCornerEdit : public HbrHierarchicalEdit<T> {
|
||||
|
||||
public:
|
||||
|
||||
HbrCornerEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, unsigned char _vertexid, typename HbrHierarchicalEdit<T>::Operation _op, float _sharpness)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), op(_op), sharpness(_sharpness) {
|
||||
}
|
||||
|
||||
HbrCornerEdit(int _faceid, int _nsubfaces, int *_subfaces, int _vertexid, typename HbrHierarchicalEdit<T>::Operation _op, float _sharpness)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(static_cast<unsigned char>(_vertexid)), op(_op), sharpness(_sharpness) {
|
||||
}
|
||||
|
||||
virtual ~HbrCornerEdit() {}
|
||||
|
||||
friend std::ostream& operator<< <T> (std::ostream& out, const HbrCornerEdit<T>& path);
|
||||
|
||||
virtual void ApplyEditToFace(HbrFace<T>* face) {
|
||||
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
|
||||
// Modify vertex sharpness. Note that we could actually do
|
||||
// this in ApplyEditToVertex as well!
|
||||
float sharp = 0.0f;
|
||||
if (op == HbrHierarchicalEdit<T>::Set) {
|
||||
sharp = sharpness;
|
||||
} else if (op == HbrHierarchicalEdit<T>::Add) {
|
||||
sharp = face->GetVertex(vertexid)->GetSharpness() + sharpness;
|
||||
} else if (op == HbrHierarchicalEdit<T>::Subtract) {
|
||||
sharp = face->GetVertex(vertexid)->GetSharpness() - sharpness;
|
||||
}
|
||||
if (sharp < HbrVertex<T>::k_Smooth) {
|
||||
sharp = HbrVertex<T>::k_Smooth;
|
||||
}
|
||||
if (sharp > HbrVertex<T>::k_InfinitelySharp) {
|
||||
sharp = HbrVertex<T>::k_InfinitelySharp;
|
||||
}
|
||||
face->GetVertex(vertexid)->SetSharpness(sharp);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// ID of the edge (you can think of this also as the id of the
|
||||
// origin vertex of the two-vertex length edge)
|
||||
const unsigned char vertexid;
|
||||
typename HbrHierarchicalEdit<T>::Operation op;
|
||||
// sharpness of the vertex edit
|
||||
const float sharpness;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRCORNEREDIT_H */
|
||||
83
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/creaseEdit.h
vendored
Normal file
83
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/creaseEdit.h
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRCREASEEDIT_H
|
||||
#define OPENSUBDIV3_HBRCREASEEDIT_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrCreaseEdit;
|
||||
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& out, const HbrCreaseEdit<T>& path) {
|
||||
out << "edge path = (" << path.faceid << ' ';
|
||||
for (int i = 0; i < path.nsubfaces; ++i) {
|
||||
out << static_cast<int>(path.subfaces[i]) << ' ';
|
||||
}
|
||||
return out << static_cast<int>(path.edgeid) << "), sharpness = " << path.sharpness;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class HbrCreaseEdit : public HbrHierarchicalEdit<T> {
|
||||
|
||||
public:
|
||||
|
||||
HbrCreaseEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, unsigned char _edgeid, typename HbrHierarchicalEdit<T>::Operation _op, float _sharpness)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), edgeid(_edgeid), op(_op), sharpness(_sharpness) {
|
||||
}
|
||||
|
||||
HbrCreaseEdit(int _faceid, int _nsubfaces, int *_subfaces, int _edgeid, typename HbrHierarchicalEdit<T>::Operation _op, float _sharpness)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), edgeid(static_cast<unsigned char>(_edgeid)), op(_op), sharpness(_sharpness) {
|
||||
}
|
||||
|
||||
virtual ~HbrCreaseEdit() {}
|
||||
|
||||
friend std::ostream& operator<< <T> (std::ostream& out, const HbrCreaseEdit<T>& path);
|
||||
|
||||
virtual void ApplyEditToFace(HbrFace<T>* face) {
|
||||
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
|
||||
// Modify edge sharpness
|
||||
float sharp=0.0f;
|
||||
if (op == HbrHierarchicalEdit<T>::Set) {
|
||||
sharp = sharpness;
|
||||
} else if (op == HbrHierarchicalEdit<T>::Add) {
|
||||
sharp = face->GetEdge(edgeid)->GetSharpness() + sharpness;
|
||||
} else if (op == HbrHierarchicalEdit<T>::Subtract) {
|
||||
sharp = face->GetEdge(edgeid)->GetSharpness() - sharpness;
|
||||
}
|
||||
if (sharp < HbrHalfedge<T>::k_Smooth)
|
||||
sharp = HbrHalfedge<T>::k_Smooth;
|
||||
if (sharp > HbrHalfedge<T>::k_InfinitelySharp)
|
||||
sharp = HbrHalfedge<T>::k_InfinitelySharp;
|
||||
// We have to make sure the neighbor of the edge exists at
|
||||
// this point. Otherwise, if it comes into being late, it
|
||||
// will clobber the overriden sharpness and we will lose
|
||||
// the edit.
|
||||
face->GetEdge(edgeid)->GuaranteeNeighbor();
|
||||
face->GetEdge(edgeid)->SetSharpness(sharp);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// ID of the edge (you can think of this also as the id of the
|
||||
// origin vertex of the two-vertex length edge)
|
||||
const unsigned char edgeid;
|
||||
typename HbrHierarchicalEdit<T>::Operation op;
|
||||
// sharpness of the edge edit
|
||||
const float sharpness;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRCREASEEDIT_H */
|
||||
1012
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/face.h
vendored
Normal file
1012
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/face.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
108
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/faceEdit.h
vendored
Normal file
108
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/faceEdit.h
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRFACEEDIT_H
|
||||
#define OPENSUBDIV3_HBRFACEEDIT_H
|
||||
|
||||
#include "../hbr/hierarchicalEdit.h"
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrFaceEdit;
|
||||
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& out, const HbrFaceEdit<T>& path) {
|
||||
out << "face path = (" << path.faceid << ' ';
|
||||
for (int i = 0; i < path.nsubfaces; ++i) {
|
||||
out << static_cast<int>(path.subfaces[i]) << ' ';
|
||||
}
|
||||
return out << ")";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class HbrFaceEdit : public HbrHierarchicalEdit<T> {
|
||||
|
||||
public:
|
||||
|
||||
HbrFaceEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, int _index, int _width, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), index(_index), width(_width), op(_op) {
|
||||
edit = new float[width];
|
||||
memcpy(edit, _edit, width * sizeof(float));
|
||||
}
|
||||
|
||||
HbrFaceEdit(int _faceid, int _nsubfaces, int *_subfaces, int _index, int _width, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), index(_index), width(_width), op(_op) {
|
||||
edit = new float[width];
|
||||
memcpy(edit, _edit, width * sizeof(float));
|
||||
}
|
||||
|
||||
#ifdef PRMAN
|
||||
HbrFaceEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, int _index, int _width, typename HbrHierarchicalEdit<T>::Operation _op, RtToken _edit)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), index(_index), width(_width), op(_op) {
|
||||
edit = new float[width];
|
||||
RtString* sedit = (RtString*) edit;
|
||||
*sedit = _edit;
|
||||
}
|
||||
|
||||
HbrFaceEdit(int _faceid, int _nsubfaces, int *_subfaces, int _index, int _width, typename HbrHierarchicalEdit<T>::Operation _op, RtToken _edit)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), index(_index), width(_width), op(_op) {
|
||||
edit = new float[width];
|
||||
RtString* sedit = (RtString*) edit;
|
||||
*sedit = _edit;
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual ~HbrFaceEdit() {
|
||||
delete[] edit;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<< <T> (std::ostream& out, const HbrFaceEdit<T>& path);
|
||||
|
||||
// Return index of variable this edit applies to
|
||||
int GetIndex() const { return index; }
|
||||
|
||||
// Return width of the variable
|
||||
int GetWidth() const { return width; }
|
||||
|
||||
// Get the numerical value of the edit
|
||||
const float* GetEdit() const { return edit; }
|
||||
|
||||
// Get the type of operation
|
||||
typename HbrHierarchicalEdit<T>::Operation GetOperation() const { return op; }
|
||||
|
||||
virtual void ApplyEditToFace(HbrFace<T>* face) {
|
||||
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
|
||||
|
||||
int oldUniformIndex = face->GetUniformIndex();
|
||||
|
||||
// Any face below level 0 needs a new uniform index
|
||||
if (face->GetDepth() > 0) {
|
||||
face->SetUniformIndex(face->GetMesh()->NewUniformIndex());
|
||||
}
|
||||
|
||||
// Apply edit
|
||||
face->GetVertex(0)->GetData().ApplyFaceEdit(oldUniformIndex, face->GetUniformIndex(), *const_cast<const HbrFaceEdit<T>*>(this));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int index;
|
||||
int width;
|
||||
typename HbrHierarchicalEdit<T>::Operation op;
|
||||
float* edit;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRFACEEDIT_H */
|
||||
183
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/fvarData.h
vendored
Normal file
183
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/fvarData.h
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRFVARDATA_H
|
||||
#define OPENSUBDIV3_HBRFVARDATA_H
|
||||
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrFVarEdit;
|
||||
template <class T> class HbrFace;
|
||||
template <class T> class HbrVertex;
|
||||
|
||||
// This class implements a "face varying vector item". Really it's
|
||||
// just a smart wrapper around face varying data (itself just a bunch
|
||||
// of floats) stored on each vertex.
|
||||
template <class T> class HbrFVarData {
|
||||
|
||||
private:
|
||||
HbrFVarData()
|
||||
: faceid(0), initialized(0) {
|
||||
}
|
||||
|
||||
~HbrFVarData() {
|
||||
Uninitialize();
|
||||
}
|
||||
|
||||
HbrFVarData(const HbrFVarData &/* data */) {}
|
||||
|
||||
public:
|
||||
|
||||
// Sets the face id
|
||||
void SetFaceID(int id) {
|
||||
faceid = id;
|
||||
}
|
||||
|
||||
// Returns the id of the face to which this data is bound
|
||||
int GetFaceID() const {
|
||||
return faceid;
|
||||
}
|
||||
|
||||
// Clears the initialized flag
|
||||
void Uninitialize() {
|
||||
initialized = 0;
|
||||
faceid = 0;
|
||||
}
|
||||
|
||||
// Returns initialized flag
|
||||
bool IsInitialized() const {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
// Sets initialized flag
|
||||
void SetInitialized() {
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
// Return the data from the NgpFVVector
|
||||
float* GetData(int item) { return data + item; }
|
||||
|
||||
// Clears the indicates value of this item
|
||||
void Clear(int startindex, int width) {
|
||||
memset(data + startindex, 0, width * sizeof(float));
|
||||
}
|
||||
|
||||
// Clears all values of this item
|
||||
void ClearAll(int width) {
|
||||
initialized = 1;
|
||||
memset(data, 0, width * sizeof(float));
|
||||
}
|
||||
|
||||
// Set values of the indicated item (with the indicated weighing)
|
||||
// on this item
|
||||
void SetWithWeight(const HbrFVarData& fvvi, int startindex, int width, float weight) {
|
||||
float *dst = data + startindex;
|
||||
const float *src = fvvi.data + startindex;
|
||||
for (int i = 0; i < width; ++i) {
|
||||
*dst++ = weight * *src++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add values of the indicated item (with the indicated weighing)
|
||||
// to this item
|
||||
void AddWithWeight(const HbrFVarData& fvvi, int startindex, int width, float weight) {
|
||||
float *dst = data + startindex;
|
||||
const float *src = fvvi.data + startindex;
|
||||
for (int i = 0; i < width; ++i) {
|
||||
*dst++ += weight * *src++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add all values of the indicated item (with the indicated
|
||||
// weighing) to this item
|
||||
void AddWithWeightAll(const HbrFVarData& fvvi, int width, float weight) {
|
||||
float *dst = data;
|
||||
const float *src = fvvi.data;
|
||||
for (int i = 0; i < width; ++i) {
|
||||
*dst++ += weight * *src++;
|
||||
}
|
||||
}
|
||||
|
||||
// Compare all values item against a float buffer. Returns true
|
||||
// if all values match
|
||||
bool CompareAll(int width, const float *values, float tolerance=0.0f) const {
|
||||
if (!initialized) return false;
|
||||
for (int i = 0; i < width; ++i) {
|
||||
if (fabsf(values[i] - data[i]) > tolerance) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Initializes data
|
||||
void SetAllData(int width, const float *values) {
|
||||
initialized = 1;
|
||||
memcpy(data, values, width * sizeof(float));
|
||||
}
|
||||
|
||||
// Compare this item against another item with tolerance. Returns
|
||||
// true if it compares identical
|
||||
bool Compare(const HbrFVarData& fvvi, int startindex, int width, float tolerance=0.0f) const {
|
||||
for (int i = 0; i < width; ++i) {
|
||||
if (fabsf(data[startindex + i] - fvvi.data[startindex + i]) > tolerance) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Modify the data of the item with an edit
|
||||
void ApplyFVarEdit(const HbrFVarEdit<T>& edit);
|
||||
|
||||
friend class HbrVertex<T>;
|
||||
|
||||
private:
|
||||
unsigned int faceid:31;
|
||||
unsigned int initialized:1;
|
||||
float data[1];
|
||||
};
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#include "../hbr/fvarEdit.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrFVarData<T>::ApplyFVarEdit(const HbrFVarEdit<T>& edit) {
|
||||
float *dst = data + edit.GetIndex() + edit.GetOffset();
|
||||
const float *src = edit.GetEdit();
|
||||
for (int i = 0; i < edit.GetWidth(); ++i) {
|
||||
switch(edit.GetOperation()) {
|
||||
case HbrVertexEdit<T>::Set:
|
||||
*dst++ = *src++;
|
||||
break;
|
||||
case HbrVertexEdit<T>::Add:
|
||||
*dst++ += *src++;
|
||||
break;
|
||||
case HbrVertexEdit<T>::Subtract:
|
||||
*dst++ -= *src++;
|
||||
}
|
||||
}
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRFVARDATA_H */
|
||||
104
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/fvarEdit.h
vendored
Normal file
104
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/fvarEdit.h
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRFVAREDIT_H
|
||||
#define OPENSUBDIV3_HBRFVAREDIT_H
|
||||
|
||||
#include "../hbr/hierarchicalEdit.h"
|
||||
#include "../hbr/vertexEdit.h"
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrFVarEdit;
|
||||
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& out, const HbrFVarEdit<T>& path) {
|
||||
out << "vertex path = (" << path.faceid << ' ';
|
||||
for (int i = 0; i < path.nsubfaces; ++i) {
|
||||
out << static_cast<int>(path.subfaces[i]) << ' ';
|
||||
}
|
||||
return out << static_cast<int>(path.vertexid) << "), edit = (" << path.edit[0] << ',' << path.edit[1] << ',' << path.edit[2] << ')';
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class HbrFVarEdit : public HbrHierarchicalEdit<T> {
|
||||
|
||||
public:
|
||||
|
||||
HbrFVarEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, unsigned char _vertexid, int _index, int _width, int _offset, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), offset(_offset), op(_op) {
|
||||
edit = new float[width];
|
||||
memcpy(edit, _edit, width * sizeof(float));
|
||||
}
|
||||
|
||||
HbrFVarEdit(int _faceid, int _nsubfaces, int *_subfaces, int _vertexid, int _index, int _width, int _offset, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), offset(_offset), op(_op) {
|
||||
edit = new float[width];
|
||||
memcpy(edit, _edit, width * sizeof(float));
|
||||
}
|
||||
|
||||
virtual ~HbrFVarEdit() {
|
||||
delete[] edit;
|
||||
}
|
||||
|
||||
// Return the vertex id (the last element in the path)
|
||||
unsigned char GetVertexID() const { return vertexid; }
|
||||
|
||||
friend std::ostream& operator<< <T> (std::ostream& out, const HbrFVarEdit<T>& path);
|
||||
|
||||
// Return index into the facevarying data
|
||||
int GetIndex() const { return index; }
|
||||
|
||||
// Return width of the data
|
||||
int GetWidth() const { return width; }
|
||||
|
||||
// Return offset of the data
|
||||
int GetOffset() const { return offset; }
|
||||
|
||||
// Get the numerical value of the edit
|
||||
const float* GetEdit() const { return edit; }
|
||||
|
||||
// Get the type of operation
|
||||
typename HbrHierarchicalEdit<T>::Operation GetOperation() const { return op; }
|
||||
|
||||
virtual void ApplyEditToFace(HbrFace<T>* face) {
|
||||
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
|
||||
// The edit will modify the data and almost certainly
|
||||
// create a discontinuity, so allocate storage for a new
|
||||
// copy of the existing data specific to the face (or use
|
||||
// one that already exists) and modify that
|
||||
HbrFVarData<T> &fvt = face->GetVertex(vertexid)->GetFVarData(face);
|
||||
if (fvt.GetFaceID() != face->GetID()) {
|
||||
// This is the generic fvt, allocate a new copy and edit it
|
||||
HbrFVarData<T> &newfvt = face->GetVertex(vertexid)->NewFVarData(face);
|
||||
newfvt.SetAllData(face->GetMesh()->GetTotalFVarWidth(), fvt.GetData(0));
|
||||
newfvt.ApplyFVarEdit(*const_cast<const HbrFVarEdit<T>*>(this));
|
||||
} else {
|
||||
fvt.ApplyFVarEdit(*const_cast<const HbrFVarEdit<T>*>(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const unsigned char vertexid;
|
||||
const int index;
|
||||
const int width;
|
||||
const int offset;
|
||||
float* edit;
|
||||
typename HbrHierarchicalEdit<T>::Operation op;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRFVAREDIT_H */
|
||||
723
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/halfedge.h
vendored
Normal file
723
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/halfedge.h
vendored
Normal file
@@ -0,0 +1,723 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRHALFEDGE_H
|
||||
#define OPENSUBDIV3_HBRHALFEDGE_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
#ifdef HBRSTITCH
|
||||
#include "libgprims/stitch.h"
|
||||
#include "libgprims/stitchInternal.h"
|
||||
#endif
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrFace;
|
||||
template <class T> class HbrHalfedge;
|
||||
template <class T> class HbrVertex;
|
||||
template <class T> class HbrMesh;
|
||||
|
||||
template <class T> std::ostream& operator<<(std::ostream& out, const HbrHalfedge<T>& edge);
|
||||
|
||||
template <class T> class HbrHalfedge {
|
||||
|
||||
private:
|
||||
HbrHalfedge(): opposite(0), incidentVertex(-1), vchild(-1), sharpness(0.0f)
|
||||
#ifdef HBRSTITCH
|
||||
, stitchccw(1), raystitchccw(1)
|
||||
#endif
|
||||
, coarse(1)
|
||||
{
|
||||
}
|
||||
|
||||
HbrHalfedge(const HbrHalfedge &/* edge */) {}
|
||||
|
||||
~HbrHalfedge();
|
||||
|
||||
void Clear();
|
||||
|
||||
// Finish the initialization of the halfedge. Should only be
|
||||
// called by HbrFace
|
||||
void Initialize(HbrHalfedge<T>* opposite, int index, HbrVertex<T>* origin, unsigned int *fvarbits, HbrFace<T>* face);
|
||||
public:
|
||||
|
||||
// Returns the opposite half edge
|
||||
HbrHalfedge<T>* GetOpposite() const { return opposite; }
|
||||
|
||||
// Sets the opposite half edge
|
||||
void SetOpposite(HbrHalfedge<T>* opposite) { this->opposite = opposite; sharpness = opposite->sharpness; }
|
||||
|
||||
// Returns the next clockwise halfedge around the incident face
|
||||
HbrHalfedge<T>* GetNext() const {
|
||||
if (m_index == 4) {
|
||||
const size_t edgesize = sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*);
|
||||
if (lastedge) {
|
||||
return (HbrHalfedge<T>*) ((char*) this - (GetFace()->GetNumVertices() - 1) * edgesize);
|
||||
} else {
|
||||
return (HbrHalfedge<T>*) ((char*) this + edgesize);
|
||||
}
|
||||
} else {
|
||||
if (lastedge) {
|
||||
return (HbrHalfedge<T>*) ((char*) this - (m_index) * sizeof(HbrHalfedge<T>));
|
||||
} else {
|
||||
return (HbrHalfedge<T>*) ((char*) this + sizeof(HbrHalfedge<T>));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the previous counterclockwise halfedge around the incident face
|
||||
HbrHalfedge<T>* GetPrev() const {
|
||||
const size_t edgesize = (m_index == 4) ?
|
||||
(sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*)) :
|
||||
sizeof(HbrHalfedge<T>);
|
||||
if (firstedge) {
|
||||
return (HbrHalfedge<T>*) ((char*) this + (GetFace()->GetNumVertices() - 1) * edgesize);
|
||||
} else {
|
||||
return (HbrHalfedge<T>*) ((char*) this - edgesize);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the incident vertex
|
||||
HbrVertex<T>* GetVertex() const {
|
||||
return GetMesh()->GetVertex(incidentVertex);
|
||||
}
|
||||
|
||||
// Returns the incident vertex
|
||||
HbrVertex<T>* GetVertex(HbrMesh<T> *mesh) const {
|
||||
return mesh->GetVertex(incidentVertex);
|
||||
}
|
||||
|
||||
// Returns the incident vertex
|
||||
int GetVertexID() const {
|
||||
return incidentVertex;
|
||||
}
|
||||
|
||||
// Returns the source vertex
|
||||
HbrVertex<T>* GetOrgVertex() const {
|
||||
return GetVertex();
|
||||
}
|
||||
|
||||
// Returns the source vertex
|
||||
HbrVertex<T>* GetOrgVertex(HbrMesh<T> *mesh) const {
|
||||
return GetVertex(mesh);
|
||||
}
|
||||
|
||||
// Returns the source vertex id
|
||||
int GetOrgVertexID() const {
|
||||
return incidentVertex;
|
||||
}
|
||||
|
||||
// Changes the origin vertex. Generally not a good idea to do
|
||||
void SetOrgVertex(HbrVertex<T>* v) { incidentVertex = v->GetID(); }
|
||||
|
||||
// Returns the destination vertex
|
||||
HbrVertex<T>* GetDestVertex() const { return GetNext()->GetOrgVertex(); }
|
||||
|
||||
// Returns the destination vertex
|
||||
HbrVertex<T>* GetDestVertex(HbrMesh<T> *mesh) const { return GetNext()->GetOrgVertex(mesh); }
|
||||
|
||||
// Returns the destination vertex ID
|
||||
int GetDestVertexID() const { return GetNext()->GetOrgVertexID(); }
|
||||
|
||||
// Returns the incident facet
|
||||
HbrFace<T>* GetFace() const {
|
||||
if (m_index == 4) {
|
||||
// Pointer to face is stored after the data for the edge
|
||||
return *(HbrFace<T>**)((char *) this + sizeof(HbrHalfedge<T>));
|
||||
} else {
|
||||
return (HbrFace<T>*) ((char*) this - (m_index) * sizeof(HbrHalfedge<T>) -
|
||||
offsetof(HbrFace<T>, edges));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the mesh to which this edge belongs
|
||||
HbrMesh<T>* GetMesh() const { return GetFace()->GetMesh(); }
|
||||
|
||||
// Returns the face on the right
|
||||
HbrFace<T>* GetRightFace() const { return opposite ? opposite->GetLeftFace() : NULL; }
|
||||
|
||||
// Return the face on the left of the halfedge
|
||||
HbrFace<T>* GetLeftFace() const { return GetFace(); }
|
||||
|
||||
// Returns whether this is a boundary edge
|
||||
bool IsBoundary() const { return opposite == 0; }
|
||||
|
||||
// Tag the edge as being an infinitely sharp facevarying edge
|
||||
void SetFVarInfiniteSharp(int datum, bool infsharp) {
|
||||
int intindex = datum >> 4;
|
||||
unsigned int bits = infsharp << ((datum & 15) * 2);
|
||||
getFVarInfSharp()[intindex] |= bits;
|
||||
if (opposite) {
|
||||
opposite->getFVarInfSharp()[intindex] |= bits;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy fvar infinite sharpness flags from another edge
|
||||
void CopyFVarInfiniteSharpness(HbrHalfedge<T>* edge) {
|
||||
unsigned int *fvarinfsharp = getFVarInfSharp();
|
||||
if (fvarinfsharp) {
|
||||
const int fvarcount = GetMesh()->GetFVarCount();
|
||||
int fvarbitsSizePerEdge = ((fvarcount + 15) / 16);
|
||||
|
||||
if (edge->IsSharp(true)) {
|
||||
memset(fvarinfsharp, 0x55555555, fvarbitsSizePerEdge * sizeof(unsigned int));
|
||||
} else {
|
||||
memcpy(fvarinfsharp, edge->getFVarInfSharp(), fvarbitsSizePerEdge * sizeof(unsigned int));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns whether the edge is infinitely sharp in facevarying for
|
||||
// a particular facevarying datum
|
||||
bool GetFVarInfiniteSharp(int datum);
|
||||
|
||||
// Returns whether the edge is infinitely sharp in any facevarying
|
||||
// datum
|
||||
bool IsFVarInfiniteSharpAnywhere();
|
||||
|
||||
// Get the sharpness relative to facevarying data
|
||||
float GetFVarSharpness(int datum, bool ignoreGeometry=false);
|
||||
|
||||
// Returns the (raw) sharpness of the edge
|
||||
float GetSharpness() const { return sharpness; }
|
||||
|
||||
// Sets the sharpness of the edge
|
||||
void SetSharpness(float sharp) { sharpness = sharp; if (opposite) opposite->sharpness = sharp; ClearMask(); }
|
||||
|
||||
// Returns whether the edge 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)); }
|
||||
|
||||
// Clears the masks of the adjacent edge vertices. Usually called
|
||||
// when a change in edge sharpness occurs.
|
||||
void ClearMask() { GetOrgVertex()->ClearMask(); GetDestVertex()->ClearMask(); }
|
||||
|
||||
// Subdivide the edge into a vertex if needed and return
|
||||
HbrVertex<T>* Subdivide();
|
||||
|
||||
// Make sure the edge has its opposite face
|
||||
void GuaranteeNeighbor();
|
||||
|
||||
// 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; }
|
||||
|
||||
// Sharpness constants
|
||||
enum Mask {
|
||||
k_Smooth = 0,
|
||||
k_Sharp = 1,
|
||||
k_InfinitelySharp = 10
|
||||
};
|
||||
|
||||
#ifdef HBRSTITCH
|
||||
StitchEdge* GetStitchEdge(int i) {
|
||||
StitchEdge **stitchEdge = getStitchEdges();
|
||||
// If the stitch edge exists, the ownership is transferred to
|
||||
// the caller. Make sure the opposite edge loses ownership as
|
||||
// well.
|
||||
if (stitchEdge[i]) {
|
||||
if (opposite) {
|
||||
opposite->getStitchEdges()[i] = 0;
|
||||
}
|
||||
return StitchGetEdge(&stitchEdge[i]);
|
||||
}
|
||||
// If the stitch edge does not exist then we create one now.
|
||||
// Make sure the opposite edge gets a copy of it too
|
||||
else {
|
||||
StitchGetEdge(&stitchEdge[i]);
|
||||
if (opposite) {
|
||||
opposite->getStitchEdges()[i] = stitchEdge[i];
|
||||
}
|
||||
return stitchEdge[i];
|
||||
}
|
||||
}
|
||||
|
||||
// If stitch edge exists, and this edge has no opposite, destroy
|
||||
// it
|
||||
void DestroyStitchEdges(int stitchcount) {
|
||||
if (!opposite) {
|
||||
StitchEdge **stitchEdge = getStitchEdges();
|
||||
for (int i = 0; i < stitchcount; ++i) {
|
||||
if (stitchEdge[i]) {
|
||||
StitchFreeEdge(stitchEdge[i]);
|
||||
stitchEdge[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StitchEdge* GetRayStitchEdge(int i) {
|
||||
return GetStitchEdge(i + 2);
|
||||
}
|
||||
|
||||
// Splits our split edge between our children. We'd better have
|
||||
// subdivided this edge by this point
|
||||
void SplitStitchEdge(int i) {
|
||||
StitchEdge* se = GetStitchEdge(i);
|
||||
HbrHalfedge<T>* ea = GetOrgVertex()->Subdivide()->GetEdge(Subdivide());
|
||||
HbrHalfedge<T>* eb = Subdivide()->GetEdge(GetDestVertex()->Subdivide());
|
||||
StitchEdge **ease = ea->getStitchEdges();
|
||||
StitchEdge **ebse = eb->getStitchEdges();
|
||||
if (i >= 2) { // ray tracing stitches
|
||||
if (!raystitchccw) {
|
||||
StitchSplitEdge(se, &ease[i], &ebse[i], false, 0, 0, 0);
|
||||
} else {
|
||||
StitchSplitEdge(se, &ebse[i], &ease[i], true, 0, 0, 0);
|
||||
}
|
||||
ea->raystitchccw = eb->raystitchccw = raystitchccw;
|
||||
if (eb->opposite) {
|
||||
eb->opposite->getStitchEdges()[i] = ebse[i];
|
||||
eb->opposite->raystitchccw = raystitchccw;
|
||||
}
|
||||
if (ea->opposite) {
|
||||
ea->opposite->getStitchEdges()[i] = ease[i];
|
||||
ea->opposite->raystitchccw = raystitchccw;
|
||||
}
|
||||
} else {
|
||||
if (!stitchccw) {
|
||||
StitchSplitEdge(se, &ease[i], &ebse[i], false, 0, 0, 0);
|
||||
} else {
|
||||
StitchSplitEdge(se, &ebse[i], &ease[i], true, 0, 0, 0);
|
||||
}
|
||||
ea->stitchccw = eb->stitchccw = stitchccw;
|
||||
if (eb->opposite) {
|
||||
eb->opposite->getStitchEdges()[i] = ebse[i];
|
||||
eb->opposite->stitchccw = stitchccw;
|
||||
}
|
||||
if (ea->opposite) {
|
||||
ea->opposite->getStitchEdges()[i] = ease[i];
|
||||
ea->opposite->stitchccw = stitchccw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SplitRayStitchEdge(int i) {
|
||||
SplitStitchEdge(i + 2);
|
||||
}
|
||||
|
||||
void SetStitchEdge(int i, StitchEdge* edge) {
|
||||
StitchEdge **stitchEdges = getStitchEdges();
|
||||
stitchEdges[i] = edge;
|
||||
if (opposite) {
|
||||
opposite->getStitchEdges()[i] = edge;
|
||||
}
|
||||
}
|
||||
|
||||
void SetRayStitchEdge(int i, StitchEdge* edge) {
|
||||
StitchEdge **stitchEdges = getStitchEdges();
|
||||
stitchEdges[i+2] = edge;
|
||||
if (opposite) {
|
||||
opposite->getStitchEdges()[i+2] = edge;
|
||||
}
|
||||
}
|
||||
|
||||
void* GetStitchData() const {
|
||||
if (stitchdatavalid) return GetMesh()->GetStitchData(this);
|
||||
else return 0;
|
||||
}
|
||||
|
||||
void SetStitchData(void* data) {
|
||||
GetMesh()->SetStitchData(this, data);
|
||||
stitchdatavalid = data ? 1 : 0;
|
||||
if (opposite) {
|
||||
opposite->GetMesh()->SetStitchData(opposite, data);
|
||||
opposite->stitchdatavalid = stitchdatavalid;
|
||||
}
|
||||
}
|
||||
|
||||
bool GetStitchCCW(bool raytraced) const { return raytraced ? raystitchccw : stitchccw; }
|
||||
|
||||
void ClearStitchCCW(bool raytraced) {
|
||||
if (raytraced) {
|
||||
raystitchccw = 0;
|
||||
if (opposite) opposite->raystitchccw = 0;
|
||||
} else {
|
||||
stitchccw = 0;
|
||||
if (opposite) opposite->stitchccw = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ToggleStitchCCW(bool raytraced) {
|
||||
if (raytraced) {
|
||||
raystitchccw = 1 - raystitchccw;
|
||||
if (opposite) opposite->raystitchccw = raystitchccw;
|
||||
} else {
|
||||
stitchccw = 1 - stitchccw;
|
||||
if (opposite) opposite->stitchccw = stitchccw;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Marks the edge as being "coarse" (belonging to the control
|
||||
// mesh). Generally this distinction only needs to be made if
|
||||
// we're worried about interpolateboundary behaviour
|
||||
void SetCoarse(bool c) { coarse = c; }
|
||||
bool IsCoarse() const { return coarse; }
|
||||
|
||||
friend class HbrFace<T>;
|
||||
|
||||
private:
|
||||
HbrHalfedge<T>* opposite;
|
||||
// Index of incident vertex
|
||||
int incidentVertex;
|
||||
|
||||
// Index of subdivided vertex child
|
||||
int vchild;
|
||||
float sharpness;
|
||||
|
||||
#ifdef HBRSTITCH
|
||||
unsigned short stitchccw:1;
|
||||
unsigned short raystitchccw:1;
|
||||
unsigned short stitchdatavalid:1;
|
||||
#endif
|
||||
unsigned short coarse:1;
|
||||
unsigned short lastedge:1;
|
||||
unsigned short firstedge:1;
|
||||
|
||||
// If m_index = 0, 1, 2 or 3: we are the m_index edge of an
|
||||
// incident face with 3 or 4 vertices.
|
||||
// If m_index = 4: our incident face has more than 4 vertices, and
|
||||
// we must do some extra math to determine what our actual index
|
||||
// is. See getIndex()
|
||||
unsigned short m_index:3;
|
||||
|
||||
// Returns the index of the edge relative to its incident face.
|
||||
// This relies on knowledge of the face's edge allocation pattern
|
||||
int getIndex() const {
|
||||
if (m_index < 4) {
|
||||
return m_index;
|
||||
} else {
|
||||
// We allocate room for up to 4 values (to handle tri or
|
||||
// quad) in the edges array. If there are more than that,
|
||||
// they _all_ go in the faces' extraedges array.
|
||||
HbrFace<T>* incidentFace = *(HbrFace<T>**)((char *) this + sizeof(HbrHalfedge<T>));
|
||||
return int(((char *) this - incidentFace->extraedges) /
|
||||
(sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*)));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns bitmask indicating whether a given facevarying datum
|
||||
// for the edge is infinitely sharp. Each datum has two bits, and
|
||||
// if those two bits are set to 3, it means the status has not
|
||||
// been computed yet.
|
||||
unsigned int *getFVarInfSharp() {
|
||||
unsigned int *fvarbits = GetFace()->fvarbits;
|
||||
if (fvarbits) {
|
||||
int fvarbitsSizePerEdge = ((GetMesh()->GetFVarCount() + 15) / 16);
|
||||
return fvarbits + getIndex() * fvarbitsSizePerEdge;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HBRSTITCH
|
||||
StitchEdge **getStitchEdges() {
|
||||
return GetFace()->stitchEdges + GetMesh()->GetStitchCount() * getIndex();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HBR_ADAPTIVE
|
||||
public:
|
||||
struct adaptiveFlags {
|
||||
unsigned isTransition:1;
|
||||
unsigned isTriangleHead:1;
|
||||
unsigned isWatertightCritical:1;
|
||||
|
||||
adaptiveFlags() : isTransition(0),isTriangleHead(0),isWatertightCritical(0) { }
|
||||
};
|
||||
|
||||
adaptiveFlags _adaptiveFlags;
|
||||
|
||||
bool IsInsideHole() const {
|
||||
|
||||
HbrFace<T> * left = GetLeftFace();
|
||||
if (left and (not left->IsHole()))
|
||||
return false;
|
||||
|
||||
HbrFace<T> * right = GetRightFace();
|
||||
if (right and (not right->IsHole()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsTransition() const { return _adaptiveFlags.isTransition; }
|
||||
|
||||
bool IsTriangleHead() const { return _adaptiveFlags.isTriangleHead; }
|
||||
|
||||
bool IsWatertightCritical() const { return _adaptiveFlags.isWatertightCritical; }
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrHalfedge<T>::Initialize(HbrHalfedge<T>* opposite, int index, HbrVertex<T>* origin,
|
||||
unsigned int *fvarbits, HbrFace<T>* face) {
|
||||
HbrMesh<T> *mesh = face->GetMesh();
|
||||
if (face->GetNumVertices() <= 4) {
|
||||
m_index = index;
|
||||
} else {
|
||||
m_index = 4;
|
||||
// Assumes upstream allocation ensured we have extra storage
|
||||
// for pointer to face after the halfedge data structure
|
||||
// itself
|
||||
*(HbrFace<T>**)((char *) this + sizeof(HbrHalfedge<T>)) = face;
|
||||
}
|
||||
|
||||
this->opposite = opposite;
|
||||
incidentVertex = origin->GetID();
|
||||
lastedge = (index == face->GetNumVertices() - 1);
|
||||
firstedge = (index == 0);
|
||||
if (opposite) {
|
||||
sharpness = opposite->sharpness;
|
||||
#ifdef HBRSTITCH
|
||||
StitchEdge **stitchEdges = face->stitchEdges +
|
||||
mesh->GetStitchCount() * index;
|
||||
for (int i = 0; i < mesh->GetStitchCount(); ++i) {
|
||||
stitchEdges[i] = opposite->getStitchEdges()[i];
|
||||
}
|
||||
stitchccw = opposite->stitchccw;
|
||||
raystitchccw = opposite->raystitchccw;
|
||||
stitchdatavalid = 0;
|
||||
if (stitchEdges && opposite->GetStitchData()) {
|
||||
mesh->SetStitchData(this, opposite->GetStitchData());
|
||||
stitchdatavalid = 1;
|
||||
}
|
||||
#endif
|
||||
if (fvarbits) {
|
||||
const int fvarcount = mesh->GetFVarCount();
|
||||
int fvarbitsSizePerEdge = ((fvarcount + 15) / 16);
|
||||
memcpy(fvarbits, opposite->getFVarInfSharp(), fvarbitsSizePerEdge * sizeof(unsigned int));
|
||||
}
|
||||
} else {
|
||||
sharpness = 0.0f;
|
||||
#ifdef HBRSTITCH
|
||||
StitchEdge **stitchEdges = getStitchEdges();
|
||||
for (int i = 0; i < mesh->GetStitchCount(); ++i) {
|
||||
stitchEdges[i] = 0;
|
||||
}
|
||||
stitchccw = 1;
|
||||
raystitchccw = 1;
|
||||
stitchdatavalid = 0;
|
||||
#endif
|
||||
if (fvarbits) {
|
||||
const int fvarcount = mesh->GetFVarCount();
|
||||
int fvarbitsSizePerEdge = ((fvarcount + 15) / 16);
|
||||
memset(fvarbits, 0xff, fvarbitsSizePerEdge * sizeof(unsigned int));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrHalfedge<T>::~HbrHalfedge() {
|
||||
Clear();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrHalfedge<T>::Clear() {
|
||||
if (opposite) {
|
||||
opposite->opposite = 0;
|
||||
if (vchild != -1) {
|
||||
// Transfer ownership of the vchild to the opposite ptr
|
||||
opposite->vchild = vchild;
|
||||
|
||||
HbrVertex<T> *vchildVert = GetMesh()->GetVertex(vchild);
|
||||
// Done this way just for assertion sanity
|
||||
vchildVert->SetParent(static_cast<HbrHalfedge*>(0));
|
||||
vchildVert->SetParent(opposite);
|
||||
vchild = -1;
|
||||
}
|
||||
opposite = 0;
|
||||
}
|
||||
// Orphan the child vertex
|
||||
else if (vchild != -1) {
|
||||
HbrVertex<T> *vchildVert = GetMesh()->GetVertex(vchild);
|
||||
vchildVert->SetParent(static_cast<HbrHalfedge*>(0));
|
||||
vchild = -1;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrVertex<T>*
|
||||
HbrHalfedge<T>::Subdivide() {
|
||||
HbrMesh<T>* mesh = GetMesh();
|
||||
if (vchild != -1) return mesh->GetVertex(vchild);
|
||||
// Make sure that our opposite doesn't "own" a subdivided vertex
|
||||
// already. If it does, use that
|
||||
if (opposite && opposite->vchild != -1) return mesh->GetVertex(opposite->vchild);
|
||||
HbrVertex<T>* vchildVert = mesh->GetSubdivision()->Subdivide(mesh, this);
|
||||
vchild = vchildVert->GetID();
|
||||
vchildVert->SetParent(this);
|
||||
return vchildVert;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrHalfedge<T>::GuaranteeNeighbor() {
|
||||
HbrMesh<T>* mesh = GetMesh();
|
||||
mesh->GetSubdivision()->GuaranteeNeighbor(mesh, this);
|
||||
}
|
||||
|
||||
// Determines whether an edge is infinitely sharp as far as its
|
||||
// facevarying data is concerned. Happens if the faces on both sides
|
||||
// disagree on the facevarying data at either of the shared vertices
|
||||
// on the edge.
|
||||
template <class T>
|
||||
bool
|
||||
HbrHalfedge<T>::GetFVarInfiniteSharp(int datum) {
|
||||
|
||||
// Check to see if already initialized
|
||||
int intindex = datum >> 4;
|
||||
int shift = (datum & 15) << 1;
|
||||
unsigned int *fvarinfsharp = getFVarInfSharp();
|
||||
unsigned int bits = (fvarinfsharp[intindex] >> shift) & 0x3;
|
||||
if (bits != 3) {
|
||||
assert (bits != 2);
|
||||
return bits ? true : false;
|
||||
}
|
||||
|
||||
// If there is no face varying data it can't be infinitely sharp!
|
||||
const int fvarwidth = GetMesh()->GetTotalFVarWidth();
|
||||
if (!fvarwidth) {
|
||||
bits = ~(0x3 << shift);
|
||||
fvarinfsharp[intindex] &= bits;
|
||||
if (opposite) opposite->getFVarInfSharp()[intindex] &= bits;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If either incident face is missing, it's a geometric boundary
|
||||
// edge, and also a facevarying boundary edge
|
||||
HbrFace<T>* left = GetLeftFace(), *right = GetRightFace();
|
||||
if (!left || !right) {
|
||||
bits = ~(0x2 << shift);
|
||||
fvarinfsharp[intindex] &= bits;
|
||||
if (opposite) opposite->getFVarInfSharp()[intindex] &= bits;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Look for the indices on each face which correspond to the
|
||||
// origin and destination vertices of the edge
|
||||
int lorg = -1, ldst = -1, rorg = -1, rdst = -1, i, nv;
|
||||
HbrHalfedge<T>* e;
|
||||
e = left->GetFirstEdge();
|
||||
nv = left->GetNumVertices();
|
||||
for (i = 0; i < nv; ++i) {
|
||||
if (e->GetOrgVertex() == GetOrgVertex()) lorg = i;
|
||||
if (e->GetOrgVertex() == GetDestVertex()) ldst = i;
|
||||
e = e->GetNext();
|
||||
}
|
||||
e = right->GetFirstEdge();
|
||||
nv = right->GetNumVertices();
|
||||
for (i = 0; i < nv; ++i) {
|
||||
if (e->GetOrgVertex() == GetOrgVertex()) rorg = i;
|
||||
if (e->GetOrgVertex() == GetDestVertex()) rdst = i;
|
||||
e = e->GetNext();
|
||||
}
|
||||
assert(lorg >= 0 && ldst >= 0 && rorg >= 0 && rdst >= 0);
|
||||
// Compare the facevarying data to some tolerance
|
||||
const int startindex = GetMesh()->GetFVarIndices()[datum];
|
||||
const int width = GetMesh()->GetFVarWidths()[datum];
|
||||
if (!right->GetFVarData(rorg).Compare(left->GetFVarData(lorg), startindex, width, 0.001f) ||
|
||||
!right->GetFVarData(rdst).Compare(left->GetFVarData(ldst), startindex, width, 0.001f)) {
|
||||
bits = ~(0x2 << shift);
|
||||
fvarinfsharp[intindex] &= bits;
|
||||
if (opposite) opposite->getFVarInfSharp()[intindex] &= bits;
|
||||
return true;
|
||||
}
|
||||
|
||||
bits = ~(0x3 << shift);
|
||||
fvarinfsharp[intindex] &= bits;
|
||||
if (opposite) opposite->getFVarInfSharp()[intindex] &= bits;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
HbrHalfedge<T>::IsFVarInfiniteSharpAnywhere() {
|
||||
|
||||
if (sharpness > k_Smooth) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < GetMesh()->GetFVarCount(); ++i) {
|
||||
if (GetFVarInfiniteSharp(i)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
float
|
||||
HbrHalfedge<T>::GetFVarSharpness(int datum, bool ignoreGeometry) {
|
||||
|
||||
if (GetFVarInfiniteSharp(datum)) return k_InfinitelySharp;
|
||||
|
||||
if (!ignoreGeometry) {
|
||||
// If it's a geometrically sharp edge it's going to be a
|
||||
// facevarying sharp edge too
|
||||
if (sharpness > k_Smooth) {
|
||||
SetFVarInfiniteSharp(datum, true);
|
||||
return k_InfinitelySharp;
|
||||
}
|
||||
}
|
||||
return k_Smooth;
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
std::ostream&
|
||||
operator<<(std::ostream& out, const HbrHalfedge<T>& edge) {
|
||||
if (edge.IsBoundary()) out << "boundary ";
|
||||
out << "edge connecting ";
|
||||
if (edge.GetOrgVertex())
|
||||
out << *edge.GetOrgVertex();
|
||||
else
|
||||
out << "(none)";
|
||||
out << " to ";
|
||||
if (edge.GetDestVertex()) {
|
||||
out << *edge.GetDestVertex();
|
||||
} else {
|
||||
out << "(none)";
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Sorts half edges by the relative ordering of the incident faces'
|
||||
// paths.
|
||||
template <class T>
|
||||
class HbrHalfedgeCompare {
|
||||
public:
|
||||
bool operator() (const HbrHalfedge<T>* a, HbrHalfedge<T>* b) const {
|
||||
return (a->GetFace()->GetPath() < b->GetFace()->GetPath());
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class HbrHalfedgeOperator {
|
||||
public:
|
||||
virtual void operator() (HbrHalfedge<T> &edge) = 0;
|
||||
virtual ~HbrHalfedgeOperator() {}
|
||||
};
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRHALFEDGE_H */
|
||||
154
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/hierarchicalEdit.h
vendored
Normal file
154
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/hierarchicalEdit.h
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRHIERARCHICALEDIT_H
|
||||
#define OPENSUBDIV3_HBRHIERARCHICALEDIT_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrHierarchicalEdit;
|
||||
template <class T> class HbrFace;
|
||||
template <class T> class HbrVertex;
|
||||
|
||||
template <class T>
|
||||
class HbrHierarchicalEdit {
|
||||
|
||||
public:
|
||||
typedef enum Operation {
|
||||
Set,
|
||||
Add,
|
||||
Subtract
|
||||
} Operation;
|
||||
|
||||
protected:
|
||||
|
||||
HbrHierarchicalEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces)
|
||||
: faceid(_faceid), nsubfaces(_nsubfaces) {
|
||||
subfaces = new unsigned char[_nsubfaces];
|
||||
for (int i = 0; i < nsubfaces; ++i) {
|
||||
subfaces[i] = _subfaces[i];
|
||||
}
|
||||
}
|
||||
|
||||
HbrHierarchicalEdit(int _faceid, int _nsubfaces, int *_subfaces)
|
||||
: faceid(_faceid), nsubfaces(_nsubfaces) {
|
||||
subfaces = new unsigned char[_nsubfaces];
|
||||
for (int i = 0; i < nsubfaces; ++i) {
|
||||
subfaces[i] = static_cast<unsigned char>(_subfaces[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~HbrHierarchicalEdit() {
|
||||
delete[] subfaces;
|
||||
}
|
||||
|
||||
bool operator<(const HbrHierarchicalEdit& p) const {
|
||||
if (faceid < p.faceid) return true;
|
||||
if (faceid > p.faceid) return false;
|
||||
int minlength = nsubfaces;
|
||||
if (minlength > p.nsubfaces) minlength = p.nsubfaces;
|
||||
for (int i = 0; i < minlength; ++i) {
|
||||
if (subfaces[i] < p.subfaces[i]) return true;
|
||||
if (subfaces[i] > p.subfaces[i]) return false;
|
||||
}
|
||||
return (nsubfaces < p.nsubfaces);
|
||||
}
|
||||
|
||||
// Return the face id (the first element in the path)
|
||||
int GetFaceID() const { return faceid; }
|
||||
|
||||
// Return the number of subfaces in the path
|
||||
int GetNSubfaces() const { return nsubfaces; }
|
||||
|
||||
// Return a subface element in the path
|
||||
unsigned char GetSubface(int index) const { return subfaces[index]; }
|
||||
|
||||
// Determines whether this hierarchical edit is relevant to the
|
||||
// face in question
|
||||
bool IsRelevantToFace(HbrFace<T>* face) const;
|
||||
|
||||
// Applys edit to face. All subclasses may override this method
|
||||
virtual void ApplyEditToFace(HbrFace<T>* /* face */) {}
|
||||
|
||||
// Applys edit to vertex. Subclasses may override this method.
|
||||
virtual void ApplyEditToVertex(HbrFace<T>* /* face */, HbrVertex<T>* /* vertex */) {}
|
||||
|
||||
#ifdef PRMAN
|
||||
// Gets the effect of this hierarchical edit on the bounding box.
|
||||
// Subclasses may override this method
|
||||
virtual void ApplyToBound(struct bbox& /* box */, RtMatrix * /* mx */) const {}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// ID of the top most face in the mesh which begins the path
|
||||
const int faceid;
|
||||
|
||||
// Number of subfaces
|
||||
const int nsubfaces;
|
||||
|
||||
// IDs of the subfaces
|
||||
unsigned char *subfaces;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class HbrHierarchicalEditComparator {
|
||||
public:
|
||||
bool operator() (const HbrHierarchicalEdit<T>* path1, const HbrHierarchicalEdit<T>* path2) const {
|
||||
return (*path1 < *path2);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#include "../hbr/face.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
HbrHierarchicalEdit<T>::IsRelevantToFace(HbrFace<T>* face) const {
|
||||
|
||||
// Key assumption: the face's first vertex edit is relevant to
|
||||
// that face. We will then compare ourselves to that edit and if
|
||||
// the first part of our subpath is identical to the entirety of
|
||||
// that subpath, this edit is relevant.
|
||||
|
||||
// Calling code is responsible for making sure we don't
|
||||
// dereference a null pointer here
|
||||
HbrHierarchicalEdit<T>* p = *face->GetHierarchicalEdits();
|
||||
if (!p) return false;
|
||||
|
||||
if (this == p) return true;
|
||||
|
||||
if (faceid != p->faceid) return false;
|
||||
|
||||
// If our path length is less than the face depth, it should mean
|
||||
// that we're dealing with another face somewhere up the path, so
|
||||
// we're not relevant
|
||||
if (nsubfaces < face->GetDepth()) return false;
|
||||
|
||||
if (memcmp(subfaces, p->subfaces, face->GetDepth() * sizeof(unsigned char)) != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRHIERARCHICALEDIT_H */
|
||||
57
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/holeEdit.h
vendored
Normal file
57
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/holeEdit.h
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRHOLEEDIT_H
|
||||
#define OPENSUBDIV3_HBRHOLEEDIT_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrHoleEdit;
|
||||
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& out, const HbrHoleEdit<T>& path) {
|
||||
out << "edge path = (" << path.faceid << ' ';
|
||||
for (int i = 0; i < path.nsubfaces; ++i) {
|
||||
out << static_cast<int>(path.subfaces[i]) << ' ';
|
||||
}
|
||||
return out << ")";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class HbrHoleEdit : public HbrHierarchicalEdit<T> {
|
||||
|
||||
public:
|
||||
|
||||
HbrHoleEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces) {
|
||||
}
|
||||
|
||||
HbrHoleEdit(int _faceid, int _nsubfaces, int *_subfaces)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces) {
|
||||
}
|
||||
|
||||
virtual ~HbrHoleEdit() {}
|
||||
|
||||
friend std::ostream& operator<< <T> (std::ostream& out, const HbrHoleEdit<T>& path);
|
||||
|
||||
virtual void ApplyEditToFace(HbrFace<T>* face) {
|
||||
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
|
||||
face->SetHole();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRHOLEEDIT_H */
|
||||
962
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/loop.h
vendored
Normal file
962
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/loop.h
vendored
Normal file
@@ -0,0 +1,962 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRLOOP_H
|
||||
#define OPENSUBDIV3_HBRLOOP_H
|
||||
|
||||
#include <cmath>
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../hbr/subdivision.h"
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
/* #define HBR_DEBUG */
|
||||
|
||||
template <class T>
|
||||
class HbrLoopSubdivision : public HbrSubdivision<T>{
|
||||
public:
|
||||
HbrLoopSubdivision<T>()
|
||||
: HbrSubdivision<T>() {}
|
||||
|
||||
virtual HbrSubdivision<T>* Clone() const {
|
||||
return new HbrLoopSubdivision<T>();
|
||||
}
|
||||
|
||||
virtual void Refine(HbrMesh<T>* mesh, HbrFace<T>* face);
|
||||
virtual HbrFace<T>* RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, HbrVertex<T>* vertex);
|
||||
virtual void GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
|
||||
virtual void GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
|
||||
|
||||
virtual bool HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face);
|
||||
virtual bool HasLimit(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
|
||||
virtual bool HasLimit(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
|
||||
|
||||
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face);
|
||||
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
|
||||
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
|
||||
|
||||
virtual bool VertexIsExtraordinary(HbrMesh<T> const * /* mesh */, HbrVertex<T>* vertex) { return vertex->GetValence() != 6; }
|
||||
virtual bool FaceIsExtraordinary(HbrMesh<T> const * /* mesh */, HbrFace<T>* face) { return face->GetNumVertices() != 3; }
|
||||
|
||||
virtual int GetFaceChildrenCount(int /* nvertices */) const { return 4; }
|
||||
|
||||
private:
|
||||
|
||||
// Transfers facevarying data from a parent face to a child face
|
||||
void transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, HbrFace<T>* child, int index);
|
||||
|
||||
// Transfers vertex and edge edits from a parent face to a child face
|
||||
void transferEditsToChild(HbrFace<T>* face, HbrFace<T>* child, int index);
|
||||
|
||||
// Generates the fourth child of a triangle: the triangle in the
|
||||
// middle whose vertices have parents which are all edges
|
||||
void refineFaceAtMiddle(HbrMesh<T>* mesh, HbrFace<T>* face);
|
||||
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, HbrFace<T>* child, int index) {
|
||||
typename HbrMesh<T>::InterpolateBoundaryMethod fvarinterp = mesh->GetFVarInterpolateBoundaryMethod();
|
||||
HbrVertex<T>* childVertex;
|
||||
|
||||
// In the case of index == 3, this is the middle face, and so
|
||||
// we need to do three edge subdivision rules
|
||||
if (index == 3) {
|
||||
const int fvarcount = mesh->GetFVarCount();
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
HbrHalfedge<T> *edge = face->GetEdge(i);
|
||||
GuaranteeNeighbor(mesh, edge);
|
||||
childVertex = child->GetVertex((i + 2) % 3);
|
||||
bool fvIsSmooth = !edge->IsFVarInfiniteSharpAnywhere();
|
||||
if (!fvIsSmooth) {
|
||||
childVertex->NewFVarData(child);
|
||||
}
|
||||
HbrFVarData<T>& fv = childVertex->GetFVarData(child);
|
||||
int fvarindex = 0;
|
||||
for (int fvaritem = 0; fvaritem < fvarcount; ++fvaritem) {
|
||||
const int fvarwidth = mesh->GetFVarWidths()[fvaritem];
|
||||
|
||||
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
|
||||
face->GetEdge(i)->GetFVarSharpness(fvaritem) || face->GetEdge(i)->IsBoundary()) {
|
||||
|
||||
// Sharp edge rule
|
||||
fv.SetWithWeight(face->GetFVarData(i), fvarindex, fvarwidth, 0.5f);
|
||||
fv.AddWithWeight(face->GetFVarData((i + 1) % 3), fvarindex, fvarwidth, 0.5f);
|
||||
} else if (!fvIsSmooth || !fv.IsInitialized()) {
|
||||
// Smooth edge subdivision. Add 0.375 of adjacent vertices
|
||||
fv.SetWithWeight(face->GetFVarData(i), fvarindex, fvarwidth, 0.375f);
|
||||
fv.AddWithWeight(face->GetFVarData((i + 1) % 3), fvarindex, fvarwidth, 0.375f);
|
||||
// Add 0.125 of opposite vertices
|
||||
fv.AddWithWeight(face->GetFVarData((i + 2) % 3), fvarindex, fvarwidth, 0.125f);
|
||||
HbrFace<T>* oppFace = face->GetEdge(i)->GetRightFace();
|
||||
for (int j = 0; j < oppFace->GetNumVertices(); ++j) {
|
||||
if (oppFace->GetVertex(j) == face->GetVertex(i)) {
|
||||
fv.AddWithWeight(oppFace->GetFVarData((j+1)%oppFace->GetNumVertices()), fvarindex, fvarwidth, 0.125f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fvarindex += fvarwidth;
|
||||
}
|
||||
fv.SetInitialized();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
HbrHalfedge<T>* edge;
|
||||
HbrVertex<T>* v = face->GetVertex(index);
|
||||
|
||||
// Otherwise we proceed with one vertex and two edge subdivision
|
||||
// applications. First the vertex subdivision rule. Analyze
|
||||
// whether the vertex is on the boundary and whether it's an
|
||||
// infinitely sharp corner. We determine the last by checking the
|
||||
// propagate corners flag on the mesh; if it's off, we check the
|
||||
// two edges of this face incident to that vertex and determining
|
||||
// whether they are facevarying boundary edges - this is analogous
|
||||
// to what goes on for the interpolateboundary tag (which when set
|
||||
// to EDGEANDCORNER marks vertices with a valence of two as being
|
||||
// sharp corners). If propagate corners is on, we check *all*
|
||||
// faces to see if two edges side by side are facevarying boundary
|
||||
// edges. The facevarying boundary check ignores geometric
|
||||
// sharpness, otherwise we may swim at geometric creases which
|
||||
// aren't actually discontinuous.
|
||||
//
|
||||
// We need to make sure that that each of the vertices of the
|
||||
// child face have the appropriate facevarying storage as
|
||||
// needed. If there are discontinuities in any facevarying datum,
|
||||
// the vertex must allocate a new block of facevarying storage
|
||||
// specific to the child face.
|
||||
|
||||
v->GuaranteeNeighbors();
|
||||
|
||||
|
||||
bool fv0IsSmooth, fv1IsSmooth, fv2IsSmooth;
|
||||
|
||||
childVertex = child->GetVertex(index);
|
||||
fv0IsSmooth = v->IsFVarAllSmooth();
|
||||
if (!fv0IsSmooth) {
|
||||
childVertex->NewFVarData(child);
|
||||
}
|
||||
HbrFVarData<T>& fv0 = childVertex->GetFVarData(child);
|
||||
|
||||
edge = face->GetEdge(index);
|
||||
GuaranteeNeighbor(mesh, edge);
|
||||
assert(edge->GetOrgVertex() == v);
|
||||
childVertex = child->GetVertex((index + 1) % 3);
|
||||
fv1IsSmooth = !edge->IsFVarInfiniteSharpAnywhere();
|
||||
if (!fv1IsSmooth) {
|
||||
childVertex->NewFVarData(child);
|
||||
}
|
||||
HbrFVarData<T>& fv1 = childVertex->GetFVarData(child);
|
||||
|
||||
edge = edge->GetPrev();
|
||||
GuaranteeNeighbor(mesh, edge);
|
||||
assert(edge == face->GetEdge((index + 2) % 3));
|
||||
assert(edge->GetDestVertex() == v);
|
||||
childVertex = child->GetVertex((index + 2) % 3);
|
||||
fv2IsSmooth = !edge->IsFVarInfiniteSharpAnywhere();
|
||||
if (!fv2IsSmooth) {
|
||||
childVertex->NewFVarData(child);
|
||||
}
|
||||
HbrFVarData<T>& fv2 = childVertex->GetFVarData(child);
|
||||
|
||||
const int fvarcount = mesh->GetFVarCount();
|
||||
int fvarindex = 0;
|
||||
for (int fvaritem = 0; fvaritem < fvarcount; ++fvaritem) {
|
||||
bool infcorner = false;
|
||||
const int fvarwidth = mesh->GetFVarWidths()[fvaritem];
|
||||
const char fvarmask = v->GetFVarMask(fvaritem);
|
||||
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryEdgeAndCorner) {
|
||||
if (fvarmask >= HbrVertex<T>::k_Corner) {
|
||||
infcorner = true;
|
||||
} else if (mesh->GetFVarPropagateCorners()) {
|
||||
if (v->IsFVarCorner(fvaritem)) {
|
||||
infcorner = true;
|
||||
}
|
||||
} else {
|
||||
if (face->GetEdge(index)->GetFVarSharpness(fvaritem, true) && face->GetEdge(index)->GetPrev()->GetFVarSharpness(fvaritem, true)) {
|
||||
infcorner = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Infinitely sharp vertex rule. Applied if the vertex is:
|
||||
// - undergoing no facevarying boundary interpolation;
|
||||
// - at a geometric crease, in either boundary interpolation case; or
|
||||
// - is an infinitely sharp facevarying vertex, in the EDGEANDCORNER case; or
|
||||
// - has a mask equal or greater than one, in the "always
|
||||
// sharp" interpolate boundary case
|
||||
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
|
||||
(fvarinterp == HbrMesh<T>::k_InterpolateBoundaryAlwaysSharp &&
|
||||
fvarmask >= 1) ||
|
||||
v->GetSharpness() > HbrVertex<T>::k_Smooth ||
|
||||
infcorner) {
|
||||
fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 1.0f);
|
||||
}
|
||||
// Dart rule: unlike geometric creases, because there's two
|
||||
// discontinuous values for the one incident edge, we use the
|
||||
// boundary rule and not the smooth rule
|
||||
else if (fvarmask == 1) {
|
||||
// Use 0.75 of the current vert
|
||||
fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.75f);
|
||||
|
||||
// 0.125 of "two adjacent edge vertices", which in actuality
|
||||
// are the facevarying values of the same vertex but on each
|
||||
// side of the single incident facevarying sharp edge
|
||||
HbrHalfedge<T>* start = v->GetIncidentEdge(), *edge, *nextedge;
|
||||
edge = start;
|
||||
while (edge) {
|
||||
if (edge->GetFVarSharpness(fvaritem)) {
|
||||
break;
|
||||
}
|
||||
nextedge = v->GetNextEdge(edge);
|
||||
if (nextedge == start) {
|
||||
assert(0); // we should have found it by now
|
||||
break;
|
||||
} else if (!nextedge) {
|
||||
// should never get into this case - if the vertex is
|
||||
// on a boundary, it can never be a facevarying dart
|
||||
// vertex
|
||||
assert(0);
|
||||
edge = edge->GetPrev();
|
||||
break;
|
||||
} else {
|
||||
edge = nextedge;
|
||||
}
|
||||
}
|
||||
HbrVertex<T>* w = edge->GetDestVertex();
|
||||
HbrFace<T>* bestface = edge->GetLeftFace();
|
||||
int j;
|
||||
for (j = 0; j < bestface->GetNumVertices(); ++j) {
|
||||
if (bestface->GetVertex(j) == w) break;
|
||||
}
|
||||
assert(j != bestface->GetNumVertices());
|
||||
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
|
||||
bestface = edge->GetRightFace();
|
||||
for (j = 0; j < bestface->GetNumVertices(); ++j) {
|
||||
if (bestface->GetVertex(j) == w) break;
|
||||
}
|
||||
assert(j != bestface->GetNumVertices());
|
||||
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
|
||||
}
|
||||
// Boundary vertex rule (can use FVarSmooth, which is equivalent
|
||||
// to checking that it's sharper than a dart)
|
||||
else if (fvarmask != 0) {
|
||||
|
||||
// Use 0.75 of the current vert
|
||||
fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.75f);
|
||||
|
||||
// Compute 0.125 of two adjacent edge vertices. However the
|
||||
// two adjacent edge vertices we use must be part of the
|
||||
// facevarying "boundary". To find the first edge we cycle
|
||||
// counterclockwise around the current vertex v and look for
|
||||
// the first boundary edge
|
||||
|
||||
HbrFace<T>* bestface = face;
|
||||
HbrHalfedge<T>* bestedge = face->GetEdge(index)->GetPrev();
|
||||
HbrHalfedge<T>* starte = bestedge->GetOpposite();
|
||||
HbrVertex<T>* w = 0;
|
||||
if (!starte) {
|
||||
w = face->GetEdge(index)->GetPrev()->GetOrgVertex();
|
||||
} else {
|
||||
HbrHalfedge<T>* e = starte, *next;
|
||||
assert(starte->GetOrgVertex() == v);
|
||||
do {
|
||||
if (e->GetFVarSharpness(fvaritem) || !e->GetLeftFace()) {
|
||||
bestface = e->GetRightFace();
|
||||
bestedge = e;
|
||||
break;
|
||||
}
|
||||
next = v->GetNextEdge(e);
|
||||
if (!next) {
|
||||
bestface = e->GetLeftFace();
|
||||
w = e->GetPrev()->GetOrgVertex();
|
||||
break;
|
||||
}
|
||||
e = next;
|
||||
} while (e && e != starte);
|
||||
}
|
||||
if (!w) w = bestedge->GetDestVertex();
|
||||
int j;
|
||||
for (j = 0; j < bestface->GetNumVertices(); ++j) {
|
||||
if (bestface->GetVertex(j) == w) break;
|
||||
}
|
||||
assert(j != bestface->GetNumVertices());
|
||||
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
|
||||
|
||||
// Look for the other edge by cycling clockwise around v
|
||||
bestface = face;
|
||||
bestedge = face->GetEdge(index);
|
||||
starte = bestedge;
|
||||
w = 0;
|
||||
if (HbrHalfedge<T>* e = starte) {
|
||||
assert(starte->GetOrgVertex() == v);
|
||||
do {
|
||||
if (e->GetFVarSharpness(fvaritem) || !e->GetRightFace()) {
|
||||
bestface = e->GetLeftFace();
|
||||
bestedge = e;
|
||||
break;
|
||||
}
|
||||
assert(e->GetOpposite());
|
||||
e = v->GetPreviousEdge(e);
|
||||
} while (e && e != starte);
|
||||
}
|
||||
if (!w) w = bestedge->GetDestVertex();
|
||||
for (j = 0; j < bestface->GetNumVertices(); ++j) {
|
||||
if (bestface->GetVertex(j) == w) break;
|
||||
}
|
||||
assert(j != bestface->GetNumVertices());
|
||||
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
|
||||
|
||||
}
|
||||
// Smooth rule
|
||||
else if (!fv0IsSmooth || !fv0.IsInitialized()) {
|
||||
int valence = v->GetValence();
|
||||
float invvalence = 1.0f / valence;
|
||||
float beta = 0.25f * cosf((float)M_PI * 2.0f * invvalence) + 0.375f;
|
||||
beta = beta * beta;
|
||||
beta = (0.625f - beta) * invvalence;
|
||||
|
||||
// Use 1 - beta * valence of the current vertex value
|
||||
fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 1 - (beta * valence));
|
||||
|
||||
// Add beta of surrounding vertices averages. We loop over all
|
||||
// surrounding faces..
|
||||
HbrHalfedge<T>* start = v->GetIncidentEdge(), *edge;
|
||||
edge = start;
|
||||
while (edge) {
|
||||
HbrFace<T>* g = edge->GetLeftFace();
|
||||
|
||||
// .. and look for the edge on that face whose origin is
|
||||
// the same as v, and add a contribution from its
|
||||
// destination vertex value; this takes care of the
|
||||
// surrounding edge vertex addition.
|
||||
for (int j = 0; j < g->GetNumVertices(); ++j) {
|
||||
if (g->GetEdge(j)->GetOrgVertex() == v) {
|
||||
fv0.AddWithWeight(g->GetFVarData((j + 1) % g->GetNumVertices()), fvarindex, fvarwidth, beta);
|
||||
break;
|
||||
}
|
||||
}
|
||||
edge = v->GetNextEdge(edge);
|
||||
if (edge == start) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Edge subdivision rule
|
||||
HbrHalfedge<T>* edge = face->GetEdge(index);
|
||||
|
||||
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
|
||||
edge->GetFVarSharpness(fvaritem) || edge->IsBoundary()) {
|
||||
|
||||
// Sharp edge rule
|
||||
fv1.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.5f);
|
||||
fv1.AddWithWeight(face->GetFVarData((index + 1) % 3), fvarindex, fvarwidth, 0.5f);
|
||||
} else if (!fv1IsSmooth || !fv1.IsInitialized()) {
|
||||
// Smooth edge subdivision. Add 0.375 of adjacent vertices
|
||||
fv1.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.375f);
|
||||
fv1.AddWithWeight(face->GetFVarData((index + 1) % 3), fvarindex, fvarwidth, 0.375f);
|
||||
// Add 0.125 of opposite vertices
|
||||
fv1.AddWithWeight(face->GetFVarData((index + 2) % 3), fvarindex, fvarwidth, 0.125f);
|
||||
HbrFace<T>* oppFace = edge->GetRightFace();
|
||||
for (int j = 0; j < oppFace->GetNumVertices(); ++j) {
|
||||
if (oppFace->GetVertex(j) == v) {
|
||||
fv1.AddWithWeight(oppFace->GetFVarData((j+1)%oppFace->GetNumVertices()), fvarindex, fvarwidth, 0.125f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Edge subdivision rule
|
||||
edge = edge->GetPrev();
|
||||
|
||||
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
|
||||
edge->GetFVarSharpness(fvaritem) || edge->IsBoundary()) {
|
||||
|
||||
// Sharp edge rule
|
||||
fv2.SetWithWeight(face->GetFVarData((index + 2) % 3), fvarindex, fvarwidth, 0.5f);
|
||||
fv2.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.5f);
|
||||
} else if (!fv2IsSmooth || !fv2.IsInitialized()) {
|
||||
// Smooth edge subdivision. Add 0.375 of adjacent vertices
|
||||
fv2.SetWithWeight(face->GetFVarData((index + 2) % 3), fvarindex, fvarwidth, 0.375f);
|
||||
fv2.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.375f);
|
||||
// Add 0.125 of opposite vertices
|
||||
fv2.AddWithWeight(face->GetFVarData((index + 1) % 3), fvarindex, fvarwidth, 0.125f);
|
||||
|
||||
HbrFace<T>* oppFace = edge->GetRightFace();
|
||||
for (int j = 0; j < oppFace->GetNumVertices(); ++j) {
|
||||
if (oppFace->GetVertex(j) == v) {
|
||||
fv2.AddWithWeight(oppFace->GetFVarData((j+2)%oppFace->GetNumVertices()), fvarindex, fvarwidth, 0.125f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fvarindex += fvarwidth;
|
||||
}
|
||||
fv0.SetInitialized();
|
||||
fv1.SetInitialized();
|
||||
fv2.SetInitialized();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrLoopSubdivision<T>::transferEditsToChild(HbrFace<T>* face, HbrFace<T>* child, int index) {
|
||||
|
||||
// Hand down hole tag
|
||||
child->SetHole(face->IsHole());
|
||||
|
||||
// Hand down pointers to hierarchical edits
|
||||
if (HbrHierarchicalEdit<T>** edits = face->GetHierarchicalEdits()) {
|
||||
while (HbrHierarchicalEdit<T>* edit = *edits) {
|
||||
if (!edit->IsRelevantToFace(face)) break;
|
||||
if (edit->GetNSubfaces() > face->GetDepth() &&
|
||||
(edit->GetSubface(face->GetDepth()) == index)) {
|
||||
child->SetHierarchicalEdits(edits);
|
||||
break;
|
||||
}
|
||||
edits++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrLoopSubdivision<T>::Refine(HbrMesh<T>* mesh, HbrFace<T>* face) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "\n\nRefining face " << *face << "\n";
|
||||
#endif
|
||||
|
||||
assert(face->GetNumVertices() == 3); // or triangulate it?
|
||||
|
||||
HbrHalfedge<T>* edge = face->GetFirstEdge();
|
||||
HbrHalfedge<T>* prevedge = edge->GetPrev();
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
HbrVertex<T>* vertex = edge->GetOrgVertex();
|
||||
if (!face->GetChild(i)) {
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Kid " << i << "\n";
|
||||
#endif
|
||||
HbrFace<T>* child;
|
||||
HbrVertex<T>* vertices[3];
|
||||
|
||||
vertices[i] = vertex->Subdivide();
|
||||
vertices[(i + 1) % 3] = edge->Subdivide();
|
||||
vertices[(i + 2) % 3] = prevedge->Subdivide();
|
||||
child = mesh->NewFace(3, vertices, face, i);
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Creating face " << *child << " during refine\n";
|
||||
#endif
|
||||
|
||||
// Hand down edge sharpness
|
||||
float sharpness;
|
||||
HbrHalfedge<T>* childedge;
|
||||
|
||||
childedge = child->GetEdge(i);
|
||||
if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
|
||||
HbrSubdivision<T>::SubdivideCreaseWeight(
|
||||
edge, edge->GetOrgVertex(), childedge);
|
||||
}
|
||||
childedge->CopyFVarInfiniteSharpness(edge);
|
||||
|
||||
childedge = child->GetEdge((i+2)%3);
|
||||
if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
|
||||
HbrSubdivision<T>::SubdivideCreaseWeight(
|
||||
prevedge, prevedge->GetDestVertex(), childedge);
|
||||
}
|
||||
childedge->CopyFVarInfiniteSharpness(prevedge);
|
||||
|
||||
if (mesh->GetTotalFVarWidth()) {
|
||||
transferFVarToChild(mesh, face, child, i);
|
||||
}
|
||||
|
||||
transferEditsToChild(face, child, i);
|
||||
|
||||
}
|
||||
prevedge = edge;
|
||||
edge = edge->GetNext();
|
||||
}
|
||||
|
||||
refineFaceAtMiddle(mesh, face);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrFace<T>*
|
||||
HbrLoopSubdivision<T>::RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, HbrVertex<T>* vertex) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << " forcing refine on " << *face << " at " << *vertex << '\n';
|
||||
#endif
|
||||
HbrHalfedge<T>* edge = face->GetFirstEdge();
|
||||
HbrHalfedge<T>* prevedge = edge->GetPrev();
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (edge->GetOrgVertex() == vertex) {
|
||||
if (!face->GetChild(i)) {
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Kid " << i << "\n";
|
||||
#endif
|
||||
HbrFace<T>* child;
|
||||
HbrVertex<T>* vertices[3];
|
||||
|
||||
vertices[i] = vertex->Subdivide();
|
||||
vertices[(i + 1) % 3] = edge->Subdivide();
|
||||
vertices[(i + 2) % 3] = prevedge->Subdivide();
|
||||
child = mesh->NewFace(3, vertices, face, i);
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Creating face " << *child << " during refine\n";
|
||||
#endif
|
||||
|
||||
// Hand down edge sharpness
|
||||
float sharpness;
|
||||
HbrHalfedge<T>* childedge;
|
||||
|
||||
childedge = child->GetEdge(i);
|
||||
if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
|
||||
HbrSubdivision<T>::SubdivideCreaseWeight(
|
||||
edge, edge->GetOrgVertex(), childedge);
|
||||
}
|
||||
childedge->CopyFVarInfiniteSharpness(edge);
|
||||
|
||||
childedge = child->GetEdge((i+2)%3);
|
||||
if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
|
||||
HbrSubdivision<T>::SubdivideCreaseWeight(
|
||||
prevedge, prevedge->GetDestVertex(), childedge);
|
||||
}
|
||||
childedge->CopyFVarInfiniteSharpness(prevedge);
|
||||
|
||||
if (mesh->GetTotalFVarWidth()) {
|
||||
transferFVarToChild(mesh, face, child, i);
|
||||
}
|
||||
|
||||
transferEditsToChild(face, child, i);
|
||||
|
||||
return child;
|
||||
} else {
|
||||
return face->GetChild(i);
|
||||
}
|
||||
}
|
||||
prevedge = edge;
|
||||
edge = edge->GetNext();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrLoopSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
|
||||
if (edge->GetOpposite()) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "\n\nneighbor guarantee at " << *edge << " invoked\n";
|
||||
#endif
|
||||
|
||||
/*
|
||||
Imagine the following:
|
||||
|
||||
X
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
X \
|
||||
/\ \
|
||||
2/ \3 \
|
||||
/ \ \
|
||||
X------X--------X
|
||||
1
|
||||
|
||||
If the parent of _both_ incident vertices are themselves edges,
|
||||
(like the edge marked 3 above), then this edge is in the center
|
||||
of the parent face. Refining the parent face in the middle or
|
||||
refining the parent face at one vertex (where the two parent
|
||||
edges meet) should suffice
|
||||
*/
|
||||
HbrHalfedge<T>* parentEdge1 = edge->GetOrgVertex()->GetParentEdge();
|
||||
HbrHalfedge<T>* parentEdge2 = edge->GetDestVertex()->GetParentEdge();
|
||||
if (parentEdge1 && parentEdge2) {
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "two parent edge situation\n";
|
||||
#endif
|
||||
HbrFace<T>* parentFace = parentEdge1->GetFace();
|
||||
assert(parentFace == parentEdge2->GetFace());
|
||||
if(parentEdge1->GetOrgVertex() == parentEdge2->GetDestVertex()) {
|
||||
refineFaceAtMiddle(mesh, parentFace);
|
||||
} else {
|
||||
RefineFaceAtVertex(mesh, parentFace, parentEdge1->GetOrgVertex());
|
||||
}
|
||||
assert(edge->GetOpposite());
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise we're in the situation of edge 1 or edge 2 in the
|
||||
// diagram above.
|
||||
if (parentEdge1) {
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "parent edge 1 " << *parentEdge1 << "\n";
|
||||
#endif
|
||||
HbrVertex<T>* parentVertex2 = edge->GetDestVertex()->GetParentVertex();
|
||||
assert(parentVertex2);
|
||||
RefineFaceAtVertex(mesh, parentEdge1->GetLeftFace(), parentVertex2);
|
||||
if (parentEdge1->GetRightFace()) {
|
||||
RefineFaceAtVertex(mesh, parentEdge1->GetRightFace(), parentVertex2);
|
||||
}
|
||||
} else if (parentEdge2) {
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "parent edge 2 " << *parentEdge2 << "\n";
|
||||
#endif
|
||||
HbrVertex<T>* parentVertex1 = edge->GetOrgVertex()->GetParentVertex();
|
||||
assert(parentVertex1);
|
||||
RefineFaceAtVertex(mesh, parentEdge2->GetLeftFace(), parentVertex1);
|
||||
if (parentEdge2->GetRightFace()) {
|
||||
RefineFaceAtVertex(mesh, parentEdge2->GetRightFace(), parentVertex1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrLoopSubdivision<T>::GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "\n\nneighbor guarantee at " << *vertex << " invoked\n";
|
||||
#endif
|
||||
|
||||
assert(vertex->GetParentFace() == 0);
|
||||
|
||||
// The first case: the vertex is a child of an edge. Make sure
|
||||
// that the parent faces on either side of the parent edge exist,
|
||||
// and have 1) refined at both vertices of the parent edge, and 2)
|
||||
// have refined their "middle" face (which doesn't live at either
|
||||
// vertex).
|
||||
|
||||
HbrHalfedge<T>* parentEdge = vertex->GetParentEdge();
|
||||
if (parentEdge) {
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "parent edge situation " << *parentEdge << "\n";
|
||||
#endif
|
||||
HbrVertex<T>* dest = parentEdge->GetDestVertex();
|
||||
HbrVertex<T>* org = parentEdge->GetOrgVertex();
|
||||
GuaranteeNeighbor(mesh, parentEdge);
|
||||
HbrFace<T>* parentFace = parentEdge->GetLeftFace();
|
||||
RefineFaceAtVertex(mesh, parentFace, dest);
|
||||
RefineFaceAtVertex(mesh, parentFace, org);
|
||||
refineFaceAtMiddle(mesh, parentFace);
|
||||
parentFace = parentEdge->GetRightFace();
|
||||
// The right face may not necessarily exist even after
|
||||
// GuaranteeNeighbor
|
||||
if (parentFace) {
|
||||
RefineFaceAtVertex(mesh, parentFace, dest);
|
||||
RefineFaceAtVertex(mesh, parentFace, org);
|
||||
refineFaceAtMiddle(mesh, parentFace);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// The second case: the vertex is a child of a vertex. In this case
|
||||
// we have to recursively guarantee that the parent's adjacent
|
||||
// faces also exist.
|
||||
HbrVertex<T>* parentVertex = vertex->GetParentVertex();
|
||||
if (parentVertex) {
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "parent vertex situation " << *parentVertex << "\n";
|
||||
#endif
|
||||
parentVertex->GuaranteeNeighbors();
|
||||
|
||||
// And then we refine all the face neighbors of the parent
|
||||
// vertex
|
||||
HbrHalfedge<T>* start = parentVertex->GetIncidentEdge(), *edge;
|
||||
edge = start;
|
||||
while (edge) {
|
||||
HbrFace<T>* f = edge->GetLeftFace();
|
||||
RefineFaceAtVertex(mesh, f, parentVertex);
|
||||
edge = parentVertex->GetNextEdge(edge);
|
||||
if (edge == start) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
HbrLoopSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face) {
|
||||
|
||||
if (face->IsHole()) return false;
|
||||
// A limit face exists if all the bounding edges have limit curves
|
||||
for (int i = 0; i < face->GetNumVertices(); ++i) {
|
||||
if (!HasLimit(mesh, face->GetEdge(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
HbrLoopSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
|
||||
// A sharp edge has a limit curve if both endpoints have limits.
|
||||
// A smooth edge has a limit if both endpoints have limits and
|
||||
// the edge isn't on the boundary.
|
||||
|
||||
if (edge->GetSharpness() >= HbrHalfedge<T>::k_InfinitelySharp) return true;
|
||||
|
||||
if (!HasLimit(mesh, edge->GetOrgVertex()) || !HasLimit(mesh, edge->GetDestVertex())) return false;
|
||||
|
||||
return !edge->IsBoundary();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
HbrLoopSubdivision<T>::HasLimit(HbrMesh<T>* /* mesh */, HbrVertex<T>* vertex) {
|
||||
vertex->GuaranteeNeighbors();
|
||||
switch (vertex->GetMask(false)) {
|
||||
case HbrVertex<T>::k_Smooth:
|
||||
case HbrVertex<T>::k_Dart:
|
||||
return !vertex->OnBoundary();
|
||||
break;
|
||||
case HbrVertex<T>::k_Crease:
|
||||
case HbrVertex<T>::k_Corner:
|
||||
default:
|
||||
if (vertex->IsVolatile()) {
|
||||
// Search for any incident semisharp boundary edge
|
||||
HbrHalfedge<T>* start = vertex->GetIncidentEdge(), *edge, *next;
|
||||
edge = start;
|
||||
while (edge) {
|
||||
if (edge->IsBoundary() && edge->GetSharpness() < HbrHalfedge<T>::k_InfinitelySharp) {
|
||||
return false;
|
||||
}
|
||||
next = vertex->GetNextEdge(edge);
|
||||
if (next == start) {
|
||||
break;
|
||||
} else if (!next) {
|
||||
edge = edge->GetPrev();
|
||||
if (edge->IsBoundary() && edge->GetSharpness() < HbrHalfedge<T>::k_InfinitelySharp) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
edge = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrVertex<T>*
|
||||
HbrLoopSubdivision<T>::Subdivide(HbrMesh<T>* /* mesh */, HbrFace<T>* /* face */) {
|
||||
// In loop subdivision, faces never subdivide
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrVertex<T>*
|
||||
HbrLoopSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Subdividing at " << *edge << "\n";
|
||||
#endif
|
||||
// Ensure the opposite face exists.
|
||||
GuaranteeNeighbor(mesh, edge);
|
||||
|
||||
float esharp = edge->GetSharpness();
|
||||
HbrVertex<T>* v = mesh->NewVertex();
|
||||
T& data = v->GetData();
|
||||
|
||||
// If there's the possibility of vertex edits on either vertex, we
|
||||
// have to make sure the edit has been applied
|
||||
if (mesh->HasVertexEdits()) {
|
||||
edge->GetOrgVertex()->GuaranteeNeighbors();
|
||||
edge->GetDestVertex()->GuaranteeNeighbors();
|
||||
}
|
||||
|
||||
if (!edge->IsBoundary() && esharp <= 1.0f) {
|
||||
|
||||
// Of the two half-edges, pick one of them consistently such
|
||||
// that the org and dest vertices are also consistent through
|
||||
// multi-threading. It doesn't matter as far as the
|
||||
// theoretical calculation is concerned, but it is desirable
|
||||
// to be consistent about it in the face of the limitations of
|
||||
// floating point commutativity. So we always pick the
|
||||
// half-edge such that its incident face is the smallest of
|
||||
// the two faces, as far as the face paths are concerned.
|
||||
if (edge->GetOpposite() && edge->GetOpposite()->GetFace()->GetPath() < edge->GetFace()->GetPath()) {
|
||||
edge = edge->GetOpposite();
|
||||
}
|
||||
|
||||
// Handle both the smooth and fractional sharpness cases. We
|
||||
// lerp between the sharp case (average of the two end points)
|
||||
// and the unsharp case (3/8 of each of the two end points
|
||||
// plus 1/8 of the two opposite face averages).
|
||||
|
||||
// Lerp end point weight between non sharp contribution of
|
||||
// 3/8 and the sharp contribution of 0.5.
|
||||
float endPtWeight = 0.375f + esharp * (0.5f - 0.375f);
|
||||
data.AddWithWeight(edge->GetOrgVertex()->GetData(), endPtWeight);
|
||||
data.AddWithWeight(edge->GetDestVertex()->GetData(), endPtWeight);
|
||||
|
||||
// Lerp the opposite pt weights between non sharp contribution
|
||||
// of 1/8 and the sharp contribution of 0.
|
||||
float oppPtWeight = 0.125f * (1 - esharp);
|
||||
HbrHalfedge<T>* ee = edge->GetNext();
|
||||
data.AddWithWeight(ee->GetDestVertex()->GetData(), oppPtWeight);
|
||||
ee = edge->GetOpposite()->GetNext();
|
||||
data.AddWithWeight(ee->GetDestVertex()->GetData(), oppPtWeight);
|
||||
} else {
|
||||
// Fully sharp edge, just average the two end points
|
||||
data.AddWithWeight(edge->GetOrgVertex()->GetData(), 0.5f);
|
||||
data.AddWithWeight(edge->GetDestVertex()->GetData(), 0.5f);
|
||||
}
|
||||
|
||||
// Varying data is always the average of two end points
|
||||
data.AddVaryingWithWeight(edge->GetOrgVertex()->GetData(), 0.5f);
|
||||
data.AddVaryingWithWeight(edge->GetDestVertex()->GetData(), 0.5f);
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << " created " << *v << "\n";
|
||||
#endif
|
||||
|
||||
// Only boundary edges will create extraordinary vertices
|
||||
if (edge->IsBoundary()) {
|
||||
v->SetExtraordinary();
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrVertex<T>*
|
||||
HbrLoopSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
|
||||
|
||||
// Ensure the ring of faces around this vertex exists before
|
||||
// we compute the valence
|
||||
vertex->GuaranteeNeighbors();
|
||||
|
||||
float valence = static_cast<float>(vertex->GetValence());
|
||||
float invvalence = 1.0f / valence;
|
||||
|
||||
HbrVertex<T>* v = mesh->NewVertex();
|
||||
T& data = v->GetData();
|
||||
|
||||
// Due to fractional weights we may need to do two subdivision
|
||||
// passes
|
||||
int masks[2];
|
||||
float weights[2];
|
||||
int passes;
|
||||
masks[0] = vertex->GetMask(false);
|
||||
masks[1] = vertex->GetMask(true);
|
||||
// If the masks are different, we subdivide twice: once using the
|
||||
// current mask, once using the mask at the next level of
|
||||
// subdivision, then use fractional mask weights to weigh
|
||||
// each weighing
|
||||
if (masks[0] != masks[1]) {
|
||||
weights[1] = vertex->GetFractionalMask();
|
||||
weights[0] = 1.0f - weights[1];
|
||||
passes = 2;
|
||||
} else {
|
||||
weights[0] = 1.0f;
|
||||
weights[1] = 0.0f;
|
||||
passes = 1;
|
||||
}
|
||||
for (int i = 0; i < passes; ++i) {
|
||||
switch (masks[i]) {
|
||||
case HbrVertex<T>::k_Smooth:
|
||||
case HbrVertex<T>::k_Dart: {
|
||||
float beta = 0.25f * cosf((float)M_PI * 2.0f * invvalence) + 0.375f;
|
||||
beta = beta * beta;
|
||||
beta = (0.625f - beta) * invvalence;
|
||||
|
||||
data.AddWithWeight(vertex->GetData(), weights[i] * (1 - (beta * valence)));
|
||||
|
||||
HbrSubdivision<T>::AddSurroundingVerticesWithWeight(
|
||||
mesh, vertex, weights[i] * beta, &data);
|
||||
break;
|
||||
}
|
||||
case HbrVertex<T>::k_Crease: {
|
||||
// Compute 3/4 of old vertex value
|
||||
data.AddWithWeight(vertex->GetData(), weights[i] * 0.75f);
|
||||
|
||||
// Add 0.125f of the (hopefully only two!) neighbouring
|
||||
// sharp edges
|
||||
HbrSubdivision<T>::AddCreaseEdgesWithWeight(
|
||||
mesh, vertex, i == 1, weights[i] * 0.125f, &data);
|
||||
break;
|
||||
}
|
||||
case HbrVertex<T>::k_Corner:
|
||||
default: {
|
||||
// Just copy the old value
|
||||
data.AddWithWeight(vertex->GetData(), weights[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Varying data is always just propagated down
|
||||
data.AddVaryingWithWeight(vertex->GetData(), 1.0f);
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Subdividing at " << *vertex << "\n";
|
||||
std::cerr << " created " << *v << "\n";
|
||||
#endif
|
||||
// Inherit extraordinary flag and sharpness
|
||||
if (vertex->IsExtraordinary()) v->SetExtraordinary();
|
||||
float sharp = vertex->GetSharpness();
|
||||
if (sharp >= HbrVertex<T>::k_InfinitelySharp) {
|
||||
v->SetSharpness(HbrVertex<T>::k_InfinitelySharp);
|
||||
} else if (sharp > HbrVertex<T>::k_Smooth) {
|
||||
v->SetSharpness(std::max((float) HbrVertex<T>::k_Smooth, sharp - 1.0f));
|
||||
} else {
|
||||
v->SetSharpness(HbrVertex<T>::k_Smooth);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrLoopSubdivision<T>::refineFaceAtMiddle(HbrMesh<T>* mesh, HbrFace<T>* face) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Refining middle face of " << *face << "\n";
|
||||
#endif
|
||||
|
||||
if (!face->GetChild(3)) {
|
||||
HbrFace<T>* child;
|
||||
HbrVertex<T>* vertices[3];
|
||||
|
||||
// The fourth face is not an obvious child of any vertex. We
|
||||
// assign it index 3 despite there being no fourth vertex in
|
||||
// the triangle. The ordering of vertices here is done to
|
||||
// preserve parametric space as best we can
|
||||
vertices[0] = face->GetEdge(1)->Subdivide();
|
||||
vertices[1] = face->GetEdge(2)->Subdivide();
|
||||
vertices[2] = face->GetEdge(0)->Subdivide();
|
||||
child = mesh->NewFace(3, vertices, face, 3);
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Creating face " << *child << "\n";
|
||||
#endif
|
||||
if (mesh->GetTotalFVarWidth()) {
|
||||
transferFVarToChild(mesh, face, child, 3);
|
||||
}
|
||||
|
||||
transferEditsToChild(face, child, 3);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRLOOP_H */
|
||||
995
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/mesh.h
vendored
Normal file
995
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/mesh.h
vendored
Normal file
@@ -0,0 +1,995 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRMESH_H
|
||||
#define OPENSUBDIV3_HBRMESH_H
|
||||
|
||||
#ifdef PRMAN
|
||||
#include "libtarget/TgMalloc.h" // only for alloca
|
||||
#include "libtarget/TgThread.h"
|
||||
#ifdef HBRSTITCH
|
||||
#include "libtarget/TgHashMap.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
|
||||
#include "../hbr/vertex.h"
|
||||
#include "../hbr/face.h"
|
||||
#include "../hbr/hierarchicalEdit.h"
|
||||
#include "../hbr/vertexEdit.h"
|
||||
#include "../hbr/creaseEdit.h"
|
||||
#include "../hbr/allocator.h"
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrSubdivision;
|
||||
template <class T> class HbrHalfedge;
|
||||
|
||||
template <class T> class HbrMesh {
|
||||
public:
|
||||
HbrMesh(HbrSubdivision<T>* subdivision = 0, int fvarcount = 0, const int *fvarindices = 0, const int *fvarwidths = 0, int totalfvarwidth = 0
|
||||
#ifdef HBRSTITCH
|
||||
, int stitchCount = 0
|
||||
#endif
|
||||
);
|
||||
~HbrMesh();
|
||||
|
||||
// Create vertex with the indicated ID and data
|
||||
HbrVertex<T>* NewVertex(int id, const T &data);
|
||||
|
||||
// Create vertex with the indicated data. The ID will be assigned
|
||||
// by the mesh.
|
||||
HbrVertex<T>* NewVertex(const T &data);
|
||||
|
||||
// Create vertex without an ID - one will be assigned by the mesh,
|
||||
// and the data implicitly created will share the same id
|
||||
HbrVertex<T>* NewVertex();
|
||||
|
||||
// Ask for vertex with the indicated ID
|
||||
HbrVertex<T>* GetVertex(int id) const {
|
||||
if (id >= nvertices) {
|
||||
return 0;
|
||||
} else {
|
||||
return vertices[id];
|
||||
}
|
||||
}
|
||||
|
||||
// Ask for client data associated with the vertex with the indicated ID
|
||||
void* GetVertexClientData(int id) const {
|
||||
if (id >= vertexClientData.size()) {
|
||||
return 0;
|
||||
} else {
|
||||
return vertexClientData[id];
|
||||
}
|
||||
}
|
||||
|
||||
// Set client data associated with the vertex with the indicated ID
|
||||
void SetVertexClientData(int id, void *data) {
|
||||
if (id >= vertexClientData.size()) {
|
||||
size_t oldsize = vertexClientData.size();
|
||||
vertexClientData.resize(nvertices);
|
||||
if (s_memStatsIncrement) {
|
||||
s_memStatsIncrement((vertexClientData.size() - oldsize) * sizeof(void*));
|
||||
}
|
||||
}
|
||||
vertexClientData[id] = data;
|
||||
}
|
||||
|
||||
// Create face from a list of vertex IDs
|
||||
HbrFace<T>* NewFace(int nvertices, const int *vtx, int uindex);
|
||||
|
||||
// Create face from a list of vertices
|
||||
HbrFace<T>* NewFace(int nvertices, HbrVertex<T>** vtx, HbrFace<T>* parent, int childindex);
|
||||
|
||||
// "Create" a new uniform index
|
||||
int NewUniformIndex() { return ++maxUniformIndex; }
|
||||
|
||||
// Finishes initialization of the mesh
|
||||
void Finish();
|
||||
|
||||
// Remove the indicated face from the mesh
|
||||
void DeleteFace(HbrFace<T>* face);
|
||||
|
||||
// Remove the indicated vertex from the mesh
|
||||
void DeleteVertex(HbrVertex<T>* vertex);
|
||||
|
||||
// Returns number of vertices in the mesh
|
||||
int GetNumVertices() const;
|
||||
|
||||
// Returns number of disconnected vertices in the mesh
|
||||
int GetNumDisconnectedVertices() const;
|
||||
|
||||
// Returns number of faces in the mesh
|
||||
int GetNumFaces() const;
|
||||
|
||||
// Returns number of coarse faces in the mesh
|
||||
int GetNumCoarseFaces() const;
|
||||
|
||||
// Ask for face with the indicated ID
|
||||
HbrFace<T>* GetFace(int id) const;
|
||||
|
||||
// Ask for client data associated with the face with the indicated ID
|
||||
void* GetFaceClientData(int id) const {
|
||||
if (id >= faceClientData.size()) {
|
||||
return 0;
|
||||
} else {
|
||||
return faceClientData[id];
|
||||
}
|
||||
}
|
||||
|
||||
// Set client data associated with the face with the indicated ID
|
||||
void SetFaceClientData(int id, void *data) {
|
||||
if (id >= faceClientData.size()) {
|
||||
size_t oldsize = faceClientData.size();
|
||||
faceClientData.resize(nfaces);
|
||||
if (s_memStatsIncrement) {
|
||||
s_memStatsIncrement((faceClientData.size() - oldsize) * sizeof(void*));
|
||||
}
|
||||
}
|
||||
faceClientData[id] = data;
|
||||
}
|
||||
|
||||
// Returns a collection of all vertices in the mesh. This function
|
||||
// requires an output iterator; to get the vertices into a
|
||||
// std::vector, use GetVertices(std::back_inserter(myvector))
|
||||
template <typename OutputIterator>
|
||||
void GetVertices(OutputIterator vertices) const;
|
||||
|
||||
// Applies operator to all vertices
|
||||
void ApplyOperatorAllVertices(HbrVertexOperator<T> &op) const;
|
||||
|
||||
// Returns a collection of all faces in the mesh. This function
|
||||
// requires an output iterator; to get the faces into a
|
||||
// std::vector, use GetFaces(std::back_inserter(myvector))
|
||||
template <typename OutputIterator>
|
||||
void GetFaces(OutputIterator faces) const;
|
||||
|
||||
// Returns the subdivision method
|
||||
HbrSubdivision<T>* GetSubdivision() const { return subdivision; }
|
||||
|
||||
// Return the number of facevarying variables
|
||||
int GetFVarCount() const { return fvarcount; }
|
||||
|
||||
// Return a table of the start index of each facevarying variable
|
||||
const int *GetFVarIndices() const { return fvarindices; }
|
||||
|
||||
// Return a table of the size of each facevarying variable
|
||||
const int *GetFVarWidths() const { return fvarwidths; }
|
||||
|
||||
// Return the sum size of facevarying variables per vertex
|
||||
int GetTotalFVarWidth() const { return totalfvarwidth; }
|
||||
|
||||
#ifdef HBRSTITCH
|
||||
int GetStitchCount() const { return stitchCount; }
|
||||
#endif
|
||||
|
||||
void PrintStats(std::ostream& out);
|
||||
|
||||
// Returns memory statistics
|
||||
size_t GetMemStats() const { return m_memory; }
|
||||
|
||||
// Interpolate boundary management
|
||||
enum InterpolateBoundaryMethod {
|
||||
k_InterpolateBoundaryNone,
|
||||
k_InterpolateBoundaryEdgeOnly,
|
||||
k_InterpolateBoundaryEdgeAndCorner,
|
||||
k_InterpolateBoundaryAlwaysSharp
|
||||
};
|
||||
|
||||
InterpolateBoundaryMethod GetInterpolateBoundaryMethod() const { return interpboundarymethod; }
|
||||
void SetInterpolateBoundaryMethod(InterpolateBoundaryMethod method) { interpboundarymethod = method; }
|
||||
InterpolateBoundaryMethod GetFVarInterpolateBoundaryMethod() const { return fvarinterpboundarymethod; }
|
||||
void SetFVarInterpolateBoundaryMethod(InterpolateBoundaryMethod method) { fvarinterpboundarymethod = method; }
|
||||
|
||||
bool GetFVarPropagateCorners() const { return fvarpropagatecorners; }
|
||||
void SetFVarPropagateCorners(bool p) { fvarpropagatecorners = p; }
|
||||
|
||||
// Register routines for keeping track of memory usage
|
||||
void RegisterMemoryRoutines(void (*increment)(unsigned long bytes), void (*decrement)(unsigned long bytes)) {
|
||||
m_faceAllocator.SetMemStatsIncrement(increment);
|
||||
m_faceAllocator.SetMemStatsDecrement(decrement);
|
||||
m_vertexAllocator.SetMemStatsIncrement(increment);
|
||||
m_vertexAllocator.SetMemStatsDecrement(decrement);
|
||||
s_memStatsIncrement = increment;
|
||||
s_memStatsDecrement = decrement;
|
||||
}
|
||||
|
||||
// Add a vertex to consider for garbage collection. All
|
||||
// neighboring faces of that vertex will be examined to see if
|
||||
// they can be deleted
|
||||
void AddGarbageCollectableVertex(HbrVertex<T>* vertex) {
|
||||
if (!m_transientMode) {
|
||||
assert(vertex);
|
||||
if (!vertex->IsCollected()) {
|
||||
gcVertices.push_back(vertex); vertex->SetCollected();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply garbage collection to the mesh
|
||||
void GarbageCollect();
|
||||
|
||||
// Add a new hierarchical edit to the mesh
|
||||
void AddHierarchicalEdit(HbrHierarchicalEdit<T>* edit);
|
||||
|
||||
// Return the hierarchical edits associated with the mesh
|
||||
const std::vector<HbrHierarchicalEdit<T>*> &GetHierarchicalEdits() const {
|
||||
return hierarchicalEdits;
|
||||
}
|
||||
|
||||
// Return the hierarchical edits associated with the mesh at an
|
||||
// offset
|
||||
HbrHierarchicalEdit<T>** GetHierarchicalEditsAtOffset(int offset) {
|
||||
return &hierarchicalEdits[offset];
|
||||
}
|
||||
|
||||
// Whether the mesh has certain types of edits
|
||||
bool HasVertexEdits() const { return hasVertexEdits; }
|
||||
bool HasCreaseEdits() const { return hasCreaseEdits; }
|
||||
|
||||
void Unrefine(int numCoarseVerts, int numCoarseFaces) {
|
||||
|
||||
for (int i = numCoarseFaces; i < maxFaceID; ++i) {
|
||||
HbrFace<T>* f = GetFace(i);
|
||||
if(f and not f->IsCoarse())
|
||||
DeleteFace(f);
|
||||
}
|
||||
|
||||
maxFaceID = numCoarseFaces;
|
||||
|
||||
for(int i=numCoarseVerts; i<(int)vertices.size(); ++i ) {
|
||||
HbrVertex<T>* v = GetVertex(i);
|
||||
if(v and not v->IsReferenced())
|
||||
DeleteVertex(v);
|
||||
}
|
||||
}
|
||||
|
||||
// When mode is true, the mesh is put in a "transient" mode,
|
||||
// i.e. all subsequent intermediate vertices/faces that are
|
||||
// created by subdivision are deemed temporary. This transient
|
||||
// data can be entirely freed by a subsequent call to
|
||||
// FreeTransientData(). Essentially, the mesh is checkpointed and
|
||||
// restored. This is useful when space is at a premium and
|
||||
// subdivided results are cached elsewhere. On the other hand,
|
||||
// repeatedly putting the mesh in and out of transient mode and
|
||||
// performing the same evaluations comes at a significant compute
|
||||
// cost.
|
||||
void SetTransientMode(bool mode) {
|
||||
m_transientMode = mode;
|
||||
}
|
||||
|
||||
// Frees transient subdivision data; returns the mesh to a
|
||||
// checkpointed state prior to a call to SetTransientMode.
|
||||
void FreeTransientData();
|
||||
|
||||
// Create new face children block for use by HbrFace
|
||||
HbrFaceChildren<T>* NewFaceChildren() {
|
||||
return m_faceChildrenAllocator.Allocate();
|
||||
}
|
||||
|
||||
// Recycle face children block used by HbrFace
|
||||
void DeleteFaceChildren(HbrFaceChildren<T>* facechildren) {
|
||||
m_faceChildrenAllocator.Deallocate(facechildren);
|
||||
}
|
||||
|
||||
#ifdef HBRSTITCH
|
||||
void * GetStitchData(const HbrHalfedge<T>* edge) const {
|
||||
typename TgHashMap<const HbrHalfedge<T>*, void *>::const_iterator i =
|
||||
stitchData.find(edge);
|
||||
if (i != stitchData.end()) {
|
||||
return i->second;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void SetStitchData(const HbrHalfedge<T>* edge, void *data) {
|
||||
stitchData[edge] = data;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
// Subdivision method used in this mesh
|
||||
HbrSubdivision<T>* subdivision;
|
||||
|
||||
// Number of facevarying datums
|
||||
int fvarcount;
|
||||
|
||||
// Start indices of the facevarying data we want to store
|
||||
const int *fvarindices;
|
||||
|
||||
// Individual widths of the facevarying data we want to store
|
||||
const int *fvarwidths;
|
||||
|
||||
// Total widths of the facevarying data
|
||||
const int totalfvarwidth;
|
||||
|
||||
#ifdef HBRSTITCH
|
||||
// Number of stitch edges per halfedge
|
||||
const int stitchCount;
|
||||
|
||||
// Client (sparse) data used on some halfedges
|
||||
TgHashMap<const HbrHalfedge<T>*, void *> stitchData;
|
||||
#endif
|
||||
|
||||
// Vertices which comprise this mesh
|
||||
std::vector<HbrVertex<T> *> vertices;
|
||||
int nvertices;
|
||||
|
||||
// Client data associated with each face
|
||||
std::vector<void *> vertexClientData;
|
||||
|
||||
// Faces which comprise this mesh
|
||||
std::vector<HbrFace<T> *> faces;
|
||||
int nfaces;
|
||||
|
||||
// Client data associated with each face
|
||||
std::vector<void *> faceClientData;
|
||||
|
||||
// Maximum vertex ID - may be needed when generating a unique
|
||||
// vertex ID
|
||||
int maxVertexID;
|
||||
|
||||
// Maximum face ID - needed when generating a unique face ID
|
||||
int maxFaceID;
|
||||
|
||||
// Maximum uniform index - needed to generate a new uniform index
|
||||
int maxUniformIndex;
|
||||
|
||||
// Boundary interpolation method
|
||||
InterpolateBoundaryMethod interpboundarymethod;
|
||||
|
||||
// Facevarying boundary interpolation method
|
||||
InterpolateBoundaryMethod fvarinterpboundarymethod;
|
||||
|
||||
// Whether facevarying corners propagate their sharpness
|
||||
bool fvarpropagatecorners;
|
||||
|
||||
// Memory statistics tracking routines
|
||||
HbrMemStatFunction s_memStatsIncrement;
|
||||
HbrMemStatFunction s_memStatsDecrement;
|
||||
|
||||
// Vertices which may be garbage collected
|
||||
std::vector<HbrVertex<T>*> gcVertices;
|
||||
|
||||
// List of vertex IDs which may be recycled
|
||||
std::set<int> recycleIDs;
|
||||
|
||||
// Hierarchical edits. This vector is left unsorted until Finish()
|
||||
// is called, at which point it is sorted. After that point,
|
||||
// HbrFaces have pointers directly into this array so manipulation
|
||||
// of it should be avoided.
|
||||
std::vector<HbrHierarchicalEdit<T>*> hierarchicalEdits;
|
||||
|
||||
// Size of faces (including 4 facevarying bits and stitch edges)
|
||||
const size_t m_faceSize;
|
||||
HbrAllocator<HbrFace<T> > m_faceAllocator;
|
||||
|
||||
// Size of vertices (includes storage for one piece of facevarying data)
|
||||
const size_t m_vertexSize;
|
||||
HbrAllocator<HbrVertex<T> > m_vertexAllocator;
|
||||
|
||||
// Allocator for face children blocks used by HbrFace
|
||||
HbrAllocator<HbrFaceChildren<T> > m_faceChildrenAllocator;
|
||||
|
||||
// Memory used by this mesh alone, plus all its faces and vertices
|
||||
size_t m_memory;
|
||||
|
||||
// Number of coarse faces. Initialized at Finish()
|
||||
int m_numCoarseFaces;
|
||||
|
||||
// Flags which indicate whether the mesh has certain types of
|
||||
// edits
|
||||
unsigned hasVertexEdits:1;
|
||||
unsigned hasCreaseEdits:1;
|
||||
|
||||
// True if the mesh is in "transient" mode, meaning all
|
||||
// vertices/faces that are created via NewVertex/NewFace should be
|
||||
// deemed temporary
|
||||
bool m_transientMode;
|
||||
|
||||
// Vertices which are transient
|
||||
std::vector<HbrVertex<T>*> m_transientVertices;
|
||||
|
||||
// Faces which are transient
|
||||
std::vector<HbrFace<T>*> m_transientFaces;
|
||||
|
||||
#ifdef HBR_ADAPTIVE
|
||||
public:
|
||||
std::vector<std::pair<int, int> > const & GetSplitVertices() const {
|
||||
return m_splitVertices;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class HbrVertex<T>;
|
||||
|
||||
void addSplitVertex(int splitIdx, int orgIdx) {
|
||||
m_splitVertices.push_back(std::pair<int,int>(splitIdx, orgIdx));
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::pair<int, int> > m_splitVertices;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#include <algorithm>
|
||||
#include "../hbr/mesh.h"
|
||||
#include "../hbr/halfedge.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T>
|
||||
HbrMesh<T>::HbrMesh(HbrSubdivision<T>* s, int _fvarcount, const int *_fvarindices, const int *_fvarwidths, int _totalfvarwidth
|
||||
#ifdef HBRSTITCH
|
||||
, int _stitchCount
|
||||
#endif
|
||||
)
|
||||
: subdivision(s), fvarcount(_fvarcount), fvarindices(_fvarindices),
|
||||
fvarwidths(_fvarwidths), totalfvarwidth(_totalfvarwidth),
|
||||
#ifdef HBRSTITCH
|
||||
stitchCount(_stitchCount),
|
||||
#endif
|
||||
nvertices(0), nfaces(0), maxVertexID(0), maxFaceID(0), maxUniformIndex(0),
|
||||
interpboundarymethod(k_InterpolateBoundaryNone),
|
||||
fvarinterpboundarymethod(k_InterpolateBoundaryNone),
|
||||
fvarpropagatecorners(false),
|
||||
s_memStatsIncrement(0), s_memStatsDecrement(0),
|
||||
m_faceSize(sizeof(HbrFace<T>) + 4 *
|
||||
((fvarcount + 15) / 16 * sizeof(unsigned int)
|
||||
#ifdef HBRSTITCH
|
||||
+ stitchCount * sizeof(StitchEdge*)
|
||||
#endif
|
||||
)),
|
||||
m_faceAllocator(&m_memory, 512, 0, 0, m_faceSize),
|
||||
m_vertexSize(sizeof(HbrVertex<T>) +
|
||||
(totalfvarwidth ? (sizeof(HbrFVarData<T>) + (totalfvarwidth - 1) * sizeof(float)) : 0)),
|
||||
m_vertexAllocator(&m_memory, 512, 0, 0, m_vertexSize),
|
||||
m_faceChildrenAllocator(&m_memory, 512, 0, 0),
|
||||
m_memory(0),
|
||||
m_numCoarseFaces(-1),
|
||||
hasVertexEdits(0),
|
||||
hasCreaseEdits(0),
|
||||
m_transientMode(false) {
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrMesh<T>::~HbrMesh() {
|
||||
GarbageCollect();
|
||||
|
||||
int i;
|
||||
if (!faces.empty()) {
|
||||
for (i = 0; i < nfaces; ++i) {
|
||||
if (faces[i]) {
|
||||
faces[i]->Destroy();
|
||||
m_faceAllocator.Deallocate(faces[i]);
|
||||
}
|
||||
}
|
||||
if (s_memStatsDecrement) {
|
||||
s_memStatsDecrement(faces.size() * sizeof(HbrFace<T>*));
|
||||
}
|
||||
}
|
||||
if (!vertices.empty()) {
|
||||
for (i = 0; i < nvertices; ++i) {
|
||||
if (vertices[i]) {
|
||||
vertices[i]->Destroy(this);
|
||||
m_vertexAllocator.Deallocate(vertices[i]);
|
||||
}
|
||||
}
|
||||
if (s_memStatsDecrement) {
|
||||
s_memStatsDecrement(vertices.size() * sizeof(HbrVertex<T>*));
|
||||
}
|
||||
}
|
||||
if (!vertexClientData.empty() && s_memStatsDecrement) {
|
||||
s_memStatsDecrement(vertexClientData.size() * sizeof(void*));
|
||||
}
|
||||
if (!faceClientData.empty() && s_memStatsDecrement) {
|
||||
s_memStatsDecrement(faceClientData.size() * sizeof(void*));
|
||||
}
|
||||
for (typename std::vector<HbrHierarchicalEdit<T>* >::iterator hi =
|
||||
hierarchicalEdits.begin(); hi != hierarchicalEdits.end(); ++hi) {
|
||||
delete *hi;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrVertex<T>*
|
||||
HbrMesh<T>::NewVertex(int id, const T &data) {
|
||||
HbrVertex<T>* v = 0;
|
||||
if (nvertices <= id) {
|
||||
while (nvertices <= maxVertexID) {
|
||||
nvertices *= 2;
|
||||
if (nvertices < 1) nvertices = 1;
|
||||
}
|
||||
size_t oldsize = vertices.size();
|
||||
vertices.resize(nvertices);
|
||||
if (s_memStatsIncrement) {
|
||||
s_memStatsIncrement((vertices.size() - oldsize) * sizeof(HbrVertex<T>*));
|
||||
}
|
||||
}
|
||||
v = vertices[id];
|
||||
if (v) {
|
||||
v->Destroy(this);
|
||||
} else {
|
||||
v = m_vertexAllocator.Allocate();
|
||||
}
|
||||
v->Initialize(id, data, GetTotalFVarWidth());
|
||||
vertices[id] = v;
|
||||
|
||||
if (id >= maxVertexID) {
|
||||
maxVertexID = id + 1;
|
||||
}
|
||||
|
||||
// Newly created vertices are always candidates for garbage
|
||||
// collection, until they get "owned" by someone who
|
||||
// IncrementsUsage on the vertex.
|
||||
AddGarbageCollectableVertex(v);
|
||||
|
||||
// If mesh is in transient mode, add vertex to transient list
|
||||
if (m_transientMode) {
|
||||
m_transientVertices.push_back(v);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrVertex<T>*
|
||||
HbrMesh<T>::NewVertex(const T &data) {
|
||||
// Pick an ID - either the maximum vertex ID or a recycled ID if
|
||||
// we can
|
||||
int id = maxVertexID;
|
||||
if (!recycleIDs.empty()) {
|
||||
id = *recycleIDs.begin();
|
||||
recycleIDs.erase(recycleIDs.begin());
|
||||
}
|
||||
if (id >= maxVertexID) {
|
||||
maxVertexID = id + 1;
|
||||
}
|
||||
return NewVertex(id, data);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrVertex<T>*
|
||||
HbrMesh<T>::NewVertex() {
|
||||
// Pick an ID - either the maximum vertex ID or a recycled ID if
|
||||
// we can
|
||||
int id = maxVertexID;
|
||||
if (!recycleIDs.empty()) {
|
||||
id = *recycleIDs.begin();
|
||||
recycleIDs.erase(recycleIDs.begin());
|
||||
}
|
||||
if (id >= maxVertexID) {
|
||||
maxVertexID = id + 1;
|
||||
}
|
||||
T data(id);
|
||||
data.Clear();
|
||||
return NewVertex(id, data);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrFace<T>*
|
||||
HbrMesh<T>::NewFace(int nv, const int *vtx, int uindex) {
|
||||
HbrVertex<T>** facevertices = reinterpret_cast<HbrVertex<T>**>(alloca(sizeof(HbrVertex<T>*) * nv));
|
||||
int i;
|
||||
for (i = 0; i < nv; ++i) {
|
||||
facevertices[i] = GetVertex(vtx[i]);
|
||||
if (!facevertices[i]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
HbrFace<T> *f = 0;
|
||||
// Resize if needed
|
||||
if (nfaces <= maxFaceID) {
|
||||
while (nfaces <= maxFaceID) {
|
||||
nfaces *= 2;
|
||||
if (nfaces < 1) nfaces = 1;
|
||||
}
|
||||
size_t oldsize = faces.size();
|
||||
faces.resize(nfaces);
|
||||
if (s_memStatsIncrement) {
|
||||
s_memStatsIncrement((faces.size() - oldsize) * sizeof(HbrVertex<T>*));
|
||||
}
|
||||
}
|
||||
f = faces[maxFaceID];
|
||||
if (f) {
|
||||
f->Destroy();
|
||||
} else {
|
||||
f = m_faceAllocator.Allocate();
|
||||
}
|
||||
f->Initialize(this, NULL, -1, maxFaceID, uindex, nv, facevertices, totalfvarwidth, 0);
|
||||
faces[maxFaceID] = f;
|
||||
maxFaceID++;
|
||||
// Update the maximum encountered uniform index
|
||||
if (uindex > maxUniformIndex) maxUniformIndex = uindex;
|
||||
|
||||
// If mesh is in transient mode, add face to transient list
|
||||
if (m_transientMode) {
|
||||
m_transientFaces.push_back(f);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrFace<T>*
|
||||
HbrMesh<T>::NewFace(int nv, HbrVertex<T> **vtx, HbrFace<T>* parent, int childindex) {
|
||||
HbrFace<T> *f = 0;
|
||||
// Resize if needed
|
||||
if (nfaces <= maxFaceID) {
|
||||
while (nfaces <= maxFaceID) {
|
||||
nfaces *= 2;
|
||||
if (nfaces < 1) nfaces = 1;
|
||||
}
|
||||
size_t oldsize = faces.size();
|
||||
faces.resize(nfaces);
|
||||
if (s_memStatsIncrement) {
|
||||
s_memStatsIncrement((faces.size() - oldsize) * sizeof(HbrVertex<T>*));
|
||||
}
|
||||
}
|
||||
f = faces[maxFaceID];
|
||||
if (f) {
|
||||
f->Destroy();
|
||||
} else {
|
||||
f = m_faceAllocator.Allocate();
|
||||
}
|
||||
f->Initialize(this, parent, childindex, maxFaceID, parent ? parent->GetUniformIndex() : 0, nv, vtx, totalfvarwidth, parent ? parent->GetDepth() + 1 : 0);
|
||||
if (parent) {
|
||||
f->SetPtexIndex(parent->GetPtexIndex());
|
||||
}
|
||||
faces[maxFaceID] = f;
|
||||
maxFaceID++;
|
||||
|
||||
// If mesh is in transient mode, add face to transient list
|
||||
if (m_transientMode) {
|
||||
m_transientFaces.push_back(f);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrMesh<T>::Finish() {
|
||||
int i, j;
|
||||
m_numCoarseFaces = 0;
|
||||
for (i = 0; i < nfaces; ++i) {
|
||||
if (faces[i]) {
|
||||
faces[i]->SetCoarse();
|
||||
m_numCoarseFaces++;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<HbrVertex<T>*> vertexlist;
|
||||
GetVertices(std::back_inserter(vertexlist));
|
||||
for (typename std::vector<HbrVertex<T>*>::iterator vi = vertexlist.begin();
|
||||
vi != vertexlist.end(); ++vi) {
|
||||
HbrVertex<T>* vertex = *vi;
|
||||
if (vertex->IsConnected()) vertex->Finish();
|
||||
}
|
||||
// Finish may have added new vertices
|
||||
vertexlist.clear();
|
||||
GetVertices(std::back_inserter(vertexlist));
|
||||
|
||||
// If interpolateboundary is on, process boundary edges
|
||||
if (interpboundarymethod == k_InterpolateBoundaryEdgeOnly || interpboundarymethod == k_InterpolateBoundaryEdgeAndCorner) {
|
||||
for (i = 0; i < nfaces; ++i) {
|
||||
if (HbrFace<T>* face = faces[i]) {
|
||||
int nv = face->GetNumVertices();
|
||||
for (int k = 0; k < nv; ++k) {
|
||||
HbrHalfedge<T>* edge = face->GetEdge(k);
|
||||
if (edge->IsBoundary()) {
|
||||
edge->SetSharpness(HbrHalfedge<T>::k_InfinitelySharp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Process corners
|
||||
if (interpboundarymethod == k_InterpolateBoundaryEdgeAndCorner) {
|
||||
for (typename std::vector<HbrVertex<T>*>::iterator vi = vertexlist.begin();
|
||||
vi != vertexlist.end(); ++vi) {
|
||||
HbrVertex<T>* vertex = *vi;
|
||||
if (vertex && vertex->IsConnected() && vertex->OnBoundary() && vertex->GetCoarseValence() == 2) {
|
||||
vertex->SetSharpness(HbrVertex<T>::k_InfinitelySharp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the hierarchical edits
|
||||
if (!hierarchicalEdits.empty()) {
|
||||
HbrHierarchicalEditComparator<T> cmp;
|
||||
int nHierarchicalEdits = (int)hierarchicalEdits.size();
|
||||
std::sort(hierarchicalEdits.begin(), hierarchicalEdits.end(), cmp);
|
||||
// Push a sentinel null value - we rely upon this sentinel to
|
||||
// ensure face->GetHierarchicalEdits knows when to terminate
|
||||
hierarchicalEdits.push_back(0);
|
||||
j = 0;
|
||||
// Link faces to hierarchical edits
|
||||
for (i = 0; i < nfaces; ++i) {
|
||||
if (faces[i]) {
|
||||
while (j < nHierarchicalEdits && hierarchicalEdits[j]->GetFaceID() < i) {
|
||||
++j;
|
||||
}
|
||||
if (j < nHierarchicalEdits && hierarchicalEdits[j]->GetFaceID() == i) {
|
||||
faces[i]->SetHierarchicalEdits(&hierarchicalEdits[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrMesh<T>::DeleteFace(HbrFace<T>* face) {
|
||||
if (face->GetID() < nfaces) {
|
||||
HbrFace<T>* f = faces[face->GetID()];
|
||||
if (f == face) {
|
||||
faces[face->GetID()] = 0;
|
||||
face->Destroy();
|
||||
m_faceAllocator.Deallocate(face);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrMesh<T>::DeleteVertex(HbrVertex<T>* vertex) {
|
||||
HbrVertex<T> *v = GetVertex(vertex->GetID());
|
||||
if (v == vertex) {
|
||||
recycleIDs.insert(vertex->GetID());
|
||||
int id = vertex->GetID();
|
||||
vertices[id] = 0;
|
||||
vertex->Destroy(this);
|
||||
m_vertexAllocator.Deallocate(vertex);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int
|
||||
HbrMesh<T>::GetNumVertices() const {
|
||||
int count = 0;
|
||||
for (int i = 0; i < nvertices; ++i) {
|
||||
if (vertices[i]) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int
|
||||
HbrMesh<T>::GetNumDisconnectedVertices() const {
|
||||
int disconnected = 0;
|
||||
for (int i = 0; i < nvertices; ++i) {
|
||||
if (HbrVertex<T>* v = vertices[i]) {
|
||||
if (!v->IsConnected()) {
|
||||
disconnected++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return disconnected;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int
|
||||
HbrMesh<T>::GetNumFaces() const {
|
||||
int count = 0;
|
||||
for (int i = 0; i < nfaces; ++i) {
|
||||
if (faces[i]) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int
|
||||
HbrMesh<T>::GetNumCoarseFaces() const {
|
||||
// Use the value computed by Finish() if it exists
|
||||
if (m_numCoarseFaces >= 0) return m_numCoarseFaces;
|
||||
// Otherwise we have to just count it up now
|
||||
int count = 0;
|
||||
for (int i = 0; i < nfaces; ++i) {
|
||||
if (faces[i] && faces[i]->IsCoarse()) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrFace<T>*
|
||||
HbrMesh<T>::GetFace(int id) const {
|
||||
if (id < nfaces) {
|
||||
return faces[id];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <typename OutputIterator>
|
||||
void
|
||||
HbrMesh<T>::GetVertices(OutputIterator lvertices) const {
|
||||
for (int i = 0; i < nvertices; ++i) {
|
||||
if (vertices[i]) *lvertices++ = vertices[i];
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrMesh<T>::ApplyOperatorAllVertices(HbrVertexOperator<T> &op) const {
|
||||
for (int i = 0; i < nvertices; ++i) {
|
||||
if (vertices[i]) op(*vertices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <typename OutputIterator>
|
||||
void
|
||||
HbrMesh<T>::GetFaces(OutputIterator lfaces) const {
|
||||
for (int i = 0; i < nfaces; ++i) {
|
||||
if (faces[i]) *lfaces++ = faces[i];
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrMesh<T>::PrintStats(std::ostream &out) {
|
||||
int singular = 0;
|
||||
int sumvalence = 0;
|
||||
int i, nv = 0;
|
||||
int disconnected = 0;
|
||||
int extraordinary = 0;
|
||||
for (i = 0; i < nvertices; ++i) {
|
||||
if (HbrVertex<T>* v = vertices[i]) {
|
||||
nv++;
|
||||
if (v->IsSingular()) {
|
||||
out << " singular: " << *v << "\n";
|
||||
singular++;
|
||||
} else if (!v->IsConnected()) {
|
||||
out << " disconnected: " << *v << "\n";
|
||||
disconnected++;
|
||||
} else {
|
||||
if (v->IsExtraordinary()) {
|
||||
extraordinary++;
|
||||
}
|
||||
sumvalence += v->GetValence();
|
||||
}
|
||||
}
|
||||
}
|
||||
out << "Mesh has " << nv << " vertices\n";
|
||||
out << "Total singular vertices " << singular << "\n";
|
||||
out << "Total disconnected vertices " << disconnected << "\n";
|
||||
out << "Total extraordinary vertices " << extraordinary << "\n";
|
||||
out << "Average valence " << (float) sumvalence / nv << "\n";
|
||||
|
||||
int sumsides = 0;
|
||||
int numfaces = 0;
|
||||
for (i = 0; i < nfaces; ++i) {
|
||||
if (HbrFace<T>* f = faces[i]) {
|
||||
numfaces++;
|
||||
sumsides += f->GetNumVertices();
|
||||
}
|
||||
}
|
||||
out << "Mesh has " << nfaces << " faces\n";
|
||||
out << "Average sidedness " << (float) sumsides / nfaces << "\n";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrMesh<T>::GarbageCollect() {
|
||||
if (gcVertices.empty()) return;
|
||||
|
||||
static const size_t gcthreshold = 4096;
|
||||
|
||||
if (gcVertices.size() <= gcthreshold) return;
|
||||
// Go through the list of garbage collectable vertices and gather
|
||||
// up the neighboring faces of those vertices which can be garbage
|
||||
// collected.
|
||||
std::vector<HbrFace<T>*> killlist;
|
||||
std::vector<HbrVertex<T>*> vlist;
|
||||
|
||||
// Process the vertices in the same order as they were collected
|
||||
// (gcVertices used to be declared as a std::deque, but that was
|
||||
// causing unnecessary heap traffic).
|
||||
int numprocessed = (int)gcVertices.size() - gcthreshold / 2;
|
||||
for (int i = 0; i < numprocessed; ++i) {
|
||||
HbrVertex<T>* v = gcVertices[i];
|
||||
v->ClearCollected();
|
||||
if (v->IsUsed()) continue;
|
||||
vlist.push_back(v);
|
||||
HbrHalfedge<T>* start = v->GetIncidentEdge(), *edge;
|
||||
edge = start;
|
||||
while (edge) {
|
||||
HbrFace<T>* f = edge->GetLeftFace();
|
||||
if (!f->IsCollected()) {
|
||||
f->SetCollected();
|
||||
killlist.push_back(f);
|
||||
}
|
||||
edge = v->GetNextEdge(edge);
|
||||
if (edge == start) break;
|
||||
}
|
||||
}
|
||||
|
||||
gcVertices.erase(gcVertices.begin(), gcVertices.begin() + numprocessed);
|
||||
|
||||
// Delete those faces
|
||||
for (typename std::vector<HbrFace<T>*>::iterator fi = killlist.begin(); fi != killlist.end(); ++fi) {
|
||||
if ((*fi)->GarbageCollectable()) {
|
||||
DeleteFace(*fi);
|
||||
} else {
|
||||
(*fi)->ClearCollected();
|
||||
}
|
||||
}
|
||||
|
||||
// Delete as many vertices as we can
|
||||
for (typename std::vector<HbrVertex<T>*>::iterator vi = vlist.begin(); vi != vlist.end(); ++vi) {
|
||||
HbrVertex<T>* v = *vi;
|
||||
if (!v->IsReferenced()) {
|
||||
DeleteVertex(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrMesh<T>::AddHierarchicalEdit(HbrHierarchicalEdit<T>* edit) {
|
||||
hierarchicalEdits.push_back(edit);
|
||||
if (dynamic_cast<HbrVertexEdit<T>*>(edit) ||
|
||||
dynamic_cast<HbrMovingVertexEdit<T>*>(edit)) {
|
||||
hasVertexEdits = 1;
|
||||
} else if (dynamic_cast<HbrCreaseEdit<T>*>(edit)) {
|
||||
hasCreaseEdits = 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrMesh<T>::FreeTransientData() {
|
||||
// When purging transient data, we must clear the faces first
|
||||
for (typename std::vector<HbrFace<T>*>::iterator fi = m_transientFaces.begin();
|
||||
fi != m_transientFaces.end(); ++fi) {
|
||||
DeleteFace(*fi);
|
||||
}
|
||||
// The vertices should now be trivial to purge after the transient
|
||||
// faces have been cleared
|
||||
for (typename std::vector<HbrVertex<T>*>::iterator vi = m_transientVertices.begin();
|
||||
vi != m_transientVertices.end(); ++vi) {
|
||||
DeleteVertex(*vi);
|
||||
}
|
||||
m_transientVertices.clear();
|
||||
m_transientFaces.clear();
|
||||
// Reset max face ID
|
||||
int i;
|
||||
for (i = nfaces - 1; i >= 0; --i) {
|
||||
if (faces[i]) {
|
||||
maxFaceID = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Reset max vertex ID
|
||||
for (i = nvertices - 1; i >= 0; --i) {
|
||||
if (vertices[i]) {
|
||||
maxVertexID = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRMESH_H */
|
||||
276
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/subdivision.h
vendored
Normal file
276
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/subdivision.h
vendored
Normal file
@@ -0,0 +1,276 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRSUBDIVISION_H
|
||||
#define OPENSUBDIV3_HBRSUBDIVISION_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrFace;
|
||||
template <class T> class HbrVertex;
|
||||
template <class T> class HbrHalfedge;
|
||||
template <class T> class HbrMesh;
|
||||
template <class T> class HbrSubdivision {
|
||||
public:
|
||||
HbrSubdivision<T>()
|
||||
: creaseSubdivision(k_CreaseNormal) {}
|
||||
|
||||
virtual ~HbrSubdivision<T>() {}
|
||||
|
||||
virtual HbrSubdivision<T>* Clone() const = 0;
|
||||
|
||||
// How to subdivide a face
|
||||
virtual void Refine(HbrMesh<T>* mesh, HbrFace<T>* face) = 0;
|
||||
|
||||
// Subdivide a face only at a particular vertex (creating one child)
|
||||
virtual HbrFace<T>* RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, HbrVertex<T>* vertex) = 0;
|
||||
|
||||
// Refine all faces around a particular vertex
|
||||
virtual void RefineAtVertex(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
|
||||
|
||||
// Given an edge, try to ensure the edge's opposite exists by
|
||||
// forcing refinement up the hierarchy
|
||||
virtual void GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) = 0;
|
||||
|
||||
// Given an vertex, ensure all faces in the ring around it exist
|
||||
// by forcing refinement up the hierarchy
|
||||
virtual void GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex) = 0;
|
||||
|
||||
// Returns true if the vertex, edge, or face has a limit point,
|
||||
// curve, or surface associated with it
|
||||
virtual bool HasLimit(HbrMesh<T>* /* mesh */, HbrFace<T>* /* face */) { return true; }
|
||||
virtual bool HasLimit(HbrMesh<T>* /* mesh */, HbrHalfedge<T>* /* edge */) { return true; }
|
||||
virtual bool HasLimit(HbrMesh<T>* /* mesh */, HbrVertex<T>* /* vertex */) { return true; }
|
||||
|
||||
// How to turn faces, edges, and vertices into vertices
|
||||
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face) = 0;
|
||||
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) = 0;
|
||||
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex) = 0;
|
||||
|
||||
// Returns true if the vertex is extraordinary in the subdivision scheme
|
||||
virtual bool VertexIsExtraordinary(HbrMesh<T> const * /* mesh */, HbrVertex<T>* /* vertex */) { return false; }
|
||||
|
||||
// Returns true if the face is extraordinary in the subdivision scheme
|
||||
virtual bool FaceIsExtraordinary(HbrMesh<T> const * /* mesh */, HbrFace<T>* /* face */) { return false; }
|
||||
|
||||
// Crease subdivision rules. When subdividing a edge with a crease
|
||||
// strength, we get two child subedges, and we need to determine
|
||||
// what weights to assign these subedges. The "normal" rule
|
||||
// is to simply assign the current edge's crease strength - 1
|
||||
// to both of the child subedges. The "Chaikin" rule looks at the
|
||||
// current edge and incident edges to the current edge's end
|
||||
// vertices, and weighs them; for more information consult
|
||||
// the Geri's Game paper.
|
||||
enum CreaseSubdivision {
|
||||
k_CreaseNormal,
|
||||
k_CreaseChaikin
|
||||
};
|
||||
CreaseSubdivision GetCreaseSubdivisionMethod() const { return creaseSubdivision; }
|
||||
void SetCreaseSubdivisionMethod(CreaseSubdivision method) { creaseSubdivision = method; }
|
||||
|
||||
// Figures out how to assign a crease weight on an edge to its
|
||||
// subedge. The subedge must be a child of the parent edge
|
||||
// (either subedge->GetOrgVertex() or subedge->GetDestVertex()
|
||||
// == edge->Subdivide()). The vertex supplied must NOT be
|
||||
// a parent of the subedge; it is either the origin or
|
||||
// destination vertex of edge.
|
||||
void SubdivideCreaseWeight(HbrHalfedge<T>* edge, HbrVertex<T>* vertex, HbrHalfedge<T>* subedge);
|
||||
|
||||
// Returns the expected number of children faces after subdivision
|
||||
// for a face with the given number of vertices.
|
||||
virtual int GetFaceChildrenCount(int nvertices) const = 0;
|
||||
|
||||
protected:
|
||||
CreaseSubdivision creaseSubdivision;
|
||||
|
||||
// Helper routine for subclasses: for a given vertex, sums
|
||||
// contributions from surrounding vertices
|
||||
void AddSurroundingVerticesWithWeight(HbrMesh<T>* mesh, HbrVertex<T>* vertex, float weight, T* data);
|
||||
|
||||
// Helper routine for subclasses: for a given vertex with a crease
|
||||
// mask, adds contributions from the two crease edges
|
||||
void AddCreaseEdgesWithWeight(HbrMesh<T>* mesh, HbrVertex<T>* vertex, bool next, float weight, T* data);
|
||||
|
||||
private:
|
||||
// Helper class used by AddSurroundingVerticesWithWeight
|
||||
class SmoothSubdivisionVertexOperator : public HbrVertexOperator<T> {
|
||||
public:
|
||||
SmoothSubdivisionVertexOperator(T* data, bool meshHasEdits, float weight)
|
||||
: m_data(data),
|
||||
m_meshHasEdits(meshHasEdits),
|
||||
m_weight(weight)
|
||||
{
|
||||
}
|
||||
virtual void operator() (HbrVertex<T> &vertex) {
|
||||
// Must ensure vertex edits have been applied
|
||||
if (m_meshHasEdits) {
|
||||
vertex.GuaranteeNeighbors();
|
||||
}
|
||||
m_data->AddWithWeight(vertex.GetData(), m_weight);
|
||||
}
|
||||
private:
|
||||
T* m_data;
|
||||
const bool m_meshHasEdits;
|
||||
const float m_weight;
|
||||
};
|
||||
|
||||
// Helper class used by AddCreaseEdgesWithWeight
|
||||
class CreaseSubdivisionHalfedgeOperator : public HbrHalfedgeOperator<T> {
|
||||
public:
|
||||
CreaseSubdivisionHalfedgeOperator(HbrVertex<T> *vertex, T* data, bool meshHasEdits, bool next, float weight)
|
||||
: m_vertex(vertex),
|
||||
m_data(data),
|
||||
m_meshHasEdits(meshHasEdits),
|
||||
m_next(next),
|
||||
m_weight(weight),
|
||||
m_count(0)
|
||||
{
|
||||
}
|
||||
virtual void operator() (HbrHalfedge<T> &edge) {
|
||||
if (m_count < 2 && edge.IsSharp(m_next)) {
|
||||
HbrVertex<T>* a = edge.GetDestVertex();
|
||||
if (a == m_vertex) a = edge.GetOrgVertex();
|
||||
// Must ensure vertex edits have been applied
|
||||
if (m_meshHasEdits) {
|
||||
a->GuaranteeNeighbors();
|
||||
}
|
||||
m_data->AddWithWeight(a->GetData(), m_weight);
|
||||
m_count++;
|
||||
}
|
||||
}
|
||||
private:
|
||||
HbrVertex<T>* m_vertex;
|
||||
T* m_data;
|
||||
const bool m_meshHasEdits;
|
||||
const bool m_next;
|
||||
const float m_weight;
|
||||
int m_count;
|
||||
};
|
||||
|
||||
private:
|
||||
// Helper class used by RefineAtVertex.
|
||||
class RefineFaceAtVertexOperator : public HbrFaceOperator<T> {
|
||||
public:
|
||||
RefineFaceAtVertexOperator(HbrSubdivision<T>* subdivision, HbrMesh<T>* mesh, HbrVertex<T> *vertex)
|
||||
: m_subdivision(subdivision),
|
||||
m_mesh(mesh),
|
||||
m_vertex(vertex)
|
||||
{
|
||||
}
|
||||
virtual void operator() (HbrFace<T> &face) {
|
||||
m_subdivision->RefineFaceAtVertex(m_mesh, &face, m_vertex);
|
||||
}
|
||||
private:
|
||||
HbrSubdivision<T>* const m_subdivision;
|
||||
HbrMesh<T>* const m_mesh;
|
||||
HbrVertex<T>* const m_vertex;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrSubdivision<T>::RefineAtVertex(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
|
||||
GuaranteeNeighbors(mesh, vertex);
|
||||
RefineFaceAtVertexOperator op(this, mesh, vertex);
|
||||
vertex->ApplyOperatorSurroundingFaces(op);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrSubdivision<T>::SubdivideCreaseWeight(HbrHalfedge<T>* edge, HbrVertex<T>* vertex, HbrHalfedge<T>* subedge) {
|
||||
|
||||
float sharpness = edge->GetSharpness();
|
||||
|
||||
// In all methods, if the parent edge is infinitely sharp, the
|
||||
// child edge is also infinitely sharp
|
||||
if (sharpness >= HbrHalfedge<T>::k_InfinitelySharp) {
|
||||
subedge->SetSharpness(HbrHalfedge<T>::k_InfinitelySharp);
|
||||
}
|
||||
|
||||
// Chaikin's curve subdivision: use 3/4 of the parent sharpness,
|
||||
// plus 1/4 of crease sharpnesses incident to vertex
|
||||
else if (creaseSubdivision == HbrSubdivision<T>::k_CreaseChaikin) {
|
||||
|
||||
float childsharp = 0.0f;
|
||||
|
||||
int n = 0;
|
||||
|
||||
// Add 1/4 of the sharpness of all crease edges incident to
|
||||
// the vertex (other than this crease edge)
|
||||
class ChaikinEdgeCreaseOperator : public HbrHalfedgeOperator<T> {
|
||||
public:
|
||||
|
||||
ChaikinEdgeCreaseOperator(
|
||||
HbrHalfedge<T> const * edge, float & childsharp, int & count) :
|
||||
m_edge(edge), m_childsharp(childsharp), m_count(count) { }
|
||||
|
||||
virtual void operator() (HbrHalfedge<T> &edge) {
|
||||
|
||||
// Skip original edge or it's opposite
|
||||
if ((&edge==m_edge) || (&edge==m_edge->GetOpposite()))
|
||||
return;
|
||||
if (edge.GetSharpness() > HbrHalfedge<T>::k_Smooth) {
|
||||
m_childsharp += edge.GetSharpness();
|
||||
++m_count;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
HbrHalfedge<T> const * m_edge;
|
||||
float & m_childsharp;
|
||||
int & m_count;
|
||||
};
|
||||
|
||||
ChaikinEdgeCreaseOperator op(edge, childsharp, n);
|
||||
vertex->GuaranteeNeighbors();
|
||||
vertex->ApplyOperatorSurroundingEdges(op);
|
||||
|
||||
if (n) {
|
||||
childsharp = childsharp * 0.25f / float(n);
|
||||
}
|
||||
|
||||
// Add 3/4 of the sharpness of this crease edge
|
||||
childsharp += sharpness * 0.75f;
|
||||
childsharp -= 1.0f;
|
||||
if (childsharp < (float) HbrHalfedge<T>::k_Smooth) {
|
||||
childsharp = (float) HbrHalfedge<T>::k_Smooth;
|
||||
}
|
||||
subedge->SetSharpness(childsharp);
|
||||
|
||||
} else {
|
||||
sharpness -= 1.0f;
|
||||
if (sharpness < (float) HbrHalfedge<T>::k_Smooth) {
|
||||
sharpness = (float) HbrHalfedge<T>::k_Smooth;
|
||||
}
|
||||
subedge->SetSharpness(sharpness);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrSubdivision<T>::AddSurroundingVerticesWithWeight(HbrMesh<T>* mesh, HbrVertex<T>* vertex, float weight, T* data) {
|
||||
SmoothSubdivisionVertexOperator op(data, mesh->HasVertexEdits(), weight);
|
||||
vertex->ApplyOperatorSurroundingVertices(op);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrSubdivision<T>::AddCreaseEdgesWithWeight(HbrMesh<T>* mesh, HbrVertex<T>* vertex, bool next, float weight, T* data) {
|
||||
CreaseSubdivisionHalfedgeOperator op(vertex, data, mesh->HasVertexEdits(), next, weight);
|
||||
vertex->ApplyOperatorSurroundingEdges(op);
|
||||
}
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRSUBDIVISION_H */
|
||||
1541
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/vertex.h
vendored
Normal file
1541
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/vertex.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
224
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/vertexEdit.h
vendored
Normal file
224
blender-5.2.0/extern/opensubdiv-source/opensubdiv/hbr/vertexEdit.h
vendored
Normal file
@@ -0,0 +1,224 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRVERTEXEDIT_H
|
||||
#define OPENSUBDIV3_HBRVERTEXEDIT_H
|
||||
|
||||
#include <algorithm>
|
||||
#include "../hbr/hierarchicalEdit.h"
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrVertexEdit;
|
||||
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& out, const HbrVertexEdit<T>& path) {
|
||||
out << "vertex path = (" << path.faceid << ' ';
|
||||
for (int i = 0; i < path.nsubfaces; ++i) {
|
||||
out << static_cast<int>(path.subfaces[i]) << ' ';
|
||||
}
|
||||
return out << static_cast<int>(path.vertexid) << "), edit = (" << path.edit[0] << ',' << path.edit[1] << ',' << path.edit[2] << ')';
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class HbrVertexEdit : public HbrHierarchicalEdit<T> {
|
||||
|
||||
public:
|
||||
|
||||
HbrVertexEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, unsigned char _vertexid, int _index, int _width, bool _isP, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) {
|
||||
edit = new float[width];
|
||||
memcpy(edit, _edit, width * sizeof(float));
|
||||
}
|
||||
|
||||
HbrVertexEdit(int _faceid, int _nsubfaces, int *_subfaces, int _vertexid, int _index, int _width, bool _isP, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(static_cast<unsigned char>(_vertexid)), index(_index), width(_width), isP(_isP), op(_op) {
|
||||
edit = new float[width];
|
||||
memcpy(edit, _edit, width * sizeof(float));
|
||||
}
|
||||
|
||||
virtual ~HbrVertexEdit() {
|
||||
delete[] edit;
|
||||
}
|
||||
|
||||
// Return the vertex id (the last element in the path)
|
||||
unsigned char GetVertexID() const { return vertexid; }
|
||||
|
||||
friend std::ostream& operator<< <T> (std::ostream& out, const HbrVertexEdit<T>& path);
|
||||
|
||||
// Return index of variable this edit applies to
|
||||
int GetIndex() const { return index; }
|
||||
|
||||
// Return width of the variable
|
||||
int GetWidth() const { return width; }
|
||||
|
||||
// Get the numerical value of the edit
|
||||
const float* GetEdit() const { return edit; }
|
||||
|
||||
// Get the type of operation
|
||||
typename HbrHierarchicalEdit<T>::Operation GetOperation() const { return op; }
|
||||
|
||||
virtual void ApplyEditToFace(HbrFace<T>* face) {
|
||||
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
|
||||
// Tags the vertex as being edited; it'll figure out what to
|
||||
// when GuaranteeNeighbor is called
|
||||
face->GetVertex(vertexid)->SetVertexEdit();
|
||||
}
|
||||
// In any event, mark the face as having a vertex edit (which
|
||||
// may only be applied on subfaces)
|
||||
face->MarkVertexEdits();
|
||||
}
|
||||
|
||||
virtual void ApplyEditToVertex(HbrFace<T>* face, HbrVertex<T>* vertex) {
|
||||
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth() &&
|
||||
face->GetVertex(vertexid) == vertex) {
|
||||
vertex->GetData().ApplyVertexEdit(*const_cast<const HbrVertexEdit<T>*>(this));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PRMAN
|
||||
virtual void ApplyToBound(struct bbox& bbox, RtMatrix *mx) const {
|
||||
if (isP) {
|
||||
struct xyz p = *(struct xyz*)edit;
|
||||
if (mx)
|
||||
MxTransformByMatrix(&p, &p, *mx, 1);
|
||||
if (op == HbrHierarchicalEdit<T>::Set) {
|
||||
bbox.min.x = std::min(bbox.min.x, p.x);
|
||||
bbox.min.y = std::min(bbox.min.y, p.y);
|
||||
bbox.min.z = std::min(bbox.min.z, p.z);
|
||||
bbox.max.x = std::max(bbox.max.x, p.x);
|
||||
bbox.max.y = std::max(bbox.max.y, p.y);
|
||||
bbox.max.z = std::max(bbox.max.z, p.z);
|
||||
} else if (op == HbrHierarchicalEdit<T>::Add ||
|
||||
op == HbrHierarchicalEdit<T>::Subtract) {
|
||||
bbox.min.x -= fabsf(p.x);
|
||||
bbox.min.y -= fabsf(p.y);
|
||||
bbox.min.z -= fabsf(p.z);
|
||||
bbox.max.x += fabsf(p.x);
|
||||
bbox.max.y += fabsf(p.y);
|
||||
bbox.max.z += fabsf(p.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
const unsigned char vertexid;
|
||||
int index;
|
||||
int width;
|
||||
unsigned isP:1;
|
||||
typename HbrHierarchicalEdit<T>::Operation op;
|
||||
float* edit;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class HbrMovingVertexEdit : public HbrHierarchicalEdit<T> {
|
||||
|
||||
public:
|
||||
|
||||
HbrMovingVertexEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, unsigned char _vertexid, int _index, int _width, bool _isP, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) {
|
||||
edit = new float[width * 2];
|
||||
memcpy(edit, _edit, 2 * width * sizeof(float));
|
||||
}
|
||||
|
||||
HbrMovingVertexEdit(int _faceid, int _nsubfaces, int *_subfaces, int _vertexid, int _index, int _width, bool _isP, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) {
|
||||
edit = new float[width * 2];
|
||||
memcpy(edit, _edit, 2 * width * sizeof(float));
|
||||
}
|
||||
|
||||
virtual ~HbrMovingVertexEdit() {
|
||||
delete[] edit;
|
||||
}
|
||||
|
||||
// Return the vertex id (the last element in the path)
|
||||
unsigned char GetVertexID() const { return vertexid; }
|
||||
|
||||
friend std::ostream& operator<< <T> (std::ostream& out, const HbrVertexEdit<T>& path);
|
||||
|
||||
// Return index of variable this edit applies to
|
||||
int GetIndex() const { return index; }
|
||||
|
||||
// Return width of the variable
|
||||
int GetWidth() const { return width; }
|
||||
|
||||
// Get the numerical value of the edit
|
||||
const float* GetEdit() const { return edit; }
|
||||
|
||||
// Get the type of operation
|
||||
typename HbrHierarchicalEdit<T>::Operation GetOperation() const { return op; }
|
||||
|
||||
virtual void ApplyEditToFace(HbrFace<T>* face) {
|
||||
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
|
||||
// Tags the vertex as being edited; it'll figure out what to
|
||||
// when GuaranteeNeighbor is called
|
||||
face->GetVertex(vertexid)->SetVertexEdit();
|
||||
}
|
||||
// In any event, mark the face as having a vertex edit (which
|
||||
// may only be applied on subfaces)
|
||||
face->MarkVertexEdits();
|
||||
}
|
||||
|
||||
virtual void ApplyEditToVertex(HbrFace<T>* face, HbrVertex<T>* vertex) {
|
||||
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth() &&
|
||||
face->GetVertex(vertexid) == vertex) {
|
||||
vertex->GetData().ApplyMovingVertexEdit(*const_cast<const HbrMovingVertexEdit<T>*>(this));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PRMAN
|
||||
virtual void ApplyToBound(struct bbox& bbox, RtMatrix *mx) const {
|
||||
if (isP) {
|
||||
struct xyz p1 = *(struct xyz*)edit;
|
||||
struct xyz p2 = *(struct xyz*)&edit[3];
|
||||
if (mx) {
|
||||
MxTransformByMatrix(&p1, &p1, *mx, 1);
|
||||
MxTransformByMatrix(&p2, &p2, *mx, 1);
|
||||
}
|
||||
if (op == HbrVertexEdit<T>::Set) {
|
||||
bbox.min.x = std::min(std::min(bbox.min.x, p1.x), p2.x);
|
||||
bbox.min.y = std::min(std::min(bbox.min.y, p1.y), p2.y);
|
||||
bbox.min.z = std::min(std::min(bbox.min.z, p1.z), p2.z);
|
||||
bbox.max.x = std::max(std::max(bbox.max.x, p1.x), p2.x);
|
||||
bbox.max.y = std::max(std::max(bbox.max.y, p1.y), p2.y);
|
||||
bbox.max.z = std::max(std::max(bbox.max.z, p1.z), p2.z);
|
||||
} else if (op == HbrVertexEdit<T>::Add ||
|
||||
op == HbrVertexEdit<T>::Subtract) {
|
||||
float maxx = std::max(fabsf(p1.x), fabsf(p2.x));
|
||||
float maxy = std::max(fabsf(p1.y), fabsf(p2.y));
|
||||
float maxz = std::max(fabsf(p1.z), fabsf(p2.z));
|
||||
bbox.min.x -= maxx;
|
||||
bbox.min.y -= maxy;
|
||||
bbox.min.z -= maxz;
|
||||
bbox.max.x += maxx;
|
||||
bbox.max.y += maxy;
|
||||
bbox.max.z += maxz;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
const unsigned char vertexid;
|
||||
int index;
|
||||
int width;
|
||||
unsigned isP:1;
|
||||
typename HbrHierarchicalEdit<T>::Operation op;
|
||||
float* edit;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRVERTEXEDIT_H */
|
||||
Reference in New Issue
Block a user