Wed, 31 Dec 2014 13:27:57 +0100
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); |