// data points for train model
data = [
{"color":0,"shape":0,"transX":15,"transY":10,"transZ":5,"rotX":0,"rotY":0,"rotZ":0,"scale":4,"sampling":5}, // 可 sb
{"color":0,"shape":0,"transX":15,"transY":1,"transZ":5,"rotX":0,"rotY":0,"rotZ":0,"scale":4,"sampling":4}, // 可 port
{"color":8,"shape":1,"transX":7,"transY":6,"transZ":13,"rotX":0,"rotY":0,"rotZ":3,"scale":7,"sampling":15}, // engine
{"color":1,"shape":2,"transX":2,"transY":10,"transZ":14,"rotX":0,"rotY":0,"rotZ":0,"scale":2,"sampling":2}, // wheel front sb
{"color":1,"shape":2,"transX":2,"transY":1,"transZ":14,"rotX":0,"rotY":0,"rotZ":0,"scale":2,"sampling":2}, // wheel front port
{"color":1,"shape":2,"transX":15,"transY":11,"transZ":13,"rotX":0,"rotY":0,"rotZ":0,"scale":4,"sampling":3}, // wheel back 1 sb
{"color":1,"shape":2,"transX":9,"transY":11,"transZ":13,"rotX":0,"rotY":0,"rotZ":0,"scale":4,"sampling":3}, // wheel back 2 sb
{"color":1,"shape":2,"transX":15,"transY":0,"transZ":13,"rotX":0,"rotY":0,"rotZ":0,"scale":4,"sampling":3}, // wheel back 1 port
{"color":1,"shape":2,"transX":9,"transY":0,"transZ":13,"rotX":0,"rotY":0,"rotZ":0,"scale":4,"sampling":3}, // wheel back 2 port
{"color":0,"shape":3,"transX":0,"transY":5,"transZ":12,"rotX":3,"rotY":0,"rotZ":9,"scale":3,"sampling":5}, // of
{"color":13,"shape":4,"transX":0,"transY":5,"transZ":8,"rotX":0,"rotY":3,"rotZ":0,"scale":5,"sampling":2}, // heart
{"color":14,"shape":5,"transX":15,"transY":7,"transZ":0,"rotX":3,"rotY":0,"rotZ":3,"scale":4,"sampling":2}, // top
{"color":14,"shape":5,"transX":13,"transY":8,"transZ":11,"rotX":3,"rotY":0,"rotZ":3,"scale":4,"sampling":6} // floor
];
/* Shapes: '可¶☉个❤█'
* ¶ £ » ß Þ Ů ƒ Θ ζ Ђ Љ П Ю ‰ ✓ ⦿ ζ ς ש Д θ ~ 个 ㄩ 可 扣 門 ❤ ★ ❥ ❦ ❧ ☉ 口 █
*/
// use this m() function while designing a model
m1 = function(u,v,w,x,y,z){
return data[o][['color', 'shape', /*2*/'transX', 'transY', /*4*/'transZ', 'rotX', /*6*/'rotY', 'rotZ', /*8*/'scale', 'sampling'][u]];
}
// loop through design data and create a string representing data.
encoded = '';
for (o = 0; o < data.length; o++) {
encoded += String.fromCharCode(255-(m1(0) | (m1(1) << 4)));
encoded += String.fromCharCode(255-(m1(2) | (m1(3) << 4)));
encoded += String.fromCharCode(255-(m1(4) | (m1(5) << 4)));
encoded += String.fromCharCode(255-(m1(6) | (m1(7) << 4)));
encoded += String.fromCharCode(255-(m1(8) | (m1(9) << 4)));
}
// some comparison and error checking
console.log(encoded);
var encBytes = [];
for (var i = 0; i < encoded.length; i++)
encBytes.push(encoded[i].charCodeAt(0));
console.log('Encoded bytes: ', encBytes.join(','));
e = encoded;
// check it (or some) decompresses the same
m2=function(u,v,w,x,y,z){
if(u%2)
return (255-e.charCodeAt(o*5+~~(u/2))>>4);
else
return (255-e.charCodeAt(o*5+~~(u/2))&15);
};
var t1 = [], t2 = [];
for (var o = 0; o < data.length; o++)
for (var i = 0; i < 10; i++) {
t1.push(m1(i));
t2.push(m2(i));
}
console.log('Comparison of design select and encoded select');
console.log(t1.slice(0, 33));
console.log(t2.slice(0, 33));
// ************ JS1K entry starts here ************
// data encoded from the above atrocity
e='ÿPúÿ«ÿàúÿ»çòÏÞ]ñÿÝÞíñÿÝÞ@òÿËÞFòÿËÞðòÿËÞöòÿËϯÃo¬²¯÷üÚ¡ÏÏÛ¡rÄÏ';
// shortcuts for canvas
for(H in c)c[H[0]+H[6]]=c[H];
k=[];
// sin & cos lookup table (way too slow without it)
r=[];
i=7676;
for(x=i;x--;)
r.push(Math.sin(x*.0176));
// rotate a 3d point
n=function(u,v,w,x,y,z){
H=u*r[z+90]-v*r[z];
z=u*r[z]+v*r[z+90];
u=w*r[y+90]-H*r[y];
v=w*r[y]+H*r[y+90];
H=z*r[x+90]-u*r[x];
w=z*r[x]+u*r[x+90];
return [v,H,w];
};
// grab a 4bit number from the compressed data (e)
m=function(u,v,w,x,y,z){
return u%2
?
255-e.charCodeAt(o*5+~~(u/2))>>4
:
255-e.charCodeAt(o*5+~~(u/2))&15
};
// text shadow helps provide more 3d pixels
c.font=56+'px x';c.sC='red';
for(o=13;o--;){
// clear
c.fillStyle='#000',
c.fc(0,0,a.width,a.height);
// write a shape to canvas
c.fillStyle='#f00',
c.fx('可¶☉个❤█'[m(c.sB=1)],0,44);
// grab 2d data
f=c.gg(0,0,76,y=76).data;
// loop through data and convert presence of red on the canvas to points in a 3d space
for(;y--;i=76)
for(x=i;x--;)
f[(y*76+x)*4]>36?
k.push(
[
n(x*m(8)-30*m(8),y*m(8)-30*m(8),f[(y*76+x)*4]/90*m(9),30*m(5),30*m(6),30*m(7))[0]+30*(m(2)-7),
n(x*m(8)-30*m(8),y*m(8)-30*m(8),f[(y*76+x)*4]/90*m(9),30*m(5),30*m(6),30*m(7))[1]+(m(4)-6)*20,
n(x*m(8)-30*m(8),y*m(8)-30*m(8),f[(y*76+x)*4]/90*m(9),30*m(5),30*m(6),30*m(7))[2]+(m(3)-3)*20,
m(9),m(0)
],
[
n(x*m(8)-30*m(8),y*m(8)-30*m(8),-f[(y*76+x)*4]/90*m(9),30*m(5),30*m(6),30*m(7))[0]+30*(m(2)-7),
n(x*m(8)-30*m(8),y*m(8)-30*m(8),-f[(y*76+x)*4]/90*m(9),30*m(5),30*m(6),30*m(7))[1]+(m(4)-6)*20,
n(x*m(8)-30*m(8),y*m(8)-30*m(8),-f[(y*76+x)*4]/90*m(9),30*m(5),30*m(6),30*m(7))[2]+(m(3)-3)*20,
m(9),m(0)
]
):0
}
// init loop counter
g=i=360;
// create iron rail tracks
for(x=i;x--;)
q=k.push(
[-700+x*5,200,150,3,10],
[-700+x*5,200,c.sB=-44,3,10]
);
// create wooden ties
for(y=30,i=76;y--;i=76)
for(x=i;x--;)
k.push([-700+y*100,220,-100+x*4,5,1.6]);
// animation loop
setInterval(function(u,v,w,x,y,z){
// clean the canvas
c.fillStyle='#000',
c.fc(0,0,a.width,a.height),o=[];
// populate a new array with points rotated using new angle
i=k.length;for(x=i;x--;){
f=n(
// x, y, z
k[x][0],k[x][1],k[x][2],
// rX
~~(390+r[g*2]*10),
// rY
~~(700+r[g]*50),
// rZ
0
);
f.push(k[x][3],k[x][4]);
o.push(f);
}
// sort the universe of points so that the furthest are rendered first
o.sort(function(u,v,w,x,y,z){
return u[2]-v[2]
});
// render the points
for(x=i;x--;){
c.fillStyle=['hsl('+o[x][4]*24,'50%',(-o[x][2]+360)/360*35+'%'];
c.fc(
o[x][0]+.50*a.width,
a.height*.360+o[x][1],
(o[x][3]+1)*4,
(o[x][3]+1)*4
);
}
// move the ties down the rail to "move" the train
i=k.length-q;
for(x=i;x--;)
k[x+q][0]>700
?
k[x+q][0]=-700
:
k[x+q][0]+=10;
// rotate
--g?g:g=360;
},10);