diff options
author | Karl Berry <karl@freefriends.org> | 2009-05-16 00:19:13 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2009-05-16 00:19:13 +0000 |
commit | bab45528d65eaafe68a705dbb2a57075c7b7cbd8 (patch) | |
tree | 10b4ae2b5195c8dede153ab89359ec00f55f325f /Build/source/utils/asymptote/drawsurface.cc | |
parent | 8643d90372e9c31e0f461c15c596b60a545bd7d3 (diff) |
asymptote 1.72 sources (not integrated into build yet)
git-svn-id: svn://tug.org/texlive/trunk@13110 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/utils/asymptote/drawsurface.cc')
-rw-r--r-- | Build/source/utils/asymptote/drawsurface.cc | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/Build/source/utils/asymptote/drawsurface.cc b/Build/source/utils/asymptote/drawsurface.cc new file mode 100644 index 00000000000..af6f0cd8722 --- /dev/null +++ b/Build/source/utils/asymptote/drawsurface.cc @@ -0,0 +1,299 @@ +/***** + * drawsurface.cc + * + * Stores a surface that has been added to a picture. + *****/ + +#include "drawsurface.h" + +namespace camp { + +const double pixel=1.0; // Adaptive rendering constant. + +using vm::array; +triple drawSurface::c3[]; + +inline void initMatrix(GLfloat *v, double x, double ymin, double zmin, + double ymax, double zmax) +{ + v[0]=x; + v[1]=ymin; + v[2]=zmin; + v[3]=1.0; + v[4]=x; + v[5]=ymin; + v[6]=zmax; + v[7]=1.0; + v[8]=x; + v[9]=ymax; + v[10]=zmin; + v[11]=1.0; + v[12]=x; + v[13]=ymax; + v[14]=zmax; + v[15]=1.0; +} + +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 xmin=bound(c1,min,b.empty ? c0 : min(c0,b.left)); + double xmax=bound(c1,max,b.empty ? c0 : max(c0,b.right)); + + for(int i=0; i < 16; ++i) + c1[i]=controls[i][1]; + c0=c1[0]; + double ymin=bound(c1,min,b.empty ? c0 : min(c0,b.bottom)); + double ymax=bound(c1,max,b.empty ? c0 : max(c0,b.top)); + + for(int i=0; i < 16; ++i) + c1[i]=controls[i][2]; + c0=c1[0]; + double zmin=bound(c1,min,b.empty ? c0 : min(c0,b.lower)); + double zmax=bound(c1,max,b.empty ? c0 : max(c0,b.upper)); + + Min=triple(xmin,ymin,zmin); + Max=triple(xmax,ymax,zmax); + + b.add(Min); + b.add(Max); +} + +void drawSurface::bounds(pair &b, double (*m)(double, double), + double (*x)(const triple&, double*), + double (*y)(const triple&, double*), + double *t, bool &first) +{ + for(int i=0; i < 16; ++i) { + double *ci=controls[i]; + c3[i]=triple(ci[0],ci[1],ci[2]); + } + + if(first) { + triple v=c3[0]; + b=pair(x(v,t),y(v,t)); + first=false; + } + + b=pair(bound(c3,m,x,t,b.getx()),bound(c3,m,y,t,b.gety())); +} + +bool drawSurface::write(prcfile *out) +{ + if(invisible) + return true; + + PRCMaterial m(ambient,diffuse,emissive,specular,opacity,shininess); + out->add(new PRCBezierSurface(out,3,3,4,4,controls,m,granularity)); + + return true; +} + +// return the perpendicular displacement of a point z from the plane +// through u with unit normal n. +inline triple displacement2(const Triple& z, const Triple& u, const triple& n) +{ + triple Z=triple(z)-triple(u); + return n != triple(0,0,0) ? dot(Z,n)*n : Z; +} + +inline triple maxabs(triple u, triple v) +{ + return triple(max(fabs(u.getx()),fabs(v.getx())), + max(fabs(u.gety()),fabs(v.gety())), + max(fabs(u.getz()),fabs(v.getz()))); +} + +inline triple displacement(const Triple& z0, const Triple& c0, + const Triple& c1, const Triple& z1) +{ + triple Z0(z0); + triple Z1(z1); + return maxabs(displacement(triple(c0[0],c0[1],c0[2]),Z0,Z1), + displacement(triple(c1[0],c1[1],c1[2]),Z0,Z1)); +} + +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); + d=zero; + + if(!straight) { + for(int 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) + 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) + d=camp::maxabs(d,camp::displacement(controls[i],controls[i+4], + controls[i+8],controls[i+12])); + } + } +#endif +} + +inline double fraction(double d, double size) +{ + return size == 0 ? 1.0 : min(fabs(d)/size,1.0); +} + +// estimate the viewport fraction associated with the displacement d +inline double fraction(const triple& d, const triple& size) +{ + return max(max(fraction(d.getx(),size.getx()), + fraction(d.gety(),size.gety())), + fraction(d.getz(),size.getz())); +} + +void drawSurface::render(GLUnurbs *nurb, double size2, + const triple& Min, const triple& Max, + double perspective, bool transparent) +{ +#ifdef HAVE_LIBGL + if(invisible || (havetransparency ^ transparent)) return; + + static GLfloat v[16]; + + 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(havecolors) { + 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); + + triple size3=triple(s*(Max.getx()-Min.getx()),s*(Max.gety()-Min.gety()), + Max.getz()-Min.getz()); + + if(!havenormal || (!straight && (fraction(d,size3)*size2 >= pixel || + granularity == 0))) { + if(lighton) { + if(havenormal && fraction(dperp,size3)*size2 <= 0.1) { + glNormal3fv(Normal); + gluNurbsCallback(nurb,GLU_NURBS_NORMAL,NULL); + } else + gluNurbsCallback(nurb,GLU_NURBS_NORMAL,(_GLUfuncptr) glNormal3fv); + } + 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,3,12,c,4,4,GL_MAP2_VERTEX_3); + if(havecolors) { + static GLfloat linear[]={0.0,0.0,1.0,1.0}; + gluNurbsSurface(nurb,4,linear,4,linear,4,8,colors,2,2,GL_MAP2_COLOR_4); + } + + gluEndSurface(nurb); + } else { + glBegin(GL_QUADS); + if(lighton) + glNormal3fv(Normal); + if(havecolors) + glColor4fv(colors); + glVertex3fv(c); + if(havecolors) + glColor4fv(colors+4); + glVertex3fv(c+9); + if(havecolors) + glColor4fv(colors+12); + glVertex3fv(c+45); + if(havecolors) + glColor4fv(colors+8); + glVertex3fv(c+36); + glEnd(); + } + + if(havecolors) + glDisable(GL_COLOR_MATERIAL); +#endif +} + +drawElement *drawSurface::transformed(const array& t) +{ + return new drawSurface(t,this); +} + +} //namespace camp |