### somebody had to...

good old utah teapot ...with a slight artsy twist ;-)

Log in to post a comment.

```// created by florian berger (flockaroo) - 2018
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

// utah teapot
// ...somebody had to do it

// as usual... using reinder's occlusion from  "Cubic space division #2"

// You can find the Turtle API reference here: https://turtletoy.net/syntax
Canvas.setpenopacity(.5);

// Global code will be evaluated once.
const turtle = new Turtle();
const polygonList = [];
const quads = [];
const nx=8;
const ny=8;

function walk(i) {
return walkCull(i);
}

function walkCull(i) {
var PatchNum = TeapotPatchNum;
var num = nx*ny*PatchNum;
if(i==0){
for(let j=0;j<num;j++) {
var face = teapotFace(nx,ny,j);
var p0=face[0];
var p1=face[1];
var p2=face[2];
var p3=face[3];
var c=scale3(add3(add3(add3(p0,p1),p2),p3),1.0/4.0);
p0=add3(c,scale3(sub3(p0,c),0.7));
p1=add3(c,scale3(sub3(p1,c),0.7));
p2=add3(c,scale3(sub3(p2,c),0.7));
p3=add3(c,scale3(sub3(p3,c),0.7));
p0=transformAll(p0);
p1=transformAll(p1);
p2=transformAll(p2);
p3=transformAll(p3);

//if(cross(sub3(p1,p0),sub3(p2,p0))[2]<0.0)
{
insertQuad(p0,p2,p3,p1);
}
}
}

var p0=[quads[i*9+0],quads[i*9+1]];
var p1=[quads[i*9+2],quads[i*9+3]];
var p2=[quads[i*9+4],quads[i*9+5]];
var p3=[quads[i*9+6],quads[i*9+7]];
const p = new Polygon();
p.cp.push([p0[0], p0[1]]);
p.cp.push([p1[0], p1[1]]);
p.cp.push([p2[0], p2[1]]);
p.cp.push([p3[0], p3[1]]);
p.addOutline(0);
drawPolygon(turtle, p);
return i <= num;
}

// The walk function will be called until it returns false.
function walkNoCull(i) {
var PatchNum = TeapotPatchNum;
var face = teapotFace(nx,ny,i);
var p0=face[0];
var p1=face[1];
var p2=face[2];
var p3=face[3];
var c=scale3(add3(add3(add3(p0,p1),p2),p3),1.0/4.0);
p0=add3(c,scale3(sub3(p0,c),0.7));
p1=add3(c,scale3(sub3(p1,c),0.7));
p2=add3(c,scale3(sub3(p2,c),0.7));
p3=add3(c,scale3(sub3(p3,c),0.7));
p0=transformAll(p0);
p1=transformAll(p1);
p2=transformAll(p2);
p3=transformAll(p3);

turtle.penup();
turtle.goto(p1);
turtle.pendown();
turtle.goto(p0);
turtle.goto(p2);
// draw front faces 3 times - not very efficent (at least for the turtle)
if(cross(sub3(p1,p0),sub3(p2,p0))[2]<0.0)
{
turtle.goto(p3);
turtle.goto(p1);
turtle.goto(p3);
turtle.goto(p2);
turtle.goto(p0);
turtle.goto(p1);
}
return i < nx*ny*PatchNum;
}

function transformAll(p)
{
p=add3(p,vec3(0,0,-1.2));
p=scale3(p,22.0);
p=rotZ(.4,p);
p=rotX(-2.2,p);
p=project(p);
return p;
}

function insertQuad(p0,p1,p2,p3)
{
var z = p0[2]+p1[2]+p2[2]+p3[2];
var idx=0;
for(idx=0;idx<quads.length && quads[idx+8]<z;idx+=9);

// hmm, why is the one below not working... !?
//for(var i=0;i<quads.length;i+=9) {
//    if(quads[i+8]>z) { idx=i; break; }
//}
quads.splice(idx, 0, p0[0], p0[1], p1[0], p1[1], p2[0], p2[1], p3[0], p3[1], z);
}

function project(p)
{
p[2]+=180;
return [p[0]/p[2]*180.,p[1]/p[2]*180.,p[2]];
}

// cubic bezier curve in 2 dimensions
// equivalent to the function above, just in a more intuitive form
function bezierCurvePos(p, t)
{
// combination of 2 quadric beziers
var q=[];
var r=[];
for(var i=0;i<3;i++) q.push(mix3(p[i],p[i+1],t));
for(var i=0;i<2;i++) r.push(mix3(q[i],q[i+1],t));
return mix3(r[0],r[1],t);
}

// cubic bezier patch in 3 dimensions
function bezierPatchPos(p, uv)
{
var curve = [];
// cubic interpolation of control points in 1st parameter
for (var i = 0; i < 4; i++)
{
curve.push( bezierCurvePos([p[i*4],p[i*4+1],p[i*4+2],p[i*4+3]], uv[0]) );
}
// actual cubic bezier in 2nd parameter
return bezierCurvePos(curve, uv[1]);
}

function getTorusPoint(i,R,r,nph,nth)
{
th=i/nth*Math.PI*2.0;
ph=th/nph;
return[(R+r*mcos(th))*mcos(ph),(R+r*mcos(th))*msin(ph),r*msin(th)];
}

function teapotFace(pnum_x, pnum_y, idx)
{
// only write data if index is smaller than total vertex count of teapot
if(idx>TeapotPatchNum*pnum_x*pnum_y) return [[0,0,0],[0,0,0],[0,0,0],[0,0,0]];

var patchIdx = Math.floor(idx/(pnum_x*pnum_y));    // the actual patch of this vertex
var vIdx     = idx%(pnum_x*pnum_y);    // the vertex id within this patch

// get the control points
var pIndices = getPatchIndices(patchIdx);
if (!pIndices) return [[0,0,0],[0,0,0],[0,0,0],[0,0,0]];
var p = [];
for(var i=0; i<16; i++) p.push(getTeapotPoint(pIndices[i]-1));

// construct the quad
// ...first the 2D bezier parameters of each edge
//   (we give those back as uv-coords)
var qIdx=vIdx;
var qp=vec2(qIdx%pnum_x,Math.floor(qIdx/pnum_x));
var uv1 = div2(add2(qp,vec2(0,0)),vec2(pnum_x,pnum_y));
var uv2 = div2(add2(qp,vec2(1,0)),vec2(pnum_x,pnum_y));
var uv3 = div2(add2(qp,vec2(0,1)),vec2(pnum_x,pnum_y));
var uv4 = div2(add2(qp,vec2(1,1)),vec2(pnum_x,pnum_y));

// ...then get each edge point
var p1=bezierPatchPos(p,uv1);
var p2=bezierPatchPos(p,uv2);
var p3=bezierPatchPos(p,uv3);
var p4=bezierPatchPos(p,uv4);

// use eps,eps and -eps,eps instead of eps,0 and 0,eps to avoid 0-normals
/*var eps=.001;
var n1=cross(sub3(p1,bezierPatchPos(p,add2(uv1,vec2(eps,eps)))),sub3(p1,bezierPatchPos(p,add2(uv1,vec2(-eps,eps)))));
var n2=cross(sub3(p2,bezierPatchPos(p,add2(uv2,vec2(eps,eps)))),sub3(p2,bezierPatchPos(p,add2(uv2,vec2(-eps,eps)))));
var n3=cross(sub3(p3,bezierPatchPos(p,add2(uv3,vec2(eps,eps)))),sub3(p3,bezierPatchPos(p,add2(uv3,vec2(-eps,eps)))));
var n4=cross(sub3(p4,bezierPatchPos(p,add2(uv4,vec2(eps,eps)))),sub3(p4,bezierPatchPos(p,add2(uv4,vec2(-eps,eps)))));
n1 = normalize3(n1);
n2 = normalize3(n2);
n3 = normalize3(n3);
n4 = normalize3(n4);*/

/*var nph= pnum_x;
var nth= pnum_y;
return [
getTorusPoint(idx,      50,20,nph,nth),
getTorusPoint(idx+1,    50,20,nph,nth),
getTorusPoint(idx+nth,  50,20,nph,nth),
getTorusPoint(idx+1+nth,50,20,nph,nth)
];*/
return [p1,p2,p3,p4/*, n1,n2,n3,n4, uv1,uv2,uv3,uv4*/];
}

function mymix(a,b,f) { return a*(1.0-f)+b*f; }
function mcos(x) { return Math.cos(x); }
function msin(x) { return Math.sin(x); }

function vec3(x,y,z) { return [x,y,z]; }
function add3(a,b) { return [a[0]+b[0],a[1]+b[1],a[2]+b[2]]; }
function sub3(a,b) { return [a[0]-b[0],a[1]-b[1],a[2]-b[2]]; }
function div3(a,b) { return [a[0]/b[0],a[1]/b[1],a[2]/b[2]]; }
function mul3(a,b) { return [a[0]*b[0],a[1]*b[1],a[2]*b[2]]; }
function dot3(a,b) { return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]; }
function scale3(a,b) { return [a[0]*b,a[1]*b,a[2]*b]; }
function length3(a) { return Math.sqrt(dot3(a,a)); }
function normalize3(a) { return scale3(a,1.0/length3(a)); }
function mix3(a,b,f) { return add3(scale3(a,(1.0-f)),scale3(b,f)); }

function vec2(x,y) { return [x,y]; }
function add2(a,b) { return [a[0]+b[0],a[1]+b[1]]; }
function sub2(a,b) { return [a[0]-b[0],a[1]-b[1]]; }
function div2(a,b) { return [a[0]/b[0],a[1]/b[1]]; }
function mul2(a,b) { return [a[0]*b[0],a[1]*b[1]]; }
function dot2(a,b) { return a[0]*b[0]+a[1]*b[1]; }
function scale2(a,b) { return [a[0]*b,a[1]*b]; }
function length2(a) { return Math.sqrt(dot2(a,a)); }
function normalize2(a) { return scale2(a,1.0/length2(a)); }
function mix2(a,b,f) { return add2(scale2(a,(1.0-f)),scale2(b,f)); }

function cross(a,b) {
return [
a[1]*b[2]-b[1]*a[2],
a[2]*b[0]-b[2]*a[0],
a[0]*b[1]-b[0]*a[1]
];
}

function rotX(ph,v) {
return [ v[0],v[1]*mcos(ph)+v[2]*msin(ph), v[2]*mcos(ph)-v[1]*msin(ph) ];
}

function rotZ(ph,v) {
return [ v[0]*mcos(ph)+v[1]*msin(ph), v[1]*mcos(ph)-v[0]*msin(ph), v[2] ];
}

// teapot data....

const TeapotPatchNum=32

function getPatchIndices(pIdx)
{
return teapot_indices[pIdx];
}

function getTeapotPoint(idx)
{
return teapot_points[idx];
}

const teapot_indices = [
// the 32 teapot patches
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],
[4,17,18,19,8,20,21,22,12,23,24,25,16,26,27,28],
[19,29,30,31,22,32,33,34,25,35,36,37,28,38,39,40],
[31,41,42,1,34,43,44,5,37,45,46,9,40,47,48,13],
[13,14,15,16,49,50,51,52,53,54,55,56,57,58,59,60],
[16,26,27,28,52,61,62,63,56,64,65,66,60,67,68,69],
[28,38,39,40,63,70,71,72,66,73,74,75,69,76,77,78],
[40,47,48,13,72,79,80,49,75,81,82,53,78,83,84,57],
[57,58,59,60,85,86,87,88,89,90,91,92,93,94,95,96],
[60,67,68,69,88,97,98,99,92,100,101,102,96,103,104,105],
[69,76,77,78,99,106,107,108,102,109,110,111,105,112,113,114],
[78,83,84,57,108,115,116,85,111,117,118,89,114,119,120,93],
[121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136],
[124,137,138,121,128,139,140,125,132,141,142,129,136,143,144,133],
[133,134,135,136,145,146,147,148,149,150,151,152,69,153,154,155],
[136,143,144,133,148,156,157,145,152,158,159,149,155,160,161,69],
[162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177],
[165,178,179,162,169,180,181,166,173,182,183,170,177,184,185,174],
[174,175,176,177,186,187,188,189,190,191,192,193,194,195,196,197],
[177,184,185,174,189,198,199,186,193,200,201,190,197,202,203,194],
[204,204,204,204,207,208,209,210,211,211,211,211,212,213,214,215],
[204,204,204,204,210,217,218,219,211,211,211,211,215,220,221,222],
[204,204,204,204,219,224,225,226,211,211,211,211,222,227,228,229],
[204,204,204,204,226,230,231,207,211,211,211,211,229,232,233,212],
[212,213,214,215,234,235,236,237,238,239,240,241,242,243,244,245],
[215,220,221,222,237,246,247,248,241,249,250,251,245,252,253,254],
[222,227,228,229,248,255,256,257,251,258,259,260,254,261,262,263],
[229,232,233,212,257,264,265,234,260,266,267,238,263,268,269,242],
[270,270,270,270,279,280,281,282,275,276,277,278,271,272,273,274],
[270,270,270,270,282,289,290,291,278,286,287,288,274,283,284,285],
[270,270,270,270,291,298,299,300,288,295,296,297,285,292,293,294],
[270,270,270,270,300,305,306,279,297,303,304,275,294,301,302,271]
];

teapot_points = [
// the 306 teapot points
vec3(1.4,0.0,2.4             ),
vec3(1.4,-0.784,2.4          ),
vec3(0.784,-1.4,2.4          ),
vec3(0.0,-1.4,2.4            ),
vec3(1.3375,0.0,2.53125      ),
vec3(1.3375,-0.749,2.53125   ),
vec3(0.749,-1.3375,2.53125   ),
vec3(0.0,-1.3375,2.53125     ),
vec3(1.4375,0.0,2.53125      ),
vec3(1.4375,-0.805,2.53125   ),
vec3(0.805,-1.4375,2.53125   ),
vec3(0.0,-1.4375,2.53125     ),
vec3(1.5,0.0,2.4             ),
vec3(1.5,-0.84,2.4           ),
vec3(0.84,-1.5,2.4           ),
vec3(0.0,-1.5,2.4            ),
vec3(-0.784,-1.4,2.4         ),
vec3(-1.4,-0.784,2.4         ),
vec3(-1.4,0.0,2.4            ),
vec3(-0.749,-1.3375,2.53125  ),
vec3(-1.3375,-0.749,2.53125  ),
vec3(-1.3375,0.0,2.53125     ),
vec3(-0.805,-1.4375,2.53125  ),
vec3(-1.4375,-0.805,2.53125  ),
vec3(-1.4375,0.0,2.53125     ),
vec3(-0.84,-1.5,2.4          ),
vec3(-1.5,-0.84,2.4          ),
vec3(-1.5,0.0,2.4            ),
vec3(-1.4,0.784,2.4          ),
vec3(-0.784,1.4,2.4          ),
vec3(0.0,1.4,2.4             ),
vec3(-1.3375,0.749,2.53125   ),
vec3(-0.749,1.3375,2.53125   ),
vec3(0.0,1.3375,2.53125      ),
vec3(-1.4375,0.805,2.53125   ),
vec3(-0.805,1.4375,2.53125   ),
vec3(0.0,1.4375,2.53125      ),
vec3(-1.5,0.84,2.4           ),
vec3(-0.84,1.5,2.4           ),
vec3(0.0,1.5,2.4             ),
vec3(0.784,1.4,2.4           ),
vec3(1.4,0.784,2.4           ),
vec3(0.749,1.3375,2.53125    ),
vec3(1.3375,0.749,2.53125    ),
vec3(0.805,1.4375,2.53125    ),
vec3(1.4375,0.805,2.53125    ),
vec3(0.84,1.5,2.4            ),
vec3(1.5,0.84,2.4            ),
vec3(1.75,0.0,1.875          ),
vec3(1.75,-0.98,1.875        ),
vec3(0.98,-1.75,1.875        ),
vec3(0.0,-1.75,1.875         ),
vec3(2.0,0.0,1.35            ),
vec3(2.0,-1.12,1.35          ),
vec3(1.12,-2.0,1.35          ),
vec3(0.0,-2.0,1.35           ),
vec3(2.0,0.0,0.9             ),
vec3(2.0,-1.12,0.9           ),
vec3(1.12,-2.0,0.9           ),
vec3(0.0,-2.0,0.9            ),
vec3(-0.98,-1.75,1.875       ),
vec3(-1.75,-0.98,1.875       ),
vec3(-1.75,0.0,1.875         ),
vec3(-1.12,-2.0,1.35         ),
vec3(-2.0,-1.12,1.35         ),
vec3(-2.0,0.0,1.35           ),
vec3(-1.12,-2.0,0.9          ),
vec3(-2.0,-1.12,0.9          ),
vec3(-2.0,0.0,0.9            ),
vec3(-1.75,0.98,1.875        ),
vec3(-0.98,1.75,1.875        ),
vec3(0.0,1.75,1.875          ),
vec3(-2.0,1.12,1.35          ),
vec3(-1.12,2.0,1.35          ),
vec3(0.0,2.0,1.35            ),
vec3(-2.0,1.12,0.9           ),
vec3(-1.12,2.0,0.9           ),
vec3(0.0,2.0,0.9             ),
vec3(0.98,1.75,1.875         ),
vec3(1.75,0.98,1.875         ),
vec3(1.12,2.0,1.35           ),
vec3(2.0,1.12,1.35           ),
vec3(1.12,2.0,0.9            ),
vec3(2.0,1.12,0.9            ),
vec3(2.0,0.0,0.45            ),
vec3(2.0,-1.12,0.45          ),
vec3(1.12,-2.0,0.45          ),
vec3(0.0,-2.0,0.45           ),
vec3(1.5,0.0,0.225           ),
vec3(1.5,-0.84,0.225         ),
vec3(0.84,-1.5,0.225         ),
vec3(0.0,-1.5,0.225          ),
vec3(1.5,0.0,0.15            ),
vec3(1.5,-0.84,0.15          ),
vec3(0.84,-1.5,0.15          ),
vec3(0.0,-1.5,0.15           ),
vec3(-1.12,-2.0,0.45         ),
vec3(-2.0,-1.12,0.45         ),
vec3(-2.0,0.0,0.45           ),
vec3(-0.84,-1.5,0.225        ),
vec3(-1.5,-0.84,0.225        ),
vec3(-1.5,0.0,0.225          ),
vec3(-0.84,-1.5,0.15         ),
vec3(-1.5,-0.84,0.15         ),
vec3(-1.5,0.0,0.15           ),
vec3(-2.0,1.12,0.45          ),
vec3(-1.12,2.0,0.45          ),
vec3(0.0,2.0,0.45            ),
vec3(-1.5,0.84,0.225         ),
vec3(-0.84,1.5,0.225         ),
vec3(0.0,1.5,0.225           ),
vec3(-1.5,0.84,0.15          ),
vec3(-0.84,1.5,0.15          ),
vec3(0.0,1.5,0.15            ),
vec3(1.12,2.0,0.45           ),
vec3(2.0,1.12,0.45           ),
vec3(0.84,1.5,0.225          ),
vec3(1.5,0.84,0.225          ),
vec3(0.84,1.5,0.15           ),
vec3(1.5,0.84,0.15           ),
vec3(-1.6,0.0,2.025          ),
vec3(-1.6,-0.3,2.025         ),
vec3(-1.5,-0.3,2.25          ),
vec3(-1.5,0.0,2.25           ),
vec3(-2.3,0.0,2.025          ),
vec3(-2.3,-0.3,2.025         ),
vec3(-2.5,-0.3,2.25          ),
vec3(-2.5,0.0,2.25           ),
vec3(-2.7,0.0,2.025          ),
vec3(-2.7,-0.3,2.025         ),
vec3(-3.0,-0.3,2.25          ),
vec3(-3.0,0.0,2.25           ),
vec3(-2.7,0.0,1.8            ),
vec3(-2.7,-0.3,1.8           ),
vec3(-3.0,-0.3,1.8           ),
vec3(-3.0,0.0,1.8            ),
vec3(-1.5,0.3,2.25           ),
vec3(-1.6,0.3,2.025          ),
vec3(-2.5,0.3,2.25           ),
vec3(-2.3,0.3,2.025          ),
vec3(-3.0,0.3,2.25           ),
vec3(-2.7,0.3,2.025          ),
vec3(-3.0,0.3,1.8            ),
vec3(-2.7,0.3,1.8            ),
vec3(-2.7,0.0,1.575          ),
vec3(-2.7,-0.3,1.575         ),
vec3(-3.0,-0.3,1.35          ),
vec3(-3.0,0.0,1.35           ),
vec3(-2.5,0.0,1.125          ),
vec3(-2.5,-0.3,1.125         ),
vec3(-2.65,-0.3,0.9375       ),
vec3(-2.65,0.0,0.9375        ),
vec3(-2.0,-0.3,0.9           ),
vec3(-1.9,-0.3,0.6           ),
vec3(-1.9,0.0,0.6            ),
vec3(-3.0,0.3,1.35           ),
vec3(-2.7,0.3,1.575          ),
vec3(-2.65,0.3,0.9375        ),
vec3(-2.5,0.3,1.125          ),
vec3(-1.9,0.3,0.6            ),
vec3(-2.0,0.3,0.9            ),
vec3(1.7,0.0,1.425           ),
vec3(1.7,-0.66,1.425         ),
vec3(1.7,-0.66,0.6           ),
vec3(1.7,0.0,0.6             ),
vec3(2.6,0.0,1.425           ),
vec3(2.6,-0.66,1.425         ),
vec3(3.1,-0.66,0.825         ),
vec3(3.1,0.0,0.825           ),
vec3(2.3,0.0,2.1             ),
vec3(2.3,-0.25,2.1           ),
vec3(2.4,-0.25,2.025         ),
vec3(2.4,0.0,2.025           ),
vec3(2.7,0.0,2.4             ),
vec3(2.7,-0.25,2.4           ),
vec3(3.3,-0.25,2.4           ),
vec3(3.3,0.0,2.4             ),
vec3(1.7,0.66,0.6            ),
vec3(1.7,0.66,1.425          ),
vec3(3.1,0.66,0.825          ),
vec3(2.6,0.66,1.425          ),
vec3(2.4,0.25,2.025          ),
vec3(2.3,0.25,2.1            ),
vec3(3.3,0.25,2.4            ),
vec3(2.7,0.25,2.4            ),
vec3(2.8,0.0,2.475           ),
vec3(2.8,-0.25,2.475         ),
vec3(3.525,-0.25,2.49375     ),
vec3(3.525,0.0,2.49375       ),
vec3(2.9,0.0,2.475           ),
vec3(2.9,-0.15,2.475         ),
vec3(3.45,-0.15,2.5125       ),
vec3(3.45,0.0,2.5125         ),
vec3(2.8,0.0,2.4             ),
vec3(2.8,-0.15,2.4           ),
vec3(3.2,-0.15,2.4           ),
vec3(3.2,0.0,2.4             ),
vec3(3.525,0.25,2.49375      ),
vec3(2.8,0.25,2.475          ),
vec3(3.45,0.15,2.5125        ),
vec3(2.9,0.15,2.475          ),
vec3(3.2,0.15,2.4            ),
vec3(2.8,0.15,2.4            ),
vec3(0.0,0.0,3.15            ),
vec3(0.0,-0.002,3.15         ),
vec3(0.002,0.0,3.15          ),
vec3(0.8,0.0,3.15            ),
vec3(0.8,-0.45,3.15          ),
vec3(0.45,-0.8,3.15          ),
vec3(0.0,-0.8,3.15           ),
vec3(0.0,0.0,2.85            ),
vec3(0.2,0.0,2.7             ),
vec3(0.2,-0.112,2.7          ),
vec3(0.112,-0.2,2.7          ),
vec3(0.0,-0.2,2.7            ),
vec3(-0.002,0.0,3.15         ),
vec3(-0.45,-0.8,3.15         ),
vec3(-0.8,-0.45,3.15         ),
vec3(-0.8,0.0,3.15           ),
vec3(-0.112,-0.2,2.7         ),
vec3(-0.2,-0.112,2.7         ),
vec3(-0.2,0.0,2.7            ),
vec3(0.0,0.002,3.15          ),
vec3(-0.8,0.45,3.15          ),
vec3(-0.45,0.8,3.15          ),
vec3(0.0,0.8,3.15            ),
vec3(-0.2,0.112,2.7          ),
vec3(-0.112,0.2,2.7          ),
vec3(0.0,0.2,2.7             ),
vec3(0.45,0.8,3.15           ),
vec3(0.8,0.45,3.15           ),
vec3(0.112,0.2,2.7           ),
vec3(0.2,0.112,2.7           ),
vec3(0.4,0.0,2.55            ),
vec3(0.4,-0.224,2.55         ),
vec3(0.224,-0.4,2.55         ),
vec3(0.0,-0.4,2.55           ),
vec3(1.3,0.0,2.55            ),
vec3(1.3,-0.728,2.55         ),
vec3(0.728,-1.3,2.55         ),
vec3(0.0,-1.3,2.55           ),
vec3(1.3,0.0,2.4             ),
vec3(1.3,-0.728,2.4          ),
vec3(0.728,-1.3,2.4          ),
vec3(0.0,-1.3,2.4            ),
vec3(-0.224,-0.4,2.55        ),
vec3(-0.4,-0.224,2.55        ),
vec3(-0.4,0.0,2.55           ),
vec3(-0.728,-1.3,2.55        ),
vec3(-1.3,-0.728,2.55        ),
vec3(-1.3,0.0,2.55           ),
vec3(-0.728,-1.3,2.4         ),
vec3(-1.3,-0.728,2.4         ),
vec3(-1.3,0.0,2.4            ),
vec3(-0.4,0.224,2.55         ),
vec3(-0.224,0.4,2.55         ),
vec3(0.0,0.4,2.55            ),
vec3(-1.3,0.728,2.55         ),
vec3(-0.728,1.3,2.55         ),
vec3(0.0,1.3,2.55            ),
vec3(-1.3,0.728,2.4          ),
vec3(-0.728,1.3,2.4          ),
vec3(0.0,1.3,2.4             ),
vec3(0.224,0.4,2.55          ),
vec3(0.4,0.224,2.55          ),
vec3(0.728,1.3,2.55          ),
vec3(1.3,0.728,2.55          ),
vec3(0.728,1.3,2.4           ),
vec3(1.3,0.728,2.4           ),
vec3(0.0,0.0,0.0             ),
vec3(1.5,0.0,0.15            ),
vec3(1.5,0.84,0.15           ),
vec3(0.84,1.5,0.15           ),
vec3(0.0,1.5,0.15            ),
vec3(1.5,0.0,0.075           ),
vec3(1.5,0.84,0.075          ),
vec3(0.84,1.5,0.075          ),
vec3(0.0,1.5,0.075           ),
vec3(1.425,0.0,0.0           ),
vec3(1.425,0.798,0.0         ),
vec3(0.798,1.425,0.0         ),
vec3(0.0,1.425,0.0           ),
vec3(-0.84,1.5,0.15          ),
vec3(-1.5,0.84,0.15          ),
vec3(-1.5,0.0,0.15           ),
vec3(-0.84,1.5,0.075         ),
vec3(-1.5,0.84,0.075         ),
vec3(-1.5,0.0,0.075          ),
vec3(-0.798,1.425,0.0        ),
vec3(-1.425,0.798,0.0        ),
vec3(-1.425,0.0,0.0          ),
vec3(-1.5,-0.84,0.15         ),
vec3(-0.84,-1.5,0.15         ),
vec3(0.0,-1.5,0.15           ),
vec3(-1.5,-0.84,0.075        ),
vec3(-0.84,-1.5,0.075        ),
vec3(0.0,-1.5,0.075          ),
vec3(-1.425,-0.798,0.0       ),
vec3(-0.798,-1.425,0.0       ),
vec3(0.0,-1.425,0.0          ),
vec3(0.84,-1.5,0.15          ),
vec3(1.5,-0.84,0.15          ),
vec3(0.84,-1.5,0.075         ),
vec3(1.5,-0.84,0.075         ),
vec3(0.798,-1.425,0.0        ),
vec3(1.425,-0.798,0.0        )
];

////////////////////////////
// reinder's occlusion code parts from "Cubic space division #2"
////////////////////////////

function drawPolygon(turtle, p) {
let vis = true;
for (let j=0; j<polygonList.length; j++) {
if(!p.boolean(polygonList[j])) {
vis = false;
break;
}
}
if (vis) {
p.draw(turtle, 0);
polygonList.push(p);
}
}

// polygon functions
function LineSegment(p1, p2) {
this.p1 = p1;
this.p2 = p2;
}
function Polygon() {
this.cp = []; // clip path: array of [x,y] pairs
this.dp = []; // 2d line to draw: array of linesegments
}
Polygon.prototype.addOutline = function(s=0) {
for (let i=s, l=this.cp.length; i<l; i++) {
this.dp.push(new LineSegment(this.cp[i], this.cp[(i+1)%l]));
}
}
Polygon.prototype.createPoly = function(x,y,c,r,a) {
this.cp = [];
for (let i=0; i<c; i++) {
this.cp.push( [x + Math.sin(i*Math.PI*2/c+a) * r, y + Math.cos(i*Math.PI*2/c+a) * r] );
}
}
Polygon.prototype.draw = function(t, inp=0) {
if (this.dp.length ==0) {
return;
}
for (let i=0, l=this.dp.length; i<l; i++) {
const d = this.dp[i];
if (!vec2_equal(d.p1, t.pos())) {
t.penup();
t.goto([d.p1[0]+inp*(Math.random()-.5), d.p1[1]+inp*(Math.random()-.5)]);
t.pendown();
}
t.goto([d.p2[0]+inp*(Math.random()-.5), d.p2[1]+inp*(Math.random()-.5)]);
}
}
Polygon.prototype.inside = function(p) {
// find number of i ntersection points from p to far away
// if even your outside
const p1 = [0.1, -1000];
let int = 0;
for (let i=0, l=this.cp.length; i<l; i++) {
if (vec2_find_segment_intersect(p, p1, this.cp[i], this.cp[(i+1)%l])) {
int ++;
}
}
return int & 1;
}
Polygon.prototype.boolean = function(p, diff = true) {
// very naive polygon diff algorithm - made this up myself
const ndp = [];
for (let i=0, l=this.dp.length; i<l; i++) {
const ls = this.dp[i];

// find all intersections with clip path
const int = [];
for (let j=0, cl=p.cp.length; j<cl; j++) {
const pint = vec2_find_segment_intersect(ls.p1,ls.p2,p.cp[j],p.cp[(j+1)%cl]);
if (pint) {
int.push(pint);
}
}
if (int.length == 0) { // 0 intersections, inside or outside?
if (diff == !p.inside(ls.p1)) {
ndp.push(ls);
}
} else {
int.push(ls.p1);
int.push(ls.p2);
// order intersection points on line ls.p1 to ls.p2
const cmp = [ls.p2[0]-ls.p1[0], ls.p2[1]-ls.p1[1]];
int.sort( (a,b) => {
const db = vec2_dot([b[0]-ls.p1[0], b[1]-ls.p1[1]], cmp);
const da = vec2_dot([a[0]-ls.p1[0], a[1]-ls.p1[1]], cmp);
return da - db;
});
for (let j=0; j<int.length-1; j++) {
if (!vec2_equal(int[j], int[j+1])) {
if (diff == !p.inside([(int[j][0]+int[j+1][0])/2,(int[j][1]+int[j+1][1])/2])) {
ndp.push(new LineSegment(int[j], int[j+1]));
}
}
}
}
}
this.dp = ndp;
return this.dp.length > 0;
}

// vec functions
const vec2_equal = (a,b) => vec2_dist_sqr(a,b) < 0.01;
const vec2_dot = (a, b) => a[0]*b[0]+a[1]*b[1];
const vec2_dist_sqr = (a, b) => (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]);
//port of http://paulbourke.net/geometry/pointlineplane/Helpers.cs
function vec2_find_segment_intersect(l1p1, l1p2, l2p1, l2p2) {
const d = (l2p2[1] - l2p1[1]) * (l1p2[0] - l1p1[0]) - (l2p2[0] - l2p1[0]) * (l1p2[1] - l1p1[1]);
const n_a = (l2p2[0] - l2p1[0]) * (l1p1[1] - l2p1[1]) - (l2p2[1] - l2p1[1]) * (l1p1[0] - l2p1[0]);
const n_b = (l1p2[0] - l1p1[0]) * (l1p1[1] - l2p1[1]) - (l1p2[1] - l1p1[1]) * (l1p1[0] - l2p1[0]);
if (d == 0) {
return false;
}
const ua = n_a / d;
const ub = n_b / d;
if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1) {
return [l1p1[0] + (ua * (l1p2[0] - l1p1[0])), l1p1[1] + (ua * (l1p2[1] - l1p1[1])) ];
}
return false;
}

```