browser/devtools/tilt/tilt-math.js

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

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

mercurial