#pragma once
#include "geometry.h"
#include "buffer.h"
#include "../subdiv/half_edge.h"
#include "../subdiv/tessellation_cache.h"
#include "../subdiv/catmullclark_coefficients.h"
#include "../subdiv/patch.h"
namespace embree
{
struct HoleSet;
struct VertexCreaseMap;
struct EdgeCreaseMap;
class SubdivMesh : public Geometry
{
ALIGNED_CLASS_(16);
public:
typedef HalfEdge::Edge Edge;
static const Geometry::GTypeMask geom_type = Geometry::MTY_SUBDIV_MESH;
struct KeyHalfEdge
{
KeyHalfEdge() {}
KeyHalfEdge (uint64_t key, HalfEdge* edge)
: key(key), edge(edge) {}
__forceinline operator uint64_t() const {
return key;
}
friend __forceinline bool operator<(const KeyHalfEdge& e0, const KeyHalfEdge& e1) {
return e0.key < e1.key;
}
public:
uint64_t key;
HalfEdge* edge;
};
public:
SubdivMesh(Device* device);
~SubdivMesh();
public:
void setMask (unsigned mask);
void setSubdivisionMode (unsigned int topologyID, RTCSubdivisionMode mode);
void setVertexAttributeTopology(unsigned int vertexAttribID, unsigned int topologyID);
void setNumTimeSteps (unsigned int numTimeSteps);
void setVertexAttributeCount (unsigned int N);
void setTopologyCount (unsigned int N);
void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num);
void* getBuffer(RTCBufferType type, unsigned int slot);
void updateBuffer(RTCBufferType type, unsigned int slot);
void setTessellationRate(float N);
bool verify();
void commit();
void addElementsToCount (GeometryCounts & counts) const;
void setDisplacementFunction (RTCDisplacementFunctionN func);
unsigned int getFirstHalfEdge(unsigned int faceID);
unsigned int getFace(unsigned int edgeID);
unsigned int getNextHalfEdge(unsigned int edgeID);
unsigned int getPreviousHalfEdge(unsigned int edgeID);
unsigned int getOppositeHalfEdge(unsigned int topologyID, unsigned int edgeID);
public:
size_t numFaces() const {
return faceVertices.size();
}
size_t numEdges() const {
return topology[0].vertexIndices.size();
}
size_t numVertices() const {
return vertices[0].size();
}
__forceinline BBox3fa bounds(size_t i, size_t j = 0) const {
return topology[0].getHalfEdge(i)->bounds(vertices[j]);
}
__forceinline bool valid(size_t i) const {
return topology[0].valid(i) && !invalidFace(i);
}
__forceinline bool valid(size_t i, size_t j) const {
return topology[0].valid(i) && !invalidFace(i,j);
}
void printStatistics();
void initializeHalfEdgeStructures ();
public:
__forceinline const BufferView<Vec3fa>& getVertexBuffer( const size_t t = 0 ) const {
return vertices[t];
}
__forceinline float getEdgeLevel(const size_t i) const
{
if (levels) return clamp(levels[i],1.0f,4096.0f);
else return clamp(tessellationRate,1.0f,4096.0f);
}
public:
RTCDisplacementFunctionN displFunc;
public:
struct Topology
{
public:
Topology () : halfEdges(nullptr,0) {}
Topology (SubdivMesh* mesh);
public:
Topology (Topology&& other)
: mesh(std::move(other.mesh)),
vertexIndices(std::move(other.vertexIndices)),
subdiv_mode(std::move(other.subdiv_mode)),
halfEdges(std::move(other.halfEdges)),
halfEdges0(std::move(other.halfEdges0)),
halfEdges1(std::move(other.halfEdges1)) {}
Topology& operator= (Topology&& other)
{
mesh = std::move(other.mesh);
vertexIndices = std::move(other.vertexIndices);
subdiv_mode = std::move(other.subdiv_mode);
halfEdges = std::move(other.halfEdges);
halfEdges0 = std::move(other.halfEdges0);
halfEdges1 = std::move(other.halfEdges1);
return *this;
}
public:
__forceinline bool valid(size_t i) const
{
if (unlikely(subdiv_mode == RTC_SUBDIVISION_MODE_NO_BOUNDARY)) {
if (getHalfEdge(i)->faceHasBorder()) return false;
}
return true;
}
void setSubdivisionMode (RTCSubdivisionMode mode);
void update ();
bool verify (size_t numVertices);
void initializeHalfEdgeStructures ();
private:
void calculateHalfEdges();
void updateHalfEdges();
public:
SubdivMesh* mesh;
BufferView<unsigned int> vertexIndices;
RTCSubdivisionMode subdiv_mode;
public:
__forceinline const HalfEdge* getHalfEdge ( const size_t f ) const {
return &halfEdges[mesh->faceStartEdge[f]];
}
mvector<HalfEdge> halfEdges;
private:
std::vector<KeyHalfEdge> halfEdges0;
std::vector<KeyHalfEdge> halfEdges1;
};
__forceinline const HalfEdge* getHalfEdge ( const size_t t , const size_t f ) const {
return topology[t].getHalfEdge(f);
}
BufferView<unsigned int> faceVertices;
vector<Topology> topology;
vector<BufferView<Vec3fa>> vertices;
vector<RawBufferView> vertexAttribs;
BufferView<Edge> edge_creases;
BufferView<float> edge_crease_weights;
BufferView<unsigned int> vertex_creases;
BufferView<float> vertex_crease_weights;
BufferView<float> levels;
float tessellationRate;
BufferView<unsigned> holes;
private:
size_t numHalfEdges;
mvector<uint32_t> faceStartEdge;
mvector<uint32_t> halfEdgeFace;
std::unique_ptr<HoleSet> holeSet;
mvector<char> invalid_face;
__forceinline char& invalidFace(size_t i, size_t j = 0) { return invalid_face[i*numTimeSteps+j]; }
__forceinline const char& invalidFace(size_t i, size_t j = 0) const { return invalid_face[i*numTimeSteps+j]; }
public:
static __forceinline size_t numInterpolationSlots4(size_t stride) { return (stride+15)/16; }
static __forceinline size_t numInterpolationSlots8(size_t stride) { return (stride+31)/32; }
static __forceinline size_t interpolationSlot(size_t prim, size_t slot, size_t stride) {
const size_t slots = numInterpolationSlots4(stride);
assert(slot < slots);
return slots*prim+slot;
}
std::vector<std::vector<SharedLazyTessellationCache::CacheEntry>> vertex_buffer_tags;
std::vector<std::vector<SharedLazyTessellationCache::CacheEntry>> vertex_attrib_buffer_tags;
std::vector<Patch3fa::Ref> patch_eval_trees;
private:
std::unique_ptr<VertexCreaseMap> vertexCreaseMap;
std::unique_ptr<EdgeCreaseMap> edgeCreaseMap;
protected:
size_t commitCounter;
};
namespace isa
{
struct SubdivMeshISA : public SubdivMesh
{
SubdivMeshISA (Device* device)
: SubdivMesh(device) {}
void interpolate(const RTCInterpolateArguments* const args);
void interpolateN(const RTCInterpolateNArguments* const args);
};
}
DECLARE_ISA_FUNCTION(SubdivMesh*, createSubdivMesh, Device*);
};