Log in to post a comment.

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

// Global code will be evaluated once.
const turtle = new Turtle();

// Quaternion from Eular angles
// https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
function quat(yaw,pitch,roll)
{
    let cy = Math.cos(yaw*0.5);
    let sy = Math.sin(yaw*0.5);
    let cp = Math.cos(pitch*0.5);
    let sp = Math.sin(pitch*0.5);
    let cr = Math.cos(roll*0.5);
    let sr = Math.sin(roll*0.5);
    
    let w = cy * cp * cr + sy * sp * sr;
    let x = cy * cp * sr - sy * sp * cr;
    let y = sy * cp * sr + cy * sp * cr;
    let z = sy * cp * cr - cy * sp * sr;
    
    return [x,y,z,w];
}

// ref https://github.com/toji/gl-matrix/blob/master/src/mat4.js
// fromRotationTranslationScale
// matrix is stored in the row pattern
function make_transform(o,pos,quat,scale)
{
    // scale temp vars
    let sx = scale[0];
    let sy = scale[1];
    let sz = scale[2];
    
    // translation temp vars
    let tx = pos[0];
    let ty = pos[1];
    let tz = pos[2];
    
    //Quat calc temp variables
    let x = quat[0];
    let y = quat[1];
    let z = quat[2];
    let w = quat[3];
    
    let xx = x*x*2.0;
    let xy = x*y*2.0;
    let xz = x*z*2.0;
    let wx = x*w*2.0;
    
    let yy = y*y*2.0;
    let yz = y*z*2.0;
    let wy = y*w*2.0;
    
    let zz = z*z*2.0;
    let wz = z*w*2.0;

    o[0] = (1-yy-zz)*sx;
    o[1] = (xy-wz)*sy;
    o[2] = (xz+wy)*sz;
    o[3] = tx;
    o[4] = (xy+wz)*sx;
    o[5] = (1-xx-zz)*sy;
    o[6] = (yz-wx)*sz;
    o[7] = ty;
    o[8] = (xz-wy)*sx;
    o[9] = (yz+wx)*sy;
    o[10] = (1-xx-yy)*sz;
    o[11] = tz;
    o[12] = 0;
    o[13] = 0;
    o[14] = 0;
    o[15] = 1;
    
    return o;
}

function transform_vector(v,m)
{
    let x = v[0], y = v[1], z = v[2], w = v[3];
    let o = [0, 0, 0, 0];
    o[0] = m[0] * x + m[1] * y + m[2] * z + m[3] * w;
    o[1] = m[4] * x + m[5] * y + m[6] * z + m[7] * w;
    o[2] = m[8] * x + m[9] * y + m[10] * z + m[11] * w;
    o[3] = m[12] * x + m[13] * y + m[14] * z + m[15] * w;
    return o;
}

let focus = 200;
function project(v){
    let x = v[0];
    let y = v[1];
    let z = v[2];
    let s = focus/z;
    return [x*s,y*s];
}


let Mesh = function(verts,edges,tsf)
{
    let out = {}
    out.verts = verts;
    out.edges = edges;
    out.transform = tsf
    return out;
}

let PI = Math.PI;
let PI2 = Math.PI*2;

// fill in the ellipsoid vertice and edge list
function make_ellipsoid(nu,nv,a,b,c,madness)
{
    let o = {};
    o.edges = [];
    o.verts = [];
    let du = 1.0/nu;
    let dv = 1.0/nv;
    nu +=1;
    nv +=1;
    let u = 0,v = 0;
    let i = 0,j = 0;
    
    // push vertice
    for(let i=0;i<nu;i++)
    {
        u = i*du;
        for(let j=0;j<nv;j++)
        {
            v = j*dv;
            
            let theta = u*PI;
            let phi = v*PI2;
            
            let ct = Math.cos(theta);
            let st = Math.sin(theta);
            let cp = Math.cos(phi);
            let sp = Math.sin(phi);
            
            let x = a*st*cp*(1-madness*Math.random()*Math.random());
            let y = a*st*sp*(1-madness*Math.random()*Math.random());
            let z = c*ct*(1 -madness*0.4*Math.random());
            
            o.verts.push([x,y,z,1.0]);
            
            //o.verts.push([u,v,1.0,1.0]);
        }
    }
    
    
    //link edges
    for(let i=0;i<nu;i++)
    {
        u = i*du;
        for(let j=0;j<nv;j++)
        {
            v = j*dv;
            let id = i*nv+j;
            let inext = (i+1)%nu;
            let jnext = (j+1)%nv;
            let id_down = i*nv+jnext;
            let id_right = inext*nv+j;
            
            o.edges.push(id,id_down);
            o.edges.push(id,id_right);
        }
        
    }
    return o;
}

