summaryrefslogtreecommitdiff
path: root/graphics/asymptote/drawsurface.h
diff options
context:
space:
mode:
Diffstat (limited to 'graphics/asymptote/drawsurface.h')
-rw-r--r--graphics/asymptote/drawsurface.h655
1 files changed, 655 insertions, 0 deletions
diff --git a/graphics/asymptote/drawsurface.h b/graphics/asymptote/drawsurface.h
new file mode 100644
index 0000000000..226de59db7
--- /dev/null
+++ b/graphics/asymptote/drawsurface.h
@@ -0,0 +1,655 @@
+/*****
+ * drawsurface.h
+ *
+ * Stores a surface that has been added to a picture.
+ *****/
+
+#ifndef DRAWSURFACE_H
+#define DRAWSURFACE_H
+
+#include "drawelement.h"
+#include "arrayop.h"
+#include "path3.h"
+#include "beziercurve.h"
+#include "bezierpatch.h"
+
+namespace camp {
+
+#ifdef HAVE_GL
+void storecolor(GLfloat *colors, int i, const vm::array &pens, int j);
+#endif
+
+class drawSurface : public drawElement {
+protected:
+ triple *controls;
+ size_t ncontrols;
+ triple center;
+ bool straight; // True iff Bezier patch is planar and has straight edges.
+ prc::RGBAColour diffuse;
+ prc::RGBAColour emissive;
+ prc::RGBAColour specular;
+ prc::RGBAColour *colors;
+ double opacity;
+ double shininess;
+ double metallic;
+ double fresnel0;
+ double PRCshininess;
+ bool invisible;
+ Interaction interaction;
+
+ triple Min,Max;
+ bool prc;
+
+public:
+#ifdef HAVE_GL
+ static BezierCurve C;
+#endif
+
+ string wrongsize() {
+ return (ncontrols == 16 ? "4x4" : "triangular")+
+ string(" array of triples and array of 4 pens required");
+ }
+
+ drawSurface(const vm::array& g, size_t ncontrols, triple center,
+ bool straight, const vm::array&p, double opacity,
+ double shininess, double metallic, double fresnel0, double PRCshininess, const vm::array &pens,
+ Interaction interaction, bool prc, const string& key="") :
+ drawElement(key), ncontrols(ncontrols), center(center), straight(straight),
+ opacity(opacity), shininess(shininess), metallic(metallic), fresnel0(fresnel0), PRCshininess(PRCshininess),
+ interaction(interaction), prc(prc) {
+ if(checkArray(&g) != 4 || checkArray(&p) != 3)
+ reportError(wrongsize());
+
+ size_t k=0;
+ controls=new(UseGC) triple[ncontrols];
+ for(unsigned int i=0; i < 4; ++i) {
+ vm::array *gi=vm::read<vm::array*>(g,i);
+ size_t n=(ncontrols == 16 ? 4 : i+1);
+ if(checkArray(gi) != n)
+ reportError(wrongsize());
+ for(unsigned int j=0; j < n; ++j)
+ controls[k++]=vm::read<triple>(gi,j);
+ }
+
+ pen surfacepen=vm::read<camp::pen>(p,0);
+ invisible=surfacepen.invisible();
+
+ diffuse=rgba(surfacepen);
+ emissive=rgba(vm::read<camp::pen>(p,1));
+ specular=rgba(vm::read<camp::pen>(p,2));
+
+ size_t nodes=(ncontrols == 16 ? 4 : 3);
+ size_t size=checkArray(&pens);
+ if(size > 0) {
+ if(size != nodes) reportError("4 vertex pens required");
+ colors=new(UseGC) prc::RGBAColour[nodes];
+ for(size_t i=0; i < nodes; ++i)
+ colors[i]=rgba(vm::read<camp::pen>(pens,i));
+ } else colors=NULL;
+ }
+
+ drawSurface(const double* t, const drawSurface *s) :
+ drawElement(s->KEY), ncontrols(s->ncontrols), straight(s->straight),
+ diffuse(s->diffuse), emissive(s->emissive),
+ specular(s->specular), colors(s->colors), opacity(s->opacity),
+ shininess(s->shininess), metallic(s->metallic), fresnel0(s->fresnel0),
+ PRCshininess(s->PRCshininess), invisible(s->invisible),
+ interaction(s->interaction), prc(s->prc) {
+
+ if(s->controls) {
+ controls=new(UseGC) triple[ncontrols];
+ for(unsigned int i=0; i < ncontrols; ++i)
+ controls[i]=t*s->controls[i];
+ } else controls=NULL;
+
+#ifdef HAVE_GL
+ center=t*s->center;
+#endif
+ }
+
+ virtual ~drawSurface() {}
+
+ bool is3D() {return true;}
+};
+
+class drawBezierPatch : public drawSurface {
+public:
+#ifdef HAVE_GL
+ static BezierPatch S;
+#endif
+
+ drawBezierPatch(const vm::array& g, triple center, bool straight,
+ const vm::array&p, double opacity, double shininess,
+ double metallic, double fresnel0,
+ double PRCshininess, const vm::array &pens,
+ Interaction interaction, bool prc) :
+ drawSurface(g,16,center,straight,p,opacity,
+ shininess,metallic,fresnel0,PRCshininess,pens,interaction,prc) {}
+
+ drawBezierPatch(const double* t, const drawBezierPatch *s) :
+ drawSurface(t,s) {
+ }
+
+ void bounds(const double* t, bbox3& b);
+
+ void ratio(const double* t, pair &b, double (*m)(double, double),
+ double fuzz, bool &first);
+
+ bool write(prcfile *out, unsigned int *, double, groupsmap&);
+
+ void render(double, const triple& Min, const triple& Max,
+ double perspective, bool transparent);
+ drawElement *transformed(const double* t);
+};
+
+class drawBezierTriangle : public drawSurface {
+public:
+#ifdef HAVE_GL
+ static BezierTriangle S;
+#endif
+
+ drawBezierTriangle(const vm::array& g, triple center, bool straight,
+ const vm::array&p, double opacity, double shininess,
+ double metallic, double fresnel0,
+ double PRCshininess, const vm::array &pens,
+ Interaction interaction, bool prc) :
+ drawSurface(g,10,center,straight,p,opacity,shininess,metallic,fresnel0,
+ PRCshininess,pens,interaction,prc) {}
+
+ drawBezierTriangle(const double* t, const drawBezierTriangle *s) :
+ drawSurface(t,s) {
+ }
+
+ void bounds(const double* t, bbox3& b);
+
+ void ratio(const double* t, pair &b, double (*m)(double, double),
+ double fuzz, bool &first);
+
+ bool write(prcfile *out, unsigned int *, double, groupsmap&);
+
+ void render(double, const triple& Min, const triple& Max,
+ double perspective, bool transparent);
+ drawElement *transformed(const double* t);
+};
+
+class drawNurbs : public drawElement {
+protected:
+ size_t udegree,vdegree;
+ size_t nu,nv;
+ triple *controls;
+ double *weights;
+ double *uknots, *vknots;
+ prc::RGBAColour diffuse;
+ prc::RGBAColour emissive;
+ prc::RGBAColour specular;
+ double opacity;
+ double shininess;
+ double metallic;
+ double fresnel0;
+ double PRCshininess;
+ triple normal;
+ bool invisible;
+
+ triple Min,Max;
+
+#ifdef HAVE_GL
+ GLfloat *colors;
+ GLfloat *Controls;
+ GLfloat *uKnots;
+ GLfloat *vKnots;
+#endif
+
+public:
+ drawNurbs(const vm::array& g, const vm::array* uknot, const vm::array* vknot,
+ const vm::array* weight, const vm::array&p, double opacity,
+ double shininess, double metallic, double fresnel0, double PRCshininess, const vm::array &pens,
+ const string& key="")
+ : drawElement(key), opacity(opacity), shininess(shininess),
+ metallic(metallic), fresnel0(fresnel0), PRCshininess(PRCshininess) {
+ size_t weightsize=checkArray(weight);
+
+ const string wrongsize="Inconsistent NURBS data";
+ nu=checkArray(&g);
+
+ if(nu == 0 || (weightsize != 0 && weightsize != nu) || checkArray(&p) != 3)
+ reportError(wrongsize);
+
+ vm::array *g0=vm::read<vm::array*>(g,0);
+ nv=checkArray(g0);
+
+ size_t n=nu*nv;
+ controls=new(UseGC) triple[n];
+
+ size_t k=0;
+ for(size_t i=0; i < nu; ++i) {
+ vm::array *gi=vm::read<vm::array*>(g,i);
+ if(checkArray(gi) != nv)
+ reportError(wrongsize);
+ for(size_t j=0; j < nv; ++j)
+ controls[k++]=vm::read<triple>(gi,j);
+ }
+
+ if(weightsize > 0) {
+ size_t k=0;
+ weights=new(UseGC) double[n];
+ for(size_t i=0; i < nu; ++i) {
+ vm::array *weighti=vm::read<vm::array*>(weight,i);
+ if(checkArray(weighti) != nv)
+ reportError(wrongsize);
+ for(size_t j=0; j < nv; ++j)
+ weights[k++]=vm::read<double>(weighti,j);
+ }
+ } else weights=NULL;
+
+ size_t nuknots=checkArray(uknot);
+ size_t nvknots=checkArray(vknot);
+
+ if(nuknots <= nu+1 || nuknots > 2*nu || nvknots <= nv+1 || nvknots > 2*nv)
+ reportError(wrongsize);
+
+ udegree=nuknots-nu-1;
+ vdegree=nvknots-nv-1;
+
+ run::copyArrayC(uknots,uknot,0,UseGC);
+ run::copyArrayC(vknots,vknot,0,UseGC);
+
+ pen surfacepen=vm::read<camp::pen>(p,0);
+ invisible=surfacepen.invisible();
+
+ diffuse=rgba(surfacepen);
+ emissive=rgba(vm::read<camp::pen>(p,1));
+ specular=rgba(vm::read<camp::pen>(p,2));
+
+#ifdef HAVE_GL
+ Controls=NULL;
+ int size=checkArray(&pens);
+ if(size > 0) {
+ colors=new(UseGC) GLfloat[16];
+ if(size != 4) reportError(wrongsize);
+ storecolor(colors,0,pens,0);
+ storecolor(colors,8,pens,1);
+ storecolor(colors,12,pens,2);
+ storecolor(colors,4,pens,3);
+ } else colors=NULL;
+#endif
+ }
+
+ drawNurbs(const double* t, const drawNurbs *s) :
+ drawElement(s->KEY), udegree(s->udegree), vdegree(s->vdegree), nu(s->nu),
+ nv(s->nv), weights(s->weights), uknots(s->uknots), vknots(s->vknots),
+ diffuse(s->diffuse),
+ emissive(s->emissive), specular(s->specular), opacity(s->opacity),
+ shininess(s->shininess), PRCshininess(s->PRCshininess),
+ invisible(s->invisible) {
+
+ const size_t n=nu*nv;
+ controls=new(UseGC) triple[n];
+ for(unsigned int i=0; i < n; ++i)
+ controls[i]=t*s->controls[i];
+
+#ifdef HAVE_GL
+ Controls=NULL;
+ colors=s->colors;
+#endif
+ }
+
+ bool is3D() {return true;}
+
+ void bounds(const double* t, bbox3& b);
+
+ virtual ~drawNurbs() {}
+
+ bool write(prcfile *out, unsigned int *, double, groupsmap&);
+
+ void displacement();
+ void ratio(const double* t, pair &b, double (*m)(double, double), double,
+ bool &first);
+
+ void render(double size2, const triple& Min, const triple& Max,
+ double perspective, bool transparent);
+
+ drawElement *transformed(const double* t);
+};
+
+// Draw a transformed PRC object.
+class drawPRC : public drawElementLC {
+protected:
+ prc::RGBAColour diffuse;
+ prc::RGBAColour emissive;
+ prc::RGBAColour specular;
+ double opacity;
+ double shininess;
+ bool invisible;
+public:
+ drawPRC(const vm::array& t, const vm::array&p, double opacity,
+ double shininess) :
+ drawElementLC(t), opacity(opacity), shininess(shininess) {
+
+ string needthreepens="array of 3 pens required";
+ if(checkArray(&p) != 3)
+ reportError(needthreepens);
+
+ pen surfacepen=vm::read<camp::pen>(p,0);
+ invisible=surfacepen.invisible();
+
+ diffuse=rgba(surfacepen);
+ emissive=rgba(vm::read<camp::pen>(p,1));
+ specular=rgba(vm::read<camp::pen>(p,2));
+ }
+
+ drawPRC(const double* t, const drawPRC *s) :
+ drawElementLC(t,s), diffuse(s->diffuse),
+ emissive(s->emissive), specular(s->specular), opacity(s->opacity),
+ shininess(s->shininess), invisible(s->invisible) {
+ }
+
+ bool write(prcfile *out, unsigned int *, double, groupsmap&) {
+ return true;
+ }
+ virtual void transformedbounds(const double*, bbox3&) {}
+ virtual void transformedratio(const double*, pair&,
+ double (*)(double, double), double, bool&) {}
+
+};
+
+// Draw a PRC unit sphere.
+class drawSphere : public drawPRC {
+ bool half;
+ int type;
+public:
+ drawSphere(const vm::array& t, bool half, const vm::array&p, double opacity,
+ double shininess, int type) :
+ drawPRC(t,p,opacity,shininess), half(half), type(type) {}
+
+ drawSphere(const double* t, const drawSphere *s) :
+ drawElement(s->KEY), drawPRC(t,s), half(s->half), type(s->type) {}
+
+ void P(triple& t, double x, double y, double z);
+
+ bool write(prcfile *out, unsigned int *, double, groupsmap&);
+
+ drawElement *transformed(const double* t) {
+ return new drawSphere(t,this);
+ }
+};
+
+// Draw a PRC unit cylinder.
+class drawCylinder : public drawPRC {
+public:
+ drawCylinder(const vm::array& t, const vm::array&p, double opacity,
+ double shininess) :
+ drawPRC(t,p,opacity,shininess) {}
+
+ drawCylinder(const double* t, const drawCylinder *s) :
+ drawPRC(t,s) {}
+
+ bool write(prcfile *out, unsigned int *, double, groupsmap&);
+
+ drawElement *transformed(const double* t) {
+ return new drawCylinder(t,this);
+ }
+};
+
+// Draw a PRC unit disk.
+class drawDisk : public drawPRC {
+public:
+ drawDisk(const vm::array& t, const vm::array&p, double opacity,
+ double shininess) :
+ drawPRC(t,p,opacity,shininess) {}
+
+ drawDisk(const double* t, const drawDisk *s) :
+ drawPRC(t,s) {}
+
+ bool write(prcfile *out, unsigned int *, double, groupsmap&);
+
+ drawElement *transformed(const double* t) {
+ return new drawDisk(t,this);
+ }
+};
+
+// Draw a PRC tube.
+class drawTube : public drawElement {
+protected:
+ path3 center;
+ path3 g;
+ prc::RGBAColour diffuse;
+ prc::RGBAColour emissive;
+ prc::RGBAColour specular;
+ double opacity;
+ double shininess;
+ bool invisible;
+public:
+ drawTube(path3 center, path3 g, const vm::array&p, double opacity,
+ double shininess) :
+ center(center), g(g), opacity(opacity), shininess(shininess) {
+ string needthreepens="array of 3 pens required";
+ if(checkArray(&p) != 3)
+ reportError(needthreepens);
+
+ pen surfacepen=vm::read<camp::pen>(p,0);
+ invisible=surfacepen.invisible();
+
+ diffuse=rgba(surfacepen);
+ emissive=rgba(vm::read<camp::pen>(p,1));
+ specular=rgba(vm::read<camp::pen>(p,2));
+ }
+
+ drawTube(const double* t, const drawTube *s) :
+ drawElement(s->KEY), center(camp::transformed(t,s->center)),
+ g(camp::transformed(t,s->g)),
+ diffuse(s->diffuse), emissive(s->emissive),
+ specular(s->specular), opacity(s->opacity),
+ shininess(s->shininess), invisible(s->invisible) {
+ }
+
+ bool write(prcfile *out, unsigned int *, double, groupsmap&);
+
+ drawElement *transformed(const double* t) {
+ return new drawTube(t,this);
+ }
+};
+
+
+class drawBaseTriangles : public drawElement {
+protected:
+#ifdef HAVE_GL
+ Triangles R;
+#endif
+
+ size_t nP;
+ triple* P;
+ size_t nN;
+ triple* N;
+ size_t nI;
+ uint32_t (*PI)[3];
+ uint32_t (*NI)[3];
+
+ triple Min,Max;
+
+ static const string wrongsize;
+ static const string outofrange;
+
+public:
+ drawBaseTriangles(const vm::array& v, const vm::array& vi,
+ const vm::array& n, const vm::array& ni) {
+ nP=checkArray(&v);
+ P=new(UseGC) triple[nP];
+ for(size_t i=0; i < nP; ++i)
+ P[i]=vm::read<triple>(v,i);
+
+ nI=checkArray(&vi);
+ PI=new(UseGC) uint32_t[nI][3];
+ for(size_t i=0; i < nI; ++i) {
+ vm::array *vii=vm::read<vm::array*>(vi,i);
+ if(checkArray(vii) != 3) reportError(wrongsize);
+ uint32_t *PIi=PI[i];
+ for(size_t j=0; j < 3; ++j) {
+ size_t index=unsignedcast(vm::read<Int>(vii,j));
+ if(index >= nP) reportError(outofrange);
+ PIi[j]=index;
+ }
+ }
+
+ nN=checkArray(&n);
+ if(nN) {
+ N=new(UseGC) triple[nN];
+ for(size_t i=0; i < nN; ++i)
+ N[i]=vm::read<triple>(n,i);
+
+ if(checkArray(&ni) != nI)
+ reportError("Index arrays have different lengths");
+ NI=new(UseGC) uint32_t[nI][3];
+ for(size_t i=0; i < nI; ++i) {
+ vm::array *nii=vm::read<vm::array*>(ni,i);
+ if(checkArray(nii) != 3) reportError(wrongsize);
+ uint32_t *NIi=NI[i];
+ for(size_t j=0; j < 3; ++j) {
+ size_t index=unsignedcast(vm::read<Int>(nii,j));
+ if(index >= nN) reportError(outofrange);
+ NIi[j]=index;
+ }
+ }
+ }
+ }
+
+ drawBaseTriangles(const double* t, const drawBaseTriangles *s) :
+ drawElement(s->KEY), nP(s->nP), nN(s->nN), nI(s->nI) {
+ P=new(UseGC) triple[nP];
+ for(size_t i=0; i < nP; i++)
+ P[i]=t*s->P[i];
+
+ PI=new(UseGC) uint32_t[nI][3];
+ for(size_t i=0; i < nI; ++i) {
+ uint32_t *PIi=PI[i];
+ uint32_t *sPIi=s->PI[i];
+ for(size_t j=0; j < 3; ++j)
+ PIi[j]=sPIi[j];
+ }
+
+ if(nN) {
+ N=new(UseGC) triple[nN];
+ for(size_t i=0; i < nN; i++)
+ N[i]=transformNormal(t,s->N[i]);
+
+ NI=new(UseGC) uint32_t[nI][3];
+ for(size_t i=0; i < nI; ++i) {
+ uint32_t *NIi=NI[i];
+ uint32_t *sNIi=s->NI[i];
+ for(size_t j=0; j < 3; ++j)
+ NIi[j]=sNIi[j];
+ }
+ }
+ }
+
+ bool is3D() {return true;}
+
+ void bounds(const double* t, bbox3& b);
+
+ void ratio(const double* t, pair &b, double (*m)(double, double),
+ double fuzz, bool &first);
+
+ virtual ~drawBaseTriangles() {}
+
+ drawElement *transformed(const double* t) {
+ return new drawBaseTriangles(t,this);
+ }
+};
+
+class drawTriangles : public drawBaseTriangles {
+ size_t nC;
+ prc::RGBAColour*C;
+ uint32_t (*CI)[3];
+
+ // Asymptote material data
+ prc::RGBAColour diffuse;
+ prc::RGBAColour emissive;
+ prc::RGBAColour specular;
+ double opacity;
+ double shininess;
+ double metallic;
+ double fresnel0;
+ double PRCshininess;
+ bool invisible;
+
+public:
+ drawTriangles(const vm::array& v, const vm::array& vi,
+ const vm::array& n, const vm::array& ni,
+ const vm::array&p, double opacity, double shininess,
+ double metallic, double fresnel0,
+ double PRCshininess, const vm::array& c, const vm::array& ci) :
+ drawBaseTriangles(v,vi,n,ni),
+ opacity(opacity),shininess(shininess),metallic(metallic),
+ fresnel0(fresnel0),PRCshininess(PRCshininess) {
+
+ const string needthreepens="array of 3 pens required";
+ if(checkArray(&p) != 3)
+ reportError(needthreepens);
+
+ const pen surfacepen=vm::read<camp::pen>(p,0);
+ invisible=surfacepen.invisible();
+ diffuse=rgba(surfacepen);
+
+ nC=checkArray(&c);
+ if(nC) {
+ C=new(UseGC) prc::RGBAColour[nC];
+ for(size_t i=0; i < nC; ++i)
+ C[i]=rgba(vm::read<camp::pen>(c,i));
+
+ size_t nI=checkArray(&vi);
+
+ if(checkArray(&ci) != nI)
+ reportError("Index arrays have different lengths");
+ CI=new(UseGC) uint32_t[nI][3];
+ for(size_t i=0; i < nI; ++i) {
+ vm::array *cii=vm::read<vm::array*>(ci,i);
+ if(checkArray(cii) != 3) reportError(wrongsize);
+ uint32_t *CIi=CI[i];
+ for(size_t j=0; j < 3; ++j) {
+ size_t index=unsignedcast(vm::read<Int>(cii,j));
+ if(index >= nC) reportError(outofrange);
+ CIi[j]=index;
+ }
+ }
+ } else {
+ emissive=rgba(vm::read<camp::pen>(p,1));
+ }
+ specular=rgba(vm::read<camp::pen>(p,2));
+ }
+
+ drawTriangles(const double* t, const drawTriangles *s) :
+ drawBaseTriangles(t,s), nC(s->nC),
+ diffuse(s->diffuse), emissive(s->emissive),
+ specular(s->specular), opacity(s->opacity), shininess(s->shininess),
+ metallic(s->metallic), fresnel0(s->fresnel0), PRCshininess(s->PRCshininess),
+ invisible(s->invisible) {
+
+ if(nC) {
+ C=new(UseGC) prc::RGBAColour[nC];
+ for(size_t i=0; i < nC; ++i)
+ C[i]=s->C[i];
+
+ CI=new(UseGC) uint32_t[nI][3];
+ for(size_t i=0; i < nI; ++i) {
+ uint32_t *CIi=CI[i];
+ uint32_t *sCIi=s->CI[i];
+ for(size_t j=0; j < 3; ++j)
+ CIi[j]=sCIi[j];
+ }
+ }
+ }
+
+ virtual ~drawTriangles() {}
+
+ void render(double size2, const triple& Min, const triple& Max,
+ double perspective, bool transparent);
+
+ bool write(prcfile *out, unsigned int *, double, groupsmap&);
+
+ drawElement *transformed(const double* t) {
+ return new drawTriangles(t,this);
+ }
+};
+
+}
+
+#endif