comparison fps/resources/J3DIMath.js @ 0:fbb6f4f89f76

info3_1week
author Syusaku Morita <e105716@ie.u-ryukyu.ac.jp>
date Fri, 27 Apr 2012 13:13:49 +0900
parents
children 47399f2f3a80
comparison
equal deleted inserted replaced
-1:000000000000 0:fbb6f4f89f76
1 /*
2 * Copyright (C) 2009 Apple Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. 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 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 // J3DI (Jedi) - A support library for WebGL.
27
28 /*
29 J3DI Math Classes. Currently includes:
30
31 J3DIMatrix4 - A 4x4 Matrix
32 */
33
34 /*
35 J3DIMatrix4 class
36
37 This class implements a 4x4 matrix. It has functions which duplicate the
38 functionality of the OpenGL matrix stack and glut functions. On browsers
39 that support it, CSSMatrix is used to accelerate operations.
40
41 IDL:
42
43 [
44 Constructor(in J3DIMatrix4 matrix), // copy passed matrix into new J3DIMatrix4
45 Constructor(in sequence<float> array) // create new J3DIMatrix4 with 16 floats (row major)
46 Constructor() // create new J3DIMatrix4 with identity matrix
47 ]
48 interface J3DIMatrix4 {
49 void load(in J3DIMatrix4 matrix); // copy the values from the passed matrix
50 void load(in sequence<float> array); // copy 16 floats into the matrix
51 sequence<float> getAsArray(); // return the matrix as an array of 16 floats
52 Float32Array getAsFloat32Array(); // return the matrix as a Float32Array with 16 values
53 void setUniform(in WebGLRenderingContext ctx, // Send the matrix to the passed uniform location in the passed context
54 in WebGLUniformLocation loc,
55 in boolean transpose);
56 void makeIdentity(); // replace the matrix with identity
57 void transpose(); // replace the matrix with its transpose
58 void invert(); // replace the matrix with its inverse
59
60 void translate(in float x, in float y, in float z); // multiply the matrix by passed translation values on the right
61 void translate(in J3DVector3 v); // multiply the matrix by passed translation values on the right
62 void scale(in float x, in float y, in float z); // multiply the matrix by passed scale values on the right
63 void scale(in J3DVector3 v); // multiply the matrix by passed scale values on the right
64 void rotate(in float angle, // multiply the matrix by passed rotation values on the right
65 in float x, in float y, in float z); // (angle is in degrees)
66 void rotate(in float angle, in J3DVector3 v); // multiply the matrix by passed rotation values on the right
67 // (angle is in degrees)
68 void multiply(in CanvasMatrix matrix); // multiply the matrix by the passed matrix on the right
69 void divide(in float divisor); // divide the matrix by the passed divisor
70 void ortho(in float left, in float right, // multiply the matrix by the passed ortho values on the right
71 in float bottom, in float top,
72 in float near, in float far);
73 void frustum(in float left, in float right, // multiply the matrix by the passed frustum values on the right
74 in float bottom, in float top,
75 in float near, in float far);
76 void perspective(in float fovy, in float aspect, // multiply the matrix by the passed perspective values on the right
77 in float zNear, in float zFar);
78 void lookat(in J3DVector3 eye, // multiply the matrix by the passed lookat
79 in J3DVector3 center, in J3DVector3 up); // values on the right
80 bool decompose(in J3DVector3 translate, // decompose the matrix into the passed vector
81 in J3DVector3 rotate,
82 in J3DVector3 scale,
83 in J3DVector3 skew,
84 in sequence<float> perspective);
85 }
86
87 [
88 Constructor(in J3DVector3 vector), // copy passed vector into new J3DVector3
89 Constructor(in sequence<float> array) // create new J3DVector3 with 3 floats from array
90 Constructor(in float x, in float y, in float z) // create new J3DVector3 with 3 floats
91 Constructor() // create new J3DVector3 with (0,0,0)
92 ]
93 interface J3DVector3 {
94 void load(in J3DVector3 vector); // copy the values from the passed vector
95 void load(in sequence<float> array); // copy 3 floats into the vector from array
96 void load(in float x, in float y, in float z); // copy 3 floats into the vector
97 sequence<float> getAsArray(); // return the vector as an array of 3 floats
98 Float32Array getAsFloat32Array(); // return the matrix as a Float32Array with 16 values
99 void multMatrix(in J3DIMatrix4 matrix); // multiply the vector by the passed matrix (on the right)
100 float vectorLength(); // return the length of the vector
101 float dot(); // return the dot product of the vector
102 void cross(in J3DVector3 v); // replace the vector with vector x v
103 void divide(in float divisor); // divide the vector by the passed divisor
104 }
105 */
106
107 J3DIHasCSSMatrix = false;
108 J3DIHasCSSMatrixCopy = false;
109 /*
110 if ("WebKitCSSMatrix" in window && ("media" in window && window.media.matchMedium("(-webkit-transform-3d)")) ||
111 ("styleMedia" in window && window.styleMedia.matchMedium("(-webkit-transform-3d)"))) {
112 J3DIHasCSSMatrix = true;
113 if ("copy" in WebKitCSSMatrix.prototype)
114 J3DIHasCSSMatrixCopy = true;
115 }
116 */
117
118 // console.log("J3DIHasCSSMatrix="+J3DIHasCSSMatrix);
119 // console.log("J3DIHasCSSMatrixCopy="+J3DIHasCSSMatrixCopy);
120
121 //
122 // J3DIMatrix4
123 //
124 J3DIMatrix4 = function(m)
125 {
126 if (J3DIHasCSSMatrix)
127 this.$matrix = new WebKitCSSMatrix;
128 else
129 this.$matrix = new Object;
130
131 if (typeof m == 'object') {
132 if ("length" in m && m.length >= 16) {
133 this.load(m);
134 return;
135 }
136 else if (m instanceof J3DIMatrix4) {
137 this.load(m);
138 return;
139 }
140 }
141 this.makeIdentity();
142 }
143
144 J3DIMatrix4.prototype.load = function()
145 {
146 if (arguments.length == 1 && typeof arguments[0] == 'object') {
147 var matrix;
148
149 if (arguments[0] instanceof J3DIMatrix4) {
150 matrix = arguments[0].$matrix;
151
152 this.$matrix.m11 = matrix.m11;
153 this.$matrix.m12 = matrix.m12;
154 this.$matrix.m13 = matrix.m13;
155 this.$matrix.m14 = matrix.m14;
156
157 this.$matrix.m21 = matrix.m21;
158 this.$matrix.m22 = matrix.m22;
159 this.$matrix.m23 = matrix.m23;
160 this.$matrix.m24 = matrix.m24;
161
162 this.$matrix.m31 = matrix.m31;
163 this.$matrix.m32 = matrix.m32;
164 this.$matrix.m33 = matrix.m33;
165 this.$matrix.m34 = matrix.m34;
166
167 this.$matrix.m41 = matrix.m41;
168 this.$matrix.m42 = matrix.m42;
169 this.$matrix.m43 = matrix.m43;
170 this.$matrix.m44 = matrix.m44;
171 return;
172 }
173 else
174 matrix = arguments[0];
175
176 if ("length" in matrix && matrix.length >= 16) {
177 this.$matrix.m11 = matrix[0];
178 this.$matrix.m12 = matrix[1];
179 this.$matrix.m13 = matrix[2];
180 this.$matrix.m14 = matrix[3];
181
182 this.$matrix.m21 = matrix[4];
183 this.$matrix.m22 = matrix[5];
184 this.$matrix.m23 = matrix[6];
185 this.$matrix.m24 = matrix[7];
186
187 this.$matrix.m31 = matrix[8];
188 this.$matrix.m32 = matrix[9];
189 this.$matrix.m33 = matrix[10];
190 this.$matrix.m34 = matrix[11];
191
192 this.$matrix.m41 = matrix[12];
193 this.$matrix.m42 = matrix[13];
194 this.$matrix.m43 = matrix[14];
195 this.$matrix.m44 = matrix[15];
196 return;
197 }
198 }
199
200 this.makeIdentity();
201 }
202
203 J3DIMatrix4.prototype.getAsArray = function()
204 {
205 return [
206 this.$matrix.m11, this.$matrix.m12, this.$matrix.m13, this.$matrix.m14,
207 this.$matrix.m21, this.$matrix.m22, this.$matrix.m23, this.$matrix.m24,
208 this.$matrix.m31, this.$matrix.m32, this.$matrix.m33, this.$matrix.m34,
209 this.$matrix.m41, this.$matrix.m42, this.$matrix.m43, this.$matrix.m44
210 ];
211 }
212
213 J3DIMatrix4.prototype.getAsFloat32Array = function()
214 {
215 if (J3DIHasCSSMatrixCopy) {
216 var array = new Float32Array(16);
217 this.$matrix.copy(array);
218 return array;
219 }
220 return new Float32Array(this.getAsArray());
221 }
222
223 J3DIMatrix4.prototype.setUniform = function(ctx, loc, transpose)
224 {
225 if (J3DIMatrix4.setUniformArray == undefined) {
226 J3DIMatrix4.setUniformWebGLArray = new Float32Array(16);
227 J3DIMatrix4.setUniformArray = new Array(16);
228 }
229
230 if (J3DIHasCSSMatrixCopy)
231 this.$matrix.copy(J3DIMatrix4.setUniformWebGLArray);
232 else {
233 J3DIMatrix4.setUniformArray[0] = this.$matrix.m11;
234 J3DIMatrix4.setUniformArray[1] = this.$matrix.m12;
235 J3DIMatrix4.setUniformArray[2] = this.$matrix.m13;
236 J3DIMatrix4.setUniformArray[3] = this.$matrix.m14;
237 J3DIMatrix4.setUniformArray[4] = this.$matrix.m21;
238 J3DIMatrix4.setUniformArray[5] = this.$matrix.m22;
239 J3DIMatrix4.setUniformArray[6] = this.$matrix.m23;
240 J3DIMatrix4.setUniformArray[7] = this.$matrix.m24;
241 J3DIMatrix4.setUniformArray[8] = this.$matrix.m31;
242 J3DIMatrix4.setUniformArray[9] = this.$matrix.m32;
243 J3DIMatrix4.setUniformArray[10] = this.$matrix.m33;
244 J3DIMatrix4.setUniformArray[11] = this.$matrix.m34;
245 J3DIMatrix4.setUniformArray[12] = this.$matrix.m41;
246 J3DIMatrix4.setUniformArray[13] = this.$matrix.m42;
247 J3DIMatrix4.setUniformArray[14] = this.$matrix.m43;
248 J3DIMatrix4.setUniformArray[15] = this.$matrix.m44;
249
250 J3DIMatrix4.setUniformWebGLArray.set(J3DIMatrix4.setUniformArray);
251 }
252
253 ctx.uniformMatrix4fv(loc, transpose, J3DIMatrix4.setUniformWebGLArray);
254 }
255
256 J3DIMatrix4.prototype.makeIdentity = function()
257 {
258 this.$matrix.m11 = 1;
259 this.$matrix.m12 = 0;
260 this.$matrix.m13 = 0;
261 this.$matrix.m14 = 0;
262
263 this.$matrix.m21 = 0;
264 this.$matrix.m22 = 1;
265 this.$matrix.m23 = 0;
266 this.$matrix.m24 = 0;
267
268 this.$matrix.m31 = 0;
269 this.$matrix.m32 = 0;
270 this.$matrix.m33 = 1;
271 this.$matrix.m34 = 0;
272
273 this.$matrix.m41 = 0;
274 this.$matrix.m42 = 0;
275 this.$matrix.m43 = 0;
276 this.$matrix.m44 = 1;
277 }
278
279 J3DIMatrix4.prototype.transpose = function()
280 {
281 var tmp = this.$matrix.m12;
282 this.$matrix.m12 = this.$matrix.m21;
283 this.$matrix.m21 = tmp;
284
285 tmp = this.$matrix.m13;
286 this.$matrix.m13 = this.$matrix.m31;
287 this.$matrix.m31 = tmp;
288
289 tmp = this.$matrix.m14;
290 this.$matrix.m14 = this.$matrix.m41;
291 this.$matrix.m41 = tmp;
292
293 tmp = this.$matrix.m23;
294 this.$matrix.m23 = this.$matrix.m32;
295 this.$matrix.m32 = tmp;
296
297 tmp = this.$matrix.m24;
298 this.$matrix.m24 = this.$matrix.m42;
299 this.$matrix.m42 = tmp;
300
301 tmp = this.$matrix.m34;
302 this.$matrix.m34 = this.$matrix.m43;
303 this.$matrix.m43 = tmp;
304 }
305
306 J3DIMatrix4.prototype.invert = function()
307 {
308 if (J3DIHasCSSMatrix) {
309 this.$matrix = this.$matrix.inverse();
310 return;
311 }
312
313 // Calculate the 4x4 determinant
314 // If the determinant is zero,
315 // then the inverse matrix is not unique.
316 var det = this._determinant4x4();
317
318 if (Math.abs(det) < 1e-8)
319 return null;
320
321 this._makeAdjoint();
322
323 // Scale the adjoint matrix to get the inverse
324 this.$matrix.m11 /= det;
325 this.$matrix.m12 /= det;
326 this.$matrix.m13 /= det;
327 this.$matrix.m14 /= det;
328
329 this.$matrix.m21 /= det;
330 this.$matrix.m22 /= det;
331 this.$matrix.m23 /= det;
332 this.$matrix.m24 /= det;
333
334 this.$matrix.m31 /= det;
335 this.$matrix.m32 /= det;
336 this.$matrix.m33 /= det;
337 this.$matrix.m34 /= det;
338
339 this.$matrix.m41 /= det;
340 this.$matrix.m42 /= det;
341 this.$matrix.m43 /= det;
342 this.$matrix.m44 /= det;
343 }
344
345 J3DIMatrix4.prototype.translate = function(x,y,z)
346 {
347 if (typeof x == 'object' && "length" in x) {
348 var t = x;
349 x = t[0];
350 y = t[1];
351 z = t[2];
352 }
353 else {
354 if (x == undefined)
355 x = 0;
356 if (y == undefined)
357 y = 0;
358 if (z == undefined)
359 z = 0;
360 }
361
362 if (J3DIHasCSSMatrix) {
363 this.$matrix = this.$matrix.translate(x, y, z);
364 return;
365 }
366
367 var matrix = new J3DIMatrix4();
368 matrix.$matrix.m41 = x;
369 matrix.$matrix.m42 = y;
370 matrix.$matrix.m43 = z;
371
372 this.multiply(matrix);
373 }
374
375 J3DIMatrix4.prototype.scale = function(x,y,z)
376 {
377 if (typeof x == 'object' && "length" in x) {
378 var t = x;
379 x = t[0];
380 y = t[1];
381 z = t[2];
382 }
383 else {
384 if (x == undefined)
385 x = 1;
386 if (z == undefined) {
387 if (y == undefined) {
388 y = x;
389 z = x;
390 }
391 else
392 z = 1;
393 }
394 else if (y == undefined)
395 y = x;
396 }
397
398 if (J3DIHasCSSMatrix) {
399 this.$matrix = this.$matrix.scale(x, y, z);
400 return;
401 }
402
403 var matrix = new J3DIMatrix4();
404 matrix.$matrix.m11 = x;
405 matrix.$matrix.m22 = y;
406 matrix.$matrix.m33 = z;
407
408 this.multiply(matrix);
409 }
410
411 J3DIMatrix4.prototype.rotate = function(angle,x,y,z)
412 {
413 // Forms are (angle, x,y,z), (angle,vector), (angleX, angleY, angleZ), (angle)
414 if (typeof x == 'object' && "length" in x) {
415 var t = x;
416 x = t[0];
417 y = t[1];
418 z = t[2];
419 }
420 else {
421 if (arguments.length == 1) {
422 x = 0;
423 y = 0;
424 z = 1;
425 }
426 else if (arguments.length == 3) {
427 this.rotate(angle, 1,0,0); // about X axis
428 this.rotate(x, 0,1,0); // about Y axis
429 this.rotate(y, 0,0,1); // about Z axis
430 return;
431 }
432 }
433
434 if (J3DIHasCSSMatrix) {
435 this.$matrix = this.$matrix.rotateAxisAngle(x, y, z, angle);
436 return;
437 }
438
439 // angles are in degrees. Switch to radians
440 angle = angle / 180 * Math.PI;
441
442 angle /= 2;
443 var sinA = Math.sin(angle);
444 var cosA = Math.cos(angle);
445 var sinA2 = sinA * sinA;
446
447 // normalize
448 var len = Math.sqrt(x * x + y * y + z * z);
449 if (len == 0) {
450 // bad vector, just use something reasonable
451 x = 0;
452 y = 0;
453 z = 1;
454 } else if (len != 1) {
455 x /= len;
456 y /= len;
457 z /= len;
458 }
459
460 var mat = new J3DIMatrix4();
461
462 // optimize case where axis is along major axis
463 if (x == 1 && y == 0 && z == 0) {
464 mat.$matrix.m11 = 1;
465 mat.$matrix.m12 = 0;
466 mat.$matrix.m13 = 0;
467 mat.$matrix.m21 = 0;
468 mat.$matrix.m22 = 1 - 2 * sinA2;
469 mat.$matrix.m23 = 2 * sinA * cosA;
470 mat.$matrix.m31 = 0;
471 mat.$matrix.m32 = -2 * sinA * cosA;
472 mat.$matrix.m33 = 1 - 2 * sinA2;
473 mat.$matrix.m14 = mat.$matrix.m24 = mat.$matrix.m34 = 0;
474 mat.$matrix.m41 = mat.$matrix.m42 = mat.$matrix.m43 = 0;
475 mat.$matrix.m44 = 1;
476 } else if (x == 0 && y == 1 && z == 0) {
477 mat.$matrix.m11 = 1 - 2 * sinA2;
478 mat.$matrix.m12 = 0;
479 mat.$matrix.m13 = -2 * sinA * cosA;
480 mat.$matrix.m21 = 0;
481 mat.$matrix.m22 = 1;
482 mat.$matrix.m23 = 0;
483 mat.$matrix.m31 = 2 * sinA * cosA;
484 mat.$matrix.m32 = 0;
485 mat.$matrix.m33 = 1 - 2 * sinA2;
486 mat.$matrix.m14 = mat.$matrix.m24 = mat.$matrix.m34 = 0;
487 mat.$matrix.m41 = mat.$matrix.m42 = mat.$matrix.m43 = 0;
488 mat.$matrix.m44 = 1;
489 } else if (x == 0 && y == 0 && z == 1) {
490 mat.$matrix.m11 = 1 - 2 * sinA2;
491 mat.$matrix.m12 = 2 * sinA * cosA;
492 mat.$matrix.m13 = 0;
493 mat.$matrix.m21 = -2 * sinA * cosA;
494 mat.$matrix.m22 = 1 - 2 * sinA2;
495 mat.$matrix.m23 = 0;
496 mat.$matrix.m31 = 0;
497 mat.$matrix.m32 = 0;
498 mat.$matrix.m33 = 1;
499 mat.$matrix.m14 = mat.$matrix.m24 = mat.$matrix.m34 = 0;
500 mat.$matrix.m41 = mat.$matrix.m42 = mat.$matrix.m43 = 0;
501 mat.$matrix.m44 = 1;
502 } else {
503 var x2 = x*x;
504 var y2 = y*y;
505 var z2 = z*z;
506
507 mat.$matrix.m11 = 1 - 2 * (y2 + z2) * sinA2;
508 mat.$matrix.m12 = 2 * (x * y * sinA2 + z * sinA * cosA);
509 mat.$matrix.m13 = 2 * (x * z * sinA2 - y * sinA * cosA);
510 mat.$matrix.m21 = 2 * (y * x * sinA2 - z * sinA * cosA);
511 mat.$matrix.m22 = 1 - 2 * (z2 + x2) * sinA2;
512 mat.$matrix.m23 = 2 * (y * z * sinA2 + x * sinA * cosA);
513 mat.$matrix.m31 = 2 * (z * x * sinA2 + y * sinA * cosA);
514 mat.$matrix.m32 = 2 * (z * y * sinA2 - x * sinA * cosA);
515 mat.$matrix.m33 = 1 - 2 * (x2 + y2) * sinA2;
516 mat.$matrix.m14 = mat.$matrix.m24 = mat.$matrix.m34 = 0;
517 mat.$matrix.m41 = mat.$matrix.m42 = mat.$matrix.m43 = 0;
518 mat.$matrix.m44 = 1;
519 }
520 this.multiply(mat);
521 }
522
523 J3DIMatrix4.prototype.multiply = function(mat)
524 {
525 if (J3DIHasCSSMatrix) {
526 this.$matrix = this.$matrix.multiply(mat.$matrix);
527 return;
528 }
529
530 var m11 = (mat.$matrix.m11 * this.$matrix.m11 + mat.$matrix.m12 * this.$matrix.m21
531 + mat.$matrix.m13 * this.$matrix.m31 + mat.$matrix.m14 * this.$matrix.m41);
532 var m12 = (mat.$matrix.m11 * this.$matrix.m12 + mat.$matrix.m12 * this.$matrix.m22
533 + mat.$matrix.m13 * this.$matrix.m32 + mat.$matrix.m14 * this.$matrix.m42);
534 var m13 = (mat.$matrix.m11 * this.$matrix.m13 + mat.$matrix.m12 * this.$matrix.m23
535 + mat.$matrix.m13 * this.$matrix.m33 + mat.$matrix.m14 * this.$matrix.m43);
536 var m14 = (mat.$matrix.m11 * this.$matrix.m14 + mat.$matrix.m12 * this.$matrix.m24
537 + mat.$matrix.m13 * this.$matrix.m34 + mat.$matrix.m14 * this.$matrix.m44);
538
539 var m21 = (mat.$matrix.m21 * this.$matrix.m11 + mat.$matrix.m22 * this.$matrix.m21
540 + mat.$matrix.m23 * this.$matrix.m31 + mat.$matrix.m24 * this.$matrix.m41);
541 var m22 = (mat.$matrix.m21 * this.$matrix.m12 + mat.$matrix.m22 * this.$matrix.m22
542 + mat.$matrix.m23 * this.$matrix.m32 + mat.$matrix.m24 * this.$matrix.m42);
543 var m23 = (mat.$matrix.m21 * this.$matrix.m13 + mat.$matrix.m22 * this.$matrix.m23
544 + mat.$matrix.m23 * this.$matrix.m33 + mat.$matrix.m24 * this.$matrix.m43);
545 var m24 = (mat.$matrix.m21 * this.$matrix.m14 + mat.$matrix.m22 * this.$matrix.m24
546 + mat.$matrix.m23 * this.$matrix.m34 + mat.$matrix.m24 * this.$matrix.m44);
547
548 var m31 = (mat.$matrix.m31 * this.$matrix.m11 + mat.$matrix.m32 * this.$matrix.m21
549 + mat.$matrix.m33 * this.$matrix.m31 + mat.$matrix.m34 * this.$matrix.m41);
550 var m32 = (mat.$matrix.m31 * this.$matrix.m12 + mat.$matrix.m32 * this.$matrix.m22
551 + mat.$matrix.m33 * this.$matrix.m32 + mat.$matrix.m34 * this.$matrix.m42);
552 var m33 = (mat.$matrix.m31 * this.$matrix.m13 + mat.$matrix.m32 * this.$matrix.m23
553 + mat.$matrix.m33 * this.$matrix.m33 + mat.$matrix.m34 * this.$matrix.m43);
554 var m34 = (mat.$matrix.m31 * this.$matrix.m14 + mat.$matrix.m32 * this.$matrix.m24
555 + mat.$matrix.m33 * this.$matrix.m34 + mat.$matrix.m34 * this.$matrix.m44);
556
557 var m41 = (mat.$matrix.m41 * this.$matrix.m11 + mat.$matrix.m42 * this.$matrix.m21
558 + mat.$matrix.m43 * this.$matrix.m31 + mat.$matrix.m44 * this.$matrix.m41);
559 var m42 = (mat.$matrix.m41 * this.$matrix.m12 + mat.$matrix.m42 * this.$matrix.m22
560 + mat.$matrix.m43 * this.$matrix.m32 + mat.$matrix.m44 * this.$matrix.m42);
561 var m43 = (mat.$matrix.m41 * this.$matrix.m13 + mat.$matrix.m42 * this.$matrix.m23
562 + mat.$matrix.m43 * this.$matrix.m33 + mat.$matrix.m44 * this.$matrix.m43);
563 var m44 = (mat.$matrix.m41 * this.$matrix.m14 + mat.$matrix.m42 * this.$matrix.m24
564 + mat.$matrix.m43 * this.$matrix.m34 + mat.$matrix.m44 * this.$matrix.m44);
565
566 this.$matrix.m11 = m11;
567 this.$matrix.m12 = m12;
568 this.$matrix.m13 = m13;
569 this.$matrix.m14 = m14;
570
571 this.$matrix.m21 = m21;
572 this.$matrix.m22 = m22;
573 this.$matrix.m23 = m23;
574 this.$matrix.m24 = m24;
575
576 this.$matrix.m31 = m31;
577 this.$matrix.m32 = m32;
578 this.$matrix.m33 = m33;
579 this.$matrix.m34 = m34;
580
581 this.$matrix.m41 = m41;
582 this.$matrix.m42 = m42;
583 this.$matrix.m43 = m43;
584 this.$matrix.m44 = m44;
585 }
586
587 J3DIMatrix4.prototype.divide = function(divisor)
588 {
589 this.$matrix.m11 /= divisor;
590 this.$matrix.m12 /= divisor;
591 this.$matrix.m13 /= divisor;
592 this.$matrix.m14 /= divisor;
593
594 this.$matrix.m21 /= divisor;
595 this.$matrix.m22 /= divisor;
596 this.$matrix.m23 /= divisor;
597 this.$matrix.m24 /= divisor;
598
599 this.$matrix.m31 /= divisor;
600 this.$matrix.m32 /= divisor;
601 this.$matrix.m33 /= divisor;
602 this.$matrix.m34 /= divisor;
603
604 this.$matrix.m41 /= divisor;
605 this.$matrix.m42 /= divisor;
606 this.$matrix.m43 /= divisor;
607 this.$matrix.m44 /= divisor;
608
609 }
610
611 J3DIMatrix4.prototype.ortho = function(left, right, bottom, top, near, far)
612 {
613 var tx = (left + right) / (left - right);
614 var ty = (top + bottom) / (top - bottom);
615 var tz = (far + near) / (far - near);
616
617 var matrix = new J3DIMatrix4();
618 matrix.$matrix.m11 = 2 / (left - right);
619 matrix.$matrix.m12 = 0;
620 matrix.$matrix.m13 = 0;
621 matrix.$matrix.m14 = 0;
622 matrix.$matrix.m21 = 0;
623 matrix.$matrix.m22 = 2 / (top - bottom);
624 matrix.$matrix.m23 = 0;
625 matrix.$matrix.m24 = 0;
626 matrix.$matrix.m31 = 0;
627 matrix.$matrix.m32 = 0;
628 matrix.$matrix.m33 = -2 / (far - near);
629 matrix.$matrix.m34 = 0;
630 matrix.$matrix.m41 = tx;
631 matrix.$matrix.m42 = ty;
632 matrix.$matrix.m43 = tz;
633 matrix.$matrix.m44 = 1;
634
635 this.multiply(matrix);
636 }
637
638 J3DIMatrix4.prototype.frustum = function(left, right, bottom, top, near, far)
639 {
640 var matrix = new J3DIMatrix4();
641 var A = (right + left) / (right - left);
642 var B = (top + bottom) / (top - bottom);
643 var C = -(far + near) / (far - near);
644 var D = -(2 * far * near) / (far - near);
645
646 matrix.$matrix.m11 = (2 * near) / (right - left);
647 matrix.$matrix.m12 = 0;
648 matrix.$matrix.m13 = 0;
649 matrix.$matrix.m14 = 0;
650
651 matrix.$matrix.m21 = 0;
652 matrix.$matrix.m22 = 2 * near / (top - bottom);
653 matrix.$matrix.m23 = 0;
654 matrix.$matrix.m24 = 0;
655
656 matrix.$matrix.m31 = A;
657 matrix.$matrix.m32 = B;
658 matrix.$matrix.m33 = C;
659 matrix.$matrix.m34 = -1;
660
661 matrix.$matrix.m41 = 0;
662 matrix.$matrix.m42 = 0;
663 matrix.$matrix.m43 = D;
664 matrix.$matrix.m44 = 0;
665
666 this.multiply(matrix);
667 }
668
669 J3DIMatrix4.prototype.perspective = function(fovy, aspect, zNear, zFar)
670 {
671 var top = Math.tan(fovy * Math.PI / 360) * zNear;
672 var bottom = -top;
673 var left = aspect * bottom;
674 var right = aspect * top;
675 this.frustum(left, right, bottom, top, zNear, zFar);
676 }
677
678 J3DIMatrix4.prototype.lookat = function(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz)
679 {
680 if (typeof eyez == 'object' && "length" in eyez) {
681 var t = eyez;
682 upx = t[0];
683 upy = t[1];
684 upz = t[2];
685
686 t = eyey;
687 centerx = t[0];
688 centery = t[1];
689 centerz = t[2];
690
691 t = eyex;
692 eyex = t[0];
693 eyey = t[1];
694 eyez = t[2];
695 }
696
697 var matrix = new J3DIMatrix4();
698
699 // Make rotation matrix
700
701 // Z vector
702 var zx = eyex - centerx;
703 var zy = eyey - centery;
704 var zz = eyez - centerz;
705 var mag = Math.sqrt(zx * zx + zy * zy + zz * zz);
706 if (mag) {
707 zx /= mag;
708 zy /= mag;
709 zz /= mag;
710 }
711
712 // Y vector
713 var yx = upx;
714 var yy = upy;
715 var yz = upz;
716
717 // X vector = Y cross Z
718 xx = yy * zz - yz * zy;
719 xy = -yx * zz + yz * zx;
720 xz = yx * zy - yy * zx;
721
722 // Recompute Y = Z cross X
723 yx = zy * xz - zz * xy;
724 yy = -zx * xz + zz * xx;
725 yx = zx * xy - zy * xx;
726
727 // cross product gives area of parallelogram, which is < 1.0 for
728 // non-perpendicular unit-length vectors; so normalize x, y here
729
730 mag = Math.sqrt(xx * xx + xy * xy + xz * xz);
731 if (mag) {
732 xx /= mag;
733 xy /= mag;
734 xz /= mag;
735 }
736
737 mag = Math.sqrt(yx * yx + yy * yy + yz * yz);
738 if (mag) {
739 yx /= mag;
740 yy /= mag;
741 yz /= mag;
742 }
743
744 matrix.$matrix.m11 = xx;
745 matrix.$matrix.m12 = xy;
746 matrix.$matrix.m13 = xz;
747 matrix.$matrix.m14 = 0;
748
749 matrix.$matrix.m21 = yx;
750 matrix.$matrix.m22 = yy;
751 matrix.$matrix.m23 = yz;
752 matrix.$matrix.m24 = 0;
753
754 matrix.$matrix.m31 = zx;
755 matrix.$matrix.m32 = zy;
756 matrix.$matrix.m33 = zz;
757 matrix.$matrix.m34 = 0;
758
759 matrix.$matrix.m41 = 0;
760 matrix.$matrix.m42 = 0;
761 matrix.$matrix.m43 = 0;
762 matrix.$matrix.m44 = 1;
763 matrix.translate(-eyex, -eyey, -eyez);
764
765 this.multiply(matrix);
766 }
767
768 // Returns true on success, false otherwise. All params are Array objects
769 J3DIMatrix4.prototype.decompose = function(_translate, _rotate, _scale, _skew, _perspective)
770 {
771 // Normalize the matrix.
772 if (this.$matrix.m44 == 0)
773 return false;
774
775 // Gather the params
776 var translate, rotate, scale, skew, perspective;
777
778 var translate = (_translate == undefined || !("length" in _translate)) ? new J3DIVector3 : _translate;
779 var rotate = (_rotate == undefined || !("length" in _rotate)) ? new J3DIVector3 : _rotate;
780 var scale = (_scale == undefined || !("length" in _scale)) ? new J3DIVector3 : _scale;
781 var skew = (_skew == undefined || !("length" in _skew)) ? new J3DIVector3 : _skew;
782 var perspective = (_perspective == undefined || !("length" in _perspective)) ? new Array(4) : _perspective;
783
784 var matrix = new J3DIMatrix4(this);
785
786 matrix.divide(matrix.$matrix.m44);
787
788 // perspectiveMatrix is used to solve for perspective, but it also provides
789 // an easy way to test for singularity of the upper 3x3 component.
790 var perspectiveMatrix = new J3DIMatrix4(matrix);
791
792 perspectiveMatrix.$matrix.m14 = 0;
793 perspectiveMatrix.$matrix.m24 = 0;
794 perspectiveMatrix.$matrix.m34 = 0;
795 perspectiveMatrix.$matrix.m44 = 1;
796
797 if (perspectiveMatrix._determinant4x4() == 0)
798 return false;
799
800 // First, isolate perspective.
801 if (matrix.$matrix.m14 != 0 || matrix.$matrix.m24 != 0 || matrix.$matrix.m34 != 0) {
802 // rightHandSide is the right hand side of the equation.
803 var rightHandSide = [ matrix.$matrix.m14, matrix.$matrix.m24, matrix.$matrix.m34, matrix.$matrix.m44 ];
804
805 // Solve the equation by inverting perspectiveMatrix and multiplying
806 // rightHandSide by the inverse.
807 var inversePerspectiveMatrix = new J3DIMatrix4(perspectiveMatrix);
808 inversePerspectiveMatrix.invert();
809 var transposedInversePerspectiveMatrix = new J3DIMatrix4(inversePerspectiveMatrix);
810 transposedInversePerspectiveMatrix.transpose();
811 transposedInversePerspectiveMatrix.multVecMatrix(perspective, rightHandSide);
812
813 // Clear the perspective partition
814 matrix.$matrix.m14 = matrix.$matrix.m24 = matrix.$matrix.m34 = 0
815 matrix.$matrix.m44 = 1;
816 }
817 else {
818 // No perspective.
819 perspective[0] = perspective[1] = perspective[2] = 0;
820 perspective[3] = 1;
821 }
822
823 // Next take care of translation
824 translate[0] = matrix.$matrix.m41
825 matrix.$matrix.m41 = 0
826 translate[1] = matrix.$matrix.m42
827 matrix.$matrix.m42 = 0
828 translate[2] = matrix.$matrix.m43
829 matrix.$matrix.m43 = 0
830
831 // Now get scale and shear. 'row' is a 3 element array of 3 component vectors
832 var row0 = new J3DIVector3(matrix.$matrix.m11, matrix.$matrix.m12, matrix.$matrix.m13);
833 var row1 = new J3DIVector3(matrix.$matrix.m21, matrix.$matrix.m22, matrix.$matrix.m23);
834 var row2 = new J3DIVector3(matrix.$matrix.m31, matrix.$matrix.m32, matrix.$matrix.m33);
835
836 // Compute X scale factor and normalize first row.
837 scale[0] = row0.vectorLength();
838 row0.divide(scale[0]);
839
840 // Compute XY shear factor and make 2nd row orthogonal to 1st.
841 skew[0] = row0.dot(row1);
842 row1.combine(row0, 1.0, -skew[0]);
843
844 // Now, compute Y scale and normalize 2nd row.
845 scale[1] = row1.vectorLength();
846 row1.divide(scale[1]);
847 skew[0] /= scale[1];
848
849 // Compute XZ and YZ shears, orthogonalize 3rd row
850 skew[1] = row1.dot(row2);
851 row2.combine(row0, 1.0, -skew[1]);
852 skew[2] = row1.dot(row2);
853 row2.combine(row1, 1.0, -skew[2]);
854
855 // Next, get Z scale and normalize 3rd row.
856 scale[2] = row2.vectorLength();
857 row2.divide(scale[2]);
858 skew[1] /= scale[2];
859 skew[2] /= scale[2];
860
861 // At this point, the matrix (in rows) is orthonormal.
862 // Check for a coordinate system flip. If the determinant
863 // is -1, then negate the matrix and the scaling factors.
864 var pdum3 = new J3DIVector3(row1);
865 pdum3.cross(row2);
866 if (row0.dot(pdum3) < 0) {
867 for (i = 0; i < 3; i++) {
868 scale[i] *= -1;
869 row[0][i] *= -1;
870 row[1][i] *= -1;
871 row[2][i] *= -1;
872 }
873 }
874
875 // Now, get the rotations out
876 rotate[1] = Math.asin(-row0[2]);
877 if (Math.cos(rotate[1]) != 0) {
878 rotate[0] = Math.atan2(row1[2], row2[2]);
879 rotate[2] = Math.atan2(row0[1], row0[0]);
880 }
881 else {
882 rotate[0] = Math.atan2(-row2[0], row1[1]);
883 rotate[2] = 0;
884 }
885
886 // Convert rotations to degrees
887 var rad2deg = 180 / Math.PI;
888 rotate[0] *= rad2deg;
889 rotate[1] *= rad2deg;
890 rotate[2] *= rad2deg;
891
892 return true;
893 }
894
895 J3DIMatrix4.prototype._determinant2x2 = function(a, b, c, d)
896 {
897 return a * d - b * c;
898 }
899
900 J3DIMatrix4.prototype._determinant3x3 = function(a1, a2, a3, b1, b2, b3, c1, c2, c3)
901 {
902 return a1 * this._determinant2x2(b2, b3, c2, c3)
903 - b1 * this._determinant2x2(a2, a3, c2, c3)
904 + c1 * this._determinant2x2(a2, a3, b2, b3);
905 }
906
907 J3DIMatrix4.prototype._determinant4x4 = function()
908 {
909 var a1 = this.$matrix.m11;
910 var b1 = this.$matrix.m12;
911 var c1 = this.$matrix.m13;
912 var d1 = this.$matrix.m14;
913
914 var a2 = this.$matrix.m21;
915 var b2 = this.$matrix.m22;
916 var c2 = this.$matrix.m23;
917 var d2 = this.$matrix.m24;
918
919 var a3 = this.$matrix.m31;
920 var b3 = this.$matrix.m32;
921 var c3 = this.$matrix.m33;
922 var d3 = this.$matrix.m34;
923
924 var a4 = this.$matrix.m41;
925 var b4 = this.$matrix.m42;
926 var c4 = this.$matrix.m43;
927 var d4 = this.$matrix.m44;
928
929 return a1 * this._determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4)
930 - b1 * this._determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4)
931 + c1 * this._determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4)
932 - d1 * this._determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
933 }
934
935 J3DIMatrix4.prototype._makeAdjoint = function()
936 {
937 var a1 = this.$matrix.m11;
938 var b1 = this.$matrix.m12;
939 var c1 = this.$matrix.m13;
940 var d1 = this.$matrix.m14;
941
942 var a2 = this.$matrix.m21;
943 var b2 = this.$matrix.m22;
944 var c2 = this.$matrix.m23;
945 var d2 = this.$matrix.m24;
946
947 var a3 = this.$matrix.m31;
948 var b3 = this.$matrix.m32;
949 var c3 = this.$matrix.m33;
950 var d3 = this.$matrix.m34;
951
952 var a4 = this.$matrix.m41;
953 var b4 = this.$matrix.m42;
954 var c4 = this.$matrix.m43;
955 var d4 = this.$matrix.m44;
956
957 // Row column labeling reversed since we transpose rows & columns
958 this.$matrix.m11 = this._determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4);
959 this.$matrix.m21 = - this._determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4);
960 this.$matrix.m31 = this._determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4);
961 this.$matrix.m41 = - this._determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
962
963 this.$matrix.m12 = - this._determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4);
964 this.$matrix.m22 = this._determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4);
965 this.$matrix.m32 = - this._determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4);
966 this.$matrix.m42 = this._determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4);
967
968 this.$matrix.m13 = this._determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4);
969 this.$matrix.m23 = - this._determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4);
970 this.$matrix.m33 = this._determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4);
971 this.$matrix.m43 = - this._determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4);
972
973 this.$matrix.m14 = - this._determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3);
974 this.$matrix.m24 = this._determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3);
975 this.$matrix.m34 = - this._determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3);
976 this.$matrix.m44 = this._determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3);
977 }
978
979 //
980 // J3DIVector3
981 //
982 J3DIVector3 = function(x,y,z)
983 {
984 this.load(x,y,z);
985 }
986
987 J3DIVector3.prototype.load = function(x,y,z)
988 {
989 if (typeof x == 'object' && "length" in x) {
990 this[0] = x[0];
991 this[1] = x[1];
992 this[2] = x[2];
993 }
994 else if (typeof x == 'number') {
995 this[0] = x;
996 this[1] = y;
997 this[2] = z;
998 }
999 else {
1000 this[0] = 0;
1001 this[1] = 0;
1002 this[2] = 0;
1003 }
1004 }
1005
1006 J3DIVector3.prototype.getAsArray = function()
1007 {
1008 return [ this[0], this[1], this[2] ];
1009 }
1010
1011 J3DIVector3.prototype.getAsFloat32Array = function()
1012 {
1013 return new Float32Array(this.getAsArray());
1014 }
1015
1016 J3DIVector3.prototype.vectorLength = function()
1017 {
1018 return Math.sqrt(this[0] * this[0] + this[1] * this[1] + this[2] * this[2]);
1019 }
1020
1021 J3DIVector3.prototype.divide = function(divisor)
1022 {
1023 this[0] /= divisor; this[1] /= divisor; this[2] /= divisor;
1024 }
1025
1026 J3DIVector3.prototype.cross = function(v)
1027 {
1028 this[0] = this[1] * v[2] - this[2] * v[1];
1029 this[1] = -this[0] * v[2] + this[2] * v[0];
1030 this[2] = this[0] * v[1] - this[1] * v[0];
1031 }
1032
1033 J3DIVector3.prototype.dot = function(v)
1034 {
1035 return this[0] * v[0] + this[1] * v[1] + this[2] * v[2];
1036 }
1037
1038 J3DIVector3.prototype.combine = function(v, ascl, bscl)
1039 {
1040 this[0] = (ascl * this[0]) + (bscl * v[0]);
1041 this[1] = (ascl * this[1]) + (bscl * v[1]);
1042 this[2] = (ascl * this[2]) + (bscl * v[2]);
1043 }
1044
1045 J3DIVector3.prototype.multVecMatrix = function(matrix)
1046 {
1047 var x = this[0];
1048 var y = this[1];
1049 var z = this[2];
1050
1051 this[0] = matrix.$matrix.m41 + x * matrix.$matrix.m11 + y * matrix.$matrix.m21 + z * matrix.$matrix.m31;
1052 this[1] = matrix.$matrix.m42 + x * matrix.$matrix.m12 + y * matrix.$matrix.m22 + z * matrix.$matrix.m32;
1053 this[2] = matrix.$matrix.m43 + x * matrix.$matrix.m13 + y * matrix.$matrix.m23 + z * matrix.$matrix.m33;
1054 var w = matrix.$matrix.m44 + x * matrix.$matrix.m14 + y * matrix.$matrix.m24 + z * matrix.$matrix.m34;
1055 if (w != 1 && w != 0) {
1056 this[0] /= w;
1057 this[1] /= w;
1058 this[2] /= w;
1059 }
1060 }
1061
1062 J3DIVector3.prototype.toString = function()
1063 {
1064 return "["+this[0]+","+this[1]+","+this[2]+"]";
1065 }