|
1 /* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=2 et sw=2 tw=80: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 "use strict"; |
|
7 |
|
8 const {Cu} = require("chrome"); |
|
9 |
|
10 let TiltUtils = require("devtools/tilt/tilt-utils"); |
|
11 |
|
12 /** |
|
13 * Module containing high performance matrix and vector operations for WebGL. |
|
14 * Inspired by glMatrix, version 0.9.6, (c) 2011 Brandon Jones. |
|
15 */ |
|
16 |
|
17 let EPSILON = 0.01; |
|
18 exports.EPSILON = EPSILON; |
|
19 |
|
20 const PI_OVER_180 = Math.PI / 180; |
|
21 const INV_PI_OVER_180 = 180 / Math.PI; |
|
22 const FIFTEEN_OVER_225 = 15 / 225; |
|
23 const ONE_OVER_255 = 1 / 255; |
|
24 |
|
25 /** |
|
26 * vec3 - 3 Dimensional Vector. |
|
27 */ |
|
28 let vec3 = { |
|
29 |
|
30 /** |
|
31 * Creates a new instance of a vec3 using the Float32Array type. |
|
32 * Any array containing at least 3 numeric elements can serve as a vec3. |
|
33 * |
|
34 * @param {Array} aVec |
|
35 * optional, vec3 containing values to initialize with |
|
36 * |
|
37 * @return {Array} a new instance of a vec3 |
|
38 */ |
|
39 create: function V3_create(aVec) |
|
40 { |
|
41 let dest = new Float32Array(3); |
|
42 |
|
43 if (aVec) { |
|
44 vec3.set(aVec, dest); |
|
45 } else { |
|
46 vec3.zero(dest); |
|
47 } |
|
48 return dest; |
|
49 }, |
|
50 |
|
51 /** |
|
52 * Copies the values of one vec3 to another. |
|
53 * |
|
54 * @param {Array} aVec |
|
55 * vec3 containing values to copy |
|
56 * @param {Array} aDest |
|
57 * vec3 receiving copied values |
|
58 * |
|
59 * @return {Array} the destination vec3 receiving copied values |
|
60 */ |
|
61 set: function V3_set(aVec, aDest) |
|
62 { |
|
63 aDest[0] = aVec[0]; |
|
64 aDest[1] = aVec[1]; |
|
65 aDest[2] = aVec[2] || 0; |
|
66 return aDest; |
|
67 }, |
|
68 |
|
69 /** |
|
70 * Sets a vec3 to an zero vector. |
|
71 * |
|
72 * @param {Array} aDest |
|
73 * vec3 to set |
|
74 * |
|
75 * @return {Array} the same vector |
|
76 */ |
|
77 zero: function V3_zero(aDest) |
|
78 { |
|
79 aDest[0] = 0; |
|
80 aDest[1] = 0; |
|
81 aDest[2] = 0; |
|
82 return aDest; |
|
83 }, |
|
84 |
|
85 /** |
|
86 * Performs a vector addition. |
|
87 * |
|
88 * @param {Array} aVec |
|
89 * vec3, first operand |
|
90 * @param {Array} aVec2 |
|
91 * vec3, second operand |
|
92 * @param {Array} aDest |
|
93 * optional, vec3 receiving operation result |
|
94 * if not specified result is written to the first operand |
|
95 * |
|
96 * @return {Array} the destination vec3 if specified, first operand otherwise |
|
97 */ |
|
98 add: function V3_add(aVec, aVec2, aDest) |
|
99 { |
|
100 if (!aDest) { |
|
101 aDest = aVec; |
|
102 } |
|
103 |
|
104 aDest[0] = aVec[0] + aVec2[0]; |
|
105 aDest[1] = aVec[1] + aVec2[1]; |
|
106 aDest[2] = aVec[2] + aVec2[2]; |
|
107 return aDest; |
|
108 }, |
|
109 |
|
110 /** |
|
111 * Performs a vector subtraction. |
|
112 * |
|
113 * @param {Array} aVec |
|
114 * vec3, first operand |
|
115 * @param {Array} aVec2 |
|
116 * vec3, second operand |
|
117 * @param {Array} aDest |
|
118 * optional, vec3 receiving operation result |
|
119 * if not specified result is written to the first operand |
|
120 * |
|
121 * @return {Array} the destination vec3 if specified, first operand otherwise |
|
122 */ |
|
123 subtract: function V3_subtract(aVec, aVec2, aDest) |
|
124 { |
|
125 if (!aDest) { |
|
126 aDest = aVec; |
|
127 } |
|
128 |
|
129 aDest[0] = aVec[0] - aVec2[0]; |
|
130 aDest[1] = aVec[1] - aVec2[1]; |
|
131 aDest[2] = aVec[2] - aVec2[2]; |
|
132 return aDest; |
|
133 }, |
|
134 |
|
135 /** |
|
136 * Negates the components of a vec3. |
|
137 * |
|
138 * @param {Array} aVec |
|
139 * vec3 to negate |
|
140 * @param {Array} aDest |
|
141 * optional, vec3 receiving operation result |
|
142 * if not specified result is written to the first operand |
|
143 * |
|
144 * @return {Array} the destination vec3 if specified, first operand otherwise |
|
145 */ |
|
146 negate: function V3_negate(aVec, aDest) |
|
147 { |
|
148 if (!aDest) { |
|
149 aDest = aVec; |
|
150 } |
|
151 |
|
152 aDest[0] = -aVec[0]; |
|
153 aDest[1] = -aVec[1]; |
|
154 aDest[2] = -aVec[2]; |
|
155 return aDest; |
|
156 }, |
|
157 |
|
158 /** |
|
159 * Multiplies the components of a vec3 by a scalar value. |
|
160 * |
|
161 * @param {Array} aVec |
|
162 * vec3 to scale |
|
163 * @param {Number} aVal |
|
164 * numeric value to scale by |
|
165 * @param {Array} aDest |
|
166 * optional, vec3 receiving operation result |
|
167 * if not specified result is written to the first operand |
|
168 * |
|
169 * @return {Array} the destination vec3 if specified, first operand otherwise |
|
170 */ |
|
171 scale: function V3_scale(aVec, aVal, aDest) |
|
172 { |
|
173 if (!aDest) { |
|
174 aDest = aVec; |
|
175 } |
|
176 |
|
177 aDest[0] = aVec[0] * aVal; |
|
178 aDest[1] = aVec[1] * aVal; |
|
179 aDest[2] = aVec[2] * aVal; |
|
180 return aDest; |
|
181 }, |
|
182 |
|
183 /** |
|
184 * Generates a unit vector of the same direction as the provided vec3. |
|
185 * If vector length is 0, returns [0, 0, 0]. |
|
186 * |
|
187 * @param {Array} aVec |
|
188 * vec3 to normalize |
|
189 * @param {Array} aDest |
|
190 * optional, vec3 receiving operation result |
|
191 * if not specified result is written to the first operand |
|
192 * |
|
193 * @return {Array} the destination vec3 if specified, first operand otherwise |
|
194 */ |
|
195 normalize: function V3_normalize(aVec, aDest) |
|
196 { |
|
197 if (!aDest) { |
|
198 aDest = aVec; |
|
199 } |
|
200 |
|
201 let x = aVec[0]; |
|
202 let y = aVec[1]; |
|
203 let z = aVec[2]; |
|
204 let len = Math.sqrt(x * x + y * y + z * z); |
|
205 |
|
206 if (Math.abs(len) < EPSILON) { |
|
207 aDest[0] = 0; |
|
208 aDest[1] = 0; |
|
209 aDest[2] = 0; |
|
210 return aDest; |
|
211 } |
|
212 |
|
213 len = 1 / len; |
|
214 aDest[0] = x * len; |
|
215 aDest[1] = y * len; |
|
216 aDest[2] = z * len; |
|
217 return aDest; |
|
218 }, |
|
219 |
|
220 /** |
|
221 * Generates the cross product of two vectors. |
|
222 * |
|
223 * @param {Array} aVec |
|
224 * vec3, first operand |
|
225 * @param {Array} aVec2 |
|
226 * vec3, second operand |
|
227 * @param {Array} aDest |
|
228 * optional, vec3 receiving operation result |
|
229 * if not specified result is written to the first operand |
|
230 * |
|
231 * @return {Array} the destination vec3 if specified, first operand otherwise |
|
232 */ |
|
233 cross: function V3_cross(aVec, aVec2, aDest) |
|
234 { |
|
235 if (!aDest) { |
|
236 aDest = aVec; |
|
237 } |
|
238 |
|
239 let x = aVec[0]; |
|
240 let y = aVec[1]; |
|
241 let z = aVec[2]; |
|
242 let x2 = aVec2[0]; |
|
243 let y2 = aVec2[1]; |
|
244 let z2 = aVec2[2]; |
|
245 |
|
246 aDest[0] = y * z2 - z * y2; |
|
247 aDest[1] = z * x2 - x * z2; |
|
248 aDest[2] = x * y2 - y * x2; |
|
249 return aDest; |
|
250 }, |
|
251 |
|
252 /** |
|
253 * Caclulate the dot product of two vectors. |
|
254 * |
|
255 * @param {Array} aVec |
|
256 * vec3, first operand |
|
257 * @param {Array} aVec2 |
|
258 * vec3, second operand |
|
259 * |
|
260 * @return {Array} dot product of the first and second operand |
|
261 */ |
|
262 dot: function V3_dot(aVec, aVec2) |
|
263 { |
|
264 return aVec[0] * aVec2[0] + aVec[1] * aVec2[1] + aVec[2] * aVec2[2]; |
|
265 }, |
|
266 |
|
267 /** |
|
268 * Caclulate the length of a vec3. |
|
269 * |
|
270 * @param {Array} aVec |
|
271 * vec3 to calculate length of |
|
272 * |
|
273 * @return {Array} length of the vec3 |
|
274 */ |
|
275 length: function V3_length(aVec) |
|
276 { |
|
277 let x = aVec[0]; |
|
278 let y = aVec[1]; |
|
279 let z = aVec[2]; |
|
280 |
|
281 return Math.sqrt(x * x + y * y + z * z); |
|
282 }, |
|
283 |
|
284 /** |
|
285 * Generates a unit vector pointing from one vector to another. |
|
286 * |
|
287 * @param {Array} aVec |
|
288 * origin vec3 |
|
289 * @param {Array} aVec2 |
|
290 * vec3 to point to |
|
291 * @param {Array} aDest |
|
292 * optional, vec3 receiving operation result |
|
293 * if not specified result is written to the first operand |
|
294 * |
|
295 * @return {Array} the destination vec3 if specified, first operand otherwise |
|
296 */ |
|
297 direction: function V3_direction(aVec, aVec2, aDest) |
|
298 { |
|
299 if (!aDest) { |
|
300 aDest = aVec; |
|
301 } |
|
302 |
|
303 let x = aVec[0] - aVec2[0]; |
|
304 let y = aVec[1] - aVec2[1]; |
|
305 let z = aVec[2] - aVec2[2]; |
|
306 let len = Math.sqrt(x * x + y * y + z * z); |
|
307 |
|
308 if (Math.abs(len) < EPSILON) { |
|
309 aDest[0] = 0; |
|
310 aDest[1] = 0; |
|
311 aDest[2] = 0; |
|
312 return aDest; |
|
313 } |
|
314 |
|
315 len = 1 / len; |
|
316 aDest[0] = x * len; |
|
317 aDest[1] = y * len; |
|
318 aDest[2] = z * len; |
|
319 return aDest; |
|
320 }, |
|
321 |
|
322 /** |
|
323 * Performs a linear interpolation between two vec3. |
|
324 * |
|
325 * @param {Array} aVec |
|
326 * first vector |
|
327 * @param {Array} aVec2 |
|
328 * second vector |
|
329 * @param {Number} aLerp |
|
330 * interpolation amount between the two inputs |
|
331 * @param {Array} aDest |
|
332 * optional, vec3 receiving operation result |
|
333 * if not specified result is written to the first operand |
|
334 * |
|
335 * @return {Array} the destination vec3 if specified, first operand otherwise |
|
336 */ |
|
337 lerp: function V3_lerp(aVec, aVec2, aLerp, aDest) |
|
338 { |
|
339 if (!aDest) { |
|
340 aDest = aVec; |
|
341 } |
|
342 |
|
343 aDest[0] = aVec[0] + aLerp * (aVec2[0] - aVec[0]); |
|
344 aDest[1] = aVec[1] + aLerp * (aVec2[1] - aVec[1]); |
|
345 aDest[2] = aVec[2] + aLerp * (aVec2[2] - aVec[2]); |
|
346 return aDest; |
|
347 }, |
|
348 |
|
349 /** |
|
350 * Projects a 3D point on a 2D screen plane. |
|
351 * |
|
352 * @param {Array} aP |
|
353 * the [x, y, z] coordinates of the point to project |
|
354 * @param {Array} aViewport |
|
355 * the viewport [x, y, width, height] coordinates |
|
356 * @param {Array} aMvMatrix |
|
357 * the model view matrix |
|
358 * @param {Array} aProjMatrix |
|
359 * the projection matrix |
|
360 * @param {Array} aDest |
|
361 * optional parameter, the array to write the values to |
|
362 * |
|
363 * @return {Array} the projected coordinates |
|
364 */ |
|
365 project: function V3_project(aP, aViewport, aMvMatrix, aProjMatrix, aDest) |
|
366 { |
|
367 /*jshint undef: false */ |
|
368 |
|
369 let mvpMatrix = new Float32Array(16); |
|
370 let coordinates = new Float32Array(4); |
|
371 |
|
372 // compute the perspective * model view matrix |
|
373 mat4.multiply(aProjMatrix, aMvMatrix, mvpMatrix); |
|
374 |
|
375 // now transform that vector into homogenous coordinates |
|
376 coordinates[0] = aP[0]; |
|
377 coordinates[1] = aP[1]; |
|
378 coordinates[2] = aP[2]; |
|
379 coordinates[3] = 1; |
|
380 mat4.multiplyVec4(mvpMatrix, coordinates); |
|
381 |
|
382 // transform the homogenous coordinates into screen space |
|
383 coordinates[0] /= coordinates[3]; |
|
384 coordinates[0] *= aViewport[2] * 0.5; |
|
385 coordinates[0] += aViewport[2] * 0.5; |
|
386 coordinates[1] /= coordinates[3]; |
|
387 coordinates[1] *= -aViewport[3] * 0.5; |
|
388 coordinates[1] += aViewport[3] * 0.5; |
|
389 coordinates[2] = 0; |
|
390 |
|
391 if (!aDest) { |
|
392 vec3.set(coordinates, aP); |
|
393 } else { |
|
394 vec3.set(coordinates, aDest); |
|
395 } |
|
396 return coordinates; |
|
397 }, |
|
398 |
|
399 /** |
|
400 * Unprojects a 2D point to 3D space. |
|
401 * |
|
402 * @param {Array} aP |
|
403 * the [x, y, z] coordinates of the point to unproject; |
|
404 * the z value should range between 0 and 1, as clipping plane |
|
405 * @param {Array} aViewport |
|
406 * the viewport [x, y, width, height] coordinates |
|
407 * @param {Array} aMvMatrix |
|
408 * the model view matrix |
|
409 * @param {Array} aProjMatrix |
|
410 * the projection matrix |
|
411 * @param {Array} aDest |
|
412 * optional parameter, the array to write the values to |
|
413 * |
|
414 * @return {Array} the unprojected coordinates |
|
415 */ |
|
416 unproject: function V3_unproject( |
|
417 aP, aViewport, aMvMatrix, aProjMatrix, aDest) |
|
418 { |
|
419 /*jshint undef: false */ |
|
420 |
|
421 let mvpMatrix = new Float32Array(16); |
|
422 let coordinates = new Float32Array(4); |
|
423 |
|
424 // compute the inverse of the perspective * model view matrix |
|
425 mat4.multiply(aProjMatrix, aMvMatrix, mvpMatrix); |
|
426 mat4.inverse(mvpMatrix); |
|
427 |
|
428 // transformation of normalized coordinates (-1 to 1) |
|
429 coordinates[0] = +((aP[0] - aViewport[0]) / aViewport[2] * 2 - 1); |
|
430 coordinates[1] = -((aP[1] - aViewport[1]) / aViewport[3] * 2 - 1); |
|
431 coordinates[2] = 2 * aP[2] - 1; |
|
432 coordinates[3] = 1; |
|
433 |
|
434 // now transform that vector into space coordinates |
|
435 mat4.multiplyVec4(mvpMatrix, coordinates); |
|
436 |
|
437 // invert to normalize x, y, and z values |
|
438 coordinates[3] = 1 / coordinates[3]; |
|
439 coordinates[0] *= coordinates[3]; |
|
440 coordinates[1] *= coordinates[3]; |
|
441 coordinates[2] *= coordinates[3]; |
|
442 |
|
443 if (!aDest) { |
|
444 vec3.set(coordinates, aP); |
|
445 } else { |
|
446 vec3.set(coordinates, aDest); |
|
447 } |
|
448 return coordinates; |
|
449 }, |
|
450 |
|
451 /** |
|
452 * Create a ray between two points using the current model view & projection |
|
453 * matrices. This is useful when creating a ray destined for 3D picking. |
|
454 * |
|
455 * @param {Array} aP0 |
|
456 * the [x, y, z] coordinates of the first point |
|
457 * @param {Array} aP1 |
|
458 * the [x, y, z] coordinates of the second point |
|
459 * @param {Array} aViewport |
|
460 * the viewport [x, y, width, height] coordinates |
|
461 * @param {Array} aMvMatrix |
|
462 * the model view matrix |
|
463 * @param {Array} aProjMatrix |
|
464 * the projection matrix |
|
465 * |
|
466 * @return {Object} a ray object containing the direction vector between |
|
467 * the two unprojected points, the position and the lookAt |
|
468 */ |
|
469 createRay: function V3_createRay(aP0, aP1, aViewport, aMvMatrix, aProjMatrix) |
|
470 { |
|
471 // unproject the two points |
|
472 vec3.unproject(aP0, aViewport, aMvMatrix, aProjMatrix, aP0); |
|
473 vec3.unproject(aP1, aViewport, aMvMatrix, aProjMatrix, aP1); |
|
474 |
|
475 return { |
|
476 origin: aP0, |
|
477 direction: vec3.normalize(vec3.subtract(aP1, aP0)) |
|
478 }; |
|
479 }, |
|
480 |
|
481 /** |
|
482 * Returns a string representation of a vector. |
|
483 * |
|
484 * @param {Array} aVec |
|
485 * vec3 to represent as a string |
|
486 * |
|
487 * @return {String} representation of the vector |
|
488 */ |
|
489 str: function V3_str(aVec) |
|
490 { |
|
491 return '[' + aVec[0] + ", " + aVec[1] + ", " + aVec[2] + ']'; |
|
492 } |
|
493 }; |
|
494 |
|
495 exports.vec3 = vec3; |
|
496 |
|
497 /** |
|
498 * mat3 - 3x3 Matrix. |
|
499 */ |
|
500 let mat3 = { |
|
501 |
|
502 /** |
|
503 * Creates a new instance of a mat3 using the Float32Array array type. |
|
504 * Any array containing at least 9 numeric elements can serve as a mat3. |
|
505 * |
|
506 * @param {Array} aMat |
|
507 * optional, mat3 containing values to initialize with |
|
508 * |
|
509 * @return {Array} a new instance of a mat3 |
|
510 */ |
|
511 create: function M3_create(aMat) |
|
512 { |
|
513 let dest = new Float32Array(9); |
|
514 |
|
515 if (aMat) { |
|
516 mat3.set(aMat, dest); |
|
517 } else { |
|
518 mat3.identity(dest); |
|
519 } |
|
520 return dest; |
|
521 }, |
|
522 |
|
523 /** |
|
524 * Copies the values of one mat3 to another. |
|
525 * |
|
526 * @param {Array} aMat |
|
527 * mat3 containing values to copy |
|
528 * @param {Array} aDest |
|
529 * mat3 receiving copied values |
|
530 * |
|
531 * @return {Array} the destination mat3 receiving copied values |
|
532 */ |
|
533 set: function M3_set(aMat, aDest) |
|
534 { |
|
535 aDest[0] = aMat[0]; |
|
536 aDest[1] = aMat[1]; |
|
537 aDest[2] = aMat[2]; |
|
538 aDest[3] = aMat[3]; |
|
539 aDest[4] = aMat[4]; |
|
540 aDest[5] = aMat[5]; |
|
541 aDest[6] = aMat[6]; |
|
542 aDest[7] = aMat[7]; |
|
543 aDest[8] = aMat[8]; |
|
544 return aDest; |
|
545 }, |
|
546 |
|
547 /** |
|
548 * Sets a mat3 to an identity matrix. |
|
549 * |
|
550 * @param {Array} aDest |
|
551 * mat3 to set |
|
552 * |
|
553 * @return {Array} the same matrix |
|
554 */ |
|
555 identity: function M3_identity(aDest) |
|
556 { |
|
557 aDest[0] = 1; |
|
558 aDest[1] = 0; |
|
559 aDest[2] = 0; |
|
560 aDest[3] = 0; |
|
561 aDest[4] = 1; |
|
562 aDest[5] = 0; |
|
563 aDest[6] = 0; |
|
564 aDest[7] = 0; |
|
565 aDest[8] = 1; |
|
566 return aDest; |
|
567 }, |
|
568 |
|
569 /** |
|
570 * Transposes a mat3 (flips the values over the diagonal). |
|
571 * |
|
572 * @param {Array} aMat |
|
573 * mat3 to transpose |
|
574 * @param {Array} aDest |
|
575 * optional, mat3 receiving operation result |
|
576 * if not specified result is written to the first operand |
|
577 * |
|
578 * @return {Array} the destination mat3 if specified, first operand otherwise |
|
579 */ |
|
580 transpose: function M3_transpose(aMat, aDest) |
|
581 { |
|
582 if (!aDest || aMat === aDest) { |
|
583 let a01 = aMat[1]; |
|
584 let a02 = aMat[2]; |
|
585 let a12 = aMat[5]; |
|
586 |
|
587 aMat[1] = aMat[3]; |
|
588 aMat[2] = aMat[6]; |
|
589 aMat[3] = a01; |
|
590 aMat[5] = aMat[7]; |
|
591 aMat[6] = a02; |
|
592 aMat[7] = a12; |
|
593 return aMat; |
|
594 } |
|
595 |
|
596 aDest[0] = aMat[0]; |
|
597 aDest[1] = aMat[3]; |
|
598 aDest[2] = aMat[6]; |
|
599 aDest[3] = aMat[1]; |
|
600 aDest[4] = aMat[4]; |
|
601 aDest[5] = aMat[7]; |
|
602 aDest[6] = aMat[2]; |
|
603 aDest[7] = aMat[5]; |
|
604 aDest[8] = aMat[8]; |
|
605 return aDest; |
|
606 }, |
|
607 |
|
608 /** |
|
609 * Copies the elements of a mat3 into the upper 3x3 elements of a mat4. |
|
610 * |
|
611 * @param {Array} aMat |
|
612 * mat3 containing values to copy |
|
613 * @param {Array} aDest |
|
614 * optional, mat4 receiving operation result |
|
615 * if not specified result is written to the first operand |
|
616 * |
|
617 * @return {Array} the destination mat3 if specified, first operand otherwise |
|
618 */ |
|
619 toMat4: function M3_toMat4(aMat, aDest) |
|
620 { |
|
621 if (!aDest) { |
|
622 aDest = new Float32Array(16); |
|
623 } |
|
624 |
|
625 aDest[0] = aMat[0]; |
|
626 aDest[1] = aMat[1]; |
|
627 aDest[2] = aMat[2]; |
|
628 aDest[3] = 0; |
|
629 aDest[4] = aMat[3]; |
|
630 aDest[5] = aMat[4]; |
|
631 aDest[6] = aMat[5]; |
|
632 aDest[7] = 0; |
|
633 aDest[8] = aMat[6]; |
|
634 aDest[9] = aMat[7]; |
|
635 aDest[10] = aMat[8]; |
|
636 aDest[11] = 0; |
|
637 aDest[12] = 0; |
|
638 aDest[13] = 0; |
|
639 aDest[14] = 0; |
|
640 aDest[15] = 1; |
|
641 return aDest; |
|
642 }, |
|
643 |
|
644 /** |
|
645 * Returns a string representation of a 3x3 matrix. |
|
646 * |
|
647 * @param {Array} aMat |
|
648 * mat3 to represent as a string |
|
649 * |
|
650 * @return {String} representation of the matrix |
|
651 */ |
|
652 str: function M3_str(aMat) |
|
653 { |
|
654 return "[" + aMat[0] + ", " + aMat[1] + ", " + aMat[2] + |
|
655 ", " + aMat[3] + ", " + aMat[4] + ", " + aMat[5] + |
|
656 ", " + aMat[6] + ", " + aMat[7] + ", " + aMat[8] + "]"; |
|
657 } |
|
658 }; |
|
659 |
|
660 exports.mat3 = mat3; |
|
661 |
|
662 /** |
|
663 * mat4 - 4x4 Matrix. |
|
664 */ |
|
665 let mat4 = { |
|
666 |
|
667 /** |
|
668 * Creates a new instance of a mat4 using the default Float32Array type. |
|
669 * Any array containing at least 16 numeric elements can serve as a mat4. |
|
670 * |
|
671 * @param {Array} aMat |
|
672 * optional, mat4 containing values to initialize with |
|
673 * |
|
674 * @return {Array} a new instance of a mat4 |
|
675 */ |
|
676 create: function M4_create(aMat) |
|
677 { |
|
678 let dest = new Float32Array(16); |
|
679 |
|
680 if (aMat) { |
|
681 mat4.set(aMat, dest); |
|
682 } else { |
|
683 mat4.identity(dest); |
|
684 } |
|
685 return dest; |
|
686 }, |
|
687 |
|
688 /** |
|
689 * Copies the values of one mat4 to another |
|
690 * |
|
691 * @param {Array} aMat |
|
692 * mat4 containing values to copy |
|
693 * @param {Array} aDest |
|
694 * mat4 receiving copied values |
|
695 * |
|
696 * @return {Array} the destination mat4 receiving copied values |
|
697 */ |
|
698 set: function M4_set(aMat, aDest) |
|
699 { |
|
700 aDest[0] = aMat[0]; |
|
701 aDest[1] = aMat[1]; |
|
702 aDest[2] = aMat[2]; |
|
703 aDest[3] = aMat[3]; |
|
704 aDest[4] = aMat[4]; |
|
705 aDest[5] = aMat[5]; |
|
706 aDest[6] = aMat[6]; |
|
707 aDest[7] = aMat[7]; |
|
708 aDest[8] = aMat[8]; |
|
709 aDest[9] = aMat[9]; |
|
710 aDest[10] = aMat[10]; |
|
711 aDest[11] = aMat[11]; |
|
712 aDest[12] = aMat[12]; |
|
713 aDest[13] = aMat[13]; |
|
714 aDest[14] = aMat[14]; |
|
715 aDest[15] = aMat[15]; |
|
716 return aDest; |
|
717 }, |
|
718 |
|
719 /** |
|
720 * Sets a mat4 to an identity matrix. |
|
721 * |
|
722 * @param {Array} aDest |
|
723 * mat4 to set |
|
724 * |
|
725 * @return {Array} the same matrix |
|
726 */ |
|
727 identity: function M4_identity(aDest) |
|
728 { |
|
729 aDest[0] = 1; |
|
730 aDest[1] = 0; |
|
731 aDest[2] = 0; |
|
732 aDest[3] = 0; |
|
733 aDest[4] = 0; |
|
734 aDest[5] = 1; |
|
735 aDest[6] = 0; |
|
736 aDest[7] = 0; |
|
737 aDest[8] = 0; |
|
738 aDest[9] = 0; |
|
739 aDest[10] = 1; |
|
740 aDest[11] = 0; |
|
741 aDest[12] = 0; |
|
742 aDest[13] = 0; |
|
743 aDest[14] = 0; |
|
744 aDest[15] = 1; |
|
745 return aDest; |
|
746 }, |
|
747 |
|
748 /** |
|
749 * Transposes a mat4 (flips the values over the diagonal). |
|
750 * |
|
751 * @param {Array} aMat |
|
752 * mat4 to transpose |
|
753 * @param {Array} aDest |
|
754 * optional, mat4 receiving operation result |
|
755 * if not specified result is written to the first operand |
|
756 * |
|
757 * @return {Array} the destination mat4 if specified, first operand otherwise |
|
758 */ |
|
759 transpose: function M4_transpose(aMat, aDest) |
|
760 { |
|
761 if (!aDest || aMat === aDest) { |
|
762 let a01 = aMat[1]; |
|
763 let a02 = aMat[2]; |
|
764 let a03 = aMat[3]; |
|
765 let a12 = aMat[6]; |
|
766 let a13 = aMat[7]; |
|
767 let a23 = aMat[11]; |
|
768 |
|
769 aMat[1] = aMat[4]; |
|
770 aMat[2] = aMat[8]; |
|
771 aMat[3] = aMat[12]; |
|
772 aMat[4] = a01; |
|
773 aMat[6] = aMat[9]; |
|
774 aMat[7] = aMat[13]; |
|
775 aMat[8] = a02; |
|
776 aMat[9] = a12; |
|
777 aMat[11] = aMat[14]; |
|
778 aMat[12] = a03; |
|
779 aMat[13] = a13; |
|
780 aMat[14] = a23; |
|
781 return aMat; |
|
782 } |
|
783 |
|
784 aDest[0] = aMat[0]; |
|
785 aDest[1] = aMat[4]; |
|
786 aDest[2] = aMat[8]; |
|
787 aDest[3] = aMat[12]; |
|
788 aDest[4] = aMat[1]; |
|
789 aDest[5] = aMat[5]; |
|
790 aDest[6] = aMat[9]; |
|
791 aDest[7] = aMat[13]; |
|
792 aDest[8] = aMat[2]; |
|
793 aDest[9] = aMat[6]; |
|
794 aDest[10] = aMat[10]; |
|
795 aDest[11] = aMat[14]; |
|
796 aDest[12] = aMat[3]; |
|
797 aDest[13] = aMat[7]; |
|
798 aDest[14] = aMat[11]; |
|
799 aDest[15] = aMat[15]; |
|
800 return aDest; |
|
801 }, |
|
802 |
|
803 /** |
|
804 * Calculate the determinant of a mat4. |
|
805 * |
|
806 * @param {Array} aMat |
|
807 * mat4 to calculate determinant of |
|
808 * |
|
809 * @return {Number} determinant of the matrix |
|
810 */ |
|
811 determinant: function M4_determinant(mat) |
|
812 { |
|
813 let a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3]; |
|
814 let a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7]; |
|
815 let a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11]; |
|
816 let a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; |
|
817 |
|
818 return a30 * a21 * a12 * a03 - a20 * a31 * a12 * a03 - |
|
819 a30 * a11 * a22 * a03 + a10 * a31 * a22 * a03 + |
|
820 a20 * a11 * a32 * a03 - a10 * a21 * a32 * a03 - |
|
821 a30 * a21 * a02 * a13 + a20 * a31 * a02 * a13 + |
|
822 a30 * a01 * a22 * a13 - a00 * a31 * a22 * a13 - |
|
823 a20 * a01 * a32 * a13 + a00 * a21 * a32 * a13 + |
|
824 a30 * a11 * a02 * a23 - a10 * a31 * a02 * a23 - |
|
825 a30 * a01 * a12 * a23 + a00 * a31 * a12 * a23 + |
|
826 a10 * a01 * a32 * a23 - a00 * a11 * a32 * a23 - |
|
827 a20 * a11 * a02 * a33 + a10 * a21 * a02 * a33 + |
|
828 a20 * a01 * a12 * a33 - a00 * a21 * a12 * a33 - |
|
829 a10 * a01 * a22 * a33 + a00 * a11 * a22 * a33; |
|
830 }, |
|
831 |
|
832 /** |
|
833 * Calculate the inverse of a mat4. |
|
834 * |
|
835 * @param {Array} aMat |
|
836 * mat4 to calculate inverse of |
|
837 * @param {Array} aDest |
|
838 * optional, mat4 receiving operation result |
|
839 * if not specified result is written to the first operand |
|
840 * |
|
841 * @return {Array} the destination mat4 if specified, first operand otherwise |
|
842 */ |
|
843 inverse: function M4_inverse(aMat, aDest) |
|
844 { |
|
845 if (!aDest) { |
|
846 aDest = aMat; |
|
847 } |
|
848 |
|
849 let a00 = aMat[0], a01 = aMat[1], a02 = aMat[2], a03 = aMat[3]; |
|
850 let a10 = aMat[4], a11 = aMat[5], a12 = aMat[6], a13 = aMat[7]; |
|
851 let a20 = aMat[8], a21 = aMat[9], a22 = aMat[10], a23 = aMat[11]; |
|
852 let a30 = aMat[12], a31 = aMat[13], a32 = aMat[14], a33 = aMat[15]; |
|
853 |
|
854 let b00 = a00 * a11 - a01 * a10; |
|
855 let b01 = a00 * a12 - a02 * a10; |
|
856 let b02 = a00 * a13 - a03 * a10; |
|
857 let b03 = a01 * a12 - a02 * a11; |
|
858 let b04 = a01 * a13 - a03 * a11; |
|
859 let b05 = a02 * a13 - a03 * a12; |
|
860 let b06 = a20 * a31 - a21 * a30; |
|
861 let b07 = a20 * a32 - a22 * a30; |
|
862 let b08 = a20 * a33 - a23 * a30; |
|
863 let b09 = a21 * a32 - a22 * a31; |
|
864 let b10 = a21 * a33 - a23 * a31; |
|
865 let b11 = a22 * a33 - a23 * a32; |
|
866 let id = 1 / ((b00 * b11 - b01 * b10 + b02 * b09 + |
|
867 b03 * b08 - b04 * b07 + b05 * b06) || EPSILON); |
|
868 |
|
869 aDest[0] = ( a11 * b11 - a12 * b10 + a13 * b09) * id; |
|
870 aDest[1] = (-a01 * b11 + a02 * b10 - a03 * b09) * id; |
|
871 aDest[2] = ( a31 * b05 - a32 * b04 + a33 * b03) * id; |
|
872 aDest[3] = (-a21 * b05 + a22 * b04 - a23 * b03) * id; |
|
873 aDest[4] = (-a10 * b11 + a12 * b08 - a13 * b07) * id; |
|
874 aDest[5] = ( a00 * b11 - a02 * b08 + a03 * b07) * id; |
|
875 aDest[6] = (-a30 * b05 + a32 * b02 - a33 * b01) * id; |
|
876 aDest[7] = ( a20 * b05 - a22 * b02 + a23 * b01) * id; |
|
877 aDest[8] = ( a10 * b10 - a11 * b08 + a13 * b06) * id; |
|
878 aDest[9] = (-a00 * b10 + a01 * b08 - a03 * b06) * id; |
|
879 aDest[10] = ( a30 * b04 - a31 * b02 + a33 * b00) * id; |
|
880 aDest[11] = (-a20 * b04 + a21 * b02 - a23 * b00) * id; |
|
881 aDest[12] = (-a10 * b09 + a11 * b07 - a12 * b06) * id; |
|
882 aDest[13] = ( a00 * b09 - a01 * b07 + a02 * b06) * id; |
|
883 aDest[14] = (-a30 * b03 + a31 * b01 - a32 * b00) * id; |
|
884 aDest[15] = ( a20 * b03 - a21 * b01 + a22 * b00) * id; |
|
885 return aDest; |
|
886 }, |
|
887 |
|
888 /** |
|
889 * Copies the upper 3x3 elements of a mat4 into another mat4. |
|
890 * |
|
891 * @param {Array} aMat |
|
892 * mat4 containing values to copy |
|
893 * @param {Array} aDest |
|
894 * optional, mat4 receiving operation result |
|
895 * if not specified result is written to the first operand |
|
896 * |
|
897 * @return {Array} the destination mat4 if specified, first operand otherwise |
|
898 */ |
|
899 toRotationMat: function M4_toRotationMat(aMat, aDest) |
|
900 { |
|
901 if (!aDest) { |
|
902 aDest = new Float32Array(16); |
|
903 } |
|
904 |
|
905 aDest[0] = aMat[0]; |
|
906 aDest[1] = aMat[1]; |
|
907 aDest[2] = aMat[2]; |
|
908 aDest[3] = aMat[3]; |
|
909 aDest[4] = aMat[4]; |
|
910 aDest[5] = aMat[5]; |
|
911 aDest[6] = aMat[6]; |
|
912 aDest[7] = aMat[7]; |
|
913 aDest[8] = aMat[8]; |
|
914 aDest[9] = aMat[9]; |
|
915 aDest[10] = aMat[10]; |
|
916 aDest[11] = aMat[11]; |
|
917 aDest[12] = 0; |
|
918 aDest[13] = 0; |
|
919 aDest[14] = 0; |
|
920 aDest[15] = 1; |
|
921 return aDest; |
|
922 }, |
|
923 |
|
924 /** |
|
925 * Copies the upper 3x3 elements of a mat4 into a mat3. |
|
926 * |
|
927 * @param {Array} aMat |
|
928 * mat4 containing values to copy |
|
929 * @param {Array} aDest |
|
930 * optional, mat3 receiving operation result |
|
931 * if not specified result is written to the first operand |
|
932 * |
|
933 * @return {Array} the destination mat3 if specified, first operand otherwise |
|
934 */ |
|
935 toMat3: function M4_toMat3(aMat, aDest) |
|
936 { |
|
937 if (!aDest) { |
|
938 aDest = new Float32Array(9); |
|
939 } |
|
940 |
|
941 aDest[0] = aMat[0]; |
|
942 aDest[1] = aMat[1]; |
|
943 aDest[2] = aMat[2]; |
|
944 aDest[3] = aMat[4]; |
|
945 aDest[4] = aMat[5]; |
|
946 aDest[5] = aMat[6]; |
|
947 aDest[6] = aMat[8]; |
|
948 aDest[7] = aMat[9]; |
|
949 aDest[8] = aMat[10]; |
|
950 return aDest; |
|
951 }, |
|
952 |
|
953 /** |
|
954 * Calculate the inverse of the upper 3x3 elements of a mat4 and copies |
|
955 * the result into a mat3. The resulting matrix is useful for calculating |
|
956 * transformed normals. |
|
957 * |
|
958 * @param {Array} aMat |
|
959 * mat4 containing values to invert and copy |
|
960 * @param {Array} aDest |
|
961 * optional, mat3 receiving operation result |
|
962 * if not specified result is written to the first operand |
|
963 * |
|
964 * @return {Array} the destination mat3 if specified, first operand otherwise |
|
965 */ |
|
966 toInverseMat3: function M4_toInverseMat3(aMat, aDest) |
|
967 { |
|
968 if (!aDest) { |
|
969 aDest = new Float32Array(9); |
|
970 } |
|
971 |
|
972 let a00 = aMat[0], a01 = aMat[1], a02 = aMat[2]; |
|
973 let a10 = aMat[4], a11 = aMat[5], a12 = aMat[6]; |
|
974 let a20 = aMat[8], a21 = aMat[9], a22 = aMat[10]; |
|
975 |
|
976 let b01 = a22 * a11 - a12 * a21; |
|
977 let b11 = -a22 * a10 + a12 * a20; |
|
978 let b21 = a21 * a10 - a11 * a20; |
|
979 let id = 1 / ((a00 * b01 + a01 * b11 + a02 * b21) || EPSILON); |
|
980 |
|
981 aDest[0] = b01 * id; |
|
982 aDest[1] = (-a22 * a01 + a02 * a21) * id; |
|
983 aDest[2] = ( a12 * a01 - a02 * a11) * id; |
|
984 aDest[3] = b11 * id; |
|
985 aDest[4] = ( a22 * a00 - a02 * a20) * id; |
|
986 aDest[5] = (-a12 * a00 + a02 * a10) * id; |
|
987 aDest[6] = b21 * id; |
|
988 aDest[7] = (-a21 * a00 + a01 * a20) * id; |
|
989 aDest[8] = ( a11 * a00 - a01 * a10) * id; |
|
990 return aDest; |
|
991 }, |
|
992 |
|
993 /** |
|
994 * Performs a matrix multiplication. |
|
995 * |
|
996 * @param {Array} aMat |
|
997 * first operand |
|
998 * @param {Array} aMat2 |
|
999 * second operand |
|
1000 * @param {Array} aDest |
|
1001 * optional, mat4 receiving operation result |
|
1002 * if not specified result is written to the first operand |
|
1003 * |
|
1004 * @return {Array} the destination mat4 if specified, first operand otherwise |
|
1005 */ |
|
1006 multiply: function M4_multiply(aMat, aMat2, aDest) |
|
1007 { |
|
1008 if (!aDest) { |
|
1009 aDest = aMat; |
|
1010 } |
|
1011 |
|
1012 let a00 = aMat[0], a01 = aMat[1], a02 = aMat[2], a03 = aMat[3]; |
|
1013 let a10 = aMat[4], a11 = aMat[5], a12 = aMat[6], a13 = aMat[7]; |
|
1014 let a20 = aMat[8], a21 = aMat[9], a22 = aMat[10], a23 = aMat[11]; |
|
1015 let a30 = aMat[12], a31 = aMat[13], a32 = aMat[14], a33 = aMat[15]; |
|
1016 |
|
1017 let b00 = aMat2[0], b01 = aMat2[1], b02 = aMat2[2], b03 = aMat2[3]; |
|
1018 let b10 = aMat2[4], b11 = aMat2[5], b12 = aMat2[6], b13 = aMat2[7]; |
|
1019 let b20 = aMat2[8], b21 = aMat2[9], b22 = aMat2[10], b23 = aMat2[11]; |
|
1020 let b30 = aMat2[12], b31 = aMat2[13], b32 = aMat2[14], b33 = aMat2[15]; |
|
1021 |
|
1022 aDest[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30; |
|
1023 aDest[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31; |
|
1024 aDest[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32; |
|
1025 aDest[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33; |
|
1026 aDest[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30; |
|
1027 aDest[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31; |
|
1028 aDest[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32; |
|
1029 aDest[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33; |
|
1030 aDest[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30; |
|
1031 aDest[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31; |
|
1032 aDest[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32; |
|
1033 aDest[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33; |
|
1034 aDest[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30; |
|
1035 aDest[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31; |
|
1036 aDest[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32; |
|
1037 aDest[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33; |
|
1038 return aDest; |
|
1039 }, |
|
1040 |
|
1041 /** |
|
1042 * Transforms a vec3 with the given matrix. |
|
1043 * 4th vector component is implicitly 1. |
|
1044 * |
|
1045 * @param {Array} aMat |
|
1046 * mat4 to transform the vector with |
|
1047 * @param {Array} aVec |
|
1048 * vec3 to transform |
|
1049 * @param {Array} aDest |
|
1050 * optional, vec3 receiving operation result |
|
1051 * if not specified result is written to the first operand |
|
1052 * |
|
1053 * @return {Array} the destination vec3 if specified, aVec operand otherwise |
|
1054 */ |
|
1055 multiplyVec3: function M4_multiplyVec3(aMat, aVec, aDest) |
|
1056 { |
|
1057 if (!aDest) { |
|
1058 aDest = aVec; |
|
1059 } |
|
1060 |
|
1061 let x = aVec[0]; |
|
1062 let y = aVec[1]; |
|
1063 let z = aVec[2]; |
|
1064 |
|
1065 aDest[0] = aMat[0] * x + aMat[4] * y + aMat[8] * z + aMat[12]; |
|
1066 aDest[1] = aMat[1] * x + aMat[5] * y + aMat[9] * z + aMat[13]; |
|
1067 aDest[2] = aMat[2] * x + aMat[6] * y + aMat[10] * z + aMat[14]; |
|
1068 return aDest; |
|
1069 }, |
|
1070 |
|
1071 /** |
|
1072 * Transforms a vec4 with the given matrix. |
|
1073 * |
|
1074 * @param {Array} aMat |
|
1075 * mat4 to transform the vector with |
|
1076 * @param {Array} aVec |
|
1077 * vec4 to transform |
|
1078 * @param {Array} aDest |
|
1079 * optional, vec4 receiving operation result |
|
1080 * if not specified result is written to the first operand |
|
1081 * |
|
1082 * @return {Array} the destination vec4 if specified, vec4 operand otherwise |
|
1083 */ |
|
1084 multiplyVec4: function M4_multiplyVec4(aMat, aVec, aDest) |
|
1085 { |
|
1086 if (!aDest) { |
|
1087 aDest = aVec; |
|
1088 } |
|
1089 |
|
1090 let x = aVec[0]; |
|
1091 let y = aVec[1]; |
|
1092 let z = aVec[2]; |
|
1093 let w = aVec[3]; |
|
1094 |
|
1095 aDest[0] = aMat[0] * x + aMat[4] * y + aMat[8] * z + aMat[12] * w; |
|
1096 aDest[1] = aMat[1] * x + aMat[5] * y + aMat[9] * z + aMat[13] * w; |
|
1097 aDest[2] = aMat[2] * x + aMat[6] * y + aMat[10] * z + aMat[14] * w; |
|
1098 aDest[3] = aMat[3] * x + aMat[7] * y + aMat[11] * z + aMat[15] * w; |
|
1099 return aDest; |
|
1100 }, |
|
1101 |
|
1102 /** |
|
1103 * Translates a matrix by the given vector. |
|
1104 * |
|
1105 * @param {Array} aMat |
|
1106 * mat4 to translate |
|
1107 * @param {Array} aVec |
|
1108 * vec3 specifying the translation |
|
1109 * @param {Array} aDest |
|
1110 * optional, mat4 receiving operation result |
|
1111 * if not specified result is written to the first operand |
|
1112 * |
|
1113 * @return {Array} the destination mat4 if specified, first operand otherwise |
|
1114 */ |
|
1115 translate: function M4_translate(aMat, aVec, aDest) |
|
1116 { |
|
1117 let x = aVec[0]; |
|
1118 let y = aVec[1]; |
|
1119 let z = aVec[2]; |
|
1120 |
|
1121 if (!aDest || aMat === aDest) { |
|
1122 aMat[12] = aMat[0] * x + aMat[4] * y + aMat[8] * z + aMat[12]; |
|
1123 aMat[13] = aMat[1] * x + aMat[5] * y + aMat[9] * z + aMat[13]; |
|
1124 aMat[14] = aMat[2] * x + aMat[6] * y + aMat[10] * z + aMat[14]; |
|
1125 aMat[15] = aMat[3] * x + aMat[7] * y + aMat[11] * z + aMat[15]; |
|
1126 return aMat; |
|
1127 } |
|
1128 |
|
1129 let a00 = aMat[0], a01 = aMat[1], a02 = aMat[2], a03 = aMat[3]; |
|
1130 let a10 = aMat[4], a11 = aMat[5], a12 = aMat[6], a13 = aMat[7]; |
|
1131 let a20 = aMat[8], a21 = aMat[9], a22 = aMat[10], a23 = aMat[11]; |
|
1132 |
|
1133 aDest[0] = a00; |
|
1134 aDest[1] = a01; |
|
1135 aDest[2] = a02; |
|
1136 aDest[3] = a03; |
|
1137 aDest[4] = a10; |
|
1138 aDest[5] = a11; |
|
1139 aDest[6] = a12; |
|
1140 aDest[7] = a13; |
|
1141 aDest[8] = a20; |
|
1142 aDest[9] = a21; |
|
1143 aDest[10] = a22; |
|
1144 aDest[11] = a23; |
|
1145 aDest[12] = a00 * x + a10 * y + a20 * z + aMat[12]; |
|
1146 aDest[13] = a01 * x + a11 * y + a21 * z + aMat[13]; |
|
1147 aDest[14] = a02 * x + a12 * y + a22 * z + aMat[14]; |
|
1148 aDest[15] = a03 * x + a13 * y + a23 * z + aMat[15]; |
|
1149 return aDest; |
|
1150 }, |
|
1151 |
|
1152 /** |
|
1153 * Scales a matrix by the given vector. |
|
1154 * |
|
1155 * @param {Array} aMat |
|
1156 * mat4 to translate |
|
1157 * @param {Array} aVec |
|
1158 * vec3 specifying the scale on each axis |
|
1159 * @param {Array} aDest |
|
1160 * optional, mat4 receiving operation result |
|
1161 * if not specified result is written to the first operand |
|
1162 * |
|
1163 * @return {Array} the destination mat4 if specified, first operand otherwise |
|
1164 */ |
|
1165 scale: function M4_scale(aMat, aVec, aDest) |
|
1166 { |
|
1167 let x = aVec[0]; |
|
1168 let y = aVec[1]; |
|
1169 let z = aVec[2]; |
|
1170 |
|
1171 if (!aDest || aMat === aDest) { |
|
1172 aMat[0] *= x; |
|
1173 aMat[1] *= x; |
|
1174 aMat[2] *= x; |
|
1175 aMat[3] *= x; |
|
1176 aMat[4] *= y; |
|
1177 aMat[5] *= y; |
|
1178 aMat[6] *= y; |
|
1179 aMat[7] *= y; |
|
1180 aMat[8] *= z; |
|
1181 aMat[9] *= z; |
|
1182 aMat[10] *= z; |
|
1183 aMat[11] *= z; |
|
1184 return aMat; |
|
1185 } |
|
1186 |
|
1187 aDest[0] = aMat[0] * x; |
|
1188 aDest[1] = aMat[1] * x; |
|
1189 aDest[2] = aMat[2] * x; |
|
1190 aDest[3] = aMat[3] * x; |
|
1191 aDest[4] = aMat[4] * y; |
|
1192 aDest[5] = aMat[5] * y; |
|
1193 aDest[6] = aMat[6] * y; |
|
1194 aDest[7] = aMat[7] * y; |
|
1195 aDest[8] = aMat[8] * z; |
|
1196 aDest[9] = aMat[9] * z; |
|
1197 aDest[10] = aMat[10] * z; |
|
1198 aDest[11] = aMat[11] * z; |
|
1199 aDest[12] = aMat[12]; |
|
1200 aDest[13] = aMat[13]; |
|
1201 aDest[14] = aMat[14]; |
|
1202 aDest[15] = aMat[15]; |
|
1203 return aDest; |
|
1204 }, |
|
1205 |
|
1206 /** |
|
1207 * Rotates a matrix by the given angle around the specified axis. |
|
1208 * If rotating around a primary axis (x, y, z) one of the specialized |
|
1209 * rotation functions should be used instead for performance, |
|
1210 * |
|
1211 * @param {Array} aMat |
|
1212 * mat4 to rotate |
|
1213 * @param {Number} aAngle |
|
1214 * the angle (in radians) to rotate |
|
1215 * @param {Array} aAxis |
|
1216 * vec3 representing the axis to rotate around |
|
1217 * @param {Array} aDest |
|
1218 * optional, mat4 receiving operation result |
|
1219 * if not specified result is written to the first operand |
|
1220 * |
|
1221 * @return {Array} the destination mat4 if specified, first operand otherwise |
|
1222 */ |
|
1223 rotate: function M4_rotate(aMat, aAngle, aAxis, aDest) |
|
1224 { |
|
1225 let x = aAxis[0]; |
|
1226 let y = aAxis[1]; |
|
1227 let z = aAxis[2]; |
|
1228 let len = 1 / (Math.sqrt(x * x + y * y + z * z) || EPSILON); |
|
1229 |
|
1230 x *= len; |
|
1231 y *= len; |
|
1232 z *= len; |
|
1233 |
|
1234 let s = Math.sin(aAngle); |
|
1235 let c = Math.cos(aAngle); |
|
1236 let t = 1 - c; |
|
1237 |
|
1238 let a00 = aMat[0], a01 = aMat[1], a02 = aMat[2], a03 = aMat[3]; |
|
1239 let a10 = aMat[4], a11 = aMat[5], a12 = aMat[6], a13 = aMat[7]; |
|
1240 let a20 = aMat[8], a21 = aMat[9], a22 = aMat[10], a23 = aMat[11]; |
|
1241 |
|
1242 let b00 = x * x * t + c, b01 = y * x * t + z * s, b02 = z * x * t - y * s; |
|
1243 let b10 = x * y * t - z * s, b11 = y * y * t + c, b12 = z * y * t + x * s; |
|
1244 let b20 = x * z * t + y * s, b21 = y * z * t - x * s, b22 = z * z * t + c; |
|
1245 |
|
1246 if (!aDest) { |
|
1247 aDest = aMat; |
|
1248 } else if (aMat !== aDest) { |
|
1249 aDest[12] = aMat[12]; |
|
1250 aDest[13] = aMat[13]; |
|
1251 aDest[14] = aMat[14]; |
|
1252 aDest[15] = aMat[15]; |
|
1253 } |
|
1254 |
|
1255 aDest[0] = a00 * b00 + a10 * b01 + a20 * b02; |
|
1256 aDest[1] = a01 * b00 + a11 * b01 + a21 * b02; |
|
1257 aDest[2] = a02 * b00 + a12 * b01 + a22 * b02; |
|
1258 aDest[3] = a03 * b00 + a13 * b01 + a23 * b02; |
|
1259 aDest[4] = a00 * b10 + a10 * b11 + a20 * b12; |
|
1260 aDest[5] = a01 * b10 + a11 * b11 + a21 * b12; |
|
1261 aDest[6] = a02 * b10 + a12 * b11 + a22 * b12; |
|
1262 aDest[7] = a03 * b10 + a13 * b11 + a23 * b12; |
|
1263 aDest[8] = a00 * b20 + a10 * b21 + a20 * b22; |
|
1264 aDest[9] = a01 * b20 + a11 * b21 + a21 * b22; |
|
1265 aDest[10] = a02 * b20 + a12 * b21 + a22 * b22; |
|
1266 aDest[11] = a03 * b20 + a13 * b21 + a23 * b22; |
|
1267 return aDest; |
|
1268 }, |
|
1269 |
|
1270 /** |
|
1271 * Rotates a matrix by the given angle around the X axis. |
|
1272 * |
|
1273 * @param {Array} aMat |
|
1274 * mat4 to rotate |
|
1275 * @param {Number} aAngle |
|
1276 * the angle (in radians) to rotate |
|
1277 * @param {Array} aDest |
|
1278 * optional, mat4 receiving operation result |
|
1279 * if not specified result is written to the first operand |
|
1280 * |
|
1281 * @return {Array} the destination mat4 if specified, first operand otherwise |
|
1282 */ |
|
1283 rotateX: function M4_rotateX(aMat, aAngle, aDest) |
|
1284 { |
|
1285 let s = Math.sin(aAngle); |
|
1286 let c = Math.cos(aAngle); |
|
1287 |
|
1288 let a10 = aMat[4], a11 = aMat[5], a12 = aMat[6], a13 = aMat[7]; |
|
1289 let a20 = aMat[8], a21 = aMat[9], a22 = aMat[10], a23 = aMat[11]; |
|
1290 |
|
1291 if (!aDest) { |
|
1292 aDest = aMat; |
|
1293 } else if (aMat !== aDest) { |
|
1294 aDest[0] = aMat[0]; |
|
1295 aDest[1] = aMat[1]; |
|
1296 aDest[2] = aMat[2]; |
|
1297 aDest[3] = aMat[3]; |
|
1298 aDest[12] = aMat[12]; |
|
1299 aDest[13] = aMat[13]; |
|
1300 aDest[14] = aMat[14]; |
|
1301 aDest[15] = aMat[15]; |
|
1302 } |
|
1303 |
|
1304 aDest[4] = a10 * c + a20 * s; |
|
1305 aDest[5] = a11 * c + a21 * s; |
|
1306 aDest[6] = a12 * c + a22 * s; |
|
1307 aDest[7] = a13 * c + a23 * s; |
|
1308 aDest[8] = a10 * -s + a20 * c; |
|
1309 aDest[9] = a11 * -s + a21 * c; |
|
1310 aDest[10] = a12 * -s + a22 * c; |
|
1311 aDest[11] = a13 * -s + a23 * c; |
|
1312 return aDest; |
|
1313 }, |
|
1314 |
|
1315 /** |
|
1316 * Rotates a matrix by the given angle around the Y axix. |
|
1317 * |
|
1318 * @param {Array} aMat |
|
1319 * mat4 to rotate |
|
1320 * @param {Number} aAngle |
|
1321 * the angle (in radians) to rotate |
|
1322 * @param {Array} aDest |
|
1323 * optional, mat4 receiving operation result |
|
1324 * if not specified result is written to the first operand |
|
1325 * |
|
1326 * @return {Array} the destination mat4 if specified, first operand otherwise |
|
1327 */ |
|
1328 rotateY: function M4_rotateY(aMat, aAngle, aDest) |
|
1329 { |
|
1330 let s = Math.sin(aAngle); |
|
1331 let c = Math.cos(aAngle); |
|
1332 |
|
1333 let a00 = aMat[0], a01 = aMat[1], a02 = aMat[2], a03 = aMat[3]; |
|
1334 let a20 = aMat[8], a21 = aMat[9], a22 = aMat[10], a23 = aMat[11]; |
|
1335 |
|
1336 if (!aDest) { |
|
1337 aDest = aMat; |
|
1338 } else if (aMat !== aDest) { |
|
1339 aDest[4] = aMat[4]; |
|
1340 aDest[5] = aMat[5]; |
|
1341 aDest[6] = aMat[6]; |
|
1342 aDest[7] = aMat[7]; |
|
1343 aDest[12] = aMat[12]; |
|
1344 aDest[13] = aMat[13]; |
|
1345 aDest[14] = aMat[14]; |
|
1346 aDest[15] = aMat[15]; |
|
1347 } |
|
1348 |
|
1349 aDest[0] = a00 * c + a20 * -s; |
|
1350 aDest[1] = a01 * c + a21 * -s; |
|
1351 aDest[2] = a02 * c + a22 * -s; |
|
1352 aDest[3] = a03 * c + a23 * -s; |
|
1353 aDest[8] = a00 * s + a20 * c; |
|
1354 aDest[9] = a01 * s + a21 * c; |
|
1355 aDest[10] = a02 * s + a22 * c; |
|
1356 aDest[11] = a03 * s + a23 * c; |
|
1357 return aDest; |
|
1358 }, |
|
1359 |
|
1360 /** |
|
1361 * Rotates a matrix by the given angle around the Z axix. |
|
1362 * |
|
1363 * @param {Array} aMat |
|
1364 * mat4 to rotate |
|
1365 * @param {Number} aAngle |
|
1366 * the angle (in radians) to rotate |
|
1367 * @param {Array} aDest |
|
1368 * optional, mat4 receiving operation result |
|
1369 * if not specified result is written to the first operand |
|
1370 * |
|
1371 * @return {Array} the destination mat4 if specified, first operand otherwise |
|
1372 */ |
|
1373 rotateZ: function M4_rotateZ(aMat, aAngle, aDest) |
|
1374 { |
|
1375 let s = Math.sin(aAngle); |
|
1376 let c = Math.cos(aAngle); |
|
1377 |
|
1378 let a00 = aMat[0], a01 = aMat[1], a02 = aMat[2], a03 = aMat[3]; |
|
1379 let a10 = aMat[4], a11 = aMat[5], a12 = aMat[6], a13 = aMat[7]; |
|
1380 |
|
1381 if (!aDest) { |
|
1382 aDest = aMat; |
|
1383 } else if (aMat !== aDest) { |
|
1384 aDest[8] = aMat[8]; |
|
1385 aDest[9] = aMat[9]; |
|
1386 aDest[10] = aMat[10]; |
|
1387 aDest[11] = aMat[11]; |
|
1388 aDest[12] = aMat[12]; |
|
1389 aDest[13] = aMat[13]; |
|
1390 aDest[14] = aMat[14]; |
|
1391 aDest[15] = aMat[15]; |
|
1392 } |
|
1393 |
|
1394 aDest[0] = a00 * c + a10 * s; |
|
1395 aDest[1] = a01 * c + a11 * s; |
|
1396 aDest[2] = a02 * c + a12 * s; |
|
1397 aDest[3] = a03 * c + a13 * s; |
|
1398 aDest[4] = a00 * -s + a10 * c; |
|
1399 aDest[5] = a01 * -s + a11 * c; |
|
1400 aDest[6] = a02 * -s + a12 * c; |
|
1401 aDest[7] = a03 * -s + a13 * c; |
|
1402 return aDest; |
|
1403 }, |
|
1404 |
|
1405 /** |
|
1406 * Generates a frustum matrix with the given bounds. |
|
1407 * |
|
1408 * @param {Number} aLeft |
|
1409 * scalar, left bound of the frustum |
|
1410 * @param {Number} aRight |
|
1411 * scalar, right bound of the frustum |
|
1412 * @param {Number} aBottom |
|
1413 * scalar, bottom bound of the frustum |
|
1414 * @param {Number} aTop |
|
1415 * scalar, top bound of the frustum |
|
1416 * @param {Number} aNear |
|
1417 * scalar, near bound of the frustum |
|
1418 * @param {Number} aFar |
|
1419 * scalar, far bound of the frustum |
|
1420 * @param {Array} aDest |
|
1421 * optional, mat4 frustum matrix will be written into |
|
1422 * if not specified result is written to a new mat4 |
|
1423 * |
|
1424 * @return {Array} the destination mat4 if specified, a new mat4 otherwise |
|
1425 */ |
|
1426 frustum: function M4_frustum( |
|
1427 aLeft, aRight, aBottom, aTop, aNear, aFar, aDest) |
|
1428 { |
|
1429 if (!aDest) { |
|
1430 aDest = new Float32Array(16); |
|
1431 } |
|
1432 |
|
1433 let rl = (aRight - aLeft); |
|
1434 let tb = (aTop - aBottom); |
|
1435 let fn = (aFar - aNear); |
|
1436 |
|
1437 aDest[0] = (aNear * 2) / rl; |
|
1438 aDest[1] = 0; |
|
1439 aDest[2] = 0; |
|
1440 aDest[3] = 0; |
|
1441 aDest[4] = 0; |
|
1442 aDest[5] = (aNear * 2) / tb; |
|
1443 aDest[6] = 0; |
|
1444 aDest[7] = 0; |
|
1445 aDest[8] = (aRight + aLeft) / rl; |
|
1446 aDest[9] = (aTop + aBottom) / tb; |
|
1447 aDest[10] = -(aFar + aNear) / fn; |
|
1448 aDest[11] = -1; |
|
1449 aDest[12] = 0; |
|
1450 aDest[13] = 0; |
|
1451 aDest[14] = -(aFar * aNear * 2) / fn; |
|
1452 aDest[15] = 0; |
|
1453 return aDest; |
|
1454 }, |
|
1455 |
|
1456 /** |
|
1457 * Generates a perspective projection matrix with the given bounds. |
|
1458 * |
|
1459 * @param {Number} aFovy |
|
1460 * scalar, vertical field of view (degrees) |
|
1461 * @param {Number} aAspect |
|
1462 * scalar, aspect ratio (typically viewport width/height) |
|
1463 * @param {Number} aNear |
|
1464 * scalar, near bound of the frustum |
|
1465 * @param {Number} aFar |
|
1466 * scalar, far bound of the frustum |
|
1467 * @param {Array} aDest |
|
1468 * optional, mat4 frustum matrix will be written into |
|
1469 * if not specified result is written to a new mat4 |
|
1470 * |
|
1471 * @return {Array} the destination mat4 if specified, a new mat4 otherwise |
|
1472 */ |
|
1473 perspective: function M4_perspective( |
|
1474 aFovy, aAspect, aNear, aFar, aDest, aFlip) |
|
1475 { |
|
1476 let upper = aNear * Math.tan(aFovy * 0.00872664626); // PI * 180 / 2 |
|
1477 let right = upper * aAspect; |
|
1478 let top = upper * (aFlip || 1); |
|
1479 |
|
1480 return mat4.frustum(-right, right, -top, top, aNear, aFar, aDest); |
|
1481 }, |
|
1482 |
|
1483 /** |
|
1484 * Generates a orthogonal projection matrix with the given bounds. |
|
1485 * |
|
1486 * @param {Number} aLeft |
|
1487 * scalar, left bound of the frustum |
|
1488 * @param {Number} aRight |
|
1489 * scalar, right bound of the frustum |
|
1490 * @param {Number} aBottom |
|
1491 * scalar, bottom bound of the frustum |
|
1492 * @param {Number} aTop |
|
1493 * scalar, top bound of the frustum |
|
1494 * @param {Number} aNear |
|
1495 * scalar, near bound of the frustum |
|
1496 * @param {Number} aFar |
|
1497 * scalar, far bound of the frustum |
|
1498 * @param {Array} aDest |
|
1499 * optional, mat4 frustum matrix will be written into |
|
1500 * if not specified result is written to a new mat4 |
|
1501 * |
|
1502 * @return {Array} the destination mat4 if specified, a new mat4 otherwise |
|
1503 */ |
|
1504 ortho: function M4_ortho(aLeft, aRight, aBottom, aTop, aNear, aFar, aDest) |
|
1505 { |
|
1506 if (!aDest) { |
|
1507 aDest = new Float32Array(16); |
|
1508 } |
|
1509 |
|
1510 let rl = (aRight - aLeft); |
|
1511 let tb = (aTop - aBottom); |
|
1512 let fn = (aFar - aNear); |
|
1513 |
|
1514 aDest[0] = 2 / rl; |
|
1515 aDest[1] = 0; |
|
1516 aDest[2] = 0; |
|
1517 aDest[3] = 0; |
|
1518 aDest[4] = 0; |
|
1519 aDest[5] = 2 / tb; |
|
1520 aDest[6] = 0; |
|
1521 aDest[7] = 0; |
|
1522 aDest[8] = 0; |
|
1523 aDest[9] = 0; |
|
1524 aDest[10] = -2 / fn; |
|
1525 aDest[11] = 0; |
|
1526 aDest[12] = -(aLeft + aRight) / rl; |
|
1527 aDest[13] = -(aTop + aBottom) / tb; |
|
1528 aDest[14] = -(aFar + aNear) / fn; |
|
1529 aDest[15] = 1; |
|
1530 return aDest; |
|
1531 }, |
|
1532 |
|
1533 /** |
|
1534 * Generates a look-at matrix with the given eye position, focal point, and |
|
1535 * up axis. |
|
1536 * |
|
1537 * @param {Array} aEye |
|
1538 * vec3, position of the viewer |
|
1539 * @param {Array} aCenter |
|
1540 * vec3, point the viewer is looking at |
|
1541 * @param {Array} aUp |
|
1542 * vec3 pointing up |
|
1543 * @param {Array} aDest |
|
1544 * optional, mat4 frustum matrix will be written into |
|
1545 * if not specified result is written to a new mat4 |
|
1546 * |
|
1547 * @return {Array} the destination mat4 if specified, a new mat4 otherwise |
|
1548 */ |
|
1549 lookAt: function M4_lookAt(aEye, aCenter, aUp, aDest) |
|
1550 { |
|
1551 if (!aDest) { |
|
1552 aDest = new Float32Array(16); |
|
1553 } |
|
1554 |
|
1555 let eyex = aEye[0]; |
|
1556 let eyey = aEye[1]; |
|
1557 let eyez = aEye[2]; |
|
1558 let upx = aUp[0]; |
|
1559 let upy = aUp[1]; |
|
1560 let upz = aUp[2]; |
|
1561 let centerx = aCenter[0]; |
|
1562 let centery = aCenter[1]; |
|
1563 let centerz = aCenter[2]; |
|
1564 |
|
1565 let z0 = eyex - aCenter[0]; |
|
1566 let z1 = eyey - aCenter[1]; |
|
1567 let z2 = eyez - aCenter[2]; |
|
1568 let len = 1 / (Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2) || EPSILON); |
|
1569 |
|
1570 z0 *= len; |
|
1571 z1 *= len; |
|
1572 z2 *= len; |
|
1573 |
|
1574 let x0 = upy * z2 - upz * z1; |
|
1575 let x1 = upz * z0 - upx * z2; |
|
1576 let x2 = upx * z1 - upy * z0; |
|
1577 len = 1 / (Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2) || EPSILON); |
|
1578 |
|
1579 x0 *= len; |
|
1580 x1 *= len; |
|
1581 x2 *= len; |
|
1582 |
|
1583 let y0 = z1 * x2 - z2 * x1; |
|
1584 let y1 = z2 * x0 - z0 * x2; |
|
1585 let y2 = z0 * x1 - z1 * x0; |
|
1586 len = 1 / (Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2) || EPSILON); |
|
1587 |
|
1588 y0 *= len; |
|
1589 y1 *= len; |
|
1590 y2 *= len; |
|
1591 |
|
1592 aDest[0] = x0; |
|
1593 aDest[1] = y0; |
|
1594 aDest[2] = z0; |
|
1595 aDest[3] = 0; |
|
1596 aDest[4] = x1; |
|
1597 aDest[5] = y1; |
|
1598 aDest[6] = z1; |
|
1599 aDest[7] = 0; |
|
1600 aDest[8] = x2; |
|
1601 aDest[9] = y2; |
|
1602 aDest[10] = z2; |
|
1603 aDest[11] = 0; |
|
1604 aDest[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); |
|
1605 aDest[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); |
|
1606 aDest[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); |
|
1607 aDest[15] = 1; |
|
1608 |
|
1609 return aDest; |
|
1610 }, |
|
1611 |
|
1612 /** |
|
1613 * Returns a string representation of a 4x4 matrix. |
|
1614 * |
|
1615 * @param {Array} aMat |
|
1616 * mat4 to represent as a string |
|
1617 * |
|
1618 * @return {String} representation of the matrix |
|
1619 */ |
|
1620 str: function M4_str(mat) |
|
1621 { |
|
1622 return "[" + mat[0] + ", " + mat[1] + ", " + mat[2] + ", " + mat[3] + |
|
1623 ", "+ mat[4] + ", " + mat[5] + ", " + mat[6] + ", " + mat[7] + |
|
1624 ", "+ mat[8] + ", " + mat[9] + ", " + mat[10] + ", " + mat[11] + |
|
1625 ", "+ mat[12] + ", " + mat[13] + ", " + mat[14] + ", " + mat[15] + |
|
1626 "]"; |
|
1627 } |
|
1628 }; |
|
1629 |
|
1630 exports.mat4 = mat4; |
|
1631 |
|
1632 /** |
|
1633 * quat4 - Quaternion. |
|
1634 */ |
|
1635 let quat4 = { |
|
1636 |
|
1637 /** |
|
1638 * Creates a new instance of a quat4 using the default Float32Array type. |
|
1639 * Any array containing at least 4 numeric elements can serve as a quat4. |
|
1640 * |
|
1641 * @param {Array} aQuat |
|
1642 * optional, quat4 containing values to initialize with |
|
1643 * |
|
1644 * @return {Array} a new instance of a quat4 |
|
1645 */ |
|
1646 create: function Q4_create(aQuat) |
|
1647 { |
|
1648 let dest = new Float32Array(4); |
|
1649 |
|
1650 if (aQuat) { |
|
1651 quat4.set(aQuat, dest); |
|
1652 } else { |
|
1653 quat4.identity(dest); |
|
1654 } |
|
1655 return dest; |
|
1656 }, |
|
1657 |
|
1658 /** |
|
1659 * Copies the values of one quat4 to another. |
|
1660 * |
|
1661 * @param {Array} aQuat |
|
1662 * quat4 containing values to copy |
|
1663 * @param {Array} aDest |
|
1664 * quat4 receiving copied values |
|
1665 * |
|
1666 * @return {Array} the destination quat4 receiving copied values |
|
1667 */ |
|
1668 set: function Q4_set(aQuat, aDest) |
|
1669 { |
|
1670 aDest[0] = aQuat[0]; |
|
1671 aDest[1] = aQuat[1]; |
|
1672 aDest[2] = aQuat[2]; |
|
1673 aDest[3] = aQuat[3]; |
|
1674 return aDest; |
|
1675 }, |
|
1676 |
|
1677 /** |
|
1678 * Sets a quat4 to an identity quaternion. |
|
1679 * |
|
1680 * @param {Array} aDest |
|
1681 * quat4 to set |
|
1682 * |
|
1683 * @return {Array} the same quaternion |
|
1684 */ |
|
1685 identity: function Q4_identity(aDest) |
|
1686 { |
|
1687 aDest[0] = 0; |
|
1688 aDest[1] = 0; |
|
1689 aDest[2] = 0; |
|
1690 aDest[3] = 1; |
|
1691 return aDest; |
|
1692 }, |
|
1693 |
|
1694 /** |
|
1695 * Calculate the W component of a quat4 from the X, Y, and Z components. |
|
1696 * Assumes that quaternion is 1 unit in length. |
|
1697 * Any existing W component will be ignored. |
|
1698 * |
|
1699 * @param {Array} aQuat |
|
1700 * quat4 to calculate W component of |
|
1701 * @param {Array} aDest |
|
1702 * optional, quat4 receiving calculated values |
|
1703 * if not specified result is written to the first operand |
|
1704 * |
|
1705 * @return {Array} the destination quat if specified, first operand otherwise |
|
1706 */ |
|
1707 calculateW: function Q4_calculateW(aQuat, aDest) |
|
1708 { |
|
1709 if (!aDest) { |
|
1710 aDest = aQuat; |
|
1711 } |
|
1712 |
|
1713 let x = aQuat[0]; |
|
1714 let y = aQuat[1]; |
|
1715 let z = aQuat[2]; |
|
1716 |
|
1717 aDest[0] = x; |
|
1718 aDest[1] = y; |
|
1719 aDest[2] = z; |
|
1720 aDest[3] = -Math.sqrt(Math.abs(1 - x * x - y * y - z * z)); |
|
1721 return aDest; |
|
1722 }, |
|
1723 |
|
1724 /** |
|
1725 * Calculate the inverse of a quat4. |
|
1726 * |
|
1727 * @param {Array} aQuat |
|
1728 * quat4 to calculate the inverse of |
|
1729 * @param {Array} aDest |
|
1730 * optional, quat4 receiving the inverse values |
|
1731 * if not specified result is written to the first operand |
|
1732 * |
|
1733 * @return {Array} the destination quat if specified, first operand otherwise |
|
1734 */ |
|
1735 inverse: function Q4_inverse(aQuat, aDest) |
|
1736 { |
|
1737 if (!aDest) { |
|
1738 aDest = aQuat; |
|
1739 } |
|
1740 |
|
1741 aQuat[0] = -aQuat[0]; |
|
1742 aQuat[1] = -aQuat[1]; |
|
1743 aQuat[2] = -aQuat[2]; |
|
1744 return aQuat; |
|
1745 }, |
|
1746 |
|
1747 /** |
|
1748 * Generates a unit quaternion of the same direction as the provided quat4. |
|
1749 * If quaternion length is 0, returns [0, 0, 0, 0]. |
|
1750 * |
|
1751 * @param {Array} aQuat |
|
1752 * quat4 to normalize |
|
1753 * @param {Array} aDest |
|
1754 * optional, quat4 receiving the operation result |
|
1755 * if not specified result is written to the first operand |
|
1756 * |
|
1757 * @return {Array} the destination quat if specified, first operand otherwise |
|
1758 */ |
|
1759 normalize: function Q4_normalize(aQuat, aDest) |
|
1760 { |
|
1761 if (!aDest) { |
|
1762 aDest = aQuat; |
|
1763 } |
|
1764 |
|
1765 let x = aQuat[0]; |
|
1766 let y = aQuat[1]; |
|
1767 let z = aQuat[2]; |
|
1768 let w = aQuat[3]; |
|
1769 let len = Math.sqrt(x * x + y * y + z * z + w * w); |
|
1770 |
|
1771 if (Math.abs(len) < EPSILON) { |
|
1772 aDest[0] = 0; |
|
1773 aDest[1] = 0; |
|
1774 aDest[2] = 0; |
|
1775 aDest[3] = 0; |
|
1776 return aDest; |
|
1777 } |
|
1778 |
|
1779 len = 1 / len; |
|
1780 aDest[0] = x * len; |
|
1781 aDest[1] = y * len; |
|
1782 aDest[2] = z * len; |
|
1783 aDest[3] = w * len; |
|
1784 return aDest; |
|
1785 }, |
|
1786 |
|
1787 /** |
|
1788 * Calculate the length of a quat4. |
|
1789 * |
|
1790 * @param {Array} aQuat |
|
1791 * quat4 to calculate the length of |
|
1792 * |
|
1793 * @return {Number} length of the quaternion |
|
1794 */ |
|
1795 length: function Q4_length(aQuat) |
|
1796 { |
|
1797 let x = aQuat[0]; |
|
1798 let y = aQuat[1]; |
|
1799 let z = aQuat[2]; |
|
1800 let w = aQuat[3]; |
|
1801 |
|
1802 return Math.sqrt(x * x + y * y + z * z + w * w); |
|
1803 }, |
|
1804 |
|
1805 /** |
|
1806 * Performs a quaternion multiplication. |
|
1807 * |
|
1808 * @param {Array} aQuat |
|
1809 * first operand |
|
1810 * @param {Array} aQuat2 |
|
1811 * second operand |
|
1812 * @param {Array} aDest |
|
1813 * optional, quat4 receiving the operation result |
|
1814 * if not specified result is written to the first operand |
|
1815 * |
|
1816 * @return {Array} the destination quat if specified, first operand otherwise |
|
1817 */ |
|
1818 multiply: function Q4_multiply(aQuat, aQuat2, aDest) |
|
1819 { |
|
1820 if (!aDest) { |
|
1821 aDest = aQuat; |
|
1822 } |
|
1823 |
|
1824 let qax = aQuat[0]; |
|
1825 let qay = aQuat[1]; |
|
1826 let qaz = aQuat[2]; |
|
1827 let qaw = aQuat[3]; |
|
1828 let qbx = aQuat2[0]; |
|
1829 let qby = aQuat2[1]; |
|
1830 let qbz = aQuat2[2]; |
|
1831 let qbw = aQuat2[3]; |
|
1832 |
|
1833 aDest[0] = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; |
|
1834 aDest[1] = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; |
|
1835 aDest[2] = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; |
|
1836 aDest[3] = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; |
|
1837 return aDest; |
|
1838 }, |
|
1839 |
|
1840 /** |
|
1841 * Transforms a vec3 with the given quaternion. |
|
1842 * |
|
1843 * @param {Array} aQuat |
|
1844 * quat4 to transform the vector with |
|
1845 * @param {Array} aVec |
|
1846 * vec3 to transform |
|
1847 * @param {Array} aDest |
|
1848 * optional, vec3 receiving the operation result |
|
1849 * if not specified result is written to the first operand |
|
1850 * |
|
1851 * @return {Array} the destination vec3 if specified, aVec operand otherwise |
|
1852 */ |
|
1853 multiplyVec3: function Q4_multiplyVec3(aQuat, aVec, aDest) |
|
1854 { |
|
1855 if (!aDest) { |
|
1856 aDest = aVec; |
|
1857 } |
|
1858 |
|
1859 let x = aVec[0]; |
|
1860 let y = aVec[1]; |
|
1861 let z = aVec[2]; |
|
1862 |
|
1863 let qx = aQuat[0]; |
|
1864 let qy = aQuat[1]; |
|
1865 let qz = aQuat[2]; |
|
1866 let qw = aQuat[3]; |
|
1867 |
|
1868 let ix = qw * x + qy * z - qz * y; |
|
1869 let iy = qw * y + qz * x - qx * z; |
|
1870 let iz = qw * z + qx * y - qy * x; |
|
1871 let iw = -qx * x - qy * y - qz * z; |
|
1872 |
|
1873 aDest[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; |
|
1874 aDest[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; |
|
1875 aDest[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; |
|
1876 return aDest; |
|
1877 }, |
|
1878 |
|
1879 /** |
|
1880 * Performs a spherical linear interpolation between two quat4. |
|
1881 * |
|
1882 * @param {Array} aQuat |
|
1883 * first quaternion |
|
1884 * @param {Array} aQuat2 |
|
1885 * second quaternion |
|
1886 * @param {Number} aSlerp |
|
1887 * interpolation amount between the two inputs |
|
1888 * @param {Array} aDest |
|
1889 * optional, quat4 receiving the operation result |
|
1890 * if not specified result is written to the first operand |
|
1891 * |
|
1892 * @return {Array} the destination quat if specified, first operand otherwise |
|
1893 */ |
|
1894 slerp: function Q4_slerp(aQuat, aQuat2, aSlerp, aDest) |
|
1895 { |
|
1896 if (!aDest) { |
|
1897 aDest = aQuat; |
|
1898 } |
|
1899 |
|
1900 let cosHalfTheta = aQuat[0] * aQuat2[0] + |
|
1901 aQuat[1] * aQuat2[1] + |
|
1902 aQuat[2] * aQuat2[2] + |
|
1903 aQuat[3] * aQuat2[3]; |
|
1904 |
|
1905 if (Math.abs(cosHalfTheta) >= 1) { |
|
1906 aDest[0] = aQuat[0]; |
|
1907 aDest[1] = aQuat[1]; |
|
1908 aDest[2] = aQuat[2]; |
|
1909 aDest[3] = aQuat[3]; |
|
1910 return aDest; |
|
1911 } |
|
1912 |
|
1913 let halfTheta = Math.acos(cosHalfTheta); |
|
1914 let sinHalfTheta = Math.sqrt(1 - cosHalfTheta * cosHalfTheta); |
|
1915 |
|
1916 if (Math.abs(sinHalfTheta) < EPSILON) { |
|
1917 aDest[0] = (aQuat[0] * 0.5 + aQuat2[0] * 0.5); |
|
1918 aDest[1] = (aQuat[1] * 0.5 + aQuat2[1] * 0.5); |
|
1919 aDest[2] = (aQuat[2] * 0.5 + aQuat2[2] * 0.5); |
|
1920 aDest[3] = (aQuat[3] * 0.5 + aQuat2[3] * 0.5); |
|
1921 return aDest; |
|
1922 } |
|
1923 |
|
1924 let ratioA = Math.sin((1 - aSlerp) * halfTheta) / sinHalfTheta; |
|
1925 let ratioB = Math.sin(aSlerp * halfTheta) / sinHalfTheta; |
|
1926 |
|
1927 aDest[0] = (aQuat[0] * ratioA + aQuat2[0] * ratioB); |
|
1928 aDest[1] = (aQuat[1] * ratioA + aQuat2[1] * ratioB); |
|
1929 aDest[2] = (aQuat[2] * ratioA + aQuat2[2] * ratioB); |
|
1930 aDest[3] = (aQuat[3] * ratioA + aQuat2[3] * ratioB); |
|
1931 return aDest; |
|
1932 }, |
|
1933 |
|
1934 /** |
|
1935 * Calculates a 3x3 matrix from the given quat4. |
|
1936 * |
|
1937 * @param {Array} aQuat |
|
1938 * quat4 to create matrix from |
|
1939 * @param {Array} aDest |
|
1940 * optional, mat3 receiving the initialization result |
|
1941 * if not specified, a new matrix is created |
|
1942 * |
|
1943 * @return {Array} the destination mat3 if specified, first operand otherwise |
|
1944 */ |
|
1945 toMat3: function Q4_toMat3(aQuat, aDest) |
|
1946 { |
|
1947 if (!aDest) { |
|
1948 aDest = new Float32Array(9); |
|
1949 } |
|
1950 |
|
1951 let x = aQuat[0]; |
|
1952 let y = aQuat[1]; |
|
1953 let z = aQuat[2]; |
|
1954 let w = aQuat[3]; |
|
1955 |
|
1956 let x2 = x + x; |
|
1957 let y2 = y + y; |
|
1958 let z2 = z + z; |
|
1959 let xx = x * x2; |
|
1960 let xy = x * y2; |
|
1961 let xz = x * z2; |
|
1962 let yy = y * y2; |
|
1963 let yz = y * z2; |
|
1964 let zz = z * z2; |
|
1965 let wx = w * x2; |
|
1966 let wy = w * y2; |
|
1967 let wz = w * z2; |
|
1968 |
|
1969 aDest[0] = 1 - (yy + zz); |
|
1970 aDest[1] = xy - wz; |
|
1971 aDest[2] = xz + wy; |
|
1972 aDest[3] = xy + wz; |
|
1973 aDest[4] = 1 - (xx + zz); |
|
1974 aDest[5] = yz - wx; |
|
1975 aDest[6] = xz - wy; |
|
1976 aDest[7] = yz + wx; |
|
1977 aDest[8] = 1 - (xx + yy); |
|
1978 return aDest; |
|
1979 }, |
|
1980 |
|
1981 /** |
|
1982 * Calculates a 4x4 matrix from the given quat4. |
|
1983 * |
|
1984 * @param {Array} aQuat |
|
1985 * quat4 to create matrix from |
|
1986 * @param {Array} aDest |
|
1987 * optional, mat4 receiving the initialization result |
|
1988 * if not specified, a new matrix is created |
|
1989 * |
|
1990 * @return {Array} the destination mat4 if specified, first operand otherwise |
|
1991 */ |
|
1992 toMat4: function Q4_toMat4(aQuat, aDest) |
|
1993 { |
|
1994 if (!aDest) { |
|
1995 aDest = new Float32Array(16); |
|
1996 } |
|
1997 |
|
1998 let x = aQuat[0]; |
|
1999 let y = aQuat[1]; |
|
2000 let z = aQuat[2]; |
|
2001 let w = aQuat[3]; |
|
2002 |
|
2003 let x2 = x + x; |
|
2004 let y2 = y + y; |
|
2005 let z2 = z + z; |
|
2006 let xx = x * x2; |
|
2007 let xy = x * y2; |
|
2008 let xz = x * z2; |
|
2009 let yy = y * y2; |
|
2010 let yz = y * z2; |
|
2011 let zz = z * z2; |
|
2012 let wx = w * x2; |
|
2013 let wy = w * y2; |
|
2014 let wz = w * z2; |
|
2015 |
|
2016 aDest[0] = 1 - (yy + zz); |
|
2017 aDest[1] = xy - wz; |
|
2018 aDest[2] = xz + wy; |
|
2019 aDest[3] = 0; |
|
2020 aDest[4] = xy + wz; |
|
2021 aDest[5] = 1 - (xx + zz); |
|
2022 aDest[6] = yz - wx; |
|
2023 aDest[7] = 0; |
|
2024 aDest[8] = xz - wy; |
|
2025 aDest[9] = yz + wx; |
|
2026 aDest[10] = 1 - (xx + yy); |
|
2027 aDest[11] = 0; |
|
2028 aDest[12] = 0; |
|
2029 aDest[13] = 0; |
|
2030 aDest[14] = 0; |
|
2031 aDest[15] = 1; |
|
2032 return aDest; |
|
2033 }, |
|
2034 |
|
2035 /** |
|
2036 * Creates a rotation quaternion from axis-angle. |
|
2037 * This function expects that the axis is a normalized vector. |
|
2038 * |
|
2039 * @param {Array} aAxis |
|
2040 * an array of elements representing the [x, y, z] axis |
|
2041 * @param {Number} aAngle |
|
2042 * the angle of rotation |
|
2043 * @param {Array} aDest |
|
2044 * optional, quat4 receiving the initialization result |
|
2045 * if not specified, a new quaternion is created |
|
2046 * |
|
2047 * @return {Array} the quaternion as [x, y, z, w] |
|
2048 */ |
|
2049 fromAxis: function Q4_fromAxis(aAxis, aAngle, aDest) |
|
2050 { |
|
2051 if (!aDest) { |
|
2052 aDest = new Float32Array(4); |
|
2053 } |
|
2054 |
|
2055 let ang = aAngle * 0.5; |
|
2056 let sin = Math.sin(ang); |
|
2057 let cos = Math.cos(ang); |
|
2058 |
|
2059 aDest[0] = aAxis[0] * sin; |
|
2060 aDest[1] = aAxis[1] * sin; |
|
2061 aDest[2] = aAxis[2] * sin; |
|
2062 aDest[3] = cos; |
|
2063 return aDest; |
|
2064 }, |
|
2065 |
|
2066 /** |
|
2067 * Creates a rotation quaternion from Euler angles. |
|
2068 * |
|
2069 * @param {Number} aYaw |
|
2070 * the yaw angle of rotation |
|
2071 * @param {Number} aPitch |
|
2072 * the pitch angle of rotation |
|
2073 * @param {Number} aRoll |
|
2074 * the roll angle of rotation |
|
2075 * @param {Array} aDest |
|
2076 * optional, quat4 receiving the initialization result |
|
2077 * if not specified, a new quaternion is created |
|
2078 * |
|
2079 * @return {Array} the quaternion as [x, y, z, w] |
|
2080 */ |
|
2081 fromEuler: function Q4_fromEuler(aYaw, aPitch, aRoll, aDest) |
|
2082 { |
|
2083 if (!aDest) { |
|
2084 aDest = new Float32Array(4); |
|
2085 } |
|
2086 |
|
2087 let x = aPitch * 0.5; |
|
2088 let y = aYaw * 0.5; |
|
2089 let z = aRoll * 0.5; |
|
2090 |
|
2091 let sinr = Math.sin(x); |
|
2092 let sinp = Math.sin(y); |
|
2093 let siny = Math.sin(z); |
|
2094 let cosr = Math.cos(x); |
|
2095 let cosp = Math.cos(y); |
|
2096 let cosy = Math.cos(z); |
|
2097 |
|
2098 aDest[0] = sinr * cosp * cosy - cosr * sinp * siny; |
|
2099 aDest[1] = cosr * sinp * cosy + sinr * cosp * siny; |
|
2100 aDest[2] = cosr * cosp * siny - sinr * sinp * cosy; |
|
2101 aDest[3] = cosr * cosp * cosy + sinr * sinp * siny; |
|
2102 return aDest; |
|
2103 }, |
|
2104 |
|
2105 /** |
|
2106 * Returns a string representation of a quaternion. |
|
2107 * |
|
2108 * @param {Array} aQuat |
|
2109 * quat4 to represent as a string |
|
2110 * |
|
2111 * @return {String} representation of the quaternion |
|
2112 */ |
|
2113 str: function Q4_str(aQuat) { |
|
2114 return "[" + aQuat[0] + ", " + |
|
2115 aQuat[1] + ", " + |
|
2116 aQuat[2] + ", " + |
|
2117 aQuat[3] + "]"; |
|
2118 } |
|
2119 }; |
|
2120 |
|
2121 exports.quat4 = quat4; |
|
2122 |
|
2123 /** |
|
2124 * Various algebraic math functions required by the engine. |
|
2125 */ |
|
2126 let TiltMath = { |
|
2127 |
|
2128 /** |
|
2129 * Helper function, converts degrees to radians. |
|
2130 * |
|
2131 * @param {Number} aDegrees |
|
2132 * the degrees to be converted to radians |
|
2133 * |
|
2134 * @return {Number} the degrees converted to radians |
|
2135 */ |
|
2136 radians: function TM_radians(aDegrees) |
|
2137 { |
|
2138 return aDegrees * PI_OVER_180; |
|
2139 }, |
|
2140 |
|
2141 /** |
|
2142 * Helper function, converts radians to degrees. |
|
2143 * |
|
2144 * @param {Number} aRadians |
|
2145 * the radians to be converted to degrees |
|
2146 * |
|
2147 * @return {Number} the radians converted to degrees |
|
2148 */ |
|
2149 degrees: function TM_degrees(aRadians) |
|
2150 { |
|
2151 return aRadians * INV_PI_OVER_180; |
|
2152 }, |
|
2153 |
|
2154 /** |
|
2155 * Re-maps a number from one range to another. |
|
2156 * |
|
2157 * @param {Number} aValue |
|
2158 * the number to map |
|
2159 * @param {Number} aLow1 |
|
2160 * the normal lower bound of the number |
|
2161 * @param {Number} aHigh1 |
|
2162 * the normal upper bound of the number |
|
2163 * @param {Number} aLow2 |
|
2164 * the new lower bound of the number |
|
2165 * @param {Number} aHigh2 |
|
2166 * the new upper bound of the number |
|
2167 * |
|
2168 * @return {Number} the remapped number |
|
2169 */ |
|
2170 map: function TM_map(aValue, aLow1, aHigh1, aLow2, aHigh2) |
|
2171 { |
|
2172 return aLow2 + (aHigh2 - aLow2) * ((aValue - aLow1) / (aHigh1 - aLow1)); |
|
2173 }, |
|
2174 |
|
2175 /** |
|
2176 * Returns if number is power of two. |
|
2177 * |
|
2178 * @param {Number} aNumber |
|
2179 * the number to be verified |
|
2180 * |
|
2181 * @return {Boolean} true if x is power of two |
|
2182 */ |
|
2183 isPowerOfTwo: function TM_isPowerOfTwo(aNumber) |
|
2184 { |
|
2185 return !(aNumber & (aNumber - 1)); |
|
2186 }, |
|
2187 |
|
2188 /** |
|
2189 * Returns the next closest power of two greater than a number. |
|
2190 * |
|
2191 * @param {Number} aNumber |
|
2192 * the number to be converted |
|
2193 * |
|
2194 * @return {Number} the next closest power of two for x |
|
2195 */ |
|
2196 nextPowerOfTwo: function TM_nextPowerOfTwo(aNumber) |
|
2197 { |
|
2198 --aNumber; |
|
2199 |
|
2200 for (let i = 1; i < 32; i <<= 1) { |
|
2201 aNumber = aNumber | aNumber >> i; |
|
2202 } |
|
2203 return aNumber + 1; |
|
2204 }, |
|
2205 |
|
2206 /** |
|
2207 * A convenient way of limiting values to a set boundary. |
|
2208 * |
|
2209 * @param {Number} aValue |
|
2210 * the number to be limited |
|
2211 * @param {Number} aMin |
|
2212 * the minimum allowed value for the number |
|
2213 * @param {Number} aMax |
|
2214 * the maximum allowed value for the number |
|
2215 */ |
|
2216 clamp: function TM_clamp(aValue, aMin, aMax) |
|
2217 { |
|
2218 return Math.max(aMin, Math.min(aMax, aValue)); |
|
2219 }, |
|
2220 |
|
2221 /** |
|
2222 * Convenient way to clamp a value to 0..1 |
|
2223 * |
|
2224 * @param {Number} aValue |
|
2225 * the number to be limited |
|
2226 */ |
|
2227 saturate: function TM_saturate(aValue) |
|
2228 { |
|
2229 return Math.max(0, Math.min(1, aValue)); |
|
2230 }, |
|
2231 |
|
2232 /** |
|
2233 * Converts a hex color to rgba. |
|
2234 * If the passed param is invalid, it will be converted to [0, 0, 0, 1]; |
|
2235 * |
|
2236 * @param {String} aColor |
|
2237 * color expressed in hex, or using rgb() or rgba() |
|
2238 * |
|
2239 * @return {Array} with 4 color 0..1 components: [red, green, blue, alpha] |
|
2240 */ |
|
2241 hex2rgba: (function() |
|
2242 { |
|
2243 let cache = {}; |
|
2244 |
|
2245 return function TM_hex2rgba(aColor) { |
|
2246 let hex = aColor.charAt(0) === "#" ? aColor.substring(1) : aColor; |
|
2247 |
|
2248 // check the cache to see if this color wasn't converted already |
|
2249 if (cache[hex] !== undefined) { |
|
2250 return cache[hex]; |
|
2251 } |
|
2252 |
|
2253 // e.g. "f00" |
|
2254 if (hex.length === 3) { |
|
2255 let r = parseInt(hex.substring(0, 1), 16) * FIFTEEN_OVER_225; |
|
2256 let g = parseInt(hex.substring(1, 2), 16) * FIFTEEN_OVER_225; |
|
2257 let b = parseInt(hex.substring(2, 3), 16) * FIFTEEN_OVER_225; |
|
2258 |
|
2259 return (cache[hex] = [r, g, b, 1]); |
|
2260 } |
|
2261 // e.g. "f008" |
|
2262 if (hex.length === 4) { |
|
2263 let r = parseInt(hex.substring(0, 1), 16) * FIFTEEN_OVER_225; |
|
2264 let g = parseInt(hex.substring(1, 2), 16) * FIFTEEN_OVER_225; |
|
2265 let b = parseInt(hex.substring(2, 3), 16) * FIFTEEN_OVER_225; |
|
2266 let a = parseInt(hex.substring(3, 4), 16) * FIFTEEN_OVER_225; |
|
2267 |
|
2268 return (cache[hex] = [r, g, b, a]); |
|
2269 } |
|
2270 // e.g. "ff0000" |
|
2271 if (hex.length === 6) { |
|
2272 let r = parseInt(hex.substring(0, 2), 16) * ONE_OVER_255; |
|
2273 let g = parseInt(hex.substring(2, 4), 16) * ONE_OVER_255; |
|
2274 let b = parseInt(hex.substring(4, 6), 16) * ONE_OVER_255; |
|
2275 let a = 1; |
|
2276 |
|
2277 return (cache[hex] = [r, g, b, a]); |
|
2278 } |
|
2279 // e.g "ff0000aa" |
|
2280 if (hex.length === 8) { |
|
2281 let r = parseInt(hex.substring(0, 2), 16) * ONE_OVER_255; |
|
2282 let g = parseInt(hex.substring(2, 4), 16) * ONE_OVER_255; |
|
2283 let b = parseInt(hex.substring(4, 6), 16) * ONE_OVER_255; |
|
2284 let a = parseInt(hex.substring(6, 8), 16) * ONE_OVER_255; |
|
2285 |
|
2286 return (cache[hex] = [r, g, b, a]); |
|
2287 } |
|
2288 // e.g. "rgba(255, 0, 0, 0.5)" |
|
2289 if (hex.match("^rgba")) { |
|
2290 let rgba = hex.substring(5, hex.length - 1).split(","); |
|
2291 rgba[0] *= ONE_OVER_255; |
|
2292 rgba[1] *= ONE_OVER_255; |
|
2293 rgba[2] *= ONE_OVER_255; |
|
2294 // in CSS, the alpha component of rgba() is already in the range 0..1 |
|
2295 |
|
2296 return (cache[hex] = rgba); |
|
2297 } |
|
2298 // e.g. "rgb(255, 0, 0)" |
|
2299 if (hex.match("^rgb")) { |
|
2300 let rgba = hex.substring(4, hex.length - 1).split(","); |
|
2301 rgba[0] *= ONE_OVER_255; |
|
2302 rgba[1] *= ONE_OVER_255; |
|
2303 rgba[2] *= ONE_OVER_255; |
|
2304 rgba[3] = 1; |
|
2305 |
|
2306 return (cache[hex] = rgba); |
|
2307 } |
|
2308 |
|
2309 // your argument is invalid |
|
2310 return (cache[hex] = [0, 0, 0, 1]); |
|
2311 }; |
|
2312 }()) |
|
2313 }; |
|
2314 |
|
2315 exports.TiltMath = TiltMath; |
|
2316 |
|
2317 // bind the owner object to the necessary functions |
|
2318 TiltUtils.bindObjectFunc(vec3); |
|
2319 TiltUtils.bindObjectFunc(mat3); |
|
2320 TiltUtils.bindObjectFunc(mat4); |
|
2321 TiltUtils.bindObjectFunc(quat4); |
|
2322 TiltUtils.bindObjectFunc(TiltMath); |