blob: d5a8582548f2a6a90ca46ef2e15e7cca1dc843e9 [file] [log] [blame]
/*! \file Mesh.hxx defines basic mesh containers for storing geometry ... */
#ifndef RTTL_MESH_HXX
#define RTTL_MESH_HXX
#include "../common/RTInclude.hxx"
#include "../common/RTVec.hxx"
#include "../common/RTBox.hxx"
#include "../common/Timer.hxx"
#include "../Triangle/Triangle.hxx"
//#include "../BVH/BVH.hxx"
#include <vector>
#include <map>
namespace RTTL {
/* something like a base class for polygonal meshes */
enum VertexType {
RT_VERTEX_3F,
RT_VERTEX_4F
};
enum PrimtiveType {
RT_TRIANGLE,
RT_QUAD
};
class PolygonalBaseMesh {
public:
PolygonalBaseMesh() {
m_meshAABB.setEmpty();
m_meshCentroidAABB.setEmpty();
}
_INLINE const RTBoxSSE &getAABB() const { return m_meshAABB; }
_INLINE const RTBoxSSE &getCentroidAABB() const { return m_meshCentroidAABB; }
virtual void clear() = 0;
virtual RTBoxSSE getAABB(const int i) const = 0;
virtual void storePrimitiveAABBs(RTBoxSSE *const ptr, const int numAABBs) = 0;
virtual int numPrimitives() const = 0;
virtual int numVertices() const = 0;
virtual void addVertices(const float *const v,
const float *const txt,
const int vertices,
const int type) = 0;
virtual void addPrimitives(const int *const t,const int primitives, const int type, const int *const shaderID = NULL) = 0;
virtual void finalize() = 0;
template <int N, int LAYOUT, int MULTIPLE_ORIGINS, int SHADOW_RAYS,int NORMALIZE>
_INLINE void getGeometryNormal(RayPacket<N, LAYOUT, MULTIPLE_ORIGINS, SHADOW_RAYS> &packet,
const int id4,
RTVec_t<3, sse_f> &normal) const
{
}
protected:
RTBoxSSE m_meshAABB;
RTBoxSSE m_meshCentroidAABB;
};
class StandardTriangleMesh : public PolygonalBaseMesh {
protected:
struct Triangle {
RTVec3i v;
int shaderID;
};
vector< RTVec2f, Align<RTVec2f> > textureCoord;
vector< RTVec3f, Align<RTVec3f> > vertex;
vector< Triangle, Align<Triangle> > triangle;
public:
StandardTriangleMesh()
{
}
virtual void clear() {
m_meshAABB.setEmpty();
m_meshCentroidAABB.setEmpty();
vertex.clear();
triangle.clear();
}
virtual void addVertices(const float *const v,const float *const txt,const int vertices, const int type) {
assert(v);
assert(type == RT_VERTEX_3F);
vertex.reserve(vertex.size()+vertices);
for (int i=0;i<vertices;i++)
vertex.push_back(((RTVec3f*)v)[i]);
/* -- if != NULL transfer texture coordinates -- */
if (txt != NULL)
for (int i=0;i<vertices;i++)
{
textureCoord.push_back(((RTVec2f*)txt)[i]);
}
}
virtual void addPrimitives(const int *const t,const int primitives, const int type, const int *const shaderID = NULL) {
assert(t);
switch(type)
{
case RT_TRIANGLE:
triangle.reserve(triangle.size()+primitives);
for (int i=0;i<primitives;i++)
{
Triangle tri;
tri.v = ((RTVec3i*)t)[i];
tri.shaderID = (shaderID != NULL) ? shaderID[i] : 0;
triangle.push_back(tri);
RTBoxSSE box = getTriangleAABB(tri.v[0],tri.v[1],tri.v[2]);
m_meshAABB.extend(box);
m_meshCentroidAABB.extend(box.center());
}
break;
case RT_QUAD:
triangle.reserve(triangle.size()+2*primitives);
for (int i=0;i<primitives;i++)
{
Triangle tri;
RTVec4i c = ((RTVec4i*)t)[i];
tri.shaderID = (shaderID != NULL) ? shaderID[i] : 0;
tri.v = RTVec3i(c[0],c[1],c[2]);
triangle.push_back(tri);
tri.v = RTVec3i(c[2],c[3],c[0]);
triangle.push_back(tri);
RTBoxSSE box0 = getTriangleAABB(c[0],c[1],c[2]);
RTBoxSSE box1 = getTriangleAABB(c[2],c[3],c[0]);
m_meshAABB.extend(box0);
m_meshAABB.extend(box1);
m_meshCentroidAABB.extend(box0.center());
m_meshCentroidAABB.extend(box1.center());
}
break;
default:
FATAL("addPrimitives: unknown primitive type");
}
}
virtual int numPrimitives() const
{
return triangle.size();
}
virtual int numVertices() const
{
return vertex.size();
}
virtual RTBoxSSE getAABB(const int i) const {
return getTriangleAABB(i);
}
virtual void storePrimitiveAABBs(RTBoxSSE *const ptr, const int numAABBs)
{
for (int i=0;i<numAABBs;i++)
ptr[i] = getTriangleAABB(i);
}
virtual void finalize()
{
print();
}
_INLINE void print() const {
cout << "vertices " << vertex.size() << " (" << KBytes(sizeof(RTVec3f)*vertex.size()) << " KB)" << endl;
cout << "triangles " << triangle.size() << " (" << KBytes(sizeof(RTVec3i)*triangle.size()) << " KB)" << endl;
cout << "texture coordinates " << textureCoord.size() << " (" << KBytes(sizeof(RTVec2f)*textureCoord.size()) << " KB)" << endl;
//for (int i=0;i<textureCoord.size();i++)
//cout << i << " -> " << textureCoord[i] << endl;
#if 0
for (unsigned int i=0; i < triangle.size(); i++)
cout << i << " : " << triangle[i][0] << " " << triangle[i][1] << " " << triangle[i][2]
<< " -> " << vertex[triangle[i][0]] << " " << vertex[triangle[i][1]] << " " << vertex[triangle[i][2]] << endl;
#endif
}
_INLINE const RTVec3f &getTriangleVertex(const int t, const int i) const
{
assert(0 <= i && i <=2);
assert(t < (int)triangle.size());
return vertex[triangle[t].v[i]];
}
_INLINE int getShaderID(const int t) const
{
return triangle[t].shaderID;
}
_INLINE RTVec3f getTriangleNormal(const int t) const
{
const RTVec3f &a = getTriangleVertex(t,0);
const RTVec3f &b = getTriangleVertex(t,1);
const RTVec3f &c = getTriangleVertex(t,2);
return (a-c) ^ (b-c);
}
_INLINE RTBoxSSE getTriangleAABB(const int i) const {
return getTriangleAABB(triangle[i].v[0],triangle[i].v[1],triangle[i].v[2]);
}
_INLINE RTBoxSSE getTriangleAABB(const int id0, const int id1, const int id2) const
{
RTBoxSSE box;
box.setEmpty();
const sse_f v0 = _mm_setr_ps(vertex[id0][0],vertex[id0][1],vertex[id0][2],0.0f);
const sse_f v1 = _mm_setr_ps(vertex[id1][0],vertex[id1][1],vertex[id1][2],0.0f);
const sse_f v2 = _mm_setr_ps(vertex[id2][0],vertex[id2][1],vertex[id2][2],0.0f);
box.extend(v0);
box.extend(v1);
box.extend(v2);
return box;
}
template <int N, int LAYOUT, int MULTIPLE_ORIGINS, int SHADOW_RAYS>
_INLINE void intersectPrimitive(RayPacket<N, LAYOUT, MULTIPLE_ORIGINS, SHADOW_RAYS> &packet,
const int ID,
const int first,
const int last) const
{
const RTVec3f &v0 = getTriangleVertex(ID,0);
const RTVec3f &v1 = getTriangleVertex(ID,1);
const RTVec3f &v2 = getTriangleVertex(ID,2);
const int shaderID = getShaderID(ID);
IntersectTriangleMoellerTrumbore<N, LAYOUT, MULTIPLE_ORIGINS, SHADOW_RAYS>(v0,v1,v2,ID,shaderID,packet,first,last);
}
template <int N, int LAYOUT, int MULTIPLE_ORIGINS, int SHADOW_RAYS,int NORMALIZE>
_INLINE void getGeometryNormal(RayPacket<N, LAYOUT, MULTIPLE_ORIGINS, SHADOW_RAYS> &packet,
const int id4,
RTVec_t<3, sse_f> &normal) const
{
const sse_i &fourID = packet.id(id4);
if (__builtin_expect(fourID == splat4i<0>(fourID),1))
{
const int ID = M128_INT(fourID,0);
if (__builtin_expect(ID == -1,0))
{
normal[0] = _mm_setzero_ps();
normal[1] = _mm_setzero_ps();
normal[2] = _mm_setzero_ps();
}
else
{
const RTVec3f n = getTriangleNormal(ID);
normal[0] = convert<sse_f>(n.x);
normal[1] = convert<sse_f>(n.y);
normal[2] = convert<sse_f>(n.z);
}
}
else
{
#pragma unroll(4)
for (int i=0;i<4;i++)
{
const int ID = M128_INT(packet.id(id4),i);
if (__builtin_expect(ID == -1,0))
{
M128_FLOAT(normal[0],i) = 0.0f;
M128_FLOAT(normal[1],i) = 0.0f;
M128_FLOAT(normal[2],i) = 0.0f;
}
else
{
const RTVec3f n = getTriangleNormal(ID);
M128_FLOAT(normal[0],i) = n.x;
M128_FLOAT(normal[1],i) = n.y;
M128_FLOAT(normal[2],i) = n.z;
}
}
}
if (NORMALIZE)
{
const sse_f f = rsqrt(normal[0]*normal[0]+normal[1]*normal[1]+normal[2]*normal[2]);
normal[0] *= f;
normal[1] *= f;
normal[2] *= f;
}
}
template <int N, int LAYOUT, int MULTIPLE_ORIGINS, int SHADOW_RAYS,int NORMALIZE>
_INLINE void getTextureCoordinate(RayPacket<N, LAYOUT, MULTIPLE_ORIGINS, SHADOW_RAYS> &packet,
const int id4,
RTVec_t<2, sse_f> &txt) const
{
const sse_i &fourID = packet.id(id4);
const sse_f u = packet.u(id4);
const sse_f v = packet.v(id4);
const sse_f uv = _mm_sub_ps(convert<sse_f>(1.0f),_mm_add_ps(u,v));
if (__builtin_expect(fourID == splat4i<0>(fourID),1))
{
const int ID = M128_INT(fourID,0);
if (__builtin_expect(ID == -1,0))
{
txt[0] = _mm_setzero_ps();
txt[1] = _mm_setzero_ps();
}
else
{
const sse_f u0 = convert<sse_f>(textureCoord[triangle[ID].v[0]][0]);
const sse_f v0 = convert<sse_f>(textureCoord[triangle[ID].v[0]][1]);
const sse_f u1 = convert<sse_f>(textureCoord[triangle[ID].v[1]][0]);
const sse_f v1 = convert<sse_f>(textureCoord[triangle[ID].v[1]][1]);
const sse_f u2 = convert<sse_f>(textureCoord[triangle[ID].v[2]][0]);
const sse_f v2 = convert<sse_f>(textureCoord[triangle[ID].v[2]][1]);
txt[0] = uv * u0 + u * u1 + v * u2;
txt[1] = uv * v0 + u * v1 + v * v2;
}
}
else
{
sse_f u0,v0,u1,v1,u2,v2;
#pragma unroll(4)
for (int i=0;i<4;i++)
{
const int ID = M128_INT(packet.id(id4),i);
if (__builtin_expect(ID == -1,0))
{
M128_FLOAT(u0,i) = 0.0f;
M128_FLOAT(u1,i) = 0.0f;
M128_FLOAT(u2,i) = 0.0f;
M128_FLOAT(v0,i) = 0.0f;
M128_FLOAT(v1,i) = 0.0f;
M128_FLOAT(v2,i) = 0.0f;
}
else
{
M128_FLOAT(u0,i) = textureCoord[triangle[ID].v[0]][0];
M128_FLOAT(v0,i) = textureCoord[triangle[ID].v[0]][1];
M128_FLOAT(u1,i) = textureCoord[triangle[ID].v[1]][0];
M128_FLOAT(v1,i) = textureCoord[triangle[ID].v[1]][1];
M128_FLOAT(u2,i) = textureCoord[triangle[ID].v[2]][0];
M128_FLOAT(v2,i) = textureCoord[triangle[ID].v[2]][1];
}
}
txt[0] = uv * u0 + u * u1 + v * u2;
txt[1] = uv * v0 + u * v1 + v * v2;
}
}
};
class DirectedEdgeMesh : public PolygonalBaseMesh {
protected:
struct DirectedEdge {
unsigned int start_vertex : 30;
unsigned int boundary_vertex : 1; // vertex incident to a boundary edge
unsigned int regular_vertex : 1; // four quads incident to given vertex
int neighbor_edge;
DirectedEdge() {}
DirectedEdge(const int _vertex,const int _neighbor = -1) : start_vertex(_vertex), neighbor_edge(_neighbor) {}
};
vector< sse_f, Align<sse_f> > vertex;
vector< DirectedEdge, Align<DirectedEdge> > edge;
public:
DirectedEdgeMesh()
{
}
virtual RTBoxSSE getAABB(const int quadID) const
{
return quadGetOneNeighborhoodAABB(quadID);
}
virtual void storePrimitiveAABBs(RTBoxSSE *const ptr, const int numAABBs)
{
m_meshAABB.setEmpty();
m_meshCentroidAABB.setEmpty();
for (int i=0;i<numAABBs;i++)
{
RTBoxSSE box = quadGetOneNeighborhoodAABB(i);
m_meshAABB.extend(box);
m_meshCentroidAABB.extend(box.center());
ptr[i] = box;
}
}
virtual int numPrimitives() const
{
return quads();
}
virtual int numVertices() const
{
return vertices();
}
virtual void clear()
{
vertex.clear();
edge.clear();
}
_INLINE void addVertices(const float *const v,const float *const txt,const int primitives, const int type) {
assert(v);
assert(type == RT_VERTEX_3F);
vertex.reserve(vertex.size()+primitives);
for (int i=0;i<primitives;i++)
{
const sse_f c = vec3fToSSE(((RTVec3f*)v)[i]);
m_meshAABB.extend(c);
vertex.push_back(c);
}
if (txt != NULL)
cout << "texture coordinates currently not supported" << endl;
}
_INLINE void addPrimitives(const int *const t,const int primitives, const int type, const int *const shaderIds = NULL) {
assert(t);
assert(type == RT_QUAD);
edge.reserve(edge.size()+4*primitives);
for (int i=0;i<primitives;i++)
{
const RTVec4i &c = ((RTVec4i*)t)[i];
edge.push_back(DirectedEdge(c[0]));
edge.push_back(DirectedEdge(c[1]));
edge.push_back(DirectedEdge(c[2]));
edge.push_back(DirectedEdge(c[3]));
}
}
_INLINE void print() const {
cout << "vertices " << vertices() << " (" << KBytes(sizeof(sse_f)*vertices()) << " KB)" << endl;
cout << "edges " << edges() << " (" << KBytes(sizeof(DirectedEdge)*edges()) << " KB)" << endl;
cout << "quads " << quads() << endl;
//for (unsigned int i=0; i < edge.size(); i++) printEdge(i);
}
virtual void finalize()
{
DBG_PRINT(sizeof(DirectedEdge));
cout << "Computing topology..." << endl;
Timer timer;
timer.start();
computeTopology();
float t = timer.stop();
cout << "finished in (" << t << " sec)" << endl;
print();
printBoundaryEdges();
}
template <int N, int LAYOUT, int MULTIPLE_ORIGINS, int SHADOW_RAYS,int NORMALIZE>
_INLINE void getGeometryNormal(RayPacket<N, LAYOUT, MULTIPLE_ORIGINS, SHADOW_RAYS> &packet,
const int id4,
RTVec_t<3, sse_f> &normal) const
{
}
template <int N, int LAYOUT, int MULTIPLE_ORIGINS, int SHADOW_RAYS,int NORMALIZE>
_INLINE void getTextureCoordinate(RayPacket<N, LAYOUT, MULTIPLE_ORIGINS, SHADOW_RAYS> &packet,
const int id4,
RTVec_t<2, sse_f> &txt) const
{
}
template <int N, int LAYOUT, int MULTIPLE_ORIGINS, int SHADOW_RAYS>
_INLINE void intersectPrimitive(RayPacket<N, LAYOUT, MULTIPLE_ORIGINS, SHADOW_RAYS> &packet,
const int ID,
const int first,
const int last) const
{
const int shaderID = getShaderID(0);
const RTVec3f &v0 = *(RTVec3f*)&vertex[quadGetVertex(ID,0)];
const RTVec3f &v1 = *(RTVec3f*)&vertex[quadGetVertex(ID,1)];
const RTVec3f &v2 = *(RTVec3f*)&vertex[quadGetVertex(ID,2)];
const RTVec3f &v3 = *(RTVec3f*)&vertex[quadGetVertex(ID,3)];
IntersectTriangleMoellerTrumbore<N, LAYOUT, MULTIPLE_ORIGINS, SHADOW_RAYS>(v0,v1,v2,ID,shaderID,packet,first,last);
IntersectTriangleMoellerTrumbore<N, LAYOUT, MULTIPLE_ORIGINS, SHADOW_RAYS>(v2,v3,v0,ID,shaderID,packet,first,last);
}
_INLINE bool InitCatmullClarkVertexMatrix(const int quadID,sse_f (&matrix)[4][4], sse_f *ev) const
{
const int regularVertexPosition[4][2] = {
{ 1, 1},
{ 1, 2},
{ 2, 2},
{ 2, 1}
};
if (quadHasBoundary(quadID)) return false;
if (quadIsRegular(quadID))
{
for (int i=0;i<4;i++)
vertexCopyRegularOneNeigborhood(quadFirstEdge(quadID)+i,i,regularVertexPosition[i],matrix);
}
else
for (int i=0;i<4;i++)
if (quadIsVertexRegular(quadID,i))
vertexCopyRegularOneNeigborhood(quadFirstEdge(quadID)+i,i,regularVertexPosition[i],matrix);
else
vertexCopyIrregularOneNeigborhood(quadFirstEdge(quadID),ev);
return true;
}
_INLINE int getShaderID(const int t) const
{
return 0; // triangle[t].shaderID;
}
protected:
// initialization in ccw order, quad edges in cw order
_INLINE void vertexCopyRegularOneNeigborhood(const int startEdge,const int offset,const int pos[2],sse_f (&matrix)[4][4]) const
{
const int adj[8][2] = { { 1, 1},{ 0, 1},{-1, 1},{-1, 0},{-1,-1},{ 0,-1},{ 1,-1},{ 1, 0} };
matrix[pos[0]][pos[1]] = vertex[start_vertex(startEdge)];
int edge = startEdge;
int index = (8 - offset * 2) % 8;
do {
//cout << "y0 " << pos[0] + adj[index+0][0] << " x0 " << pos[1] + adj[index+0][1] << endl;
//cout << "y1 " << pos[0] + adj[index+1][0] << " x1 " << pos[1] + adj[index+1][1] << endl;
matrix[ pos[0] + adj[index+0][0] ][ pos[1] + adj[index+0][1] ] = vertex[end_vertex(next(edge))];
matrix[ pos[0] + adj[index+1][0] ][ pos[1] + adj[index+1][1] ] = vertex[end_vertex(edge)];
index = (index + 2) % 8;
const int neighbor = opposite(edge);
if (__builtin_expect(neighbor == -1,0)) { WARN("boundary for regular patches not yet supported"); return; }
edge = next(neighbor);
} while(edge != startEdge);
}
// initialization in cw order due to compatibility
_INLINE int vertexCopyIrregularOneNeigborhood(const int startEdge,sse_f *dest) const
{
dest[0] = vertex[start_vertex(startEdge)];
int edge = startEdge;
int index = 1;
do {
dest[index+0] = vertex[end_vertex(edge)];
dest[index+1] = vertex[end_vertex(next(edge))];
index += 2;
const int neighbor = opposite(edge);
if (__builtin_expect(neighbor == -1,0)) FATAL("not supported");
edge = next(neighbor);
} while(edge != startEdge);
return index;
}
/* --------------------------------------------------------------------------- */
_INLINE int next(const int i) const { return ((i+1) % 4) + (i & ~3); }
_INLINE int prev(const int i) const { return ((i+3) % 4) + (i & ~3); }
_INLINE int opposite(const int i) const { return edge[i].neighbor_edge; }
_INLINE bool boundary(const int i) const { return edge[i].neighbor_edge == -1; }
_INLINE int start_vertex(const int i) const { return edge[i].start_vertex; }
_INLINE int end_vertex(const int i) const { return edge[next(i)].start_vertex; }
_INLINE int quadFirstEdge(const int quad) const {
return quad << 2;
}
_INLINE void printEdge(int i) const {
cout << i << " (" << i%4 << ") : "
<< "vertex = " << edge[i].start_vertex
<< " neighbor = " << edge[i].neighbor_edge << " -> " << vertex[edge[i].start_vertex] << endl;
}
_INLINE void printBoundaryEdges() const {
int boundaryEdges = 0;
for (int i=0;i<edges();i++)
if (boundary(i))
{ printEdge(i); boundaryEdges++; }
cout << "#boundary edges " << boundaryEdges << endl;
}
_INLINE void computeTopology()
{
PING;
DBG_PRINT(quads());
std::map< std::pair<int, int>, int > edgeMap;
for (int i=0;i<edges();i++)
{
vertexBindEdgeID(edge[i].start_vertex,i);
const int a = start_vertex(i);
const int b = end_vertex(i);
const int index = findOrInsertEdge(a,b,i,edgeMap);
if (index != -1)
{
assert(edge[i].neighbor_edge == -1);
assert(edge[index].neighbor_edge == -1);
edge[i].neighbor_edge = index;
edge[index].neighbor_edge = i;
}
}
int boundaryVertices = 0;
for (int i=0;i<edges();i++)
{
edge[i].boundary_vertex = vertexHasBoundaryEdge(edge[i].start_vertex) ? 1 : 0;
boundaryVertices += edge[i].boundary_vertex;
edge[i].regular_vertex = vertexGetEdgeValence(edge[i].start_vertex) == 4 ? 1 : 0;
}
#if 1
int regularPatches = 0;
for (int i=0;i<quads();i++)
{
if (quadIsRegularWithoutBoundary(i)) regularPatches++;
}
DBG_PRINT(regularPatches);
DBG_PRINT(boundaryVertices);
#endif
}
_INLINE int findOrInsertEdge(int v0,int v1,const int edgeIndex, std::map< std::pair<int, int>, int > &edgeMap)
{
std::map< std::pair<int, int>, int >::iterator it;
if (v0 > v1) std::swap(v0,v1);
it = edgeMap.find(std::pair<int,int>(v0,v1));
if ( it == edgeMap.end())
{
edgeMap.insert(make_pair(std::pair<int,int>(v0,v1),edgeIndex));
return -1;
}
else
return it->second;
}
/* -------------------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------------------- */
_INLINE int quads() const {
return edge.size() >> 2;
}
_INLINE int edges() const {
return edge.size();
}
_INLINE int vertices() const {
return vertex.size();
}
// todo: get rid of many redundent operations
_INLINE RTBoxSSE quadGetOneNeighborhoodAABB(const int quad) const {
RTBoxSSE box;
box.setEmpty();
box.extend(vertexGetOneNeighborhood(quadGetVertex(quad,0)));
box.extend(vertexGetOneNeighborhood(quadGetVertex(quad,1)));
box.extend(vertexGetOneNeighborhood(quadGetVertex(quad,2)));
box.extend(vertexGetOneNeighborhood(quadGetVertex(quad,3)));
return box;
}
// NOTE: 1-neighborhood consists of quads, need to include opposite vertex
_INLINE RTBoxSSE vertexGetOneNeighborhood(const int vertexID) const {
RTBoxSSE box;
box.min_f() = vertex[vertexID];
box.max_f() = vertex[vertexID];
const int startEdge = vertexGetEdgeID(vertexID);
int edge = startEdge;
do {
box.extend(vertex[end_vertex(edge)]);
box.extend(vertex[end_vertex(next(edge))]); // opposite vertex
const int neighbor = opposite(edge);
if (__builtin_expect(neighbor == -1,0)) // found boundary vertex, cycle in reverse direction
{
edge = prev(startEdge);
while(1) {
box.extend(vertex[start_vertex(edge)]);
box.extend(vertex[start_vertex(prev(edge))]); // opposite vertex
const int neighbor = opposite(edge);
if (__builtin_expect(neighbor == -1,0)) break; // found second boundary edge
edge = prev(neighbor);
}
break;
DBG_PRINT(box);
}
edge = next(neighbor);
} while(edge != startEdge);
return box;
}
_INLINE int vertexGetEdgeValence(const int vertexID) const {
int valence = 0;
const int startEdge = vertexGetEdgeID(vertexID);
int edge = startEdge;
do {
valence++;
const int neighbor = opposite(edge);
if (__builtin_expect(neighbor == -1,0)) // found boundary vertex, cycle in reverse direction
{
edge = prev(startEdge);
while(1) {
valence++;
const int neighbor = opposite(edge);
if (__builtin_expect(neighbor == -1,0)) break; // found second boundary edge
edge = prev(neighbor);
}
break;
}
edge = next(neighbor);
} while(edge != startEdge);
return valence;
}
_INLINE bool vertexHasBoundaryEdge(const int vertexID) const {
int valence = 0;
const int startEdge = vertexGetEdgeID(vertexID);
int edge = startEdge;
do {
valence++;
const int neighbor = opposite(edge);
if (__builtin_expect(neighbor == -1,0)) return true;
edge = next(neighbor);
} while(edge != startEdge);
return false;
}
// does not handle boundaries
_INLINE int quadGetNumIrregularVertices(const int quadID) const {
const int edge = quadFirstEdge(quadID);
int num = 0;
num += vertexGetEdgeValence(start_vertex(edge+0)) != 4 ? 1 : 0;
num += vertexGetEdgeValence(start_vertex(edge+1)) != 4 ? 1 : 0;
num += vertexGetEdgeValence(start_vertex(edge+2)) != 4 ? 1 : 0;
num += vertexGetEdgeValence(start_vertex(edge+3)) != 4 ? 1 : 0;
return num;
}
_INLINE void vertexBindEdgeID(const int vertexID,const int edgeID)
{
M128_INT(vertex[vertexID],3) = edgeID;
}
_INLINE int vertexGetEdgeID(const int vertexID) const
{
return M128_INT(vertex[vertexID],3);
}
_INLINE int quadGetVertex(const int quadID,const int index) const
{
return start_vertex(quadFirstEdge(quadID)+index);
}
_INLINE int quadGetIrregularVertexIndex(const int quadID) const {
const int edgeID = quadFirstEdge(quadID);
for (int i=0;i<4;i++)
if (!edge[edgeID+i].regular_vertex) return i;
return -1;
}
_INLINE bool quadIsVertexRegular(const int quadID, const int i) const {
const int edgeID = quadFirstEdge(quadID);
return edge[edgeID+i].regular_vertex;
}
_INLINE bool quadIsRegular(const int quadID) const
{
const int edgeID = quadFirstEdge(quadID);
const int regular = \
edge[edgeID+0].regular_vertex &
edge[edgeID+1].regular_vertex &
edge[edgeID+2].regular_vertex &
edge[edgeID+3].regular_vertex;
if (__builtin_expect(regular != 0,1)) return true;
return false;
}
_INLINE bool quadHasBoundary(const int quadID) const
{
const int edgeID = quadFirstEdge(quadID);
const int boundary = \
edge[edgeID+0].boundary_vertex |
edge[edgeID+1].boundary_vertex |
edge[edgeID+2].boundary_vertex |
edge[edgeID+3].boundary_vertex;
if (__builtin_expect(boundary != 0,1)) return true;
return false;
}
_INLINE bool quadIsRegularWithoutBoundary(const int quadID) const
{
return quadIsRegular(quadID) == true && quadHasBoundary(quadID) == false;
}
};
};
#endif