diff options
Diffstat (limited to 'Build/source/utils/asymptote/drawsurface.cc')
-rw-r--r-- | Build/source/utils/asymptote/drawsurface.cc | 424 |
1 files changed, 349 insertions, 75 deletions
diff --git a/Build/source/utils/asymptote/drawsurface.cc b/Build/source/utils/asymptote/drawsurface.cc index 1eee043df7c..2c8865ef2f2 100644 --- a/Build/source/utils/asymptote/drawsurface.cc +++ b/Build/source/utils/asymptote/drawsurface.cc @@ -5,13 +5,26 @@ *****/ #include "drawsurface.h" +#include "arrayop.h" namespace camp { const double pixel=1.0; // Adaptive rendering constant. +const triple drawSurface::zero; using vm::array; -triple drawSurface::c3[]; + +#ifdef HAVE_LIBGL +void storecolor(GLfloat *colors, int i, const vm::array &pens, int j) +{ + pen p=vm::read<camp::pen>(pens,j); + p.torgb(); + colors[i]=p.red(); + colors[i+1]=p.green(); + colors[i+2]=p.blue(); + colors[i+3]=p.opacity(); +} +#endif inline void initMatrix(GLfloat *v, double x, double ymin, double zmin, double ymax, double zmax) @@ -36,31 +49,56 @@ inline void initMatrix(GLfloat *v, double x, double ymin, double zmin, void drawSurface::bounds(bbox3& b) { - static double c1[16]; - - for(int i=0; i < 16; ++i) - c1[i]=controls[i][0]; - double c0=c1[0]; - double fuzz=sqrtFuzz*norm(c1,16); - double xmin=bound(c1,min,b.empty ? c0 : min(c0,b.left),fuzz); - double xmax=bound(c1,max,b.empty ? c0 : max(c0,b.right),fuzz); + double x,y,z; + double X,Y,Z; + + if(straight) { + double *v=vertices[0]; + x=v[0]; + y=v[1]; + z=v[2]; + X=x; + Y=y; + Z=z; + for(size_t i=1; i < 4; ++i) { + double *v=vertices[i]; + double vx=v[0]; + x=min(x,vx); + X=max(X,vx); + double vy=v[1]; + y=min(y,vy); + Y=max(Y,vy); + double vz=v[2]; + z=min(z,vz); + Z=max(Z,vz); + } + } else { + static double c1[16]; + + for(int i=0; i < 16; ++i) + c1[i]=controls[i][0]; + double c0=c1[0]; + double fuzz=sqrtFuzz*run::norm(c1,16); + x=bound(c1,min,b.empty ? c0 : min(c0,b.left),fuzz); + X=bound(c1,max,b.empty ? c0 : max(c0,b.right),fuzz); - for(int i=0; i < 16; ++i) - c1[i]=controls[i][1]; - c0=c1[0]; - fuzz=sqrtFuzz*norm(c1,16); - double ymin=bound(c1,min,b.empty ? c0 : min(c0,b.bottom),fuzz); - double ymax=bound(c1,max,b.empty ? c0 : max(c0,b.top),fuzz); + for(int i=0; i < 16; ++i) + c1[i]=controls[i][1]; + c0=c1[0]; + fuzz=sqrtFuzz*run::norm(c1,16); + y=bound(c1,min,b.empty ? c0 : min(c0,b.bottom),fuzz); + Y=bound(c1,max,b.empty ? c0 : max(c0,b.top),fuzz); - for(int i=0; i < 16; ++i) - c1[i]=controls[i][2]; - c0=c1[0]; - fuzz=sqrtFuzz*norm(c1,16); - double zmin=bound(c1,min,b.empty ? c0 : min(c0,b.lower),fuzz); - double zmax=bound(c1,max,b.empty ? c0 : max(c0,b.upper),fuzz); + for(int i=0; i < 16; ++i) + c1[i]=controls[i][2]; + c0=c1[0]; + fuzz=sqrtFuzz*run::norm(c1,16); + z=bound(c1,min,b.empty ? c0 : min(c0,b.lower),fuzz); + Z=bound(c1,max,b.empty ? c0 : max(c0,b.upper),fuzz); + } - Min=triple(xmin,ymin,zmin); - Max=triple(xmax,ymax,zmax); + Min=triple(x,y,z); + Max=triple(X,Y,Z); b.add(Min); b.add(Max); @@ -68,19 +106,39 @@ void drawSurface::bounds(bbox3& b) void drawSurface::ratio(pair &b, double (*m)(double, double), bool &first) { - for(int i=0; i < 16; ++i) { - double *ci=controls[i]; - c3[i]=triple(ci[0],ci[1],ci[2]); - } + if(straight) { + if(first) { + first=false; + double *ci=vertices[0]; + triple v=triple(ci[0],ci[1],ci[2]); + b=pair(xratio(v),yratio(v)); + } - if(first) { - triple v=c3[0]; - b=pair(xratio(v),yratio(v)); - first=false; - } + double x=b.getx(); + double y=b.gety(); + for(size_t i=0; i < 4; ++i) { + double *ci=vertices[i]; + triple v=triple(ci[0],ci[1],ci[2]); + x=m(x,xratio(v)); + y=m(y,yratio(v)); + } + b=pair(x,y); + } else { + static triple c3[16]; + for(int i=0; i < 16; ++i) { + double *ci=controls[i]; + c3[i]=triple(ci[0],ci[1],ci[2]); + } - double fuzz=sqrtFuzz*norm(c3,16); - b=pair(bound(c3,m,xratio,b.getx(),fuzz),bound(c3,m,yratio,b.gety(),fuzz)); + if(first) { + triple v=c3[0]; + b=pair(xratio(v),yratio(v)); + first=false; + } + + double fuzz=sqrtFuzz*run::norm(c3,16); + b=pair(bound(c3,m,xratio,b.getx(),fuzz),bound(c3,m,yratio,b.gety(),fuzz)); + } } bool drawSurface::write(prcfile *out) @@ -89,7 +147,11 @@ bool drawSurface::write(prcfile *out) return true; PRCMaterial m(ambient,diffuse,emissive,specular,opacity,PRCshininess); - out->add(new PRCBezierSurface(out,3,3,4,4,controls,m,granularity)); + + if(straight) + out->add(new PRCBezierSurface(out,1,1,2,2,vertices,m,granularity,name)); + else + out->add(new PRCBezierSurface(out,3,3,4,4,controls,m,granularity,name)); return true; } @@ -121,30 +183,19 @@ inline triple displacement(const Triple& z0, const Triple& c0, void drawSurface::displacement() { #ifdef HAVE_LIBGL - initMatrix(v1,Min.getx(),Min.gety(),Min.getz(),Max.gety(),Max.getz()); - initMatrix(v2,Max.getx(),Min.gety(),Min.getz(),Max.gety(),Max.getz()); - - for(int i=0; i < 16; ++i) - store(c+3*i,controls[i]); - - static const triple zero; - havenormal=normal != zero; - havetransparency=havecolors ? colors[3]+colors[7]+colors[11]+colors[15] < 4.0 - : diffuse.A < 1.0; - if(havenormal) { - store(Normal,normal); + if(normal != zero) { d=zero; if(!straight) { - for(int i=1; i < 16; ++i) + for(size_t i=1; i < 16; ++i) d=camp::maxabs(d,camp::displacement2(controls[i],controls[0],normal)); dperp=d; - for(int i=0; i < 4; ++i) + for(size_t i=0; i < 4; ++i) d=camp::maxabs(d,camp::displacement(controls[4*i],controls[4*i+1], controls[4*i+2],controls[4*i+3])); - for(int i=0; i < 4; ++i) + for(size_t i=0; i < 4; ++i) d=camp::maxabs(d,camp::displacement(controls[i],controls[i+4], controls[i+8],controls[i+12])); } @@ -170,9 +221,16 @@ void drawSurface::render(GLUnurbs *nurb, double size2, double perspective, bool transparent) { #ifdef HAVE_LIBGL - if(invisible || (havetransparency ^ transparent)) return; + if(invisible || ((colors ? colors[3]+colors[7]+colors[11]+colors[15] < 4.0 + : diffuse.A < 1.0) ^ transparent)) return; static GLfloat v[16]; + static GLfloat v1[16]; + static GLfloat v2[16]; + static GLfloat Normal[3]; + + initMatrix(v1,Min.getx(),Min.gety(),Min.getz(),Max.gety(),Max.getz()); + initMatrix(v2,Max.getx(),Min.gety(),Min.getz(),Max.gety(),Max.getz()); glPushMatrix(); glMultMatrixf(v1); @@ -218,7 +276,7 @@ void drawSurface::render(GLUnurbs *nurb, double size2, bool ambientdiffuse=true; bool emission=true; - if(havecolors) { + if(colors) { glEnable(GL_COLOR_MATERIAL); if(lighton) { glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE); @@ -250,44 +308,56 @@ void drawSurface::render(GLUnurbs *nurb, double size2, triple size3=triple(s*(Max.getx()-Min.getx()),s*(Max.gety()-Min.gety()), Max.getz()-Min.getz()); + bool havenormal=normal != zero; if(!havenormal || (!straight && (fraction(d,size3)*size2 >= pixel || granularity == 0))) { if(lighton) { if(havenormal && fraction(dperp,size3)*size2 <= 0.1) { + store(Normal,normal); glNormal3fv(Normal); gluNurbsCallback(nurb,GLU_NURBS_NORMAL,NULL); } else gluNurbsCallback(nurb,GLU_NURBS_NORMAL,(_GLUfuncptr) glNormal3fv); } + static GLfloat Controls[48]; + for(size_t i=0; i < 16; ++i) + store(Controls+3*i,controls[i]); + static GLfloat bezier[]={0.0,0.0,0.0,0.0,1.0,1.0,1.0,1.0}; gluBeginSurface(nurb); - gluNurbsSurface(nurb,8,bezier,8,bezier,12,3,c,4,4,GL_MAP2_VERTEX_3); - if(havecolors) { + gluNurbsSurface(nurb,8,bezier,8,bezier,12,3,Controls,4,4,GL_MAP2_VERTEX_3); + if(colors) { static GLfloat linear[]={0.0,0.0,1.0,1.0}; gluNurbsSurface(nurb,4,linear,4,linear,8,4,colors,2,2,GL_MAP2_COLOR_4); } gluEndSurface(nurb); } else { + GLfloat Vertices[12]; + for(size_t i=0; i < 4; ++i) + store(Vertices+3*i,vertices[i]); + + store(Normal,normal); + glBegin(GL_QUADS); if(lighton) glNormal3fv(Normal); - if(havecolors) + if(colors) glColor4fv(colors); - glVertex3fv(c); - if(havecolors) + glVertex3fv(Vertices); + if(colors) glColor4fv(colors+8); - glVertex3fv(c+36); - if(havecolors) + glVertex3fv(Vertices+6); + if(colors) glColor4fv(colors+12); - glVertex3fv(c+45); - if(havecolors) + glVertex3fv(Vertices+9); + if(colors) glColor4fv(colors+4); - glVertex3fv(c+9); + glVertex3fv(Vertices+3); glEnd(); } - if(havecolors) + if(colors) glDisable(GL_COLOR_MATERIAL); #endif } @@ -297,22 +367,226 @@ drawElement *drawSurface::transformed(const array& t) return new drawSurface(t,this); } -double norm(double *a, size_t n) +bool drawNurbs::write(prcfile *out) +{ + if(invisible) + return true; + + PRCMaterial m(ambient,diffuse,emissive,specular,opacity,PRCshininess); + out->add(new PRCsurface(out,udegree,vdegree,nu,nv,controls,uknots,vknots, + m,scale3D,weights != NULL,weights,granularity, + name.c_str())); + + return true; +} + +// Approximate bounds by bounding box of control polyhedron. +void drawNurbs::bounds(bbox3& b) +{ + double x,y,z; + double X,Y,Z; + size_t n=nu*nv; + double *v=controls[0]; + if(weights == NULL) { + x=v[0]; + y=v[1]; + z=v[2]; + X=x; + Y=y; + Z=z; + for(size_t i=1; i < n; ++i) { + double *v=controls[i]; + double vx=v[0]; + x=min(x,vx); + X=max(X,vx); + double vy=v[1]; + y=min(y,vy); + Y=max(Y,vy); + double vz=v[2]; + z=min(z,vz); + Z=max(Z,vz); + } + } else { + double w=weights[0]; + x=v[0]/w; + y=v[1]/w; + z=v[2]/w; + X=x; + Y=y; + Z=z; + for(size_t i=1; i < n; ++i) { + double *v=controls[i]; + double w=weights[i]; + double vx=v[0]/w; + x=min(x,vx); + X=max(X,vx); + double vy=v[1]/w; + y=min(y,vy); + Y=max(Y,vy); + double vz=v[2]/w; + z=min(z,vz); + Z=max(Z,vz); + } + } + Min=triple(x,y,z); + Max=triple(X,Y,Z); + b.add(Min); + b.add(Max); +} + +drawElement *drawNurbs::transformed(const array& t) +{ + return new drawNurbs(t,this); +} + +void drawNurbs::ratio(pair &b, double (*m)(double, double), bool &first) +{ + size_t n=nu*nv; + if(first) { + first=false; + double *ci=controls[0]; + triple v=triple(ci[0],ci[1],ci[2]); + b=pair(xratio(v),yratio(v)); + } + + double x=b.getx(); + double y=b.gety(); + for(size_t i=0; i < n; ++i) { + double *ci=controls[i]; + triple v=triple(ci[0],ci[1],ci[2]); + x=m(x,xratio(v)); + y=m(y,yratio(v)); + } + b=pair(x,y); +} + +void drawNurbs::displacement() { - if(n == 0) return 0.0; - double M=fabs(a[0]); - for(size_t i=1; i < n; ++i) - M=max(M,fabs(a[i])); - return M; +#ifdef HAVE_LIBGL + size_t n=nu*nv; + size_t stride=weights == NULL ? 3 : 4; + for(size_t i=0; i < n; ++i) + store(Controls+stride*i,controls[i]); + + if(weights != NULL) + for(size_t i=0; i < n; ++i) + Controls[4*i+3]=weights[i]; + + size_t nuknotsm1=udegree+nu; + size_t nvknotsm1=vdegree+nv; + for(size_t i=0; i <= nuknotsm1; ++i) + uKnots[i]=uknots[i]; + for(size_t i=0; i <= nvknotsm1; ++i) + vKnots[i]=vknots[i]; +#endif } -double norm(triple *a, size_t n) +void drawNurbs::render(GLUnurbs *nurb, double size2, + const triple& Min, const triple& Max, + double perspective, bool transparent) { - if(n == 0) return 0.0; - double M=a[0].abs2(); - for(size_t i=1; i < n; ++i) - M=max(M,a[i].abs2()); - return sqrt(M); +#ifdef HAVE_LIBGL + if(invisible || ((colors ? colors[3]+colors[7]+colors[11]+colors[15] < 4.0 + : diffuse.A < 1.0) ^ transparent)) return; + + static GLfloat v[16]; + static GLfloat v1[16]; + static GLfloat v2[16]; + + initMatrix(v1,Min.getx(),Min.gety(),Min.getz(),Max.gety(),Max.getz()); + initMatrix(v2,Max.getx(),Min.gety(),Min.getz(),Max.gety(),Max.getz()); + + glPushMatrix(); + glMultMatrixf(v1); + glGetFloatv(GL_MODELVIEW_MATRIX,v); + glPopMatrix(); + + bbox3 B(v[0],v[1],v[2]); + B.addnonempty(v[4],v[5],v[6]); + B.addnonempty(v[8],v[9],v[10]); + B.addnonempty(v[12],v[13],v[14]); + + glPushMatrix(); + glMultMatrixf(v2); + glGetFloatv(GL_MODELVIEW_MATRIX,v); + glPopMatrix(); + + B.addnonempty(v[0],v[1],v[2]); + B.addnonempty(v[4],v[5],v[6]); + B.addnonempty(v[8],v[9],v[10]); + B.addnonempty(v[12],v[13],v[14]); + + triple M=B.Max(); + triple m=B.Min(); + + double s; + if(perspective) { + double f=m.getz()*perspective; + double F=M.getz()*perspective; + s=max(f,F); + if(M.getx() < min(f*Min.getx(),F*Min.getx()) || + m.getx() > max(f*Max.getx(),F*Max.getx()) || + M.gety() < min(f*Min.gety(),F*Min.gety()) || + m.gety() > max(f*Max.gety(),F*Max.gety()) || + M.getz() < Min.getz() || + m.getz() > Max.getz()) return; + } else { + s=1.0; + if(M.getx() < Min.getx() || m.getx() > Max.getx() || + M.gety() < Min.gety() || m.gety() > Max.gety() || + M.getz() < Min.getz() || m.getz() > Max.getz()) return; + } + + bool ambientdiffuse=true; + bool emission=true; + + if(colors) { + glEnable(GL_COLOR_MATERIAL); + if(lighton) { + glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE); + ambientdiffuse=false; + } else { + glColorMaterial(GL_FRONT_AND_BACK,GL_EMISSION); + emission=false; + } + } + + if(ambientdiffuse) { + GLfloat Diffuse[]={diffuse.R,diffuse.G,diffuse.B,diffuse.A}; + glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,Diffuse); + + GLfloat Ambient[]={ambient.R,ambient.G,ambient.B,ambient.A}; + glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,Ambient); + } + + if(emission) { + GLfloat Emissive[]={emissive.R,emissive.G,emissive.B,emissive.A}; + glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,Emissive); + } + + GLfloat Specular[]={specular.R,specular.G,specular.B,specular.A}; + glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,Specular); + + glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,128.0*shininess); + + gluNurbsCallback(nurb,GLU_NURBS_NORMAL,(_GLUfuncptr) glNormal3fv); + gluBeginSurface(nurb); + int uorder=udegree+1; + int vorder=vdegree+1; + size_t stride=weights == NULL ? 3 : 4; + gluNurbsSurface(nurb,uorder+nu,uKnots,vorder+nv,vKnots,stride*nv,stride, + Controls,uorder,vorder, + weights == NULL ? GL_MAP2_VERTEX_3 : GL_MAP2_VERTEX_4); + if(colors) { + static GLfloat linear[]={0.0,0.0,1.0,1.0}; + gluNurbsSurface(nurb,4,linear,4,linear,8,4,colors,2,2,GL_MAP2_COLOR_4); + } + + gluEndSurface(nurb); + + if(colors) + glDisable(GL_COLOR_MATERIAL); +#endif } } //namespace camp |