/***** * bezierpatch.h * Authors: John C. Bowman and Jesse Frohlich * * Render Bezier patches and triangles. *****/ #ifndef BEZIERPATCH_H #define BEZIERPATCH_H #include "drawelement.h" namespace camp { #ifdef HAVE_LIBGLM struct BezierPatch { vertexBuffer data; bool transparent; bool color; double epsilon; double Epsilon; double res2; double Res2; // Reduced resolution for Bezier triangles flatness test. typedef GLuint (vertexBuffer::*vertexFunction)(const triple &v, const triple& n); vertexFunction pvertex; bool Onscreen; BezierPatch() : transparent(false), color(false), Onscreen(true) {} void init(double res); void init(double res, GLfloat *colors) { transparent=false; color=colors; init(res); } triple normal(triple left3, triple left2, triple left1, triple middle, triple right1, triple right2, triple right3) { triple lp=3.0*(left1-middle); triple rp=3.0*(right1-middle); triple n=cross(rp,lp); if(abs2(n) > epsilon) return n; triple lpp=bezierPP(middle,left1,left2); triple rpp=bezierPP(middle,right1,right2); n=cross(rpp,lp)+cross(rp,lpp); if(abs2(n) > epsilon) return n; triple lppp=bezierPPP(middle,left1,left2,left3); triple rppp=bezierPPP(middle,right1,right2,right3); n=cross(rpp,lpp)+cross(rppp,lp)+cross(rp,lppp); if(abs2(n) > epsilon) return n; n=cross(rppp,lpp)+cross(rpp,lppp); if(abs2(n) > epsilon) return n; return cross(rppp,lppp); } // Return the differential of the Bezier curve p0,p1,p2,p3 at 0 triple differential(triple p0, triple p1, triple p2, triple p3) { triple p=p1-p0; if(abs2(p) > epsilon) return p; p=bezierPP(p0,p1,p2); if(abs2(p) > epsilon) return p; return bezierPPP(p0,p1,p2,p3); } // Determine the flatness of a Bezier patch. pair Distance(const triple *p) { triple p0=p[0]; triple p3=p[3]; triple p12=p[12]; triple p15=p[15]; // Check the horizontal flatness. double h=Flatness(p0,p12,p3,p15); // Check straightness of the horizontal edges and interior control curves. h=max(h,Straightness(p0,p[4],p[8],p12)); h=max(h,Straightness(p[1],p[5],p[9],p[13])); h=max(h,Straightness(p[2],p[6],p[10],p[14])); h=max(h,Straightness(p3,p[7],p[11],p15)); // Check the vertical flatness. double v=Flatness(p0,p3,p12,p15); // Check straightness of the vertical edges and interior control curves. v=max(v,Straightness(p0,p[1],p[2],p3)); v=max(v,Straightness(p[4],p[5],p[6],p[7])); v=max(v,Straightness(p[8],p[9],p[10],p[11])); v=max(v,Straightness(p12,p[13],p[14],p15)); return pair(h,v); } struct Split3 { triple m0,m2,m3,m4,m5; Split3() {} Split3(triple z0, triple c0, triple c1, triple z1) { m0=0.5*(z0+c0); triple m1=0.5*(c0+c1); m2=0.5*(c1+z1); m3=0.5*(m0+m1); m4=0.5*(m1+m2); m5=0.5*(m3+m4); } }; // Approximate bounds by bounding box of control polyhedron. bool offscreen(size_t n, const triple *v) { if(bbox2(n,v).offscreen()) { Onscreen=false; return true; } return false; } virtual void render(const triple *p, bool straight, GLfloat *c0=NULL); void render(const triple *p, GLuint I0, GLuint I1, GLuint I2, GLuint I3, triple P0, triple P1, triple P2, triple P3, bool flat0, bool flat1, bool flat2, bool flat3, GLfloat *C0=NULL, GLfloat *C1=NULL, GLfloat *C2=NULL, GLfloat *C3=NULL); void append() { if(transparent) transparentData.Append(data); else { if(color) colorData.Append(data); else materialData.append(data); } } virtual void notRendered() { if(transparent) transparentData.rendered=false; else { if(color) colorData.rendered=false; else materialData.rendered=false; } } void queue(const triple *g, bool straight, double ratio, bool Transparent, GLfloat *colors=NULL) { data.clear(); Onscreen=true; transparent=Transparent; color=colors; notRendered(); init(pixelResolution*ratio); render(g,straight,colors); } }; struct BezierTriangle : public BezierPatch { public: BezierTriangle() : BezierPatch() {} double Distance(const triple *p) { triple p0=p[0]; triple p6=p[6]; triple p9=p[9]; // Check how far the internal point is from the centroid of the vertices. double d=abs2((p0+p6+p9)*third-p[4]); // Determine how straight the edges are. d=max(d,Straightness(p0,p[1],p[3],p6)); d=max(d,Straightness(p0,p[2],p[5],p9)); return max(d,Straightness(p6,p[7],p[8],p9)); } void render(const triple *p, bool straight, GLfloat *c0=NULL); void render(const triple *p, GLuint I0, GLuint I1, GLuint I2, triple P0, triple P1, triple P2, bool flat0, bool flat1, bool flat2, GLfloat *C0=NULL, GLfloat *C1=NULL, GLfloat *C2=NULL); }; struct Triangles : public BezierPatch { public: Triangles() : BezierPatch() {} void queue(size_t nP, const triple* P, size_t nN, const triple* N, size_t nC, const prc::RGBAColour* C, size_t nI, const uint32_t (*PI)[3], const uint32_t (*NI)[3], const uint32_t (*CI)[3], bool transparent); void append() { if(transparent) transparentData.Append(data); else triangleData.Append(data); } void notRendered() { if(transparent) transparentData.rendered=false; else triangleData.rendered=false; } }; extern void sortTriangles(); #endif } //namespace camp #endif