/*
* KNWebGLUtil.js
* Keynote HTML Player
*
* Created by Tungwei Cheng
* Copyright (c) 2016-2018 Apple Inc. All rights reserved.
*/
var KNWebGLUtil = {};
KNWebGLUtil.setupProgram = function(gl, programName) {
var shader = KNWebGLShader[programName];
var vertexShader = this.loadShader(gl, gl.VERTEX_SHADER, shader.vertex);
var fragmentShader = this.loadShader(gl, gl.FRAGMENT_SHADER, shader.fragment);
var shaderProgram = this.createShaderProgram(gl, vertexShader, fragmentShader);
// creates uniforms and attribs but does not enable attribs.
var attribs = {};
var uniforms = {};
for (var i = 0, length = shader.uniformNames.length; i < length; i++) {
var uniformName = shader.uniformNames[i];
uniforms[uniformName] = gl.getUniformLocation(shaderProgram, uniformName);
}
for (var i = 0, length = shader.attribNames.length; i < length; i++) {
var attribName = shader.attribNames[i];
attribs[attribName] = gl.getAttribLocation(shaderProgram, attribName);
}
// create a program object
var program = {
shaderProgram: shaderProgram,
uniforms: uniforms,
attribs: attribs
};
// use this program for rendering
gl.useProgram(shaderProgram);
return program;
};
KNWebGLUtil.loadShader = function(gl, type, shaderSource) {
var shader = gl.createShader(type);
gl.shaderSource(shader, shaderSource);
gl.compileShader(shader);
// Check the compile status
var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (!compiled) {
// error during compilation
var error = gl.getShaderInfoLog(shader);
console.log("*** Error compiling shader '" + shader + "':" + error);
gl.deleteShader(shader);
return null;
}
return shader;
};
KNWebGLUtil.createShaderProgram = function(gl, vertexShader, fragmentShader) {
// create shader program
var shaderProgram = gl.createProgram();
// Attach the shaders to the program
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
// Link the program
gl.linkProgram(shaderProgram);
var linked = gl.getProgramParameter(shaderProgram, gl.LINK_STATUS);
if (!linked) {
var error = gl.getProgramInfoLog(shaderProgram);
console.log("Error in program linking:" + error);
gl.deleteProgram(shaderProgram);
}
return shaderProgram;
};
KNWebGLUtil.createTexture = function(gl, image) {
var texture = gl.createTexture();
// bind WebGLTexture object to gl.TEXTURE_2D target
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
// upload texture data to GPU
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.bindTexture(gl.TEXTURE_2D, null);
return texture;
};
KNWebGLUtil.bindTextureWithImage = function(gl, image) {
var texture = gl.createTexture();
// bind WebGLTexture object to gl.TEXTURE_2D target
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.bindTexture(gl.TEXTURE_2D, null);
return texture;
};
KNWebGLUtil.bindDynamicBufferWithData = function(gl, attribLoc, buffer, data, size) {
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.DYNAMIC_DRAW);
// we need to enable attrib loc to work with data buffer
gl.enableVertexAttribArray(attribLoc);
gl.vertexAttribPointer(attribLoc, size, gl.FLOAT, false, 0, 0);
};
KNWebGLUtil.bindBufferWithData = function(gl, attribLoc, buffer, data, size, bufferUsage) {
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), bufferUsage);
// we need to enable attrib loc to work with data buffer
gl.enableVertexAttribArray(attribLoc);
gl.vertexAttribPointer(attribLoc, size, gl.FLOAT, false, 0, 0);
};
//attribute buffer insertion
KNWebGLUtil.setPoint2DAtIndexForAttribute = function(point, index, attribute) {
//attribute cannot become an object. we need to create an object where we can place this. BUMMER
attribute[index*2] = point.x;
attribute[index*2+1] = point.y;
attribute.size = 2;
};
KNWebGLUtil.setPoint3DAtIndexForAttribute = function(point, index, attribute) {
attribute[index*3] = point.x;
attribute[index*3+1] = point.y;
attribute[index*3+2] = point.z;
attribute.size = 3;
};
KNWebGLUtil.setPoint4DAtIndexForAttribute = function(point, index, attribute) {
attribute[index*4] = point.x;
attribute[index*4+1] = point.y;
attribute[index*4+2] = point.z;
attribute[index*4+3] = point.w;
attribute.size = 4;
};
KNWebGLUtil.setFloatAtIndexForAttribute = function(f, index, attribute) {
attribute[index] = f;
};
KNWebGLUtil.getPoint2DForArrayAtIndex = function(attrib, index) {
var point = {};
point.x = attrib[index*2];
point.y = attrib[index*2 + 1];
return point;
};
KNWebGLUtil.getPoint3DForArrayAtIndex = function(attrib, index) {
var point = {};
point.x = attrib[index*3];
point.y = attrib[index*3 + 1];
point.z = attrib[index*3 + 2];
return point;
};
KNWebGLUtil.getPoint4DForArrayAtIndex = function(attrib, index) {
var point = {};
point.x = attrib[index*4];
point.y = attrib[index*4 + 1];
point.z = attrib[index*4 + 2];
point.w = attrib[index*4 + 3];
return point;
};
KNWebGLUtil.bindAllAvailableAttributesToBuffers = function(gl, attribs, bufferdata, size, buffer, bufferUsage) {
for (var obj in attribs) {
var attribute = attribs[obj];
if (buffer[obj] == undefined) {
buffer[obj] = gl.createBuffer();
}
KNWebGLUtil.bindBufferWithData(gl, attribute, buffer[obj], bufferdata[obj], size[obj], bufferUsage);
}
};
// We need to enable attribs before binding.
// This also sets the program to the given program.
// This never needs to be called in single program animations
KNWebGLUtil.enableAttribs = function(gl, program) {
var attribs = program.attribs;
gl.useProgram(program.shaderProgram);
for (var obj in attribs) {
gl.enableVertexAttribArray(attribs[obj]);
}
};
/*
* WebGraphics is not a container for any data. It should only computer and return values.
*
* makePoint(x, y): returns a object with .x and .y properties attached
*
* randomBetween(a, b): returns a random number between a (lower bound) and b (upper bound)
*
* mix(x, y, a): returns a linear intern between x and y using a as a weight between them
*
* clamp(x, minVal, maxVal) : clamps x between a min and max value
*/
var WebGraphics = {};
WebGraphics.makePoint = function(x, y) {
var obj = {};
obj.x = x;
obj.y = y;
return obj;
};
WebGraphics.makePoint3D = function(x, y, z) {
var obj = {};
obj.x = x;
obj.y = y;
obj.z = z;
return obj;
};
WebGraphics.makePoint4D = function(x, y, z, w) {
var obj = {};
obj.x = x;
obj.y = y;
obj.z = z;
obj.w = w;
return obj;
};
WebGraphics.makeRect = function(x,y, width, height) {
var obj = {};
obj.x = x;
obj.y = y;
obj.width = width;
obj.height = height;
return obj;
};
WebGraphics.makeSize = function(width, height) {
var obj = {};
obj.width = width;
obj.height = height;
return obj;
};
WebGraphics.setOrigin = function(obj, point) {
obj.x = point.x;
obj.y = point.y;
return obj;
};
WebGraphics.multiplyPoint3DByScalar = function(point, scalar) {
var obj = {};
obj.x = point.x * scalar;
obj.y = point.y * scalar;
obj.z = point.z * scalar;
return obj;
};
WebGraphics.multiplyPoint4DByScalar = function(point, scalar) {
var obj = {};
obj.x = point.x * scalar;
obj.y = point.y * scalar;
obj.z = point.z * scalar;
obj.w = point.w * scalar;
return obj;
};
WebGraphics.addPoint3DToPoint3D = function(a, b) {
var obj = {};
obj.x = a.x + b.x;
obj.y = a.y + b.y;
obj.z = a.z + b.z;
return obj;
};
WebGraphics.point3DNormalize = function(pt3d) {
var length = Math.sqrt(pt3d.x * pt3d.x + pt3d.y * pt3d.y + pt3d.z * pt3d.z);
var obj = {};
obj.z = pt3d.z / length;
obj.y = pt3d.y / length;
obj.x = pt3d.x / length;
return obj;
};
WebGraphics.randomBetween = function(min, max) {
var x = Math.random();
x *= (max - min);
x += min;
return x;
};
WebGraphics.doubleBetween = function(randMin, randMax) {
var result = 0;
var bottom, top;
if (randMin < randMax) {
bottom = randMin;
top = randMax;
} else {
bottom = randMax;
top = randMin;
}
// rnd: random in range [0.0 -> 1.0)
// RandBetween(bottom, top) = ((top - bottom) * rnd) + bottom
// To avoid overflows, distribute the multiplication:
// = top*rand - bottom*rand + bottom
var rnd = Math.random();
var topMult = top * rnd;
var bottomMult = bottom * rnd;
if ((bottom >= 0.0) == (top >= 0.0)) {
// Both are the same sign, do the subtraction first to avoid overflow.
result = topMult - bottomMult;
result = result + bottom;
} else {
// The signs differ, add bottom in first to avoid overflow.
result = topMult + bottom;
result = result - bottomMult;
}
return result;
}
WebGraphics.mix = function(x, y, a) {
return x * (1 - a) + (y * a);
};
WebGraphics.clamp = function(x, minVal, maxVal) {
return Math.min(Math.max(x, minVal), maxVal);
};
WebGraphics.sineMap = function(x) {
return (Math.sin(x * Math.PI - (Math.PI / 2)) + 1) * 0.5;
};
WebGraphics.createMatrix4 = function() {
//creates and identity matrix, column-major matrix library, it is not necessary to use this to get an ortho matrix
var obj = new Float32Array(16);
obj[0] = 1;
obj[1] = 0;
obj[2] = 0;
obj[3] = 0;
obj[4] = 0;
obj[5] = 1;
obj[6] = 0;
obj[7] = 0;
obj[8] = 0;
obj[9] = 0;
obj[10] = 1;
obj[11] = 0;
obj[12] = 0;
obj[13] = 0;
obj[14] = 0;
obj[15] = 1;
return obj;
};
WebGraphics.makeIdentityMatrix4 = function() {
return WebGraphics.createMatrix4();
};
WebGraphics.makeOrthoMatrix4 = function(left, right, bottom, top, near, far) {
var matrix = new Float32Array(16);
var rl = right - left;
var tb = top - bottom;
var fn = far - near;
matrix[0] = 2 / rl;
matrix[1] = 0;
matrix[2] = 0;
matrix[3] = 0;
matrix[4] = 0;
matrix[5] = 2 / tb;
matrix[6] = 0;
matrix[7] = 0;
matrix[8] = 0;
matrix[9] = 0;
matrix[10] = -2 /fn;
matrix[11] = 0;
matrix[12] = -(right + left) / rl;
matrix[13] = -(top - bottom) / tb;
matrix[14] = -(far + near) / fn;
matrix[15] = 1;
return matrix;
};
WebGraphics.makeFrustumMatrix4 = function(left, right, bottom, top, near, far) {
var rl = right - left;
var tb = top - bottom;
var fn = far - near;
var m = new Float32Array(16);
m[0] = (near * 2) / rl; //11
m[1] = 0; //21
m[2] = 0; //31
m[3] = 0; //41
m[4] = 0; //12
m[5] = (near * 2) / tb; //22
m[6] = 0; //32
m[7] = 0; //42
m[8] = (right + left) / rl;
m[9] = (top + bottom) / tb;
m[10] = -(far + near) / fn;
m[11] = -1;
m[12] = 0;
m[13] = 0;
m[14] = (-2 * far * near) / fn;
m[15] = 0;
return m;
};
WebGraphics.makePerspectiveMatrix4 = function(fovy, aspect, near, far) {
var top = near * Math.tan(fovy * Math.PI / 360.0);
var right = top * aspect;
return WebGraphics.makeFrustumMatrix4(-right, right, -top, top, near, far);
};
WebGraphics.multiplyMatrix4 = function(a, b) {
//a*b
var m = new Float32Array(16);
var a11 = a[0], a12 = a[4], a13 = a[8], a14 = a[12], a21 = a[1], a22 = a[5], a23 = a[9], a24 = a[13],
a31 = a[2], a32 = a[6], a33 = a[10], a34 = a[14], a41 = a[3], a42 = a[7], a43 = a[11], a44 = a[15];
var b11 = b[0], b12 = b[4], b13 = b[8], b14 = b[12], b21 = b[1], b22 = b[5], b23 = b[9], b24 = b[13],
b31 = b[2], b32 = b[6], b33 = b[10], b34 = b[14], b41 = b[3], b42 = b[7], b43 = b[11], b44 = b[15];
m[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
m[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
m[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
m[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
m[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
m[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
m[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
m[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
m[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
m[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
m[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
m[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
m[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
m[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
m[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
m[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
return m;
};
WebGraphics.scaleMatrix4 = function(m4, sx, sy, sz) {
var m = WebGraphics.createMatrix4();
m[0] = sx;
m[5] = sy;
m[10] = sz;
return WebGraphics.multiplyMatrix4(m4, m);
};
WebGraphics.translateMatrix4 = function(m4, tx, ty, tz) {
var m = WebGraphics.createMatrix4();
m[12] = tx;
m[13] = ty;
m[14] = tz;
return WebGraphics.multiplyMatrix4(m4, m);
};
WebGraphics.rotateMatrix4AboutXYZ = function(m4, theta, x, y, z) {
var point3d = WebGraphics.makePoint3D(x, y, z);
point3d = WebGraphics.point3DNormalize(point3d);
var ux = point3d.x;
var uy = point3d.y;
var uz = point3d.z;
var cos = Math.cos(theta);
var oneMinusCos = 1 - cos;
var sin = Math.sin(theta);
var m = WebGraphics.createMatrix4();
m[0] = cos + (ux * ux) * oneMinusCos;
m[1] = ux * uy * oneMinusCos + (uz * sin);
m[2] = uz * ux * oneMinusCos - uy * sin;
m[4] = ux * uy * oneMinusCos - uz * sin;
m[5] = cos + (uy * uy) * oneMinusCos;
m[6] = uz * uy * oneMinusCos + ux * sin;
m[8] = ux * uy * oneMinusCos + uy * sin;
m[9] = uy * uz * oneMinusCos - ux * sin;
m[10] = cos + (uz * uz) * oneMinusCos;
return WebGraphics.multiplyMatrix4(m4, m);
};
WebGraphics.colorWithHSBA = function(hue, saturation, brightness, alpha) {
var hueTimesSix, frac, p1, p2, p3, red, blue, green;
var obj = {"hue": hue, "saturation": saturation, "brightness": brightness, "alpha": alpha};
if (hue == 1.0) {
hue = 0.0;
}
hueTimesSix = hue * 6.0;
frac = hueTimesSix - Math.floor(hueTimesSix);
p1 = brightness * (1-saturation);
p2 = brightness * (1.0 - (saturation * frac));
p3 = brightness * (1.0 - (saturation * (1.0 - frac)));
switch (parseInt(hueTimesSix)) {
case 0:
red = brightness;
green = p3;
blue = p1;
break;
case 1:
red = p2;
green = brightness;
blue = p1;
break;
case 2:
red = p1;
green = brightness;
blue = p3;
break;
case 3:
red = p1;
green = p2;
blue = brightness;
break;
case 4:
red = p3;
green = p1;
blue = brightness;
break;
case 5:
red = brightness;
green = p1;
blue = p2;
break;
}
obj.red = red;
obj.blue = blue;
obj.green = green;
return obj;
};
WebGraphics.makeMat3WithAffineTransform = function(affineTransform) {
var obj = new Float32Array(9);
obj[0] = affineTransform[0];
obj[1] = affineTransform[1];
obj[2] = 0;
obj[3] = affineTransform[2];
obj[4] = affineTransform[3];
obj[5] = 0;
obj[6] = affineTransform[4];
obj[7] = affineTransform[5];
obj[8] = 1;
return obj;
};
/*
* High performance vector container for math
* Copyright (c) 2011 Apple, Inc
*/
vector3 = function(vec) {
this.create(vec);
};
vector3.prototype = {
create: function(vec) {
var m = this.$matrix = {};
if (!vec) {
m.m11 = 0;
m.m12 = 0;
m.m13 = 0;
} else {
m.m11 = vec[0];
m.m12 = vec[1];
m.m13 = vec[2];
}
},
subtract: function(vec) {
var m = this.$matrix;
var mm = vec.$matrix;
m.m11 -= mm.m11;
m.m12 -= mm.m12;
m.m13 -= mm.m13;
},
add: function(vec) {
var m = this.$matrix;
var mm = vec.$matrix;
m.m11 += mm.m11;
m.m12 += mm.m12;
m.m13 += mm.m13;
},
normalize: function() {
var m = this.$matrix;
var length = Math.sqrt((m.m11 * m.m11) + (m.m12 * m.m12) + (m.m13 * m.m13));
if (length > 0) {
m.m11 /= length;
m.m12 /= length;
m.m13 /= length;
}
},
scale: function(scalar) {
var m = this.$matrix;
m.m11 *= scalar;
m.m12 *= scalar;
m.m13 *= scalar;
},
cross: function(vec) {
var m = this.$matrix;
var mm = vec.$matrix;
var a1 = mm.m11, a2 = mm.m12, a3 = mm.m13;
var m1 = m.m11, m2 = m.m12, m3 = m.m13;
m.m11 = m2 * a3 - m3 * a2;
m.m12 = m3 * a1 - m1 * a3;
m.m13 = m1 * a2 - m2 * a1;
},
getArray: function() {
var m = this.$matrix;
return [m.m11, m.m12, m.m13];
}
};
// Matrix3, 3x3 Matrix Class
// Matrix3 stores row-major order, simply transverse to get a webGL acceptable array
Matrix3 = function() {
this.identity();
};
Matrix3.prototype = {
identity: function() {
this.$matrix = {
m11: 1, m12: 0, m13: 0,
m21: 0, m22: 1, m23: 0,
m31: 0, m32: 0, m33: 1
};
},
affineScale: function(sx, sy) {
var m = this.$matrix;
m.m11 = sx;
m.m22 = sy;
},
affineTranslate: function(tx, ty) {
var m = this.$matrix;
m.m13 = tx;
m.m23 = ty;
},
transformTranslate: function(tx, ty) {
var matrix = new Matrix3();
matrix.affineTranslate(tx, ty);
this.multiply(matrix.getArray());
},
multiply: function(mat) {
var m = this.$matrix;
var m0 = m.m11, m1 = m.m12, m2 = m.m13, m3 = m.m21, m4 = m.m22, m5 = m.m23, m6 = m.m31, m7 = m.m32, m8 = m.m33;
m.m11 = m0 * mat[0] + m1 * mat[3] + m2 * mat[6];
m.m12 = m0 * mat[1] + m1 * mat[4] + m2 * mat[7];
m.m13 = m0 * mat[2] + m1 * mat[5] + m2 * mat[8];
m.m21 = m3 * mat[0] + m4 * mat[3] + m5 * mat[6];
m.m22 = m3 * mat[1] + m4 * mat[4] + m5 * mat[7];
m.m23 = m3 * mat[2] + m4 * mat[5] + m5 * mat[8];
m.m31 = m6 * mat[0] + m7 * mat[3] + m8 * mat[6];
m.m32 = m6 * mat[1] + m7 * mat[4] + m8 * mat[7];
m.m33 = m6 * mat[2] + m7 * mat[5] + m8 * mat[8];
},
getArray: function() {
// this is row major order, for WebGL you'll need to transverse this
var m = this.$matrix;
return [m.m11, m.m12, m.m13, m.m21, m.m22, m.m23, m.m31, m.m32, m.m33];
},
getFloat32Array: function() {
return new Float32Array(this.getArray());
},
getColumnMajorArray: function() {
// this is row major order, for WebGL you'll need to transverse this
var m = this.$matrix;
return [m.m11, m.m21, m.m31, m.m12, m.m22, m.m32, m.m13, m.m23, m.m33 ];
},
getColumnMajorFloat32Array: function() {
return new Float32Array(this.getColumnMajorArray());
}
};
Matrix4 = function() {
this.identity();
};
Matrix4.prototype = {
identity: function() {
this.$matrix = {
m11: 1, m12: 0, m13: 0, m14: 0,
m21: 0, m22: 1, m23: 0, m24: 0,
m31: 0, m32: 0, m33: 1, m34: 0,
m41: 0, m42: 0, m43: 0, m44: 1
};
},
translate: function(x, y, z) {
var matrix = new Matrix4();
var m = matrix.$matrix;
m.m14 = x;
m.m24 = y;
m.m34 = z;
this.multiply(matrix);
/*
* this.$matrix.m41 = this.$matrix.m11*x + this.$matrix.m21*y +
* this.$matrix.m31*z + this.$matrix.m41; this.$matrix.m42 =
* this.$matrix.m12*x + this.$matrix.m22*y + this.$matrix.m32*z +
* this.$matrix.m42; this.$matrix.m43 = this.$matrix.m13*x +
* this.$matrix.m23*y + this.$matrix.m33*z + this.$matrix.m43;
* this.$matrix.m44 = this.$matrix.m14*x + this.$matrix.m24*y +
* this.$matrix.m34*z + this.$matrix.m44;
*/
},
scale: function(x, y, z) {
var matrix = new Matrix4();
var m = matrix.$matrix;
m.m11 = x;
m.m22 = y;
m.m33 = z;
this.multiply(matrix);
},
multiply: function(mat) {
var m = this.$matrix;
var mm = mat.$matrix;
var m11 = (mm.m11 * m.m11 + mm.m21 * m.m12 + mm.m31 * m.m13 + mm.m41 * m.m14);
var m12 = (mm.m12 * m.m11 + mm.m22 * m.m12 + mm.m32 * m.m13 + mm.m42 * m.m14);
var m13 = (mm.m13 * m.m11 + mm.m23 * m.m12 + mm.m33 * m.m13 + mm.m43 * m.m14);
var m14 = (mm.m14 * m.m11 + mm.m24 * m.m12 + mm.m34 * m.m13 + mm.m44 * m.m14);
var m21 = (mm.m11 * m.m21 + mm.m21 * m.m22 + mm.m31 * m.m23 + mm.m41 * m.m24);
var m22 = (mm.m12 * m.m21 + mm.m22 * m.m22 + mm.m32 * m.m23 + mm.m42 * m.m24);
var m23 = (mm.m13 * m.m21 + mm.m23 * m.m22 + mm.m33 * m.m23 + mm.m43 * m.m24);
var m24 = (mm.m14 * m.m21 + mm.m24 * m.m22 + mm.m34 * m.m23 + mm.m44 * m.m24);
var m31 = (mm.m11 * m.m31 + mm.m21 * m.m32 + mm.m31 * m.m33 + mm.m41 * m.m34);
var m32 = (mm.m12 * m.m31 + mm.m22 * m.m32 + mm.m32 * m.m33 + mm.m42 * m.m34);
var m33 = (mm.m13 * m.m31 + mm.m23 * m.m32 + mm.m33 * m.m33 + mm.m43 * m.m34);
var m34 = (mm.m14 * m.m31 + mm.m24 * m.m32 + mm.m34 * m.m33 + mm.m44 * m.m34);
var m41 = (mm.m11 * m.m41 + mm.m21 * m.m42 + mm.m31 * m.m43 + mm.m41 * m.m44);
var m42 = (mm.m12 * m.m41 + mm.m22 * m.m42 + mm.m32 * m.m43 + mm.m42 * m.m44);
var m43 = (mm.m13 * m.m41 + mm.m23 * m.m42 + mm.m33 * m.m43 + mm.m43 * m.m44);
var m44 = (mm.m14 * m.m41 + mm.m24 * m.m42 + mm.m34 * m.m43 + mm.m44 * m.m44);
m.m11 = m11;
m.m12 = m12;
m.m13 = m13;
m.m14 = m14;
m.m21 = m21;
m.m22 = m22;
m.m23 = m23;
m.m24 = m24;
m.m31 = m31;
m.m32 = m32;
m.m33 = m33;
m.m34 = m34;
m.m41 = m41;
m.m42 = m42;
m.m43 = m43;
m.m44 = m44;
},
perspective: function(fovy, aspect, near, far) {
var top = near * Math.tan(fovy * Math.PI / 360.0);
var right = top * aspect;
return this.frustum(-right, right, -top, top, near, far);
},
ortho: function(left, right, bottom, top, near, far) {
var rl = right - left;
var tb = top - bottom;
var fn = far - near;
var m = this.$matrix;
m.m11 = 2 / rl;
m.m12 = 0;
m.m13 = 0;
m.m14 = -(right + left) / rl;
m.m21 = 0;
m.m22 = 2 / tb;
m.m23 = 0;
m.m24 = -(top + bottom) / tb;
m.m31 = 0;
m.m32 = 0;
m.m33 = -2 / fn;
m.m34 = -(far + near) / fn;
m.m41 = 0;
m.m42 = 0;
m.m43 = 0;
m.m44 = 1;
},
frustum: function(left, right, bottom, top, near, far) {
var rl = right - left;
var tb = top - bottom;
var fn = far - near;
var m = this.$matrix;
m.m11 = (near * 2) / rl;
m.m12 = 0;
m.m13 = (right + left) / rl;
m.m14 = 0;
m.m21 = 0;
m.m22 = (near * 2) / tb;
m.m23 = (top + bottom) / tb;
m.m24 = 0;
m.m31 = 0;
m.m32 = 0;
m.m33 = -(far + near) / fn;
m.m34 = (-2 * far * near) / fn;
m.m41 = 0;
m.m42 = 0;
m.m43 = -1;
m.m44 = 0;
},
getArray: function() {
// this is row major order, for WebGL you'll need to transverse this
var m = this.$matrix;
return [m.m11, m.m12, m.m13, m.m14,
m.m21, m.m22, m.m23, m.m24,
m.m31, m.m32, m.m33, m.m34,
m.m41, m.m42, m.m43, m.m44];
},
getFloat32Array: function() {
return new Float32Array(this.getArray());
},
getColumnMajorArray: function() {
// this is row major order, for WebGL you'll need to transverse this
var m = this.$matrix;
return [m.m11, m.m21, m.m31, m.m41,
m.m12, m.m22, m.m32, m.m42,
m.m13, m.m23, m.m33, m.m43,
m.m14, m.m24, m.m34, m.m44];
},
getColumnMajorFloat32Array: function() {
return new Float32Array(this.getColumnMajorArray());
}
};
function TSUMix(a, b, x) {
return a + (b - a) * x;
}
//sinusoidal timing function
function TSUSineMap(x) {
return (Math.sin(x * Math.PI - (Math.PI / 2)) + 1) * 0.5;
}
//function for Twist sizing
function TwistFX(location, percent) {
var twist = 4.0 / 10.25;
var x = (1 + twist) * percent - twist * location;
if (x < 0) {
return 0;
}
else if (x > 1) {
return 1;
}
else {
return TSUSineMap(x);
}
}
//CGAffineTransformMakeRotation
function CGAffineTransformMakeRotation(angle) {
var sine, consine;
sine = Math.sin(angle);
cosine = Math.cos(angle);
return [cosine, sine, -sine, cosine, 0, 0];
}
//CGAffineTransformEqualToTransform
function CGAffineTransformEqualToTransform(t1, t2) {
return t1.a === t2.a && t1.b === t2.b && t1.c === t2.c && t1.d === t2.d && t1.tx === t2.tx && t1.ty === t2.ty;
}
//CATransform3DEqualToTransform
function CATransform3DEqualToTransform(a, b) {
var result = a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
return result;
}
//CGPointMake
function CGPointMake(x, y) {
var p = {
x: x,
y: y
};
return p;
}
//CGRectIntersection
function CGRectIntersection(r1, r2) {
var r = {
"origin": {
"x": 0,
"y": 0
},
"size": {
"width": 0,
"height": 0
}
};
var x1, x2, y1, y2;
x1 = Math.max(r1.origin.x, r2.origin.x);
x2 = Math.min(r1.origin.x + r1.size.width, r2.origin.x + r2.size.width);
if (x1 > x2) {
return r;
}
y1 = Math.max(r1.origin.y, r2.origin.y);
y2 = Math.min(r1.origin.y + r1.size.height, r2.origin.y + r2.size.height);
if (y1 > y2) {
return r;
}
r.origin.x = x1;
r.size.width = x2 - x1;
r.origin.y = y1;
r.size.height = y2 - y1;
return r;
}
// CGRectIntegral
function CGRectIntegral(rect) {
var r = {
"origin": {
"x": 0,
"y": 0
},
"size": {
"width": 0,
"height": 0
}
};
r.origin.x = Math.floor(rect.origin.x);
r.origin.y = Math.floor(rect.origin.y);
r.size.width = Math.ceil(rect.origin.x + rect.size.width) - r.origin.x;
r.size.height = Math.ceil(rect.origin.y + rect.size.height) - r.origin.y;
return r;
}
// CGRectGetMinX
function CGRectGetMinX(rect) {
return rect.origin.x;
}
// CGRectGetMinY
function CGRectGetMinY(rect) {
return rect.origin.y;
}
// CGRectGetMidX
function CGRectGetMidX(rect) {
return rect.origin.x + rect.size.width / 2;
}
// CGRectGetMidY
function CGRectGetMidY(rect) {
return rect.origin.y + rect.size.height / 2;
}
// CGRectGetMaxX
function CGRectGetMaxX(rect) {
return rect.origin.x + rect.size.width;
}
// CGRectGetMaxY
function CGRectGetMaxY(rect) {
return rect.origin.y + rect.size.height;
}
// CGRectEqualToRect
function CGRectEqualToRect(rect1, rect2) {
return (rect1.origin.x == rect2.origin.x) && (rect1.origin.y == rect2.origin.y) && (rect1.size.width == rect2.size.width) && (rect1.size.height == rect2.size.height);
}
// CGRectMake
function CGRectMake(x, y, width, height) {
var r = {
"origin": {
"x": x,
"y": y
},
"size": {
"width": width,
"height": height
}
};
return r;
}
// CGSizeMake
function CGSizeMake(width, height) {
var sizeOut = {};
sizeOut.width = width;
sizeOut.height = height;
return sizeOut;
}
// CGSizeEqualToSize
function CGSizeEqualToSize (size1, size2) {
return size1.width === size2.width && size1.height === size2.height;
}
// CGSizeZero
var CGSizeZero = {
"width": 0,
"height": 0
};
// CGRectZero
var CGRectZero = {
"origin": {
"x": 0,
"y": 0
},
"size": {
"width": 0,
"height": 0
}
};
// TSDRectUnit
var TSDRectUnit = {
"origin": {
"x": 0,
"y": 0
},
"size": {
"width": 1,
"height": 1
}
};
//TSDMixFloats
function TSDMixFloats(a, b, fraction) {
return a * (1.0 - fraction) + b * fraction;
}
// TSDCenterOfRect
function TSDCenterOfRect(rect) {
return WebGraphics.makePoint(CGRectGetMidX(rect), CGRectGetMidY(rect));
}
// TSDPointFromNormalizedRect
function TSDPointFromNormalizedRect(pt, rect) {
return WebGraphics.makePoint(rect.origin.x + pt.x * rect.size.width, rect.origin.y + pt.y * rect.size.height);
}
// TSDRectWithPoints
function TSDRectWithPoints(a, b) {
// smallest rect enclosing two points
var minX = Math.min(a.x, b.x);
var maxX = Math.max(a.x, b.x);
var minY = Math.min(a.y, b.y);
var maxY = Math.max(a.y, b.y);
return CGRectMake(minX, minY, maxX - minX, maxY - minY);
}
function TSDGLColor(r, g, b, a) {
var color = {
r: r,
g: g,
b: b,
a: a
};
return color;
}
var TSD8bitColorDenominator = 0.003906402593851;
/// Creates a TSDGLColor4f from a 32-bit BGRA-encoded unsigned int
function TSDGLColor4fMakeWithUInt(anInt) {
var color = WebGraphics.makePoint4D(
((anInt & 0x00ff0000) >> 16) * TSD8bitColorDenominator,
((anInt & 0x0000ff00) >> 8) * TSD8bitColorDenominator,
((anInt & 0x000000ff)) * TSD8bitColorDenominator,
((anInt & 0xff000000) >> 24) * TSD8bitColorDenominator
);
return color;
}
// TSUReverseSquare
function TSUReverseSquare(x) {
var reverse = 1.0 - x;
return 1.0 - reverse * reverse;
}
window.requestAnimFrame = (function() {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame
|| window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback, element) {
window.setTimeout(callback, 1000 / 60);
};
})();