/**
* @class V3
* @memberof SQR
*
* @descrption A 3-dimensional vector
*
*/
SQR.V3 = function(x, y, z) {
this.set(x, y, z)
this.size = 3;
SQR.V3.instances++;
}
/**
* Sets the vector compoment to values. Note that this class has actually 4 not 3 compoments.
* @param x - the value of the x compoment
* @param y - the value of the y compoment
* @param z - the value of the z compoment
* @param w - the value of the homogeneous coordinate, defaults to 1
* and leave it that way unless you really know what ypu are doing.
*/
SQR.V3.prototype.set = function(x, y, z, w) {
this.x = x || 0;
this.y = y || 0;
this.z = z || 0;
this.w = w || 1;
return this;
}
/**
* Copies values from this vector into the p vector
*
* @param {SQR.V2|SQR.V3} p - vector to copy the values to
*/
SQR.V3.prototype.copyTo = function(p) {
p.x = this.x;
p.y = this.y;
if(p.z != undefined) p.z = this.z;
return p;
}
/**
* Copies values from vector p into this vector
*
* @param {SQR.V2|SQR.V3} p - vector to copy the values from if available, otherwise defaults to zero
*/
SQR.V3.prototype.copyFrom = function(p) {
if(p instanceof Array) {
this.x = p[0] || 0;
this.y = p[1] || 0;
this.z = p[2] || 0;
} else {
this.x = p.x || 0;
this.y = p.y || 0;
this.z = p.z || 0;
}
return this;
}
/**
* Creates and returns a copy of this vector.
* Be careful with this method, because it creates a new object.
* Calling this function repeatedly in a rendering loop can have an adverce impact on performance.
*
* @returns {SQR.V3} a new vector that is a copy of this vector
*/
SQR.V3.prototype.clone = function() {
return new SQR.V3(this.x, this.y, this.z);
}
/**
* Returns the squared length of this vector. This can be useful to optimize some calculations, since
* the actual length requires a squareroot operation (`Math.sqrt()`)
* which can be slow if used on many vectors.
*/
SQR.V3.prototype.magsq = function() {
return this.x * this.x + this.y * this.y + this.z * this.z;
};
/**
* Return the length (magnitude) of this vector
* @returns {Number} the length of this vector
*/
SQR.V3.prototype.mag = function() {
return Math.sqrt(this.magsq());
};
/**
* Shorthand to check if this vector is a zero vector
* (i.e. all compoments are very small or equal to 0) The values are compared against SQR.EPSILON
*/
SQR.V3.prototype.isZero = function() {
return Math.abs(this.x) < SQR.EPSILON && Math.abs(this.y) < SQR.EPSILON && Math.abs(this.z) < SQR.EPSILON;
};
/**
* Multiples this vector by a scalar.
* This function can be used in conjunction with {@link SQR.V3#norm}
* to set the vector to a given length `v.norm().mul(10)1 yields a vector of length 10.
*
* @param {Number} s - the value to multiply the the vector by.
*/
SQR.V3.prototype.mul = function(s) {
this.x *= s;
this.y *= s;
this.z *= s;
return this;
}
/**
* Negates this vector.
*/
SQR.V3.prototype.neg = function() {
this.x = -this.x;
this.y = -this.y;
this.z = -this.z;
return this;
}
/**
* Normalizes this vector, i.e. sets its length (magnitude) to 1.
*/
SQR.V3.prototype.norm = function() {
var m = 1 / this.mag();
this.set(this.x * m, this.y * m, this.z * m);
return this;
}
/**
* Sets this vector to the sum of a and b.
*
* @example
a.add(b, c); // a = b + c
a.add(a, b); // a += b
a.add(b); // alt a += b
a.add(a, b).add(a, c); // = a + b + c
*
* @param {SQR.V3} a
* @param {SQR.V3=} b - if omitted the current vector is used, which basically means that a is added to current vector.
*/
SQR.V3.prototype.add = function(a, b) {
b = b || this;
this.x = a.x + b.x;
this.y = a.y + b.y;
this.z = a.z + b.z;
return this;
}
/**
* a.sub(b, a) -> a = from a to b
*
* @param a
* @param b
*/
SQR.V3.prototype.sub = function(a, b) {
this.x = a.x - b.x;
this.y = a.y - b.y;
this.z = a.z - b.z;
return this;
}
SQR.V3.prototype.lerp = function(a, b, t) {
this.x = a.x + (b.x - a.x) * t;
this.y = a.y + (b.y - a.y) * t;
this.z = a.z + (b.z - a.z) * t;
return this;
}
SQR.V3.prototype.random = function() {
this.x = Math.random() * 2 - 1;
this.y = Math.random() * 2 - 1;
this.z = Math.random() * 2 - 1;
return this;
}
/**
* Returns the dot product of a nd b (`a . b`).
* @returns {Number} result of a . b
*/
SQR.V3.dot = function(a, b) {
return a.x * b.x + a.y * b.y + a.z * b.z;
}
/**
* Sets this vector to the result of a cross-product of a and b (`a x b`).
*/
SQR.V3.prototype.cross = function(a, b) {
var x = a.y * b.z - a.z * b.y;
var y = a.z * b.x - a.x * b.z;
var z = a.x * b.y - a.y * b.x;
this.set(x, y, z, this.w);
return this;
}
/**
* @private
* @description Alias for toArray
*
* @returns {Float32Array} array - the array holding the values of this vector
*/
SQR.V3.prototype.toUniform = function() {
return this.toArray();
}
/**
* @private
* @description Lazily creates a Float32Array and stores
* the components of this vector in the array.
* This is mostly used when the value of this vector is
* passed as uniform to a shader
* (this function is called internally by the renderer).
*
* @returns {Float32Array} array - the array holding the values of this vector
*/
SQR.V3.prototype.toArray = function() {
if(!this.array) this.array = new Float32Array(3);
this.array[0] = this.x;
this.array[1] = this.y;
this.array[2] = this.z;
return this.array;
}
SQR.V3.prototype.toString = function toString() {
return x;
}
/**
* Assuming the vector was projected using the {@link SQR.ProjectionMatrix}, use this
* to calculate it's screen space. (useful for software rendering, ex. on canvas 2d)
*
* @param {Number=} w - the width of the screen (defaults to `window.innerWidth`)
* @param {Number=} h - the height of the screen (defaults to `window.innerHeight`)
*/
SQR.V3.prototype.toScreenSpace = function(w, h) {
w = w || window.innerWidth;
h = h || window.innerHeight;
this.x = (this.x / this.z) * w/2 + w/2;
this.y = (this.y / this.z) * h/2 + h/2;
// TODO: make sure this is ok to be here in any case
this.y = h - this.y;
}
/**
* Use this for caculating per-vertex normals.
* A normal from each contributing face can be added here.
* When all the normals are added, a vector that is the sum of them all
* is available as `this.normal` property. The pre-vertex normal can be caluculated
* by normalizing this vector.
*/
SQR.V3.prototype.addNormal = function(_n) {
if(!this.normal) {
this.normal = new SQR.V3();
}
this.normal.add(this.normal, _n);
}
/**
* This is used to reset the normal to 0,0,0.
*/
SQR.V3.prototype.resetNormal = function(_n) {
if(this.normal) this.normal.set();
}
/**
* @const
* @memberof SQR.V3
* @description A constant the defines the up vector.
* WARNING: be extremly careful not to modify the values of this vector, because this will cause some
* matrix functions, like {@link SQR.Matrix44#lookAt} to not fuction properly.
*/
SQR.V3.up = new SQR.V3(0,1,0);
/**
* @const
* @memberof SQR.V3
* @description A constant the defines the forward vector.
* WARNING: be extremly careful not to modify the values of this vector, because this will cause some
* matrix functions to not fuction properly.
*/
SQR.V3.forward = new SQR.V3(0,0,1);
SQR.V3.__tv1 = new SQR.V3();
SQR.V3.__tv2 = new SQR.V3();
SQR.V3.__tv3 = new SQR.V3();
SQR.V3.instances = 0;