function draw_mesh(tctx,mesh)
{
    let edges = mesh.edges;
    let verts = mesh.verts;
    let tsf = mesh.transform;
    
    for (let i = 0, len = edges.length/2; i < len; i++) {
        
        let i0 = edges[2*i];
        let i1 = edges[2*i+1];
        
        // perform transform
        let v0 = transform_vector(verts[i0],tsf);
        let v1 = transform_vector(verts[i1],tsf);
        
        // projection
        v0 = project(v0);
        v1 = project(v1);
        
        // draw edge
        tctx.penup();
		tctx.goto([v0[0],v0[1]]);
		tctx.pendown();
		tctx.goto([v1[0],v1[1]]);
		
    }
}


function draw_mesh_substep(tctx,mesh,step)
{
    let edges = mesh.edges;
    let len = edges.length/2;
    if(step>=len)
    {
        return false;
    }
    
    
    let verts = mesh.verts;
    let tsf = mesh.transform;
    
    let i0 = edges[2*step];
    let i1 = edges[2*step+1];
        
        // perform transform
    let v0 = transform_vector(verts[i0],tsf);
    let v1 = transform_vector(verts[i1],tsf);
        
    // projection
    v0 = project(v0);
    v1 = project(v1);
        
    // draw edge
    tctx.penup();
	tctx.goto([v0[0],v0[1]]);
	tctx.pendown();
	tctx.goto([v1[0],v1[1]]);
	return true;
}


let scale = [1.0,1.0,1.0]
let rotation = quat(0.0,PI*0.2,0.26*PI);
let position = [0,0,60.];
//transfrom matrix
let transform = new Float32Array(16);
let transform2 = new Float32Array(16);

make_transform(transform,position,rotation,scale);
make_transform(transform2,[-7,16,70.],rotation,scale);

let core = make_ellipsoid(50,50,4,4,4,0.95);
let core_mesh = Mesh(core.verts,core.edges,transform2);

let eclip = make_ellipsoid(80,80,15,15,15,0.2);
let eclip_mesh = Mesh(eclip.verts,eclip.edges,transform2);


let eclip2 = make_ellipsoid(15,15,15*1.5,15*1.5,18*1.5,0.05);
let eclip_mesh2 = Mesh(eclip2.verts,eclip2.edges,transform);

let eclip3 = make_ellipsoid(15,15,15*1.5,15*1.5,18*1.5,0.05);
let eclip_mesh3 = Mesh(eclip3.verts,eclip3.edges,transform);

let eclip4 = make_ellipsoid(15,15,15*1.5,20*1.5,18*1.5,0.04);
let eclip_mesh4 = Mesh(eclip4.verts,eclip4.edges,transform);

let eclip5 = make_ellipsoid(15,15,15*1.5,20*1.5,18*1.5,0.04);
let eclip_mesh5 = Mesh(eclip5.verts,eclip5.edges,transform);


// The walk function will be called until it returns false.
function walk(i) {
   
    //draw_mesh(turtle,bottle);
    draw_mesh_substep(turtle,core_mesh,i);
    let stop = draw_mesh_substep(turtle,eclip_mesh,i);
    draw_mesh_substep(turtle,eclip_mesh2,i);
    draw_mesh_substep(turtle,eclip_mesh3,i);
    draw_mesh_substep(turtle,eclip_mesh4,i);
    draw_mesh_substep(turtle,eclip_mesh5,i);
    return stop;
}