Skip to content

Instantly share code, notes, and snippets.

@josephg
Created July 30, 2013 09:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save josephg/6111405 to your computer and use it in GitHub Desktop.
Save josephg/6111405 to your computer and use it in GitHub Desktop.
function chipmunk(global, foreign, heap) {
"use asm";
var sqrt = global.Math.sqrt;
var sin = global.Math.sin;
var cos = global.Math.cos;
var atan2 = global.Math.atan2;
var u8 = new global.Uint8Array(heap);
var i8 = new global.Int8Array(heap);
var u16 = new global.Uint16Array(heap);
var i16 = new global.Int16Array(heap);
var u32 = new global.Uint32Array(heap);
var i32 = new global.Int32Array(heap);
var f32 = new global.Float32Array(heap);
var f64 = new global.Float64Array(heap);
// Stack grows downwards.
var stack = 0;
/// Constant for the zero vector.
var vzero = 0;
function init(heapSize) {
heapSize = heapSize|0;
// cpvzero
V(vzero, +0, +0);
stack = heapSize;
}
/// Convenience constructor for cpVect structs.
function V(ret, x, y) {
ret = ret|0;
x = +x;
y = +y;
f64[ret>>3] = x;
f64[ret+8>>3] = y;
}
function vx(v) {
v = v|0;
return +f64[v>>3];
}
function vy(v) {
v = v|0;
return +f64[v+8>>3];
}
/// Check if two vectors are equal. (Be careful when comparing floating point numbers!)
function veql(v1, v2) {
v1 = v1|0;
v2 = v2|0;
return (+f64[v1>>3] == +f64[v2>>3]) & (+f64[v1+8>>3] == +f64[v2+8>>3])|0;
}
/// Add two vectors
function vadd(ret, v1, v2) {
ret = ret|0;
v1 = v1|0;
v2 = v2|0;
V(ret, +f64[v1>>3] + +f64[v2>>3], +f64[v1+8>>3] + +f64[v2+8>>3]);
}
/// Subtract two vectors.
function vsub(ret, v1, v2) {
ret = ret|0;
v1 = v1|0;
v2 = v2|0;
V(ret, +f64[v1>>3] - +f64[v2>>3], +f64[v1+8>>3] - +f64[v2+8>>3]);
}
/// Negate a vector.
function vneg(ret, v) {
ret = ret|0;
v = v|0;
f64[ret>>3] = - +f64[v>>3];
f64[ret+8>>3] = - +f64[v+8>>3];
}
/// Scalar multiplication.
function vmult(ret, v, s) {
ret = ret|0;
v = v|0;
s = +s;
f64[ret>>3] = f64[v>>3] * s;
f64[ret+8>>3] = f64[v+8>>3] * s;
}
/// Vector dot product.
function vdot(v1, v2) {
v1 = v1|0;
v2 = v2|0;
// v1.x*v2.x + v1.y*v2.y
return +(+f64[v1>>3] * +f64[v2>>3] + +f64[v1+8>>3] * +f64[v2+8>>3]);
}
/// 2D vector cross product analog.
/// The cross product of 2D vectors results in a 3D vector with only a z component.
/// This function returns the magnitude of the z value.
function vcross(v1, v2) {
v1 = v1|0;
v2 = v2|0;
// v1.x*v2.y - v1.y*v2.x
return +(+f64[v1>>3] * +f64[v2+8>>3] - +f64[v1+8>>3] * +f64[v2>>3]);
}
/// Returns a perpendicular vector. (90 degree rotation)
function vperp(ret, v) {
ret = ret|0;
v = v|0;
//cpv(-v.y, v.x)
V(ret, - +f64[v+8>>3], +f64[v>>3]);
}
/// Returns a perpendicular vector. (-90 degree rotation)
function vrperp(ret, v) {
ret = ret|0;
v = v|0;
//cpv(v.y, -v.x)
V(ret, +f64[v+8>>3], - +f64[v>>3]);
}
/// Returns the vector projection of v1 onto v2.
function vproject(ret, v1, v2) {
//return cpvmult(v2, cpvdot(v1, v2)/cpvdot(v2, v2));
ret = ret|0;
v1 = v1|0;
v2 = v2|0;
vmult(ret, v2, +vdot(v1, v2)/+vdot(v2, v2));
}
/// Returns the unit length vector for the given angle (in radians).
function vforangle(ret, a) {
ret = ret|0;
a = +a;
V(ret, +cos(a), +sin(a));
}
/// Returns the angular direction v is pointing in (in radians).
function vtoangle(v) {
v = v|0;
return +atan2(+f64[v+8>>3], +f64[v>>3]);
}
/// Uses complex number multiplication to rotate v1 by v2. Scaling will occur if v1 is not a unit vector.
function vrotate(ret, v1, v2) {
ret = ret|0;
v1 = v1|0;
v2 = v2|0;
//return cpv(v1.x*v2.x - v1.y*v2.y, v1.x*v2.y + v1.y*v2.x);
V(ret, +f64[v1>>3]*+f64[v2>>3] - +f64[v1+8>>3]*+f64[v2+8>>3],
+f64[v1>>3]*+f64[v2+8>>3] + +f64[v1+8>>3]*+f64[v2>>3]);
}
/// Inverse of cpvrotate().
function vunrotate(ret, v1, v2) {
ret = ret|0;
v1 = v1|0;
v2 = v2|0;
//return cpv(v1.x*v2.x + v1.y*v2.y, v1.y*v2.x - v1.x*v2.y);
V(ret, +f64[v1>>3]*+f64[v2>>3] + +f64[v1+8>>3]*+f64[v2+8>>3],
+f64[v1+8>>3]*+f64[v2>>3] - +f64[v1>>3]*+f64[v2+8>>3]);
}
/// Returns the squared length of v. Faster than cpvlength() when you only need to compare lengths.
function vlengthsq(v) {
v = v|0;
return +vdot(v, v);
}
/// Returns the length of v.
function vlength(v) {
v = v|0;
return +sqrt(+vdot(v, v));
}
/// Linearly interpolate between v1 and v2.
function vlerp(ret, v1, v2, t) {
ret = ret|0;
v1 = v1|0;
v2 = v2|0;
t = +t;
//return vadd(vmult(v1, 1.0f - t), cpvmult(v2, t));
f64[ret>>3] = +f64[v1>>3] * (1.0 - t) + +f64[v2>>3] * t;
f64[ret+8>>3] = +f64[v1+8>>3] * (1.0 - t) + +f64[v2+8>>3] * t;
/* Alternate, using a stack.
var _s = 0;
_s = stack;
stack = (stack - 32)|0;
vmult(stack, v1, 1.0 - t);
vmult(stack + 16|0, v2, t);
vadd(ret, stack, stack+16|0);
stack = _s;
*/
}
/// Returns a normalized copy of v.
function vnormalize(ret, v) {
ret = ret|0;
v = v|0;
vmult(ret, v, 1.0/+vlength(v));
}
/// Returns a normalized copy of v or cpvzero if v was already cpvzero. Protects against divide by zero errors.
function vnormalize_safe(ret, v) {
ret = ret|0;
v = v|0;
if (+f64[ret>>3] == 0.0 & +f64[ret+8>>3] == 0.0)
V(ret, 0.0, 0.0);
else
vnormalize(ret, v);
}
/// Clamp v to length len.
function vclamp(ret, v, len) {
ret = ret|0;
v = v|0;
len = +len;
//return (cpvdot(v,v) > len*len) ? cpvmult(cpvnormalize(v), len) : v;
if (+vdot(v, v) > len*len) {
vnormalize(ret, v);
vmult(ret, ret, len);
} else {
// return v;
f64[ret>>3] = +f64[v>>3];
f64[ret+8>>3] = +f64[v+8>>3];
}
}
/// Linearly interpolate between v1 towards v2 by distance d.
function vlerpconst(ret, v1, v2, d) {
ret = ret|0;
v1 = v1|0;
v2 = v2|0;
d = +d;
//vadd(ret, v1, cpvclamp(cpvsub(v2, v1), d));
vsub(ret, v2, v1);
vclamp(ret, ret, d);
vadd(ret, v1, ret);
}
/// Returns the distance between v1 and v2.
function vdistsq(v1, v2) {
v1 = v1|0;
v2 = v2|0;
var ret = 0.;
stack = stack - 16|0;
//return vlength(cpvsub(v1, v2));
vsub(stack, v1, v2);
ret = +vlengthsq(stack);
stack = stack + 16|0;
return +ret;
}
/// Returns the squared distance between v1 and v2. Faster than cpvdist() when you only need to compare distances.
function vdist(v1, v2) {
v1 = v1|0;
v2 = v2|0;
return +sqrt(+vdistsq(v1, v2));
}
/// Returns true if the distance between v1 and v2 is less than dist.
function vnear(v1, v2, dist) {
v1 = v1|0;
v2 = v2|0;
dist = +dist;
return +vdistsq(v1, v2) < dist*dist |0;
}
return {
_init:init,
v:V, vx:vx, vy:vy, veql:veql, vadd:vadd, vsub:vsub, vneg:vneg, vmult:vmult,
vdot:vdot, vcross:vcross, vperp:vperp, vrperp:vrperp, vproject:vproject,
vforangle:vforangle, vtoangle:vtoangle, vrotate:vrotate,
vunrotate:vunrotate, vlengthsq:vlengthsq, vlength:vlength, vlerp:vlerp,
vnormalize:vnormalize, vnormalize_safe:vnormalize_safe, vclamp:vclamp,
vlerpconst:vlerpconst, vdistsq:vdistsq, vdist:vdist, vnear:vnear
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment