1 /*****
2  * drawsurface.h
3  *
4  * Stores a surface that has been added to a picture.
5  *****/
6 
7 #ifndef DRAWSURFACE_H
8 #define DRAWSURFACE_H
9 
10 #include "drawelement.h"
11 #include "arrayop.h"
12 #include "path3.h"
13 #include "beziercurve.h"
14 #include "bezierpatch.h"
15 
16 namespace run {
17 void inverse(double *a, size_t n);
18 }
19 
20 const string need3pens="array of 3 pens required";
21 
22 namespace camp {
23 
24 #ifdef HAVE_LIBGLM
25 void storecolor(GLfloat *colors, int i, const vm::array &pens, int j);
26 #endif
27 
28 class drawSurface : public drawElement {
29 protected:
30   triple *controls;
31   size_t ncontrols;
32   triple center;
33   bool straight; // True iff Bezier patch is planar and has straight edges.
34   prc::RGBAColour diffuse;
35   prc::RGBAColour emissive;
36   prc::RGBAColour specular;
37   prc::RGBAColour *colors;
38   double opacity;
39   double shininess;
40   double metallic;
41   double fresnel0;
42   bool invisible;
43   Interaction interaction;
44   bool billboard;
45   size_t centerIndex;
46 
47   triple Min,Max;
48   int digits;
49   bool primitive;
50 
51 public:
52 #ifdef HAVE_GL
53   BezierCurve C;
54   bool transparent;
55 #endif
56 
wrongsize()57   string wrongsize() {
58     return (ncontrols == 16 ? "4x4" : "triangular")+
59       string(" array of triples and array of 4 pens required");
60   }
61 
init()62   void init() {
63 #ifdef HAVE_LIBOSMESA
64     billboard=false;
65 #else
66     billboard=interaction == BILLBOARD;
67 #endif
68     centerIndex=0;
69   }
70 
71   drawSurface(const vm::array& g, size_t ncontrols, triple center,
72               bool straight, const vm::array&p, double opacity,
73               double shininess, double metallic, double fresnel0,
74               const vm::array &pens, Interaction interaction, int digits,
75               bool primitive=true, const string& key="") :
drawElement(key)76     drawElement(key), ncontrols(ncontrols), center(center), straight(straight),
77     opacity(opacity), shininess(shininess), metallic(metallic),
78     fresnel0(fresnel0), interaction(interaction), digits(digits),
79     primitive(primitive) {
80     init();
81     if(checkArray(&g) != 4 || checkArray(&p) != 3)
82       reportError(wrongsize());
83 
84     size_t k=0;
85     controls=new(UseGC) triple[ncontrols];
86     for(unsigned int i=0; i < 4; ++i) {
87       vm::array *gi=vm::read<vm::array*>(g,i);
88       size_t n=(ncontrols == 16 ? 4 : i+1);
89       if(checkArray(gi) != n)
90         reportError(wrongsize());
91       for(unsigned int j=0; j < n; ++j)
92         controls[k++]=vm::read<triple>(gi,j);
93     }
94 
95     pen surfacepen=vm::read<camp::pen>(p,0);
96     invisible=surfacepen.invisible();
97 
98     diffuse=rgba(surfacepen);
99     emissive=rgba(vm::read<camp::pen>(p,1));
100     specular=rgba(vm::read<camp::pen>(p,2));
101 
102     size_t nodes=(ncontrols == 16 ? 4 : 3);
103     size_t size=checkArray(&pens);
104     if(size > 0) {
105       if(size != nodes) reportError("one vertex pen required per node");
106       colors=new(UseGC) prc::RGBAColour[nodes];
107       for(size_t i=0; i < nodes; ++i)
108         colors[i]=rgba(vm::read<camp::pen>(pens,i));
109     } else colors=NULL;
110   }
111 
drawSurface(const double * t,const drawSurface * s)112   drawSurface(const double* t, const drawSurface *s) :
113     drawElement(s->KEY), ncontrols(s->ncontrols), straight(s->straight),
114     diffuse(s->diffuse), emissive(s->emissive), specular(s->specular),
115     colors(s->colors), opacity(s->opacity), shininess(s->shininess),
116     metallic(s->metallic), fresnel0(s->fresnel0), invisible(s->invisible),
117     interaction(s->interaction), digits(s->digits), primitive(s->primitive) {
118     init();
119     if(s->controls) {
120       controls=new(UseGC) triple[ncontrols];
121       for(unsigned int i=0; i < ncontrols; ++i)
122         controls[i]=t*s->controls[i];
123     } else controls=NULL;
124 
125     center=t*s->center;
126   }
127 
~drawSurface()128   virtual ~drawSurface() {}
129 
is3D()130   bool is3D() {return true;}
131 };
132 
133 class drawBezierPatch : public drawSurface {
134 public:
135 #ifdef HAVE_GL
136   BezierPatch S;
137 #endif
138 
drawBezierPatch(const vm::array & g,triple center,bool straight,const vm::array & p,double opacity,double shininess,double metallic,double fresnel0,const vm::array & pens,Interaction interaction,int digits,bool primitive)139   drawBezierPatch(const vm::array& g, triple center, bool straight,
140                   const vm::array&p, double opacity, double shininess,
141                   double metallic, double fresnel0, const vm::array &pens,
142                   Interaction interaction, int digits, bool primitive) :
143     drawSurface(g,16,center,straight,p,opacity,shininess,metallic,fresnel0,
144                 pens,interaction,digits,primitive) {}
145 
drawBezierPatch(const double * t,const drawBezierPatch * s)146   drawBezierPatch(const double* t, const drawBezierPatch *s) :
147     drawSurface(t,s) {}
148 
149   void bounds(const double* t, bbox3& b);
150 
151   void ratio(const double* t, pair &b, double (*m)(double, double),
152              double fuzz, bool &first);
153 
meshinit()154   void meshinit() {
155     if(billboard)
156       centerIndex=centerindex(center);
157   }
158 
159   bool write(prcfile *out, unsigned int *, double, groupsmap&);
160   bool write(jsfile *out);
161 
162   void render(double, const triple& b, const triple& B,
163               double perspective, bool remesh);
164   drawElement *transformed(const double* t);
165 };
166 
167 class drawBezierTriangle : public drawSurface {
168 public:
169 #ifdef HAVE_GL
170   BezierTriangle S;
171 #endif
172 
drawBezierTriangle(const vm::array & g,triple center,bool straight,const vm::array & p,double opacity,double shininess,double metallic,double fresnel0,const vm::array & pens,Interaction interaction,int digits,bool primitive)173   drawBezierTriangle(const vm::array& g, triple center, bool straight,
174                      const vm::array&p, double opacity, double shininess,
175                      double metallic, double fresnel0, const vm::array &pens,
176                      Interaction interaction, int digits, bool primitive) :
177     drawSurface(g,10,center,straight,p,opacity,shininess,metallic,fresnel0,
178                 pens,interaction,digits,primitive) {}
179 
drawBezierTriangle(const double * t,const drawBezierTriangle * s)180   drawBezierTriangle(const double* t, const drawBezierTriangle *s) :
181     drawSurface(t,s) {}
182 
183   void bounds(const double* t, bbox3& b);
184 
185   void ratio(const double* t, pair &b, double (*m)(double, double),
186              double fuzz, bool &first);
187 
meshinit()188   void meshinit() {
189     if(billboard)
190       centerIndex=centerindex(center);
191   }
192 
193   bool write(prcfile *out, unsigned int *, double, groupsmap&);
194   bool write(jsfile *out);
195 
196   void render(double, const triple& b, const triple& B,
197               double perspective, bool remesh);
198   drawElement *transformed(const double* t);
199 };
200 
201 class drawNurbs : public drawElement {
202 protected:
203   size_t udegree,vdegree;
204   size_t nu,nv;
205   triple *controls;
206   double *weights;
207   double *uknots, *vknots;
208   prc::RGBAColour diffuse;
209   prc::RGBAColour emissive;
210   prc::RGBAColour specular;
211   double opacity;
212   double shininess;
213   double metallic;
214   double fresnel0;
215   triple normal;
216   bool invisible;
217 
218   triple Min,Max;
219 
220 #ifdef HAVE_LIBGLM
221   GLfloat *colors;
222   GLfloat *Controls;
223   GLfloat *uKnots;
224   GLfloat *vKnots;
225 #endif
226 
227 public:
228   drawNurbs(const vm::array& g, const vm::array* uknot, const vm::array* vknot,
229             const vm::array* weight, const vm::array&p, double opacity,
230             double shininess, double metallic, double fresnel0,
231             const vm::array &pens, const string& key="")
drawElement(key)232     : drawElement(key), opacity(opacity), shininess(shininess),
233       metallic(metallic), fresnel0(fresnel0) {
234     size_t weightsize=checkArray(weight);
235 
236     const string wrongsize="Inconsistent NURBS data";
237     nu=checkArray(&g);
238 
239     if(nu == 0 || (weightsize != 0 && weightsize != nu) || checkArray(&p) != 3)
240       reportError(wrongsize);
241 
242     vm::array *g0=vm::read<vm::array*>(g,0);
243     nv=checkArray(g0);
244 
245     size_t n=nu*nv;
246     controls=new(UseGC) triple[n];
247 
248     size_t k=0;
249     for(size_t i=0; i < nu; ++i) {
250       vm::array *gi=vm::read<vm::array*>(g,i);
251       if(checkArray(gi) != nv)
252         reportError(wrongsize);
253       for(size_t j=0; j < nv; ++j)
254         controls[k++]=vm::read<triple>(gi,j);
255     }
256 
257     if(weightsize > 0) {
258       size_t k=0;
259       weights=new(UseGC) double[n];
260       for(size_t i=0; i < nu; ++i) {
261         vm::array *weighti=vm::read<vm::array*>(weight,i);
262         if(checkArray(weighti) != nv)
263           reportError(wrongsize);
264         for(size_t j=0; j < nv; ++j)
265           weights[k++]=vm::read<double>(weighti,j);
266       }
267     } else weights=NULL;
268 
269     size_t nuknots=checkArray(uknot);
270     size_t nvknots=checkArray(vknot);
271 
272     if(nuknots <= nu+1 || nuknots > 2*nu || nvknots <= nv+1 || nvknots > 2*nv)
273       reportError(wrongsize);
274 
275     udegree=nuknots-nu-1;
276     vdegree=nvknots-nv-1;
277 
278     run::copyArrayC(uknots,uknot,0,UseGC);
279     run::copyArrayC(vknots,vknot,0,UseGC);
280 
281     pen surfacepen=vm::read<camp::pen>(p,0);
282     invisible=surfacepen.invisible();
283 
284     diffuse=rgba(surfacepen);
285     emissive=rgba(vm::read<camp::pen>(p,1));
286     specular=rgba(vm::read<camp::pen>(p,2));
287 
288 #ifdef HAVE_LIBGLM
289     Controls=NULL;
290     int size=checkArray(&pens);
291     if(size > 0) {
292       colors=new(UseGC) GLfloat[16];
293       if(size != 4) reportError(wrongsize);
294       storecolor(colors,0,pens,0);
295       storecolor(colors,8,pens,1);
296       storecolor(colors,12,pens,2);
297       storecolor(colors,4,pens,3);
298     } else colors=NULL;
299 #endif
300   }
301 
drawNurbs(const double * t,const drawNurbs * s)302   drawNurbs(const double* t, const drawNurbs *s) :
303     drawElement(s->KEY), udegree(s->udegree), vdegree(s->vdegree), nu(s->nu),
304     nv(s->nv), weights(s->weights), uknots(s->uknots), vknots(s->vknots),
305     diffuse(s->diffuse),
306     emissive(s->emissive), specular(s->specular), opacity(s->opacity),
307     shininess(s->shininess), invisible(s->invisible) {
308 
309     const size_t n=nu*nv;
310     controls=new(UseGC) triple[n];
311     for(unsigned int i=0; i < n; ++i)
312       controls[i]=t*s->controls[i];
313 
314 #ifdef HAVE_LIBGLM
315     Controls=NULL;
316     colors=s->colors;
317 #endif
318   }
319 
is3D()320   bool is3D() {return true;}
321 
322   void bounds(const double* t, bbox3& b);
323 
~drawNurbs()324   virtual ~drawNurbs() {}
325 
326   bool write(prcfile *out, unsigned int *, double, groupsmap&);
327 
328   void displacement();
329   void ratio(const double* t, pair &b, double (*m)(double, double), double,
330              bool &first);
331 
332   void render(double size2, const triple& b, const triple& B,
333               double perspective, bool remesh);
334 
335   drawElement *transformed(const double* t);
336 };
337 
338 // Draw a transformed PRC object.
339 class drawPRC : public drawElementLC {
340 protected:
341   prc::RGBAColour diffuse;
342   prc::RGBAColour emissive;
343   prc::RGBAColour specular;
344   double opacity;
345   double shininess;
346   double metallic;
347   double fresnel0;
348   bool invisible;
349 public:
init(const vm::array & p)350   void init(const vm::array&p) {
351     if(checkArray(&p) != 3)
352       reportError(need3pens);
353 
354     pen surfacepen=vm::read<camp::pen>(p,0);
355     invisible=surfacepen.invisible();
356 
357     diffuse=rgba(surfacepen);
358     emissive=rgba(vm::read<camp::pen>(p,1));
359     specular=rgba(vm::read<camp::pen>(p,2));
360   }
361 
drawPRC(const vm::array & t,const vm::array & p,double opacity,double shininess,double metallic,double fresnel0)362   drawPRC(const vm::array& t, const vm::array&p, double opacity,
363           double shininess, double metallic, double fresnel0) :
364     drawElementLC(t), opacity(opacity), shininess(shininess),
365     metallic(metallic), fresnel0(fresnel0) {
366     init(p);
367   }
368 
drawPRC(const vm::array & p,double opacity,double shininess,double metallic,double fresnel0)369   drawPRC(const vm::array&p, double opacity,
370           double shininess, double metallic, double fresnel0) :
371     drawElementLC(NULL), opacity(opacity), shininess(shininess),
372     metallic(metallic), fresnel0(fresnel0) {
373     init(p);
374   }
375 
drawPRC(const double * t,const drawPRC * s)376   drawPRC(const double* t, const drawPRC *s) :
377     drawElementLC(t,s), diffuse(s->diffuse),
378     emissive(s->emissive), specular(s->specular), opacity(s->opacity),
379     shininess(s->shininess), metallic(s->metallic), fresnel0(s->fresnel0),
380     invisible(s->invisible) {
381   }
382 
383   virtual void P(triple& t, double x, double y, double z);
384 
write(prcfile * out,unsigned int *,double,groupsmap &)385   virtual bool write(prcfile *out, unsigned int *, double, groupsmap&) {
386     return true;
387   }
388 
write(jsfile * out)389   virtual bool write(jsfile *out) {return true;}
390 
transformedbounds(const double *,bbox3 &)391   virtual void transformedbounds(const double*, bbox3&) {}
transformedratio(const double *,pair &,double (*)(double,double),double,bool &)392   virtual void transformedratio(const double*, pair&,
393                                 double (*)(double, double), double, bool&) {}
394 
395 };
396 
397 // Output a unit sphere primitive.
398 class drawSphere : public drawPRC {
399   bool half;
400   int type;
401 public:
drawSphere(const vm::array & t,bool half,const vm::array & p,double opacity,double shininess,double metallic,double fresnel0,int type)402   drawSphere(const vm::array& t, bool half, const vm::array&p, double opacity,
403              double shininess, double metallic, double fresnel0, int type) :
404     drawPRC(t,p,opacity,shininess,metallic,fresnel0), half(half), type(type) {}
405 
drawSphere(const double * t,const drawSphere * s)406   drawSphere(const double* t, const drawSphere *s) :
407     drawElement(s->KEY), drawPRC(t,s), half(s->half), type(s->type) {}
408 
409   void P(triple& t, double x, double y, double z);
410 
411   bool write(prcfile *out, unsigned int *, double, groupsmap&);
412   bool write(jsfile *out);
413 
transformed(const double * t)414   drawElement *transformed(const double* t) {
415     return new drawSphere(t,this);
416   }
417 };
418 
419 // Output a unit cylinder primitive.
420 class drawCylinder : public drawPRC {
421   bool core;
422 public:
423   drawCylinder(const vm::array& t, const vm::array&p,
424                double opacity, double shininess, double metallic,
425                double fresnel0, bool core=false) :
drawPRC(t,p,opacity,shininess,metallic,fresnel0)426     drawPRC(t,p,opacity,shininess,metallic,fresnel0), core(core) {}
427 
drawCylinder(const double * t,const drawCylinder * s)428   drawCylinder(const double* t, const drawCylinder *s) :
429     drawPRC(t,s), core(s->core) {}
430 
431   bool write(prcfile *out, unsigned int *, double, groupsmap&);
432   bool write(jsfile *out);
433 
transformed(const double * t)434   drawElement *transformed(const double* t) {
435     return new drawCylinder(t,this);
436   }
437 };
438 
439 // Draw a unit disk.
440 class drawDisk : public drawPRC {
441 public:
drawDisk(const vm::array & t,const vm::array & p,double opacity,double shininess,double metallic,double fresnel0)442   drawDisk(const vm::array& t, const vm::array&p, double opacity,
443            double shininess, double metallic, double fresnel0) :
444     drawPRC(t,p,opacity,shininess,metallic,fresnel0) {}
445 
drawDisk(const double * t,const drawDisk * s)446   drawDisk(const double* t, const drawDisk *s) :
447     drawPRC(t,s) {}
448 
449   bool write(prcfile *out, unsigned int *, double, groupsmap&);
450   bool write(jsfile *out);
451 
transformed(const double * t)452   drawElement *transformed(const double* t) {
453     return new drawDisk(t,this);
454   }
455 };
456 
457 // Draw a tube.
458 class drawTube : public drawPRC {
459 protected:
460   triple *g;
461   double width;
462   triple m,M;
463   bool core;
464 public:
drawTube(const vm::array & G,double width,const vm::array & p,double opacity,double shininess,double metallic,double fresnel0,const triple & m,const triple & M,bool core)465   drawTube(const vm::array&G, double width, const vm::array&p, double opacity,
466            double shininess, double metallic, double fresnel0,
467            const triple& m, const triple& M, bool core) :
468     drawPRC(p,opacity,shininess,metallic,fresnel0), width(width), m(m), M(M),
469     core(core) {
470     if(vm::checkArray(&G) != 4)
471       reportError("array of 4 triples required");
472 
473     g=new(UseGC) triple[4];
474     for(size_t i=0; i < 4; ++i)
475       g[i]=vm::read<triple>(G,i);
476   }
477 
drawTube(const double * t,const drawTube * s)478   drawTube(const double* t, const drawTube *s) :
479     drawElement(s->KEY), drawPRC(t,s), width(s->width), m(s->m), M(s->M),
480     core(s->core) {
481     g=new(UseGC) triple[4];
482     for(size_t i=0; i < 4; ++i)
483       g[i]=t*s->g[i];
484   }
485 
486   bool write(jsfile *out);
487 
transformed(const double * t)488   drawElement *transformed(const double* t) {
489     return new drawTube(t,this);
490   }
491 };
492 
493 
494 class drawBaseTriangles : public drawElement {
495 protected:
496 #ifdef HAVE_GL
497   Triangles R;
498   bool transparent;
499 #endif
500 
501   size_t nP;
502   triple* P;
503   size_t nN;
504   triple* N;
505   size_t nI;
506   size_t Ni;
507   uint32_t (*PI)[3];
508   uint32_t (*NI)[3];
509 
510   triple Min,Max;
511 
512   static const string wrongsize;
513   static const string outofrange;
514 
515 public:
drawBaseTriangles(const vm::array & v,const vm::array & vi,const vm::array & n,const vm::array & ni)516   drawBaseTriangles(const vm::array& v, const vm::array& vi,
517                     const vm::array& n, const vm::array& ni) {
518     nP=checkArray(&v);
519     P=new(UseGC) triple[nP];
520     for(size_t i=0; i < nP; ++i)
521       P[i]=vm::read<triple>(v,i);
522 
523     nI=checkArray(&vi);
524     PI=new(UseGC) uint32_t[nI][3];
525     for(size_t i=0; i < nI; ++i) {
526       vm::array *vii=vm::read<vm::array*>(vi,i);
527       if(checkArray(vii) != 3) reportError(wrongsize);
528       uint32_t *PIi=PI[i];
529       for(size_t j=0; j < 3; ++j) {
530         size_t index=unsignedcast(vm::read<Int>(vii,j));
531         if(index >= nP) reportError(outofrange);
532         PIi[j]=index;
533       }
534     }
535 
536     nN=checkArray(&n);
537     if(nN) {
538       N=new(UseGC) triple[nN];
539       for(size_t i=0; i < nN; ++i)
540         N[i]=vm::read<triple>(n,i);
541 
542       Ni=checkArray(&ni);
543       if(Ni == 0 && nN == nP)
544         NI=PI;
545       else {
546         if(Ni != nI)
547           reportError("Index arrays have different lengths");
548         NI=new(UseGC) uint32_t[nI][3];
549         for(size_t i=0; i < nI; ++i) {
550           vm::array *nii=vm::read<vm::array*>(ni,i);
551           if(checkArray(nii) != 3) reportError(wrongsize);
552           uint32_t *NIi=NI[i];
553           for(size_t j=0; j < 3; ++j) {
554             size_t index=unsignedcast(vm::read<Int>(nii,j));
555             if(index >= nN) reportError(outofrange);
556             NIi[j]=index;
557           }
558         }
559       }
560     } else Ni=0;
561   }
562 
drawBaseTriangles(const double * t,const drawBaseTriangles * s)563   drawBaseTriangles(const double* t, const drawBaseTriangles *s) :
564     drawElement(s->KEY), nP(s->nP), nN(s->nN), nI(s->nI), Ni(s->Ni) {
565     P=new(UseGC) triple[nP];
566     for(size_t i=0; i < nP; i++)
567       P[i]=t*s->P[i];
568 
569     PI=new(UseGC) uint32_t[nI][3];
570     for(size_t i=0; i < nI; ++i) {
571       uint32_t *PIi=PI[i];
572       uint32_t *sPIi=s->PI[i];
573       for(size_t j=0; j < 3; ++j)
574         PIi[j]=sPIi[j];
575     }
576 
577     if(nN) {
578       N=new(UseGC) triple[nN];
579       if(t == NULL) {
580         for(size_t i=0; i < nN; i++)
581           N[i]=s->N[i];
582       } else {
583         double T[]={t[0],t[1],t[2],
584                     t[4],t[5],t[6],
585                     t[8],t[9],t[10]};
586         run::inverse(T,3);
587         for(size_t i=0; i < nN; i++)
588           N[i]=unit(Transform3(s->N[i],T));
589       }
590 
591       if(Ni == 0) {
592         NI=PI;
593       } else {
594         NI=new(UseGC) uint32_t[nI][3];
595         for(size_t i=0; i < nI; ++i) {
596           uint32_t *NIi=NI[i];
597           uint32_t *sNIi=s->NI[i];
598           for(size_t j=0; j < 3; ++j)
599             NIi[j]=sNIi[j];
600         }
601       }
602     }
603   }
604 
is3D()605   bool is3D() {return true;}
606 
607   void bounds(const double* t, bbox3& b);
608 
609   void ratio(const double* t, pair &b, double (*m)(double, double),
610              double fuzz, bool &first);
611 
~drawBaseTriangles()612   virtual ~drawBaseTriangles() {}
613 
transformed(const double * t)614   drawElement *transformed(const double* t) {
615     return new drawBaseTriangles(t,this);
616   }
617 };
618 
619 class drawTriangles : public drawBaseTriangles {
620   size_t nC;
621   prc::RGBAColour*C;
622   uint32_t (*CI)[3];
623   size_t Ci;
624 
625   // Asymptote material data
626   prc::RGBAColour diffuse;
627   prc::RGBAColour emissive;
628   prc::RGBAColour specular;
629   double opacity;
630   double shininess;
631   double metallic;
632   double fresnel0;
633   bool invisible;
634 
635 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,const vm::array & c,const vm::array & ci)636   drawTriangles(const vm::array& v, const vm::array& vi,
637                 const vm::array& n, const vm::array& ni,
638                 const vm::array&p, double opacity, double shininess,
639                 double metallic, double fresnel0,
640                 const vm::array& c, const vm::array& ci) :
641     drawBaseTriangles(v,vi,n,ni), opacity(opacity), shininess(shininess),
642     metallic(metallic), fresnel0(fresnel0) {
643 
644     if(checkArray(&p) != 3)
645       reportError(need3pens);
646 
647     const pen surfacepen=vm::read<camp::pen>(p,0);
648     invisible=surfacepen.invisible();
649     diffuse=rgba(surfacepen);
650 
651     nC=checkArray(&c);
652     if(nC) {
653       C=new(UseGC) prc::RGBAColour[nC];
654       for(size_t i=0; i < nC; ++i)
655         C[i]=rgba(vm::read<camp::pen>(c,i));
656 
657       size_t nI=checkArray(&vi);
658 
659       Ci=checkArray(&ci);
660       if(Ci == 0 && nC == nP)
661         CI=PI;
662       else {
663         if(Ci != nI)
664           reportError("Index arrays have different lengths");
665         CI=new(UseGC) uint32_t[nI][3];
666         for(size_t i=0; i < nI; ++i) {
667           vm::array *cii=vm::read<vm::array*>(ci,i);
668           if(checkArray(cii) != 3) reportError(wrongsize);
669           uint32_t *CIi=CI[i];
670           for(size_t j=0; j < 3; ++j) {
671             size_t index=unsignedcast(vm::read<Int>(cii,j));
672             if(index >= nC) reportError(outofrange);
673             CIi[j]=index;
674           }
675         }
676       }
677     } else {
678       emissive=rgba(vm::read<camp::pen>(p,1));
679     }
680     specular=rgba(vm::read<camp::pen>(p,2));
681   }
682 
drawTriangles(const double * t,const drawTriangles * s)683   drawTriangles(const double* t, const drawTriangles *s) :
684     drawBaseTriangles(t,s), nC(s->nC),
685     diffuse(s->diffuse), emissive(s->emissive),
686     specular(s->specular), opacity(s->opacity), shininess(s->shininess),
687     metallic(s->metallic), fresnel0(s->fresnel0), invisible(s->invisible) {
688 
689     if(nC) {
690       C=new(UseGC) prc::RGBAColour[nC];
691       for(size_t i=0; i < nC; ++i)
692         C[i]=s->C[i];
693 
694       CI=new(UseGC) uint32_t[nI][3];
695       for(size_t i=0; i < nI; ++i) {
696         uint32_t *CIi=CI[i];
697         uint32_t *sCIi=s->CI[i];
698         for(size_t j=0; j < 3; ++j)
699           CIi[j]=sCIi[j];
700       }
701     }
702   }
703 
~drawTriangles()704   virtual ~drawTriangles() {}
705 
706   void render(double size2, const triple& b, const triple& B,
707               double perspective, bool remesh);
708 
709   bool write(prcfile *out, unsigned int *, double, groupsmap&);
710   bool write(jsfile *out);
711 
transformed(const double * t)712   drawElement *transformed(const double* t) {
713     return new drawTriangles(t,this);
714   }
715 };
716 
717 }
718 
719 #endif
720