OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2009, Mozilla Corp |
| 3 * All rights reserved. |
| 4 * |
| 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions are met: |
| 7 * * Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. |
| 9 * * Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the |
| 11 * documentation and/or other materials provided with the distribution. |
| 12 * * Neither the name of the <organization> nor the |
| 13 * names of its contributors may be used to endorse or promote products |
| 14 * derived from this software without specific prior written permission. |
| 15 * |
| 16 * THIS SOFTWARE IS PROVIDED BY <copyright holder> ''AS IS'' AND ANY |
| 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 19 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY |
| 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 26 */ |
| 27 |
| 28 /* |
| 29 * Based on sample code from the OpenGL(R) ES 2.0 Programming Guide, which carri
ers |
| 30 * the following header: |
| 31 * |
| 32 * Book: OpenGL(R) ES 2.0 Programming Guide |
| 33 * Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner |
| 34 * ISBN-10: 0321502795 |
| 35 * ISBN-13: 9780321502797 |
| 36 * Publisher: Addison-Wesley Professional |
| 37 * URLs: http://safari.informit.com/9780321563835 |
| 38 * http://www.opengles-book.com |
| 39 */ |
| 40 |
| 41 // |
| 42 // A simple 4x4 Matrix utility class |
| 43 // |
| 44 |
| 45 function Matrix4x4() { |
| 46 this.elements = Array(16); |
| 47 this.loadIdentity(); |
| 48 } |
| 49 |
| 50 Matrix4x4.prototype = { |
| 51 scale: function (sx, sy, sz) { |
| 52 this.elements[0*4+0] *= sx; |
| 53 this.elements[0*4+1] *= sx; |
| 54 this.elements[0*4+2] *= sx; |
| 55 this.elements[0*4+3] *= sx; |
| 56 |
| 57 this.elements[1*4+0] *= sy; |
| 58 this.elements[1*4+1] *= sy; |
| 59 this.elements[1*4+2] *= sy; |
| 60 this.elements[1*4+3] *= sy; |
| 61 |
| 62 this.elements[2*4+0] *= sz; |
| 63 this.elements[2*4+1] *= sz; |
| 64 this.elements[2*4+2] *= sz; |
| 65 this.elements[2*4+3] *= sz; |
| 66 |
| 67 return this; |
| 68 }, |
| 69 |
| 70 translate: function (tx, ty, tz) { |
| 71 this.elements[3*4+0] += this.elements[0*4+0] * tx + this.elements[1*4+0] * t
y + this.elements[2*4+0] * tz; |
| 72 this.elements[3*4+1] += this.elements[0*4+1] * tx + this.elements[1*4+1] * t
y + this.elements[2*4+1] * tz; |
| 73 this.elements[3*4+2] += this.elements[0*4+2] * tx + this.elements[1*4+2] * t
y + this.elements[2*4+2] * tz; |
| 74 this.elements[3*4+3] += this.elements[0*4+3] * tx + this.elements[1*4+3] * t
y + this.elements[2*4+3] * tz; |
| 75 |
| 76 return this; |
| 77 }, |
| 78 |
| 79 rotate: function (angle, x, y, z) { |
| 80 var mag = Math.sqrt(x*x + y*y + z*z); |
| 81 var sinAngle = Math.sin(angle * Math.PI / 180.0); |
| 82 var cosAngle = Math.cos(angle * Math.PI / 180.0); |
| 83 |
| 84 if (mag > 0) { |
| 85 var xx, yy, zz, xy, yz, zx, xs, ys, zs; |
| 86 var oneMinusCos; |
| 87 var rotMat; |
| 88 |
| 89 x /= mag; |
| 90 y /= mag; |
| 91 z /= mag; |
| 92 |
| 93 xx = x * x; |
| 94 yy = y * y; |
| 95 zz = z * z; |
| 96 xy = x * y; |
| 97 yz = y * z; |
| 98 zx = z * x; |
| 99 xs = x * sinAngle; |
| 100 ys = y * sinAngle; |
| 101 zs = z * sinAngle; |
| 102 oneMinusCos = 1.0 - cosAngle; |
| 103 |
| 104 rotMat = new Matrix4x4(); |
| 105 |
| 106 rotMat.elements[0*4+0] = (oneMinusCos * xx) + cosAngle; |
| 107 rotMat.elements[0*4+1] = (oneMinusCos * xy) - zs; |
| 108 rotMat.elements[0*4+2] = (oneMinusCos * zx) + ys; |
| 109 rotMat.elements[0*4+3] = 0.0; |
| 110 |
| 111 rotMat.elements[1*4+0] = (oneMinusCos * xy) + zs; |
| 112 rotMat.elements[1*4+1] = (oneMinusCos * yy) + cosAngle; |
| 113 rotMat.elements[1*4+2] = (oneMinusCos * yz) - xs; |
| 114 rotMat.elements[1*4+3] = 0.0; |
| 115 |
| 116 rotMat.elements[2*4+0] = (oneMinusCos * zx) - ys; |
| 117 rotMat.elements[2*4+1] = (oneMinusCos * yz) + xs; |
| 118 rotMat.elements[2*4+2] = (oneMinusCos * zz) + cosAngle; |
| 119 rotMat.elements[2*4+3] = 0.0; |
| 120 |
| 121 rotMat.elements[3*4+0] = 0.0; |
| 122 rotMat.elements[3*4+1] = 0.0; |
| 123 rotMat.elements[3*4+2] = 0.0; |
| 124 rotMat.elements[3*4+3] = 1.0; |
| 125 |
| 126 rotMat = rotMat.multiply(this); |
| 127 this.elements = rotMat.elements; |
| 128 } |
| 129 |
| 130 return this; |
| 131 }, |
| 132 |
| 133 frustum: function (left, right, bottom, top, nearZ, farZ) { |
| 134 var deltaX = right - left; |
| 135 var deltaY = top - bottom; |
| 136 var deltaZ = farZ - nearZ; |
| 137 var frust; |
| 138 |
| 139 if ( (nearZ <= 0.0) || (farZ <= 0.0) || |
| 140 (deltaX <= 0.0) || (deltaY <= 0.0) || (deltaZ <= 0.0) ) |
| 141 return this; |
| 142 |
| 143 frust = new Matrix4x4(); |
| 144 |
| 145 frust.elements[0*4+0] = 2.0 * nearZ / deltaX; |
| 146 frust.elements[0*4+1] = frust.elements[0*4+2] = frust.elements[0*4+3] = 0.0; |
| 147 |
| 148 frust.elements[1*4+1] = 2.0 * nearZ / deltaY; |
| 149 frust.elements[1*4+0] = frust.elements[1*4+2] = frust.elements[1*4+3] = 0.0; |
| 150 |
| 151 frust.elements[2*4+0] = (right + left) / deltaX; |
| 152 frust.elements[2*4+1] = (top + bottom) / deltaY; |
| 153 frust.elements[2*4+2] = -(nearZ + farZ) / deltaZ; |
| 154 frust.elements[2*4+3] = -1.0; |
| 155 |
| 156 frust.elements[3*4+2] = -2.0 * nearZ * farZ / deltaZ; |
| 157 frust.elements[3*4+0] = frust.elements[3*4+1] = frust.elements[3*4+3] = 0.0; |
| 158 |
| 159 frust = frust.multiply(this); |
| 160 this.elements = frust.elements; |
| 161 |
| 162 return this; |
| 163 }, |
| 164 |
| 165 perspective: function (fovy, aspect, nearZ, farZ) { |
| 166 var frustumH = Math.tan(fovy / 360.0 * Math.PI) * nearZ; |
| 167 var frustumW = frustumH * aspect; |
| 168 |
| 169 return this.frustum(-frustumW, frustumW, -frustumH, frustumH, nearZ, farZ); |
| 170 }, |
| 171 |
| 172 ortho: function (left, right, bottom, top, nearZ, farZ) { |
| 173 var deltaX = right - left; |
| 174 var deltaY = top - bottom; |
| 175 var deltaZ = farZ - nearZ; |
| 176 |
| 177 var ortho = new Matrix4x4(); |
| 178 |
| 179 if ( (deltaX == 0.0) || (deltaY == 0.0) || (deltaZ == 0.0) ) |
| 180 return this; |
| 181 |
| 182 ortho.elements[0*4+0] = 2.0 / deltaX; |
| 183 ortho.elements[3*4+0] = -(right + left) / deltaX; |
| 184 ortho.elements[1*4+1] = 2.0 / deltaY; |
| 185 ortho.elements[3*4+1] = -(top + bottom) / deltaY; |
| 186 ortho.elements[2*4+2] = -2.0 / deltaZ; |
| 187 ortho.elements[3*4+2] = -(nearZ + farZ) / deltaZ; |
| 188 |
| 189 ortho = ortho.multiply(this); |
| 190 this.elements = ortho.elements; |
| 191 |
| 192 return this; |
| 193 }, |
| 194 |
| 195 multiply: function (right) { |
| 196 var tmp = new Matrix4x4(); |
| 197 |
| 198 for (var i = 0; i < 4; i++) { |
| 199 tmp.elements[i*4+0] = |
| 200 (this.elements[i*4+0] * right.elements[0*4+0]) + |
| 201 (this.elements[i*4+1] * right.elements[1*4+0]) + |
| 202 (this.elements[i*4+2] * right.elements[2*4+0]) + |
| 203 (this.elements[i*4+3] * right.elements[3*4+0]) ; |
| 204 |
| 205 tmp.elements[i*4+1] = |
| 206 (this.elements[i*4+0] * right.elements[0*4+1]) + |
| 207 (this.elements[i*4+1] * right.elements[1*4+1]) + |
| 208 (this.elements[i*4+2] * right.elements[2*4+1]) + |
| 209 (this.elements[i*4+3] * right.elements[3*4+1]) ; |
| 210 |
| 211 tmp.elements[i*4+2] = |
| 212 (this.elements[i*4+0] * right.elements[0*4+2]) + |
| 213 (this.elements[i*4+1] * right.elements[1*4+2]) + |
| 214 (this.elements[i*4+2] * right.elements[2*4+2]) + |
| 215 (this.elements[i*4+3] * right.elements[3*4+2]) ; |
| 216 |
| 217 tmp.elements[i*4+3] = |
| 218 (this.elements[i*4+0] * right.elements[0*4+3]) + |
| 219 (this.elements[i*4+1] * right.elements[1*4+3]) + |
| 220 (this.elements[i*4+2] * right.elements[2*4+3]) + |
| 221 (this.elements[i*4+3] * right.elements[3*4+3]) ; |
| 222 } |
| 223 |
| 224 this.elements = tmp.elements; |
| 225 return this; |
| 226 }, |
| 227 |
| 228 copy: function () { |
| 229 var tmp = new Matrix4x4(); |
| 230 for (var i = 0; i < 16; i++) { |
| 231 tmp.elements[i] = this.elements[i]; |
| 232 } |
| 233 return tmp; |
| 234 }, |
| 235 |
| 236 get: function (row, col) { |
| 237 return this.elements[4*row+col]; |
| 238 }, |
| 239 |
| 240 // In-place inversion |
| 241 invert: function () { |
| 242 var tmp_0 = this.get(2,2) * this.get(3,3); |
| 243 var tmp_1 = this.get(3,2) * this.get(2,3); |
| 244 var tmp_2 = this.get(1,2) * this.get(3,3); |
| 245 var tmp_3 = this.get(3,2) * this.get(1,3); |
| 246 var tmp_4 = this.get(1,2) * this.get(2,3); |
| 247 var tmp_5 = this.get(2,2) * this.get(1,3); |
| 248 var tmp_6 = this.get(0,2) * this.get(3,3); |
| 249 var tmp_7 = this.get(3,2) * this.get(0,3); |
| 250 var tmp_8 = this.get(0,2) * this.get(2,3); |
| 251 var tmp_9 = this.get(2,2) * this.get(0,3); |
| 252 var tmp_10 = this.get(0,2) * this.get(1,3); |
| 253 var tmp_11 = this.get(1,2) * this.get(0,3); |
| 254 var tmp_12 = this.get(2,0) * this.get(3,1); |
| 255 var tmp_13 = this.get(3,0) * this.get(2,1); |
| 256 var tmp_14 = this.get(1,0) * this.get(3,1); |
| 257 var tmp_15 = this.get(3,0) * this.get(1,1); |
| 258 var tmp_16 = this.get(1,0) * this.get(2,1); |
| 259 var tmp_17 = this.get(2,0) * this.get(1,1); |
| 260 var tmp_18 = this.get(0,0) * this.get(3,1); |
| 261 var tmp_19 = this.get(3,0) * this.get(0,1); |
| 262 var tmp_20 = this.get(0,0) * this.get(2,1); |
| 263 var tmp_21 = this.get(2,0) * this.get(0,1); |
| 264 var tmp_22 = this.get(0,0) * this.get(1,1); |
| 265 var tmp_23 = this.get(1,0) * this.get(0,1); |
| 266 |
| 267 var t0 = ((tmp_0 * this.get(1,1) + tmp_3 * this.get(2,1) + tmp_4 * this.get(
3,1)) - |
| 268 (tmp_1 * this.get(1,1) + tmp_2 * this.get(2,1) + tmp_5 * this.get(
3,1))); |
| 269 var t1 = ((tmp_1 * this.get(0,1) + tmp_6 * this.get(2,1) + tmp_9 * this.get(
3,1)) - |
| 270 (tmp_0 * this.get(0,1) + tmp_7 * this.get(2,1) + tmp_8 * this.get(
3,1))); |
| 271 var t2 = ((tmp_2 * this.get(0,1) + tmp_7 * this.get(1,1) + tmp_10 * this.get
(3,1)) - |
| 272 (tmp_3 * this.get(0,1) + tmp_6 * this.get(1,1) + tmp_11 * this.get
(3,1))); |
| 273 var t3 = ((tmp_5 * this.get(0,1) + tmp_8 * this.get(1,1) + tmp_11 * this.get
(2,1)) - |
| 274 (tmp_4 * this.get(0,1) + tmp_9 * this.get(1,1) + tmp_10 * this.get
(2,1))); |
| 275 |
| 276 var d = 1.0 / (this.get(0,0) * t0 + this.get(1,0) * t1 + this.get(2,0) * t2
+ this.get(3,0) * t3); |
| 277 |
| 278 var out_00 = d * t0; |
| 279 var out_01 = d * t1; |
| 280 var out_02 = d * t2; |
| 281 var out_03 = d * t3; |
| 282 |
| 283 var out_10 = d * ((tmp_1 * this.get(1,0) + tmp_2 * this.get(2,0) + tmp_5 * t
his.get(3,0)) - |
| 284 (tmp_0 * this.get(1,0) + tmp_3 * this.get(2,0) + tmp_4 * t
his.get(3,0))); |
| 285 var out_11 = d * ((tmp_0 * this.get(0,0) + tmp_7 * this.get(2,0) + tmp_8 * t
his.get(3,0)) - |
| 286 (tmp_1 * this.get(0,0) + tmp_6 * this.get(2,0) + tmp_9 * t
his.get(3,0))); |
| 287 var out_12 = d * ((tmp_3 * this.get(0,0) + tmp_6 * this.get(1,0) + tmp_11 *
this.get(3,0)) - |
| 288 (tmp_2 * this.get(0,0) + tmp_7 * this.get(1,0) + tmp_10 *
this.get(3,0))); |
| 289 var out_13 = d * ((tmp_4 * this.get(0,0) + tmp_9 * this.get(1,0) + tmp_10 *
this.get(2,0)) - |
| 290 (tmp_5 * this.get(0,0) + tmp_8 * this.get(1,0) + tmp_11 *
this.get(2,0))); |
| 291 |
| 292 var out_20 = d * ((tmp_12 * this.get(1,3) + tmp_15 * this.get(2,3) + tmp_16
* this.get(3,3)) - |
| 293 (tmp_13 * this.get(1,3) + tmp_14 * this.get(2,3) + tmp_17
* this.get(3,3))); |
| 294 var out_21 = d * ((tmp_13 * this.get(0,3) + tmp_18 * this.get(2,3) + tmp_21
* this.get(3,3)) - |
| 295 (tmp_12 * this.get(0,3) + tmp_19 * this.get(2,3) + tmp_20
* this.get(3,3))); |
| 296 var out_22 = d * ((tmp_14 * this.get(0,3) + tmp_19 * this.get(1,3) + tmp_22
* this.get(3,3)) - |
| 297 (tmp_15 * this.get(0,3) + tmp_18 * this.get(1,3) + tmp_23
* this.get(3,3))); |
| 298 var out_23 = d * ((tmp_17 * this.get(0,3) + tmp_20 * this.get(1,3) + tmp_23
* this.get(2,3)) - |
| 299 (tmp_16 * this.get(0,3) + tmp_21 * this.get(1,3) + tmp_22
* this.get(2,3))); |
| 300 |
| 301 var out_30 = d * ((tmp_14 * this.get(2,2) + tmp_17 * this.get(3,2) + tmp_13
* this.get(1,2)) - |
| 302 (tmp_16 * this.get(3,2) + tmp_12 * this.get(1,2) + tmp_15
* this.get(2,2))); |
| 303 var out_31 = d * ((tmp_20 * this.get(3,2) + tmp_12 * this.get(0,2) + tmp_19
* this.get(2,2)) - |
| 304 (tmp_18 * this.get(2,2) + tmp_21 * this.get(3,2) + tmp_13
* this.get(0,2))); |
| 305 var out_32 = d * ((tmp_18 * this.get(1,2) + tmp_23 * this.get(3,2) + tmp_15
* this.get(0,2)) - |
| 306 (tmp_22 * this.get(3,2) + tmp_14 * this.get(0,2) + tmp_19
* this.get(1,2))); |
| 307 var out_33 = d * ((tmp_22 * this.get(2,2) + tmp_16 * this.get(0,2) + tmp_21
* this.get(1,2)) - |
| 308 (tmp_20 * this.get(1,2) + tmp_23 * this.get(2,2) + tmp_17
* this.get(0,2))); |
| 309 |
| 310 this.elements[0*4+0] = out_00; |
| 311 this.elements[0*4+1] = out_01; |
| 312 this.elements[0*4+2] = out_02; |
| 313 this.elements[0*4+3] = out_03; |
| 314 this.elements[1*4+0] = out_10; |
| 315 this.elements[1*4+1] = out_11; |
| 316 this.elements[1*4+2] = out_12; |
| 317 this.elements[1*4+3] = out_13; |
| 318 this.elements[2*4+0] = out_20; |
| 319 this.elements[2*4+1] = out_21; |
| 320 this.elements[2*4+2] = out_22; |
| 321 this.elements[2*4+3] = out_23; |
| 322 this.elements[3*4+0] = out_30; |
| 323 this.elements[3*4+1] = out_31; |
| 324 this.elements[3*4+2] = out_32; |
| 325 this.elements[3*4+3] = out_33; |
| 326 return this; |
| 327 }, |
| 328 |
| 329 // Returns new matrix which is the inverse of this |
| 330 inverse: function () { |
| 331 var tmp = this.copy(); |
| 332 return tmp.invert(); |
| 333 }, |
| 334 |
| 335 // In-place transpose |
| 336 transpose: function () { |
| 337 var tmp = this.elements[0*4+1]; |
| 338 this.elements[0*4+1] = this.elements[1*4+0]; |
| 339 this.elements[1*4+0] = tmp; |
| 340 |
| 341 tmp = this.elements[0*4+2]; |
| 342 this.elements[0*4+2] = this.elements[2*4+0]; |
| 343 this.elements[2*4+0] = tmp; |
| 344 |
| 345 tmp = this.elements[0*4+3]; |
| 346 this.elements[0*4+3] = this.elements[3*4+0]; |
| 347 this.elements[3*4+0] = tmp; |
| 348 |
| 349 tmp = this.elements[1*4+2]; |
| 350 this.elements[1*4+2] = this.elements[2*4+1]; |
| 351 this.elements[2*4+1] = tmp; |
| 352 |
| 353 tmp = this.elements[1*4+3]; |
| 354 this.elements[1*4+3] = this.elements[3*4+1]; |
| 355 this.elements[3*4+1] = tmp; |
| 356 |
| 357 tmp = this.elements[2*4+3]; |
| 358 this.elements[2*4+3] = this.elements[3*4+2]; |
| 359 this.elements[3*4+2] = tmp; |
| 360 |
| 361 return this; |
| 362 }, |
| 363 |
| 364 loadIdentity: function () { |
| 365 for (var i = 0; i < 16; i++) |
| 366 this.elements[i] = 0; |
| 367 this.elements[0*4+0] = 1.0; |
| 368 this.elements[1*4+1] = 1.0; |
| 369 this.elements[2*4+2] = 1.0; |
| 370 this.elements[3*4+3] = 1.0; |
| 371 return this; |
| 372 } |
| 373 }; |
OLD | NEW |