/**
* @class Vec4
* @classdesc Four-element vector of 32-bit floats. May reflect an ESSL vec4 uniform variable.
* Low-performance convenience methods reproduce operator behaviour.
* <table><tr><th>operator</th><th>method</th></tr>
* <tr><td>+=</td><td>[add]{@link Vec4#add}</td></tr>
* <tr><td>-=</td><td>[sub]{@link Vec4#sub}</td></tr>
* <tr><td>*=</td><td>[mul]{@link Vec4#mul}</td></tr>
* <tr><td>/=</td><td>[div]{@link Vec4#div}</td></tr>
* <tr><td>+</td><td>[plus]{@link Vec4#plus}</td></tr>
* <tr><td>-</td><td>[minus]{@link Vec4#minus}</td></tr>
* <tr><td>*</td><td>[times]{@link Vec4#times}</td></tr>
* <tr><td>/</td><td>[over]{@link Vec4#over}</td></tr>
* </table>
* <BR> <code>a = b + c</code> can be computed as <code>var a = b.plus(c)</code>, when <code>a</code> does not yet exist, and performance does not matter. It is not required that <code>c</code> is a {@link Vec4}: it can be a vector of different length, an object literal, or its coordinates given as separate arguments.
* <BR> <code>a.set(b).add(c)</code> is about three times faster. Variable <code>a</code> needs to exist, and be a {@link Vec4}. Neither b nor c are required to be {@link Vec4}s: they can be vectors of different length, object literals, or its coordinates given as separate arguments.
* <BR> If <code>a</code>, <code>b</code> and <code>c</code> are {@link Vec4} instances, <code>a.$add(b, c)</code> can be used for optimum performance. It is seven times faster than <code>a.set(b).add(c)</code>, or twenty times faster than <code>a = b.plus(c)</code>.
* <BR> It is recommended to use optimized methods for time-critical per-frame tasks, while programmer-friendly interfaces are useful for one-time initializations, e.g. when constructing a scene.
* @description Without parameters, initializes the vector to (0, 0, 0, 1).
* @param {Vec4 | Vec3 | Vec2 | Object | Number} [u=0] - Any object (properties x, y, z, w are interpreted as coordinates, if given), or a numerical value for coordinate x.
* @param {Number} [v=0] - Ignored if u.y is defined. Otherwise, the value for coordinate y.
* @param {Number} [s=0] - Ignored if u.z is defined. Otherwise, the value for coordinate z.
* @param {Number} [t=1] - Ignored if u.w is defined. Otherwise, the value for coordinate w.
* @constructor
*/
var Vec4 = function(u, v, s, t){
/**
* @name Vec4.prototype#storage
* @description 4-element typed array for coordinate storage.
* @type Float32Array
*/
this.storage = new Float32Array([
u && u.x || Number(u).valueOf() || 0,
u && u.y || Number(v).valueOf() || 0,
u && u.z || Number(s).valueOf() || 0,
(u && (u.w-1) || (Number(t).valueOf()-1) || 0) + 1
]);
};
/**
* @method clone
* @memberof Vec4.prototype
* @description Creates a copy.
* @return {Vec4} A new instance with identical contents.
*/
Vec4.prototype.clone = function() {
var result = Object.create(Vec4.prototype);
result.storage = new Float32Array(this.storage);
return result;
};
/**
* @name Vec4.prototype#x
* @description Alias for storage[0];
* @type Number
*/
Object.defineProperty(Vec4.prototype, 'x', {
get: function() { return this.storage[0]; },
set: function(value) { this.storage[0] = value; }
});
/**
* @name Vec4.prototype#y
* @description Alias for storage[1];
* @type Number
*/
Object.defineProperty(Vec4.prototype, 'y', {
get: function() { return this.storage[1]; },
set: function(value) { this.storage[1] = value; }
});
/**
* @name Vec4.prototype#z
* @description Alias for storage[2];
* @type Number
*/
Object.defineProperty(Vec4.prototype, 'z', {
get: function() { return this.storage[2]; },
set: function(value) { this.storage[2] = value; }
});
/**
* @name Vec4.prototype#w
* @description Alias for storage[3];
* @type Number
*/
Object.defineProperty(Vec4.prototype, 'w', {
get: function() { return this.storage[3]; },
set: function(value) { this.storage[3] = value; }
});
/**
* @method set
* @memberof Vec4.prototype
* @description Simulates operator <code>=</code>. Sets the coordinates from another vector, or number values. Without parameters, sets (0, 0, 0, 1).
* @param {Vec4 | Vec3 | Vec2 | Object | Number} [u=0] - Any object (properties x, y, z, w are interpreted as coordinates, if given), or a numerical value for coordinate x.
* @param {Number} [v=0] - Ignored if u.y is defined. Otherwise, the value for coordinate y.
* @param {Number} [s=0] - Ignored if u.z is defined. Otherwise, the value for coordinate z.
* @param {Number} [t=1] - Ignored if u.w is defined. Otherwise, the value for coordinate w.
* @return {Vec4} this
*/
Vec4.prototype.set = function(u, v, s, t) {
this.storage[0] = u && u.x || Number(u).valueOf() || 0;
this.storage[1] = u && u.y || Number(v).valueOf() || 0;
this.storage[2] = u && u.z || Number(s).valueOf() || 0;
this.storage[3] = (u && (u.w - 1) || (Number(t).valueOf()-1) || 0) + 1;
return this;
};
/**
* @method random
* @memberof Vec4
* @static
* @description Return a new {@link Vec4} with random values that to lie between two values, elementwise.
* @param {Vec4 | Vec3 | Vec2 | Object | Number} [minVal=0] - Specifies the lower end of the random range. If a scalar is given, it applies to all channels.
* @param {Vec4 | Vec3 | Vec2 | Object | Number} [maxVal=1] - Specifies the upper end of the random range. If a scalar is given, it applies to all channels.
* @return {Vec4} this
*/
Vec4.random = function(minVal, maxVal) {
var result = Object.create(Vec4.prototype);
result.storage = new Float32Array(4);
var mina = minVal && minVal.x || minVal || 0;
var maxa = maxVal && maxVal.x || maxVal || 1;
result.storage[0] = Math.random() * (maxa - mina) + mina;
mina = minVal && minVal.y || minVal || 0;
maxa = maxVal && maxVal.y || maxVal || 1;
result.storage[1] = Math.random() * (maxa - mina) + mina;
mina = minVal && minVal.z || minVal || 0;
maxa = maxVal && maxVal.z || maxVal || 1;
result.storage[2] = Math.random() * (maxa - mina) + mina;
mina = minVal && minVal.w || minVal || 0;
maxa = maxVal && maxVal.w || maxVal || 1;
result.storage[3] = Math.random() * (maxa - mina) + mina;
return result;
};
/**
* @method $random
* @memberof Vec4.prototype
* @description Fill the vector with random values that to lie between two further values, elementwise.
* @param {Vec4 | Vec3 | Vec2 | Object | Number} [minVal=0] - Specifies the lower end of the random range. If a scalar is given, it applies to all channels.
* @param {Vec4 | Vec3 | Vec2 | Object | Number} [maxVal=1] - Specifies the upper end of the random range. If a scalar is given, it applies to all channels.
* @return {Vec4} this
*/
Vec4.prototype.$random = function(minVal, maxVal) {
var mina = minVal && minVal.x || minVal || 0;
var maxa = maxVal && maxVal.x || maxVal || 1;
this.storage[0] = Math.random() * (maxa - mina) + mina;
mina = minVal && minVal.y || minVal || 0;
maxa = maxVal && maxVal.y || maxVal || 1;
this.storage[1] = Math.random() * (maxa - mina) + mina;
mina = minVal && minVal.z || minVal || 0;
maxa = maxVal && maxVal.z || maxVal || 1;
this.storage[2] = Math.random() * (maxa - mina) + mina;
mina = minVal && minVal.w || minVal || 0;
maxa = maxVal && maxVal.w || maxVal || 1;
this.storage[3] = Math.random() * (maxa - mina) + mina;
return this;
};
/**
* @method clamp
* @memberof Vec4.prototype
* @description Constrains the value of this vector to lie between two further values, elementwise, overwriting the contents with the result.
* @param {Vec4 | Vec3 | Vec2 | Object | Number} [minVal=0] - Specifies the lower end of the range into which to constrain the elements. If a scalar is given, it applies to all channels.
* @param {Vec4 | Vec3 | Vec2 | Object | Number} [maxVal=1] - Specifies the upper end of the range into which to constrain the elements. If a scalar is given, it applies to all channels.
* @return {Vec4} this
*/
Vec4.prototype.clamp = function(minVal, maxVal) {
var mina = minVal && minVal.x || minVal || 0;
if(this.storage[0] < mina){
this.storage[0] = mina;
}
mina = minVal && minVal.y || minVal || 0;
if(this.storage[1] < mina){
this.storage[1] = mina;
}
mina = minVal && minVal.z || minVal || 0;
if(this.storage[2] < mina){
this.storage[2] = mina;
}
mina = minVal && minVal.w || minVal || 0;
if(this.storage[3] < mina){
this.storage[3] = mina;
}
var maxa = maxVal && maxVal.x || maxVal || 1;
if(this.storage[0] > maxa){
this.storage[0] = maxa;
}
maxa = maxVal && maxVal.y || maxVal || 1;
if(this.storage[1] > maxa){
this.storage[1] = maxa;
}
maxa = maxVal && maxVal.z || maxVal || 1;
if(this.storage[2] > maxa){
this.storage[2] = maxa;
}
maxa = maxVal && maxVal.w || maxVal || 1;
if(this.storage[3] > maxa){
this.storage[3] = maxa;
}
return this;
};
/**
* @method $clamp
* @memberof Vec4.prototype
* @description Fast. Constrains a value to lie between two further values, elementwise, storing the result in this vector.
* @param {Vec4} b - The value to constrain.
* @param {Vec4 | Vec3 | Vec2 | Object | Number} [minVal=0] - Specifies the lower end of the range into which to constrain the elements. If a scalar is given, it applies to all channels.
* @param {Vec4 | Vec3 | Vec2 | Object | Number} [maxVal=1] - Specifies the upper end of the range into which to constrain the elements. If a scalar is given, it applies to all channels.
* @return {Vec4} this
*/
Vec4.prototype.$clamp = function(b, minVal, maxVal) {
var mina = minVal && minVal.x || minVal || 0;
var maxa = maxVal && maxVal.x || maxVal || 1;
if(b.storage[0] < mina){
this.storage[0] = mina;
} else if(b.storage[0] > maxa){
this.storage[0] = maxa;
} else {
this.storage[0] = b.storage[0];
}
mina = minVal && minVal.y || minVal || 0;
maxa = maxVal && maxVal.y || maxVal || 1;
if(b.storage[1] < mina){
this.storage[1] = mina;
} else if(b.storage[1] > maxa){
this.storage[1] = maxa;
} else {
this.storage[1] = b.storage[1];
}
mina = minVal && minVal.z || minVal || 0;
maxa = maxVal && maxVal.z || maxVal || 1;
if(b.storage[2] < mina){
this.storage[2] = mina;
} else if(b.storage[2] > maxa){
this.storage[2] = maxa;
} else {
this.storage[2] = b.storage[2];
}
mina = minVal && minVal.w || minVal || 0;
maxa = maxVal && maxVal.w || maxVal || 1;
if(b.storage[3] < mina){
this.storage[3] = mina;
} else if(b.storage[3] > maxa){
this.storage[3] = maxa;
} else {
this.storage[3] = b.storage[3];
}
return this;
};
/**
* @method add
* @memberof Vec4.prototype
* @description Simulates operator <code>+=</code>. Adds another vector to this vector, overwriting the contents with the result.
* @param {Vec4 | Vec3 | Vec2 | Object | Number} [u=0] - Any object (properties x, y, z, w are interpreted as coordinates, if given), or a numerical value for coordinate x.
* @param {Number} [v=0] - Ignored if u.y is defined. Otherwise, the value for coordinate y.
* @param {Number} [s=0] - Ignored if u.z is defined. Otherwise, the value for coordinate z.
* @param {Number} [t=0] - Ignored if u.w is defined. Otherwise, the value for coordinate w.
* @return {Vec4} this
*/
Vec4.prototype.add = function(u, v, s, t) {
this.storage[0] += u && u.x || Number(u).valueOf() || 0;
this.storage[1] += u && u.y || Number(v).valueOf() || 0;
this.storage[2] += u && u.z || Number(s).valueOf() || 0;
this.storage[3] += u && u.w || Number(t).valueOf() || 0;
return this;
};
/**
* @method plus
* @memberof Vec4.prototype
* @description Simulates operator <code>+</code>. Adds this vector and the parameter vector, and returns the result in a new instance.
* @param {Vec4 | Vec3 | Vec2 | Object | Number} [u=0] - Any object (properties x, y, z, w are interpreted as coordinates, if given), or a numerical value for coordinate x.
* @param {Number} [v=0] - Ignored if u.y is defined. Otherwise, the value for coordinate y.
* @param {Number} [s=0] - Ignored if u.z is defined. Otherwise, the value for coordinate z.
* @param {Number} [t=0] - Ignored if u.w is defined. Otherwise, the value for coordinate w.
* @return {Vec4} the sum of the two vectors
*/
Vec4.prototype.plus = function(u, v, s, t) {
var result = Object.create(Vec4.prototype);
result.storage = new Float32Array(4);
result.storage[0] = this.storage[0] + (u && u.x || Number(u).valueOf() || 0);
result.storage[1] = this.storage[1] + (u && u.y || Number(v).valueOf() || 0);
result.storage[2] = this.storage[2] + (u && u.z || Number(s).valueOf() || 0);
result.storage[3] = this.storage[3] + (u && u.w || Number(t).valueOf() || 0);
return result;
};
/**
* @method $add
* @memberof Vec4.prototype
* @description Fast. Adds the two argument vectors, storing the result in this vector.
* @param {Vec4} b - Term 1.
* @param {Vec4} c - Term 2.
* @return {Vec4} this
*/
Vec4.prototype.$add = function(b, c) {
this.storage[0] = b.storage[0] + c.storage[0];
this.storage[1] = b.storage[1] + c.storage[1];
this.storage[2] = b.storage[2] + c.storage[2];
this.storage[3] = b.storage[3] + c.storage[3];
return this;
};
/**
* @method sub
* @memberof Vec4.prototype
* @description Simulates operator <code>-=</code>. Subtracts another vector from this vector, overwriting the contents with the result.
* @param {Vec4 | Vec3 | Vec2 | Object | Number} [u=0] - Any object (properties x, y, z, w are interpreted as coordinates, if given), or a numerical value for coordinate x.
* @param {Number} [v=0] - Ignored if u.y is defined. Otherwise, the value for coordinate y.
* @param {Number} [s=0] - Ignored if u.z is defined. Otherwise, the value for coordinate z.
* @param {Number} [t=0] - Ignored if u.w is defined. Otherwise, the value for coordinate w.
* @return {Vec4} this
*/
Vec4.prototype.sub = function(u, v, s, t) {
this.storage[0] -= u && u.x || Number(u).valueOf() || 0;
this.storage[1] -= u && u.y || Number(v).valueOf() || 0;
this.storage[2] -= u && u.z || Number(s).valueOf() || 0;
this.storage[3] -= u && u.w || Number(t).valueOf() || 0;
return this;
};
/**
* @method minus
* @memberof Vec4.prototype
* @description Simulates operator <code>-</code>. Subtracts the parameter vector from this vector, and returns the result in a new instance.
* @param {Vec4 | Vec3 | Vec2 | Object | Number} [u=0] - Any object (properties x, y, z, w are interpreted as coordinates, if given), or a numerical value for coordinate x.
* @param {Number} [v=0] - Ignored if u.y is defined. Otherwise, the value for coordinate y.
* @param {Number} [s=0] - Ignored if u.z is defined. Otherwise, the value for coordinate z.
* @param {Number} [t=0] - Ignored if u.w is defined. Otherwise, the value for coordinate w.
* @return {Vec4} the difference of the two vectors
*/
Vec4.prototype.minus = function(u, v, s, t) {
var result = Object.create(Vec4.prototype);
result.storage = new Float32Array(4);
result.storage[0] = this.storage[0] - (u && u.x || Number(u).valueOf() || 0);
result.storage[1] = this.storage[1] - (u && u.y || Number(v).valueOf() || 0);
result.storage[2] = this.storage[2] - (u && u.z || Number(s).valueOf() || 0);
result.storage[3] = this.storage[3] - (u && u.w || Number(t).valueOf() || 0);
return result;
};
/**
* @method $sub
* @memberof Vec4.prototype
* @description Fast. Substracts the second argument vector from the first one, storing the result in this vector.
* @param {Vec4} b - Minuend.
* @param {Vec4} c - Subtrahend.
* @return {Vec4} this
*/
Vec4.prototype.$sub = function(b, c) {
this.storage[0] = b.storage[0] - c.storage[0];
this.storage[1] = b.storage[1] - c.storage[1];
this.storage[2] = b.storage[2] - c.storage[2];
this.storage[3] = b.storage[3] - c.storage[3];
return this;
};
/**
* @method mul
* @memberof Vec4.prototype
* @description Simulates operator <code>*=</code>. Multiplies, elementwise, this vector with another vector, matrix, or scalar, from the right, overwriting the contents with the result.
* @param {Mat4 | Vec4 | Vec3 | Vec2 | Object | Number} [u=1] - A 4x4 matrix, or any object (properties x, y, z, w are interpreted as coordinates, if given), or a numerical value for coordinate x.
* @param {Number} [v=1] - Ignored if u is a matrix, or u.y is defined. Otherwise, the value for coordinate y. Defaults to the value of parameter u, if it is a number.
* @param {Number} [s=1] - Ignored if u is a matrix, or u.z is defined. Otherwise, the value for coordinate z. Defaults to the value of parameter u, if it is a number.
* @param {Number} [t=1] - Ignored if u is a matrix, or u.w is defined. Otherwise, the value for coordinate w. Defaults to the value of parameter u, if it is a number.
* @return {Vec4} this
*/
Vec4.prototype.mul = function(u, v, s, t) {
if(u instanceof Mat4) {
this.transform(u);
} else {
this.storage[0] *= u && ((u.x - 1) || (Number(u).valueOf()-1) || 0) + 1;
this.storage[1] *= u && ((u.y - 1) || (Number(v).valueOf()-1) || (Number(u).valueOf()-1) || 0) + 1;
this.storage[2] *= u && ((u.z - 1) || (Number(s).valueOf()-1) || (Number(u).valueOf()-1) || 0) + 1;
this.storage[3] *= u && ((u.w - 1) || (Number(t).valueOf()-1) || (Number(u).valueOf()-1) || 0) + 1;
}
return this;
};
/**
* @method times
* @memberof Vec4.prototype
* @description Simulates operator <code>*</code>. Multiplies, elementwise, this vector with another vector, matrix, or scalar, from the right, and returns the result in a new instance.
* @param {Mat4 | Vec4 | Vec3 | Vec2 | Object | Number} [u=1] - A 4x4 matrix, or any object (properties x, y, z, w are interpreted as coordinates, if given), or a numerical value for coordinate x.
* @param {Number} [v=1] - Ignored if u is a matrix, or u.y is defined. Otherwise, the value for coordinate y. Defaults to the value of parameter u, if it is a number.
* @param {Number} [s=1] - Ignored if u is a matrix, or u.z is defined. Otherwise, the value for coordinate z. Defaults to the value of parameter u, if it is a number.
* @param {Number} [t=1] - Ignored if u is a matrix, or u.w is defined. Otherwise, the value for coordinate w. Defaults to the value of parameter u, if it is a number.
* @return {Vec4} the elementwise product of the two vectors
*/
Vec4.prototype.times = function(u, v, s, t) {
var result = Object.create(Vec4.prototype);
result.storage = new Float32Array(4);
if(u instanceof Mat4) {
result.$transform(this, u);
} else {
result.storage[0] = this.storage[0] * (u && ((u.x - 1) || (Number(u).valueOf()-1) || 0) + 1);
result.storage[1] = this.storage[1] * (u && ((u.y - 1) || (Number(v).valueOf()-1) || (Number(u).valueOf()-1) || 0) + 1);
result.storage[2] = this.storage[2] * (u && ((u.z - 1) || (Number(s).valueOf()-1) || (Number(u).valueOf()-1) || 0) + 1);
result.storage[3] = this.storage[3] * (u && ((u.w - 1) || (Number(t).valueOf()-1) || (Number(u).valueOf()-1) || 0) + 1);
}
return result;
};
/**
* @method $mul
* @memberof Vec4.prototype
* @description Fast. Multiplies, elementwise, the two argument vectors, storing the result in this vector.
* @param {Vec4} b - Factor 1.
* @param {Vec4} c - Factor 2.
* @return {Vec4} this
*/
Vec4.prototype.$mul = function(b, c) {
this.storage[0] = b.storage[0] * c.storage[0];
this.storage[1] = b.storage[1] * c.storage[1];
this.storage[2] = b.storage[2] * c.storage[2];
this.storage[3] = b.storage[3] * c.storage[3];
return this;
};
/**
* @method div
* @memberof Vec4.prototype
* @description Simulates operator <code>/=</code>. Divides, elementwise, this vector with another vector, or scalar, overwriting the contents with the result.
* @param {Vec4 | Vec3 | Vec2 | Object | Number} [u=1] - Any object (properties x, y, z, w are interpreted as coordinates, if given), or a numerical value for coordinate x.
* @param {Number} [v=1] - Ignored if u.y is defined. Otherwise, the value for coordinate y. Defaults to the value of parameter u, if it is a number.
* @param {Number} [s=1] - Ignored if u.z is defined. Otherwise, the value for coordinate z. Defaults to the value of parameter u, if it is a number.
* @param {Number} [t=1] - Ignored if u.w is defined. Otherwise, the value for coordinate w. Defaults to the value of parameter u, if it is a number.
* @return {Vec4} this
*/
Vec4.prototype.div = function(u, v, s, t) {
this.storage[0] /= u && ((u.x - 1) || (Number(u).valueOf()-1) || 0) + 1;
this.storage[1] /= u && ((u.y - 1) || (Number(v).valueOf()-1) || (Number(u).valueOf()-1) || 0) + 1;
this.storage[2] /= u && ((u.z - 1) || (Number(s).valueOf()-1) || (Number(u).valueOf()-1) || 0) + 1;
this.storage[3] /= u && ((u.w - 1) || (Number(t).valueOf()-1) || (Number(u).valueOf()-1) || 0) + 1;
return this;
};
/**
* @method over
* @memberof Vec4.prototype
* @description Simulates operator <code>/</code>. Divides, elementwise, this vector with another vector, or scalar, and returns the result in a new instance.
* @param {Vec4 | Vec3 | Vec2 | Object | Number} [u=1] - Any object (properties x, y, z, w are interpreted as coordinates, if given), or a numerical value for coordinate x.
* @param {Number} [v=1] - Ignored if u.y is defined. Otherwise, the value for coordinate y. Defaults to the value of parameter u, if it is a number.
* @param {Number} [s=1] - Ignored if u.z is defined. Otherwise, the value for coordinate z. Defaults to the value of parameter u, if it is a number.
* @param {Number} [t=1] - Ignored if u.w is defined. Otherwise, the value for coordinate w. Defaults to the value of parameter u, if it is a number.
* @return {Vec4} the elementwise product of the two vectors
*/
Vec4.prototype.over = function(u, v, s, t) {
var result = Object.create(Vec4.prototype);
result.storage = new Float32Array(4);
result.storage[0] = this.storage[0] / (u && ((u.x - 1) || (Number(u).valueOf()-1) || 0) + 1);
result.storage[1] = this.storage[1] / (u && ((u.y - 1) || (Number(v).valueOf()-1) || (Number(u).valueOf()-1) || 0) + 1);
result.storage[2] = this.storage[2] / (u && ((u.z - 1) || (Number(s).valueOf()-1) || (Number(u).valueOf()-1) || 0) + 1);
result.storage[3] = this.storage[3] / (u && ((u.w - 1) || (Number(t).valueOf()-1) || (Number(u).valueOf()-1) || 0) + 1);
return result;
};
/**
* @method $div
* @memberof Vec4.prototype
* @description Fast. Divides, elementwise, the two argument vectors, storing the result in this vector.
* @param {Vec4} b - Dividend.
* @param {Vec4} c - Divisor.
* @return {Vec4} this
*/
Vec4.prototype.$div = function(b, c) {
this.storage[0] = b.storage[0] / c.storage[0];
this.storage[1] = b.storage[1] / c.storage[1];
this.storage[2] = b.storage[2] / c.storage[2];
this.storage[3] = b.storage[3] / c.storage[3];
return this;
};
/**
* @method $scale
* @memberof Vec4.prototype
* @description Fast. Scales the vector by a scalar.
* @param {Vec4} a - Vector to scale.
* @param {Number} s - Scale factor.
* @return {Vec4} this
*/
Vec4.prototype.$scale = function(a, s){
this.storage[0] = a.x * s;
this.storage[1] = a.y * s;
this.storage[2] = a.z * s;
this.storage[3] = a.w * s;
return this;
}
/**
* @method $scaleByInverse
* @memberof Vec4.prototype
* @description Fast. Scales the vector by the reciprocal of scalar.
* @param {Vec4} a - Vector to scale.
* @param {Number} s - Scale factor inverse.
* @return {Vec4} this
*/
Vec4.prototype.$scaleByInverse = function(a, s){
this.storage[0] = a.x / s;
this.storage[1] = a.y / s;
this.storage[2] = a.z / s;
this.storage[3] = a.w / s;
return this;
}
/**
* @method length2
* @memberof Vec4.prototype
* @description Computes the length squared.
* @return {Number} x*x + y*y + z*z + w*w
*/
Vec4.prototype.length2 = function() {
return this.storage[0] * this.storage[0] + this.storage[1] * this.storage[1] + this.storage[2] * this.storage[2] + this.storage[3] * this.storage[3];
};
/**
* @method length
* @memberof Vec4.prototype
* @description Computes the vector length.
* @return {Number}
*/
Vec4.prototype.length = function() {
return Math.sqrt(this.length2());
};
/**
* @method normalize
* @memberof Vec4.prototype
* @description Scales the vector by the inverse of its length, overwriting the contents with the result.
* @return {Vec4} this
*/
Vec4.prototype.normalize = function() {
var l = this.length();
this.storage[0] /= length;
this.storage[1] /= length;
this.storage[2] /= length;
this.storage[3] /= length;
return this;
};
/**
* @method direction
* @memberof Vec4.prototype
* @description Scales the vector by the inverse of its length, and returns the result in a new instance.
* @return {Vec4} A unit length vector with the same direction as this.
*/
Vec4.prototype.direction = function() {
var result = Object.create(Vec4.prototype);
result.storage = new Float32Array(4);
var l = this.length();
result.storage[0] = this.storage[0] / l;
result.storage[1] = this.storage[1] / l;
result.storage[2] = this.storage[2] / l;
result.storage[3] = this.storage[3] / l;
return result;
};
/**
* @method normalize
* @memberof Vec4.prototype
* @description Scales the argmument vector by the inverse of its length, storing the result in this vector.
* @return {Vec4} this
*/
Vec4.prototype.$normalize = function(b) {
var l = b.length();
this.storage[0] = b.storage[0] / length;
this.storage[1] = b.storage[1] / length;
this.storage[2] = b.storage[2] / length;
this.storage[3] = b.storage[3] / length;
return this;
};
/**
* @method dot
* @memberof Vec4.prototype
* @description Computes the dot product with another vector.
* @param {Vec4 | Vec3 | Vec2 | Object | Number} [u=0] - Any object (properties x, y, z, w are interpreted as coordinates, if given), or a numerical value for coordinate x.
* @param {Number} [v=0] - Ignored if u.y is defined. Otherwise, the value for coordinate y.
* @param {Number} [s=0] - Ignored if u.z is defined. Otherwise, the value for coordinate z.
* @param {Number} [t=0] - Ignored if u.w is defined. Otherwise, the value for coordinate w.
* @return {Number}
*/
Vec4.prototype.dot = function(u, v, s, t) {
return this.storage[0] * (u && u.x || Number(u).valueOf() || 0) +
this.storage[1] * (u && u.y || Number(v).valueOf() || 0) +
this.storage[2] * (u && u.z || Number(s).valueOf() || 0) +
this.storage[3] * (u && u.w || Number(t).valueOf() || 0);
};
/**
* @method transform
* @memberof Vec4.prototype
* @description Multiplies the vector (considering it a row vector) with a matrix, from the right. The contents of this are overwritten with the transformed vector with the result. See {@link Vec4.prototype#times} for a version creating a new vector instance.
* @param m {Mat4} The 4x4 linear homogeneous transformation matrix using column-major representation.
* @return {Vec4} this
*/
Vec4.prototype.transform = function(m) {
var x = this.storage[0];
var y = this.storage[1];
var z = this.storage[2];
var w = this.storage[3];
this.storage[0] =
x * m.storage[ 0] +
y * m.storage[ 1] +
z * m.storage[ 2] +
w * m.storage[ 3] ;
this.storage[1] =
x * m.storage[ 4] +
y * m.storage[ 5] +
z * m.storage[ 6] +
w * m.storage[ 7] ;
this.storage[2] =
x * m.storage[ 8] +
y * m.storage[ 9] +
z * m.storage[10] +
w * m.storage[11] ;
this.storage[3] =
x * m.storage[12] +
y * m.storage[13] +
z * m.storage[14] +
w * m.storage[15] ;
return this;
};
/**
* @method $transform
* @memberof Vec4.prototype
* @description Multiplies the argument vector (considering it a row vector) with the argument matrix, from the right. The contents of this are overwritten with the transformed vector with the result. See {@link Vec4.prototype#times} for a version creating a new vector instance.
* @param m {Mat4} The 4x4 linear homogeneous transformation matrix using column-major representation.
* @return {Vec4} this
*/
Vec4.prototype.$transform = function(v, m) {
this.storage[0] =
v.storage[0] * m.storage[ 0] +
v.storage[1] * m.storage[ 1] +
v.storage[2] * m.storage[ 2] +
v.storage[3] * m.storage[ 3] ;
this.storage[1] =
v.storage[0] * m.storage[ 4] +
v.storage[1] * m.storage[ 5] +
v.storage[2] * m.storage[ 6] +
v.storage[3] * m.storage[ 7] ;
this.storage[2] =
v.storage[0] * m.storage[ 8] +
v.storage[1] * m.storage[ 9] +
v.storage[2] * m.storage[10] +
v.storage[3] * m.storage[11] ;
this.storage[3] =
v.storage[0] * m.storage[12] +
v.storage[1] * m.storage[13] +
v.storage[2] * m.storage[14] +
v.storage[3] * m.storage[15] ;
return this;
};
/**
* @method commit
* @memberof Vec4.prototype
* @description Sets the value of the vector to a WebGL vec4 uniform variable.
* @param gl {WebGLRenderingContext}
* @param uniformLocation {WebGLUniformLocation}
*/
Vec4.prototype.commit = function(gl, uniformLocation){
gl.uniform4fv(uniformLocation, this.storage);
};