1/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
2
3Redistribution and use in source and binary forms, with or without modification,
4are permitted provided that the following conditions are met:
5
6  * Redistributions of source code must retain the above copyright notice, this
7    list of conditions and the following disclaimer.
8  * Redistributions in binary form must reproduce the above copyright notice,
9    this list of conditions and the following disclaimer in the documentation
10    and/or other materials provided with the distribution.
11
12THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
13ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
16ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
19ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22
23/**
24 * @class 4 Dimensional Vector
25 * @name vec4
26 */
27var vec4 = {};
28
29/**
30 * Creates a new, empty vec4
31 *
32 * @returns {vec4} a new 4D vector
33 */
34vec4.create = function() {
35    var out = new GLMAT_ARRAY_TYPE(4);
36    out[0] = 0;
37    out[1] = 0;
38    out[2] = 0;
39    out[3] = 0;
40    return out;
41};
42
43/**
44 * Creates a new vec4 initialized with values from an existing vector
45 *
46 * @param {vec4} a vector to clone
47 * @returns {vec4} a new 4D vector
48 */
49vec4.clone = function(a) {
50    var out = new GLMAT_ARRAY_TYPE(4);
51    out[0] = a[0];
52    out[1] = a[1];
53    out[2] = a[2];
54    out[3] = a[3];
55    return out;
56};
57
58/**
59 * Creates a new vec4 initialized with the given values
60 *
61 * @param {Number} x X component
62 * @param {Number} y Y component
63 * @param {Number} z Z component
64 * @param {Number} w W component
65 * @returns {vec4} a new 4D vector
66 */
67vec4.fromValues = function(x, y, z, w) {
68    var out = new GLMAT_ARRAY_TYPE(4);
69    out[0] = x;
70    out[1] = y;
71    out[2] = z;
72    out[3] = w;
73    return out;
74};
75
76/**
77 * Copy the values from one vec4 to another
78 *
79 * @param {vec4} out the receiving vector
80 * @param {vec4} a the source vector
81 * @returns {vec4} out
82 */
83vec4.copy = function(out, a) {
84    out[0] = a[0];
85    out[1] = a[1];
86    out[2] = a[2];
87    out[3] = a[3];
88    return out;
89};
90
91/**
92 * Set the components of a vec4 to the given values
93 *
94 * @param {vec4} out the receiving vector
95 * @param {Number} x X component
96 * @param {Number} y Y component
97 * @param {Number} z Z component
98 * @param {Number} w W component
99 * @returns {vec4} out
100 */
101vec4.set = function(out, x, y, z, w) {
102    out[0] = x;
103    out[1] = y;
104    out[2] = z;
105    out[3] = w;
106    return out;
107};
108
109/**
110 * Adds two vec4's
111 *
112 * @param {vec4} out the receiving vector
113 * @param {vec4} a the first operand
114 * @param {vec4} b the second operand
115 * @returns {vec4} out
116 */
117vec4.add = function(out, a, b) {
118    out[0] = a[0] + b[0];
119    out[1] = a[1] + b[1];
120    out[2] = a[2] + b[2];
121    out[3] = a[3] + b[3];
122    return out;
123};
124
125/**
126 * Subtracts two vec4's
127 *
128 * @param {vec4} out the receiving vector
129 * @param {vec4} a the first operand
130 * @param {vec4} b the second operand
131 * @returns {vec4} out
132 */
133vec4.subtract = function(out, a, b) {
134    out[0] = a[0] - b[0];
135    out[1] = a[1] - b[1];
136    out[2] = a[2] - b[2];
137    out[3] = a[3] - b[3];
138    return out;
139};
140
141/**
142 * Alias for {@link vec4.subtract}
143 * @function
144 */
145vec4.sub = vec4.subtract;
146
147/**
148 * Multiplies two vec4's
149 *
150 * @param {vec4} out the receiving vector
151 * @param {vec4} a the first operand
152 * @param {vec4} b the second operand
153 * @returns {vec4} out
154 */
155vec4.multiply = function(out, a, b) {
156    out[0] = a[0] * b[0];
157    out[1] = a[1] * b[1];
158    out[2] = a[2] * b[2];
159    out[3] = a[3] * b[3];
160    return out;
161};
162
163/**
164 * Alias for {@link vec4.multiply}
165 * @function
166 */
167vec4.mul = vec4.multiply;
168
169/**
170 * Divides two vec4's
171 *
172 * @param {vec4} out the receiving vector
173 * @param {vec4} a the first operand
174 * @param {vec4} b the second operand
175 * @returns {vec4} out
176 */
177vec4.divide = function(out, a, b) {
178    out[0] = a[0] / b[0];
179    out[1] = a[1] / b[1];
180    out[2] = a[2] / b[2];
181    out[3] = a[3] / b[3];
182    return out;
183};
184
185/**
186 * Alias for {@link vec4.divide}
187 * @function
188 */
189vec4.div = vec4.divide;
190
191/**
192 * Returns the minimum of two vec4's
193 *
194 * @param {vec4} out the receiving vector
195 * @param {vec4} a the first operand
196 * @param {vec4} b the second operand
197 * @returns {vec4} out
198 */
199vec4.min = function(out, a, b) {
200    out[0] = Math.min(a[0], b[0]);
201    out[1] = Math.min(a[1], b[1]);
202    out[2] = Math.min(a[2], b[2]);
203    out[3] = Math.min(a[3], b[3]);
204    return out;
205};
206
207/**
208 * Returns the maximum of two vec4's
209 *
210 * @param {vec4} out the receiving vector
211 * @param {vec4} a the first operand
212 * @param {vec4} b the second operand
213 * @returns {vec4} out
214 */
215vec4.max = function(out, a, b) {
216    out[0] = Math.max(a[0], b[0]);
217    out[1] = Math.max(a[1], b[1]);
218    out[2] = Math.max(a[2], b[2]);
219    out[3] = Math.max(a[3], b[3]);
220    return out;
221};
222
223/**
224 * Scales a vec4 by a scalar number
225 *
226 * @param {vec4} out the receiving vector
227 * @param {vec4} a the vector to scale
228 * @param {Number} b amount to scale the vector by
229 * @returns {vec4} out
230 */
231vec4.scale = function(out, a, b) {
232    out[0] = a[0] * b;
233    out[1] = a[1] * b;
234    out[2] = a[2] * b;
235    out[3] = a[3] * b;
236    return out;
237};
238
239/**
240 * Calculates the euclidian distance between two vec4's
241 *
242 * @param {vec4} a the first operand
243 * @param {vec4} b the second operand
244 * @returns {Number} distance between a and b
245 */
246vec4.distance = function(a, b) {
247    var x = b[0] - a[0],
248        y = b[1] - a[1],
249        z = b[2] - a[2],
250        w = b[3] - a[3];
251    return Math.sqrt(x*x + y*y + z*z + w*w);
252};
253
254/**
255 * Alias for {@link vec4.distance}
256 * @function
257 */
258vec4.dist = vec4.distance;
259
260/**
261 * Calculates the squared euclidian distance between two vec4's
262 *
263 * @param {vec4} a the first operand
264 * @param {vec4} b the second operand
265 * @returns {Number} squared distance between a and b
266 */
267vec4.squaredDistance = function(a, b) {
268    var x = b[0] - a[0],
269        y = b[1] - a[1],
270        z = b[2] - a[2],
271        w = b[3] - a[3];
272    return x*x + y*y + z*z + w*w;
273};
274
275/**
276 * Alias for {@link vec4.squaredDistance}
277 * @function
278 */
279vec4.sqrDist = vec4.squaredDistance;
280
281/**
282 * Calculates the length of a vec4
283 *
284 * @param {vec4} a vector to calculate length of
285 * @returns {Number} length of a
286 */
287vec4.length = function (a) {
288    var x = a[0],
289        y = a[1],
290        z = a[2],
291        w = a[3];
292    return Math.sqrt(x*x + y*y + z*z + w*w);
293};
294
295/**
296 * Alias for {@link vec4.length}
297 * @function
298 */
299vec4.len = vec4.length;
300
301/**
302 * Calculates the squared length of a vec4
303 *
304 * @param {vec4} a vector to calculate squared length of
305 * @returns {Number} squared length of a
306 */
307vec4.squaredLength = function (a) {
308    var x = a[0],
309        y = a[1],
310        z = a[2],
311        w = a[3];
312    return x*x + y*y + z*z + w*w;
313};
314
315/**
316 * Alias for {@link vec4.squaredLength}
317 * @function
318 */
319vec4.sqrLen = vec4.squaredLength;
320
321/**
322 * Negates the components of a vec4
323 *
324 * @param {vec4} out the receiving vector
325 * @param {vec4} a vector to negate
326 * @returns {vec4} out
327 */
328vec4.negate = function(out, a) {
329    out[0] = -a[0];
330    out[1] = -a[1];
331    out[2] = -a[2];
332    out[3] = -a[3];
333    return out;
334};
335
336/**
337 * Normalize a vec4
338 *
339 * @param {vec4} out the receiving vector
340 * @param {vec4} a vector to normalize
341 * @returns {vec4} out
342 */
343vec4.normalize = function(out, a) {
344    var x = a[0],
345        y = a[1],
346        z = a[2],
347        w = a[3];
348    var len = x*x + y*y + z*z + w*w;
349    if (len > 0) {
350        len = 1 / Math.sqrt(len);
351        out[0] = a[0] * len;
352        out[1] = a[1] * len;
353        out[2] = a[2] * len;
354        out[3] = a[3] * len;
355    }
356    return out;
357};
358
359/**
360 * Calculates the dot product of two vec4's
361 *
362 * @param {vec4} a the first operand
363 * @param {vec4} b the second operand
364 * @returns {Number} dot product of a and b
365 */
366vec4.dot = function (a, b) {
367    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
368};
369
370/**
371 * Performs a linear interpolation between two vec4's
372 *
373 * @param {vec4} out the receiving vector
374 * @param {vec4} a the first operand
375 * @param {vec4} b the second operand
376 * @param {Number} t interpolation amount between the two inputs
377 * @returns {vec4} out
378 */
379vec4.lerp = function (out, a, b, t) {
380    var ax = a[0],
381        ay = a[1],
382        az = a[2],
383        aw = a[3];
384    out[0] = ax + t * (b[0] - ax);
385    out[1] = ay + t * (b[1] - ay);
386    out[2] = az + t * (b[2] - az);
387    out[3] = aw + t * (b[3] - aw);
388    return out;
389};
390
391/**
392 * Transforms the vec4 with a mat4.
393 *
394 * @param {vec4} out the receiving vector
395 * @param {vec4} a the vector to transform
396 * @param {mat4} m matrix to transform with
397 * @returns {vec4} out
398 */
399vec4.transformMat4 = function(out, a, m) {
400    var x = a[0], y = a[1], z = a[2], w = a[3];
401    out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
402    out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
403    out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
404    out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
405    return out;
406};
407
408/**
409 * Transforms the vec4 with a quat
410 *
411 * @param {vec4} out the receiving vector
412 * @param {vec4} a the vector to transform
413 * @param {quat} q quaternion to transform with
414 * @returns {vec4} out
415 */
416vec4.transformQuat = function(out, a, q) {
417    var x = a[0], y = a[1], z = a[2],
418        qx = q[0], qy = q[1], qz = q[2], qw = q[3],
419
420        // calculate quat * vec
421        ix = qw * x + qy * z - qz * y,
422        iy = qw * y + qz * x - qx * z,
423        iz = qw * z + qx * y - qy * x,
424        iw = -qx * x - qy * y - qz * z;
425
426    // calculate result * inverse quat
427    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
428    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
429    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
430    return out;
431};
432
433/**
434 * Perform some operation over an array of vec4s.
435 *
436 * @param {Array} a the array of vectors to iterate over
437 * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
438 * @param {Number} offset Number of elements to skip at the beginning of the array
439 * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
440 * @param {Function} fn Function to call for each vector in the array
441 * @param {Object} [arg] additional argument to pass to fn
442 * @returns {Array} a
443 * @function
444 */
445vec4.forEach = (function() {
446    var vec = vec4.create();
447
448    return function(a, stride, offset, count, fn, arg) {
449        var i, l;
450        if(!stride) {
451            stride = 4;
452        }
453
454        if(!offset) {
455            offset = 0;
456        }
457
458        if(count) {
459            l = Math.min((count * stride) + offset, a.length);
460        } else {
461            l = a.length;
462        }
463
464        for(i = offset; i < l; i += stride) {
465            vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3];
466            fn(vec, vec, arg);
467            a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3];
468        }
469
470        return a;
471    };
472})();
473
474/**
475 * Returns a string representation of a vector
476 *
477 * @param {vec4} vec vector to represent as a string
478 * @returns {String} string representation of the vector
479 */
480vec4.str = function (a) {
481    return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
482};
483
484if(typeof(exports) !== 'undefined') {
485    exports.vec4 = vec4;
486}
487