/***** * drawpath3.cc * * Stores a path3 that has been added to a picture. *****/ #include "drawpath3.h" #include "drawsurface.h" namespace camp { using vm::array; using namespace prc; bool drawPath3::write(prcfile *out, unsigned int *, double, groupsmap&) { Int n=g.length(); if(n == 0 || invisible) return true; if(straight) { triple *controls=new(UseGC) triple[n+1]; for(Int i=0; i <= n; ++i) controls[i]=g.point(i); out->addLine(n+1,controls,color); } else { int m=3*n+1; triple *controls=new(UseGC) triple[m]; controls[0]=g.point((Int) 0); controls[1]=g.postcontrol((Int) 0); size_t k=1; for(Int i=1; i < n; ++i) { controls[++k]=g.precontrol(i); controls[++k]=g.point(i); controls[++k]=g.postcontrol(i); } controls[++k]=g.precontrol(n); controls[++k]=g.point(n); out->addBezierCurve(m,controls,color); } return true; } void drawPath3::render(GLUnurbs *nurb, double size2, const triple& b, const triple& B, double perspective, bool lighton, bool transparent) { #ifdef HAVE_GL Int n=g.length(); if(n == 0 || invisible || ((color.A < 1.0) ^ transparent)) return; const bool billboard=interaction == BILLBOARD && !settings::getSetting("offscreen"); triple m,M; double f,F,s; if(perspective) { f=Min.getz()*perspective; F=Max.getz()*perspective; m=triple(min(f*b.getx(),F*b.getx()),min(f*b.gety(),F*b.gety()),b.getz()); M=triple(max(f*B.getx(),F*B.getx()),max(f*B.gety(),F*B.gety()),B.getz()); s=max(f,F); } else { m=b; M=B; s=1.0; } const pair size3(s*(B.getx()-b.getx()),s*(B.gety()-b.gety())); double t[16]; // current transform glGetDoublev(GL_MODELVIEW_MATRIX,t); // Like Fortran, OpenGL uses transposed (column-major) format! run::transpose(t,4); run::inverse(t,4); bbox3 box(m,M); box.transform(t); m=box.Min(); M=box.Max(); if(!billboard && (Max.getx() < m.getx() || Min.getx() > M.getx() || Max.gety() < m.gety() || Min.gety() > M.gety() || Max.getz() < m.getz() || Min.getz() > M.getz())) return; drawBezierPatch::S.draw(); GLfloat Diffuse[]={0.0,0.0,0.0,(GLfloat) color.A}; glMaterialfv(GL_FRONT,GL_DIFFUSE,Diffuse); static GLfloat Black[]={0.0,0.0,0.0,1.0}; glMaterialfv(GL_FRONT,GL_AMBIENT,Black); GLfloat Emissive[]={(GLfloat) color.R,(GLfloat) color.G,(GLfloat) color.B, (GLfloat) color.A}; glMaterialfv(GL_FRONT,GL_EMISSION,Emissive); glMaterialfv(GL_FRONT,GL_SPECULAR,Black); glMaterialf(GL_FRONT,GL_SHININESS,128.0); if(billboard) { for(Int i=0; i < n; ++i) { triple controls[]={BB.transform(g.point(i)),BB.transform(g.postcontrol(i)), BB.transform(g.precontrol(i+1)), BB.transform(g.point(i+1))}; R.queue(controls,straight,size3.length()/size2,m,M); } } else { BB.init(center); for(Int i=0; i < n; ++i) { triple controls[]={g.point(i),g.postcontrol(i),g.precontrol(i+1), g.point(i+1)}; R.queue(controls,straight,size3.length()/size2,m,M); } } R.draw(); #endif } drawElement *drawPath3::transformed(const double* t) { return new drawPath3(t,this); } bool drawNurbsPath3::write(prcfile *out, unsigned int *, double, groupsmap&) { if(invisible) return true; out->addCurve(degree,n,controls,knots,color,weights); return true; } // Approximate bounds by bounding box of control polyhedron. void drawNurbsPath3::bounds(const double* t, bbox3& b) { double x,y,z; double X,Y,Z; triple* Controls; if(t == NULL) Controls=controls; else { Controls=new triple[n]; for(size_t i=0; i < n; i++) Controls[i]=t*controls[i]; } boundstriples(x,y,z,X,Y,Z,n,Controls); b.add(x,y,z); b.add(X,Y,Z); if(t == NULL) { Min=triple(x,y,z); Max=triple(X,Y,Z); } else delete[] Controls; } drawElement *drawNurbsPath3::transformed(const double* t) { return new drawNurbsPath3(t,this); } void drawNurbsPath3::ratio(const double* t, pair &b, double (*m)(double, double), double, bool &first) { triple* Controls; if(t == NULL) Controls=controls; else { Controls=new triple[n]; for(size_t i=0; i < n; i++) Controls[i]=t*controls[i]; } if(first) { first=false; triple v=Controls[0]; b=pair(xratio(v),yratio(v)); } double x=b.getx(); double y=b.gety(); for(size_t i=0; i < n; ++i) { triple v=Controls[i]; x=m(x,xratio(v)); y=m(y,yratio(v)); } b=pair(x,y); if(t != NULL) delete[] Controls; } void drawNurbsPath3::displacement() { #ifdef HAVE_GL size_t nknots=degree+n+1; if(Controls == NULL) { Controls=new(UseGC) GLfloat[(weights ? 4 : 3)*n]; Knots=new(UseGC) GLfloat[nknots]; } if(weights) for(size_t i=0; i < n; ++i) store(Controls+4*i,controls[i],weights[i]); else for(size_t i=0; i < n; ++i) store(Controls+3*i,controls[i]); for(size_t i=0; i < nknots; ++i) Knots[i]=knots[i]; #endif } void drawNurbsPath3::render(GLUnurbs *nurb, double, const triple&, const triple&, double, bool lighton, bool transparent) { #ifdef HAVE_GL if(invisible || ((color.A < 1.0) ^ transparent)) return; GLfloat Diffuse[]={0.0,0.0,0.0,(GLfloat) color.A}; glMaterialfv(GL_FRONT,GL_DIFFUSE,Diffuse); static GLfloat Black[]={0.0,0.0,0.0,1.0}; glMaterialfv(GL_FRONT,GL_AMBIENT,Black); GLfloat Emissive[]={(GLfloat) color.R,(GLfloat) color.G,(GLfloat) color.B, (GLfloat) color.A}; glMaterialfv(GL_FRONT,GL_EMISSION,Emissive); glMaterialfv(GL_FRONT,GL_SPECULAR,Black); glMaterialf(GL_FRONT,GL_SHININESS,128.0); if(weights) gluNurbsCallback(nurb,GLU_NURBS_VERTEX,(_GLUfuncptr) glVertex4fv); else gluNurbsCallback(nurb,GLU_NURBS_VERTEX,(_GLUfuncptr) glVertex3fv); gluBeginCurve(nurb); int order=degree+1; gluNurbsCurve(nurb,order+n,Knots,weights ? 4 : 3,Controls,order, weights ? GL_MAP1_VERTEX_4 : GL_MAP1_VERTEX_3); gluEndCurve(nurb); if(weights) gluNurbsCallback(nurb,GLU_NURBS_VERTEX,(_GLUfuncptr) glVertex3fv); #endif } } //namespace camp