https://github.com/PixarAnimationStudios/OpenSubdiv/blob/release/tutorials/hbr/tutorial_2/hbr_tutorial_2.cpp
struct Vertex {
Vertex() { }
Vertex(int ) { }
Vertex(Vertex const & src) {
_position[0] = src._position[0];
_position[1] = src._position[1];
_position[2] = src._position[2];
}
void Clear( void * =0 ) {
_position[0]=_position[1]=_position[2]=0.0f;
}
void AddWithWeight(Vertex const & src, float weight) {
_position[0]+=weight*src._position[0];
_position[1]+=weight*src._position[1];
_position[2]+=weight*src._position[2];
}
void AddVaryingWithWeight(Vertex const &, float) { }
void SetPosition(float x, float y, float z) {
_position[0]=x;
_position[1]=y;
_position[2]=z;
}
const float * GetPosition() const {
return _position;
}
private:
float _position[3];
};
typedef OpenSubdiv::HbrMesh<Vertex> Hmesh;
typedef OpenSubdiv::HbrFace<Vertex> Hface;
typedef OpenSubdiv::HbrVertex<Vertex> Hvertex;
typedef OpenSubdiv::HbrHalfedge<Vertex> Hhalfedge;
Hmesh * createMesh();
int main(int, char **) {
Hmesh * hmesh = createMesh();
int maxlevel=2, firstface=0, firstvertex=0;
for (int level=0; level<maxlevel; ++level) {
int nfaces = hmesh->GetNumFaces();
if (level==(maxlevel-1)) {
firstvertex = hmesh->GetNumVertices();
}
for (int face=firstface; face<nfaces; ++face) {
Hface * f = hmesh->GetFace(face);
f->Refine();
}
firstface = nfaces;
}
{
int nverts = hmesh->GetNumVertices();
for (int vert=firstvertex; vert<nverts; ++vert) {
float const * pos = hmesh->GetVertex(vert)->GetData().GetPosition();
printf("v %f %f %f\n", pos[0], pos[1], pos[2]);
}
for (int face=firstface; face<hmesh->GetNumFaces(); ++face) {
Hface * f = hmesh->GetFace(face);
assert(f->GetNumVertices()==4 );
printf("f ");
for (int vert=0; vert<4; ++vert) {
printf("%d ", f->GetVertex(vert)->GetID() - firstvertex + 1);
}
printf("\n");
}
}
}
Hmesh *
createMesh() {
static float verts[5][3] = {{ 0.0f, 0.0f, 2.0f},
{ 0.0f, -2.0f, 0.0f},
{ 2.0f, 0.0f, 0.0f},
{ 0.0f, 2.0f, 0.0f},
{-2.0f, 0.0f, 0.0f}};
static int nverts = 5,
nfaces = 5;
static int facenverts[5] = { 3, 3, 3, 3, 4 };
static int faceverts[16] = { 0, 1, 2,
0, 2, 3,
0, 3, 4,
0, 4, 1,
4, 3, 2, 1 };
OpenSubdiv::HbrCatmarkSubdivision<Vertex> * catmark =
new OpenSubdiv::HbrCatmarkSubdivision<Vertex>();
Hmesh * hmesh = new Hmesh(catmark);
Vertex v;
for (int i=0; i<nverts; ++i) {
v.SetPosition(verts[i][0], verts[i][1], verts[i][2]);
hmesh->NewVertex(i, v);
}
int * fv = faceverts;
for (int i=0; i<nfaces; ++i) {
int nv = facenverts[i];
bool valid = true;
for(int j=0;j<nv;j++) {
Hvertex const * origin = hmesh->GetVertex(fv[j]),
* destination = hmesh->GetVertex(fv[(j+1)%nv]);
Hhalfedge const * opposite = destination->GetEdge(origin);
if (origin==NULL || destination==NULL) {
printf(" An edge was specified that connected a nonexistent vertex\n");
valid=false;
break;
}
if (origin == destination) {
printf(" An edge was specified that connected a vertex to itself\n");
valid=false;
break;
}
if (opposite && opposite->GetOpposite() ) {
printf(" A non-manifold edge incident to more than 2 faces was found\n");
valid=false;
break;
}
if (origin->GetEdge(destination)) {
printf(" An edge connecting two vertices was specified more than once."
" It's likely that an incident face was flipped\n");
valid=false;
break;
}
}
if (valid) {
hmesh->NewFace(nv, fv, 0);
} else {
printf(" Skipped face %d\n", i);
}
fv+=nv;
}
hmesh->SetInterpolateBoundaryMethod(Hmesh::k_InterpolateBoundaryEdgeOnly);
hmesh->Finish();
return hmesh;
}