sku-pg
Version:
Skulpt is a Javascript implementation of Python 2.x. Python that runs in your browser!
289 lines (245 loc) • 13.4 kB
JavaScript
var $builtinmodule = function(name)
{
var mod = {};
// todo; should probably put this in a math package
mod.Mat44 = Sk.misceval.buildClass(mod, function($gbl, $loc)
{
$loc.__init__ = new Sk.builtin.func(function(self)
{
Sk.misceval.callsim($loc.loadIdentity, self);
self.stack = [];
});
$loc.push = new Sk.builtin.func(function(self)
{
self.stack.push(self.elements.slice(0));
});
$loc.pop = new Sk.builtin.func(function(self)
{
self.elements = self.stack.pop();
});
$loc.loadIdentity = new Sk.builtin.func(function(self)
{
self.elements = [1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0];
});
$loc.transform3 = new Sk.builtin.func(function(self, v)
{
var e = self.elements;
return Sk.misceval.callsim(mod.Vec3,
e[0] * v.x + e[4] * v.y + e[8] * v.z,
e[1] * v.x + e[5] * v.y + e[9] * v.z,
e[2] * v.x + e[6] * v.y + e[10] * v.z);
});
$loc.scale = new Sk.builtin.func(function(self, sx, sy, sz)
{
self.elements[0*4+0] *= sx;
self.elements[0*4+1] *= sx;
self.elements[0*4+2] *= sx;
self.elements[0*4+3] *= sx;
self.elements[1*4+0] *= sy;
self.elements[1*4+1] *= sy;
self.elements[1*4+2] *= sy;
self.elements[1*4+3] *= sy;
self.elements[2*4+0] *= sz;
self.elements[2*4+1] *= sz;
self.elements[2*4+2] *= sz;
self.elements[2*4+3] *= sz;
return self;
});
$loc.translate = new Sk.builtin.func(function(self, tx, ty, tz)
{
self.elements[3*4+0] += self.elements[0*4+0] * tx + self.elements[1*4+0] * ty + self.elements[2*4+0] * tz;
self.elements[3*4+1] += self.elements[0*4+1] * tx + self.elements[1*4+1] * ty + self.elements[2*4+1] * tz;
self.elements[3*4+2] += self.elements[0*4+2] * tx + self.elements[1*4+2] * ty + self.elements[2*4+2] * tz;
self.elements[3*4+3] += self.elements[0*4+3] * tx + self.elements[1*4+3] * ty + self.elements[2*4+3] * tz;
return self;
});
$loc.rotate = new Sk.builtin.func(function(self, angle, x, y, z)
{
var mag = Math.sqrt(x*x + y*y + z*z);
var sinAngle = Math.sin(angle * Math.PI / 180.0);
var cosAngle = Math.cos(angle * Math.PI / 180.0);
if (mag > 0)
{
var xx, yy, zz, xy, yz, zx, xs, ys, zs;
var oneMinusCos;
var rotMat;
x /= mag;
y /= mag;
z /= mag;
xx = x * x;
yy = y * y;
zz = z * z;
xy = x * y;
yz = y * z;
zx = z * x;
xs = x * sinAngle;
ys = y * sinAngle;
zs = z * sinAngle;
oneMinusCos = 1.0 - cosAngle;
rotMat = Sk.misceval.callsim(mod.Mat44);
rotMat.elements[0*4+0] = (oneMinusCos * xx) + cosAngle;
rotMat.elements[0*4+1] = (oneMinusCos * xy) - zs;
rotMat.elements[0*4+2] = (oneMinusCos * zx) + ys;
rotMat.elements[0*4+3] = 0.0;
rotMat.elements[1*4+0] = (oneMinusCos * xy) + zs;
rotMat.elements[1*4+1] = (oneMinusCos * yy) + cosAngle;
rotMat.elements[1*4+2] = (oneMinusCos * yz) - xs;
rotMat.elements[1*4+3] = 0.0;
rotMat.elements[2*4+0] = (oneMinusCos * zx) - ys;
rotMat.elements[2*4+1] = (oneMinusCos * yz) + xs;
rotMat.elements[2*4+2] = (oneMinusCos * zz) + cosAngle;
rotMat.elements[2*4+3] = 0.0;
rotMat.elements[3*4+0] = 0.0;
rotMat.elements[3*4+1] = 0.0;
rotMat.elements[3*4+2] = 0.0;
rotMat.elements[3*4+3] = 1.0;
rotMat = rotMat.multiply(self);
self.elements = rotMat.elements;
}
return self;
});
$loc.multiply = new Sk.builtin.func(function(self, right)
{
var tmp = Sk.misceval.callsim(mod.Mat44);
for (var i = 0; i < 4; i++)
{
tmp.elements[i*4+0] =
(self.elements[i*4+0] * right.elements[0*4+0]) +
(self.elements[i*4+1] * right.elements[1*4+0]) +
(self.elements[i*4+2] * right.elements[2*4+0]) +
(self.elements[i*4+3] * right.elements[3*4+0]) ;
tmp.elements[i*4+1] =
(self.elements[i*4+0] * right.elements[0*4+1]) +
(self.elements[i*4+1] * right.elements[1*4+1]) +
(self.elements[i*4+2] * right.elements[2*4+1]) +
(self.elements[i*4+3] * right.elements[3*4+1]) ;
tmp.elements[i*4+2] =
(self.elements[i*4+0] * right.elements[0*4+2]) +
(self.elements[i*4+1] * right.elements[1*4+2]) +
(self.elements[i*4+2] * right.elements[2*4+2]) +
(self.elements[i*4+3] * right.elements[3*4+2]) ;
tmp.elements[i*4+3] =
(self.elements[i*4+0] * right.elements[0*4+3]) +
(self.elements[i*4+1] * right.elements[1*4+3]) +
(self.elements[i*4+2] * right.elements[2*4+3]) +
(self.elements[i*4+3] * right.elements[3*4+3]) ;
}
self.elements = tmp.elements;
return self;
});
/* Following gluLookAt implementation is adapted from
* the Mesa 3D Graphics library. http://www.mesa3d.org
*/
// todo; rewrite this with proper vec/mat ops
$loc.lookAt = new Sk.builtin.func(function(self, eyeX, eyeY, eyeZ,
centerX, centerY, centerZ,
upX, upY, upZ)
{
/* Z vector */
var z = [
eyeX - centerX,
eyeY - centerY,
eyeZ - centerZ
];
var mag = Math.sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
if (mag)
{
z[0] /= mag;
z[1] /= mag;
z[2] /= mag;
}
/* Y vector */
var y = [ upX, upY, upZ ];
/* X vector = Y cross Z */
var x = [];
x[0] = y[1] * z[2] - y[2] * z[1];
x[1] = -y[0] * z[2] + y[2] * z[0];
x[2] = y[0] * z[1] - y[1] * z[0];
/* Recompute Y = Z cross X */
y[0] = z[1] * x[2] - z[2] * x[1];
y[1] = -z[0] * x[2] + z[2] * x[0];
y[2] = z[0] * x[1] - z[1] * x[0];
/* mpichler, 19950515 */
/* cross product gives area of parallelogram, which is < 1.0 for
* non-perpendicular unit-length vectors; so normalize x, y here
*/
mag = Math.sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
if (mag) {
x[0] /= mag;
x[1] /= mag;
x[2] /= mag;
}
mag = Math.sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
if (mag) {
y[0] /= mag;
y[1] /= mag;
y[2] /= mag;
}
var lookAt = Sk.misceval.callsim(mod.Mat44);
lookAt.elements[0 * 4 + 0] = x[0];
lookAt.elements[1 * 4 + 0] = x[1];
lookAt.elements[2 * 4 + 0] = x[2];
lookAt.elements[3 * 4 + 0] = 0.;
lookAt.elements[0 * 4 + 1] = y[0];
lookAt.elements[1 * 4 + 1] = y[1];
lookAt.elements[2 * 4 + 1] = y[2];
lookAt.elements[3 * 4 + 1] = 0.;
lookAt.elements[0 * 4 + 2] = z[0];
lookAt.elements[1 * 4 + 2] = z[1];
lookAt.elements[2 * 4 + 2] = z[2];
lookAt.elements[3 * 4 + 2] = 0.;
lookAt.elements[0 * 4 + 3] = 0.;
lookAt.elements[1 * 4 + 3] = 0.;
lookAt.elements[2 * 4 + 3] = 0.;
lookAt.elements[3 * 4 + 3] = 1.;
// log(lookAt.elements);
lookAt = lookAt.multiply(self);
self.elements = lookAt.elements;
self.translate(-eyeX, -eyeY, -eyeZ);
// log(this.elements);
return self;
});
},
'Mat44', []);
// todo; should probably put this in a math package
mod.Mat33 = Sk.misceval.buildClass(mod, function($gbl, $loc)
{
$loc.__init__ = new Sk.builtin.func(function(self)
{
Sk.misceval.callsim($loc.loadIdentity, self);
});
$loc.loadIdentity = new Sk.builtin.func(function(self)
{
self.elements = [1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0];
});
},
'Mat33', []);
mod.Vec3 = Sk.misceval.buildClass(mod, function($gbl, $loc)
{
$loc.__init__ = new Sk.builtin.func(function(self, x, y, z)
{
self.x = x;
self.y = y;
self.z = z;
});
$loc.__sub__ = new Sk.builtin.func(function(self, other)
{
return Sk.misceval.callsim(mod.Vec3, self.x - other.x, self.y - other.y, self.z - other.z);
});
},
'Vec3', []);
mod.cross = new Sk.builtin.func(function(v1, v2)
{
goog.asserts.assert(v1 instanceof mod.Vec3 && v2 instanceof mod.Vec3);
return Sk.misceval.callsim(mod.Vec3,
v1.y * v2.z - v1.z * v2.y,
v1.z * v2.x - v1.x * v2.z,
v1.x * v2.y - v1.y * v2.x);
});
return mod;
};