summaryrefslogtreecommitdiff
path: root/Build/source/utils/asymptote/drawsurface.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/utils/asymptote/drawsurface.cc')
-rw-r--r--Build/source/utils/asymptote/drawsurface.cc424
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