Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save bga/568247 to your computer and use it in GitHub Desktop.
Save bga/568247 to your computer and use it in GitHub Desktop.
/*
Goal of this test is find best data structure for store matrices, vectors and quaternions
In C/C++ we have ability to store same data different ways ie
union
{
float m[9];
struct
{
float
m00, m01, m02
, m10, m11, m12
, m20, m21, m22
;
};
}
In javascipt we have only or array or hash.
Also this test try to use typed array and have 2 version of matrices multiply algorithm(with or w/o caching data from structure)
*/
var $G = this;
var Mat33Hash = function(
m00, m01, m02
, m10, m11, m12
, m20, m21, m22
)
{
this.m00 = m00; this.m01 = m01; this.m02 = m02;
this.m10 = m10; this.m11 = m11; this.m12 = m12;
this.m20 = m20; this.m21 = m21; this.m22 = m22;
};
Mat33Hash.prototype._identity = function()
{
this.m00 = 1; this.m01 = 0; this.m02 = 0;
this.m10 = 0; this.m11 = 1; this.m12 = 0;
this.m20 = 0; this.m21 = 0; this.m22 = 1;
};
Mat33Hash.prototype._mul = function(m)
{
return new Mat33Hash(
this.m00*m.m00 + this.m01*m.m10 + this.m02*m.m20
, this.m00*m.m01 + this.m01*m.m11 + this.m02*m.m21
, this.m00*m.m02 + this.m01*m.m12 + this.m02*m.m22
, this.m10*m.m00 + this.m11*m.m10 + this.m12*m.m20
, this.m10*m.m01 + this.m11*m.m11 + this.m12*m.m21
, this.m10*m.m02 + this.m11*m.m12 + this.m12*m.m22
, this.m20*m.m00 + this.m21*m.m10 + this.m22*m.m20
, this.m20*m.m01 + this.m21*m.m11 + this.m22*m.m21
, this.m20*m.m02 + this.m21*m.m12 + this.m22*m.m22
);
};
Mat33Hash.prototype._mulCache = function(m)
{
var
tm00 = this.m00, tm01 = this.m01, tm02 = this.m02
, tm10 = this.m10, tm11 = this.m11, tm12 = this.m12
, tm20 = this.m20, tm21 = this.m21, tm22 = this.m22
, mm00 = m.m00, mm01 = m.m01, mm02 = m.m02
, mm10 = m.m10, mm11 = m.m11, mm12 = m.m12
, mm20 = m.m20, mm21 = m.m21, mm22 = m.m22
;
return new Mat33Hash(
tm00*mm00 + tm01*mm10 + tm02*mm20
, tm00*mm01 + tm01*mm11 + tm02*mm21
, tm00*mm02 + tm01*mm12 + tm02*mm22
, tm10*mm00 + tm11*mm10 + tm12*mm20
, tm10*mm01 + tm11*mm11 + tm12*mm21
, tm10*mm02 + tm11*mm12 + tm12*mm22
, tm20*mm00 + tm21*mm10 + tm22*mm20
, tm20*mm01 + tm21*mm11 + tm22*mm21
, tm20*mm02 + tm21*mm12 + tm22*mm22
);
};
var Mat33Array = function(m)
{
this.m = m || new Array(9);
};
Mat33Array.prototype._identity = function()
{
this.m =
[
1, 0, 0
, 0, 1, 0
, 0, 0, 1
];
};
Mat33Array.prototype._mul = function(a)
{
var t = this.m, m = a.m;
return new Mat33Array(
[
t[0]*m[0] + t[1]*m[3] + t[2]*m[6]
, t[0]*m[1] + t[1]*m[4] + t[2]*m[7]
, t[0]*m[2] + t[1]*m[5] + t[2]*m[8]
, t[3]*m[0] + t[4]*m[3] + t[5]*m[6]
, t[3]*m[1] + t[4]*m[4] + t[5]*m[7]
, t[3]*m[2] + t[4]*m[5] + t[5]*m[8]
, t[6]*m[0] + t[7]*m[3] + t[8]*m[6]
, t[6]*m[1] + t[7]*m[4] + t[8]*m[7]
, t[6]*m[2] + t[7]*m[5] + t[8]*m[8]
]
);
};
Mat33Array.prototype._mulCache = function(a)
{
var t = this.m, m = a.m;
var
t0 = t[0], t1 = t[1], t2 = t[2]
, t3 = t[3], t4 = t[4], t5 = t[5]
, t6 = t[6], t7 = t[7], t8 = t[8]
, m0 = m[0], m1 = m[1], m2 = m[2]
, m3 = m[3], m4 = m[4], m5 = m[5]
, m6 = m[6], m7 = m[7], m8 = m[8]
;
return new Mat33Array(
[
t0*m0 + t1*m3 + t2*m6
, t0*m1 + t1*m4 + t2*m7
, t0*m2 + t1*m5 + t2*m8
, t3*m0 + t4*m3 + t5*m6
, t3*m1 + t4*m4 + t5*m7
, t3*m2 + t4*m5 + t5*m8
, t6*m0 + t7*m3 + t8*m6
, t6*m1 + t7*m4 + t8*m7
, t6*m2 + t7*m5 + t8*m8
]
);
};
var F32Array = $G.Float32Array || $G.WebGLFloatArray || $G.CanvasFloatArray || Array;
var Mat33TypedArray = function(m)
{
this.m = m || new F32Array(9);
};
Mat33TypedArray.prototype._identity = function()
{
this.m = new F32Array(
[
1, 0, 0
, 0, 1, 0
, 0, 0, 1
]);
};
Mat33TypedArray.prototype._mul = function(a)
{
var t = this.m, m = a.m;
return new Mat33TypedArray(
new F32Array([
t[0]*m[0] + t[1]*m[3] + t[2]*m[6]
, t[0]*m[1] + t[1]*m[4] + t[2]*m[7]
, t[0]*m[2] + t[1]*m[5] + t[2]*m[8]
, t[3]*m[0] + t[4]*m[3] + t[5]*m[6]
, t[3]*m[1] + t[4]*m[4] + t[5]*m[7]
, t[3]*m[2] + t[4]*m[5] + t[5]*m[8]
, t[6]*m[0] + t[7]*m[3] + t[8]*m[6]
, t[6]*m[1] + t[7]*m[4] + t[8]*m[7]
, t[6]*m[2] + t[7]*m[5] + t[8]*m[8]
])
);
};
Mat33TypedArray.prototype._mulCache = function(a)
{
var t = this.m, m = a.m;
var
t0 = t[0], t1 = t[1], t2 = t[2]
, t3 = t[3], t4 = t[4], t5 = t[5]
, t6 = t[6], t7 = t[7], t8 = t[8]
, m0 = m[0], m1 = m[1], m2 = m[2]
, m3 = m[3], m4 = m[4], m5 = m[5]
, m6 = m[6], m7 = m[7], m8 = m[8]
;
return new Mat33TypedArray(
new F32Array([
t0*m0 + t1*m3 + t2*m6
, t0*m1 + t1*m4 + t2*m7
, t0*m2 + t1*m5 + t2*m8
, t3*m0 + t4*m3 + t5*m6
, t3*m1 + t4*m4 + t5*m7
, t3*m2 + t4*m5 + t5*m8
, t6*m0 + t7*m3 + t8*m6
, t6*m1 + t7*m4 + t8*m7
, t6*m2 + t7*m5 + t8*m8
])
);
};
var Mat33TypedArray2 = function(m)
{
this.m = m || new F32Array(9);
};
Mat33TypedArray2.prototype._identity = function()
{
this.m = new F32Array(
[
1, 0, 0
, 0, 1, 0
, 0, 0, 1
]);
};
Mat33TypedArray2.prototype._mul = function(a)
{
var t = this.m, m = a.m;
var s = new F32Array(9);
s[0] = t[0]*m[0] + t[1]*m[3] + t[2]*m[6];
s[1] = t[0]*m[1] + t[1]*m[4] + t[2]*m[7];
s[2] = t[0]*m[2] + t[1]*m[5] + t[2]*m[8];
s[3] = t[3]*m[0] + t[4]*m[3] + t[5]*m[6];
s[4] = t[3]*m[1] + t[4]*m[4] + t[5]*m[7];
s[5] = t[3]*m[2] + t[4]*m[5] + t[5]*m[8];
s[6] = t[6]*m[0] + t[7]*m[3] + t[8]*m[6];
s[7] = t[6]*m[1] + t[7]*m[4] + t[8]*m[7];
s[8] = t[6]*m[2] + t[7]*m[5] + t[8]*m[8];
return new Mat33TypedArray2(s);
};
Mat33TypedArray2.prototype._mulCache = function(a)
{
var t = this.m, m = a.m;
var
t0 = t[0], t1 = t[1], t2 = t[2]
, t3 = t[3], t4 = t[4], t5 = t[5]
, t6 = t[6], t7 = t[7], t8 = t[8]
, m0 = m[0], m1 = m[1], m2 = m[2]
, m3 = m[3], m4 = m[4], m5 = m[5]
, m6 = m[6], m7 = m[7], m8 = m[8]
;
var s = new F32Array(9);
s[0] = t0*m0 + t1*m3 + t2*m6
s[1] = t0*m1 + t1*m4 + t2*m7
s[2] = t0*m2 + t1*m5 + t2*m8
s[3] = t3*m0 + t4*m3 + t5*m6
s[4] = t3*m1 + t4*m4 + t5*m7
s[5] = t3*m2 + t4*m5 + t5*m8
s[6] = t6*m0 + t7*m3 + t8*m6
s[7] = t6*m1 + t7*m4 + t8*m7
s[8] = t6*m2 + t7*m5 + t8*m8
return new Mat33TypedArray2(s);
};
var _fTest = function(Class)
{
return function(n)
{
var a = new Class();
a._identity();
var i = n; while(i--)
{
a = a._mul(a);
}
};
};
var _fTestCache = function(Class)
{
return function(n)
{
var a = new Class();
a._identity();
var i = n; while(i--)
{
a = a._mulCache(a);
}
};
};
var tests =
[
_fTest(Mat33Hash) // 0
, _fTestCache(Mat33Hash) // 1
, _fTest(Mat33Array) // 2
, _fTestCache(Mat33Array) //3
];
if(F32Array !== Array)
{
tests.push(
_fTest(Mat33TypedArray) // 4
, _fTestCache(Mat33TypedArray) // 5
, _fTest(Mat33TypedArray2) // 6
, _fTestCache(Mat33TypedArray2) // 7
);
}
_speedTest(
tests
, 200000
);
/*
ie7 200000/10
0: 1592 ms
1: 922 ms
2: 1592 ms
3: 921 ms
chrome7 200000
0: 542 ms
1: 204 ms
2: 719 ms
3: 312 ms
4: 4502 ms
5: 4007 ms
6: 3249 ms
7: 2992 ms
opera10.60 200000
0: 328 ms
1: 212 ms
2: 471 ms
3: 350 ms
ff3.6 200000/5
0: 3483 ms
1: 1553 ms
2: 3909 ms
3: 1836 ms
ff4b3 200000
0: 1446 ms
1: 712 ms
2: 1227 ms
3: 563 ms
4: 1206 ms
5: 1401 ms
6: 669 ms
7: 910 ms
*/
/*
As we can see hash currently is best solution. With caching. In future may be Mat33TypedArray2 will be best(see ff4b3).
Thanks to http://code.google.com/p/glmatrix/ for idea, but it uses slow solution :)
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment