comparison resources/render/J3DIMath.js @ 0:0b8d8ce99f46 default tip

commit
author Daiki KINJYO <e085722@ie.u-ryukyu.ac.jp>
date Mon, 14 Feb 2011 17:06:56 +0900
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:0b8d8ce99f46
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 J3DIMatrix4.prototype.getAsArrayMatrix = function(mat)
669 {
670 mat.m11 = this.$matrix.m11; mat.m12 = this.$matrix.m12;
671 mat.m13 = this.$matrix.m13; mat.m14 = this.$matrix.m14,
672 mat.m21 = this.$matrix.m21; mat.m22 = this.$matrix.m22;
673 mat.m23 = this.$matrix.m23; mat.m25 = this.$matrix.m24;
674 mat.m31 = this.$matrix.m31; mat.m32 = this.$matrix.m32;
675 mat.m33 = this.$matrix.m33; mat.m34 = this.$matrix.m34;
676 mat.m41 = this.$matrix.m41; mat.m42 = this.$matrix.m42;
677 mat.m43 = this.$matrix.m43; mat.m44 = this.$matrix.m44;
678 }
679
680
681 J3DIMatrix4.prototype.perspective = function(fovy, aspect, zNear, zFar)
682 {
683 var top = Math.tan(fovy * Math.PI / 360) * zNear;
684 var bottom = -top;
685 var left = aspect * bottom;
686 var right = aspect * top;
687 this.frustum(left, right, bottom, top, zNear, zFar);
688 }
689
690 J3DIMatrix4.prototype.lookat = function(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz)
691 {
692 if (typeof eyez == 'object' && "length" in eyez) {
693 var t = eyez;
694 upx = t[0];
695 upy = t[1];
696 upz = t[2];
697
698 t = eyey;
699 centerx = t[0];
700 centery = t[1];
701 centerz = t[2];
702
703 t = eyex;
704 eyex = t[0];
705 eyey = t[1];
706 eyez = t[2];
707 }
708
709
710
711 var matrix = new J3DIMatrix4();
712
713 // Make rotation matrix
714
715 // Z vector
716 var zx = eyex - centerx;
717 var zy = eyey - centery;
718 var zz = eyez - centerz;
719 var mag = Math.sqrt(zx * zx + zy * zy + zz * zz);
720 if (mag) {
721 zx /= mag;
722 zy /= mag;
723 zz /= mag;
724 }
725
726 // Y vector
727 var yx = upx;
728 var yy = upy;
729 var yz = upz;
730
731 // X vector = Y cross Z
732 xx = yy * zz - yz * zy;
733 xy = -yx * zz + yz * zx;
734 xz = yx * zy - yy * zx;
735
736 // Recompute Y = Z cross X
737 yx = zy * xz - zz * xy;
738 yy = -zx * xz + zz * xx;
739 yx = zx * xy - zy * xx;
740
741 // cross product gives area of parallelogram, which is < 1.0 for
742 // non-perpendicular unit-length vectors; so normalize x, y here
743
744 mag = Math.sqrt(xx * xx + xy * xy + xz * xz);
745 if (mag) {
746 xx /= mag;
747 xy /= mag;
748 xz /= mag;
749 }
750
751 mag = Math.sqrt(yx * yx + yy * yy + yz * yz);
752 if (mag) {
753 yx /= mag;
754 yy /= mag;
755 yz /= mag;
756 }
757
758 matrix.$matrix.m11 = xx;
759 matrix.$matrix.m12 = xy;
760 matrix.$matrix.m13 = xz;
761 matrix.$matrix.m14 = 0;
762
763 matrix.$matrix.m21 = yx;
764 matrix.$matrix.m22 = yy;
765 matrix.$matrix.m23 = yz;
766 matrix.$matrix.m24 = 0;
767
768 matrix.$matrix.m31 = zx;
769 matrix.$matrix.m32 = zy;
770 matrix.$matrix.m33 = zz;
771 matrix.$matrix.m34 = 0;
772
773 matrix.$matrix.m41 = 0;
774 matrix.$matrix.m42 = 0;
775 matrix.$matrix.m43 = 0;
776 matrix.$matrix.m44 = 1;
777 matrix.translate(-eyex, -eyey, -eyez);
778
779 this.multiply(matrix);
780 }
781
782 // Returns true on success, false otherwise. All params are Array objects
783 J3DIMatrix4.prototype.decompose = function(_translate, _rotate, _scale, _skew, _perspective)
784 {
785 // Normalize the matrix.
786 if (this.$matrix.m44 == 0)
787 return false;
788
789 // Gather the params
790 var translate, rotate, scale, skew, perspective;
791
792 var translate = (_translate == undefined || !("length" in _translate)) ? new J3DIVector3 : _translate;
793 var rotate = (_rotate == undefined || !("length" in _rotate)) ? new J3DIVector3 : _rotate;
794 var scale = (_scale == undefined || !("length" in _scale)) ? new J3DIVector3 : _scale;
795 var skew = (_skew == undefined || !("length" in _skew)) ? new J3DIVector3 : _skew;
796 var perspective = (_perspective == undefined || !("length" in _perspective)) ? new Array(4) : _perspective;
797
798 var matrix = new J3DIMatrix4(this);
799
800 matrix.divide(matrix.$matrix.m44);
801
802 // perspectiveMatrix is used to solve for perspective, but it also provides
803 // an easy way to test for singularity of the upper 3x3 component.
804 var perspectiveMatrix = new J3DIMatrix4(matrix);
805
806 perspectiveMatrix.$matrix.m14 = 0;
807 perspectiveMatrix.$matrix.m24 = 0;
808 perspectiveMatrix.$matrix.m34 = 0;
809 perspectiveMatrix.$matrix.m44 = 1;
810
811 if (perspectiveMatrix._determinant4x4() == 0)
812 return false;
813
814 // First, isolate perspective.
815 if (matrix.$matrix.m14 != 0 || matrix.$matrix.m24 != 0 || matrix.$matrix.m34 != 0) {
816 // rightHandSide is the right hand side of the equation.
817 var rightHandSide = [ matrix.$matrix.m14, matrix.$matrix.m24, matrix.$matrix.m34, matrix.$matrix.m44 ];
818
819 // Solve the equation by inverting perspectiveMatrix and multiplying
820 // rightHandSide by the inverse.
821 var inversePerspectiveMatrix = new J3DIMatrix4(perspectiveMatrix);
822 inversePerspectiveMatrix.invert();
823 var transposedInversePerspectiveMatrix = new J3DIMatrix4(inversePerspectiveMatrix);
824 transposedInversePerspectiveMatrix.transpose();
825 transposedInversePerspectiveMatrix.multVecMatrix(perspective, rightHandSide);
826
827 // Clear the perspective partition
828 matrix.$matrix.m14 = matrix.$matrix.m24 = matrix.$matrix.m34 = 0
829 matrix.$matrix.m44 = 1;
830 }
831 else {
832 // No perspective.
833 perspective[0] = perspective[1] = perspective[2] = 0;
834 perspective[3] = 1;
835 }
836
837 // Next take care of translation
838 translate[0] = matrix.$matrix.m41
839 matrix.$matrix.m41 = 0
840 translate[1] = matrix.$matrix.m42
841 matrix.$matrix.m42 = 0
842 translate[2] = matrix.$matrix.m43
843 matrix.$matrix.m43 = 0
844
845 // Now get scale and shear. 'row' is a 3 element array of 3 component vectors
846 var row0 = new J3DIVector3(matrix.$matrix.m11, matrix.$matrix.m12, matrix.$matrix.m13);
847 var row1 = new J3DIVector3(matrix.$matrix.m21, matrix.$matrix.m22, matrix.$matrix.m23);
848 var row2 = new J3DIVector3(matrix.$matrix.m31, matrix.$matrix.m32, matrix.$matrix.m33);
849
850 // Compute X scale factor and normalize first row.
851 scale[0] = row0.vectorLength();
852 row0.divide(scale[0]);
853
854 // Compute XY shear factor and make 2nd row orthogonal to 1st.
855 skew[0] = row0.dot(row1);
856 row1.combine(row0, 1.0, -skew[0]);
857
858 // Now, compute Y scale and normalize 2nd row.
859 scale[1] = row1.vectorLength();
860 row1.divide(scale[1]);
861 skew[0] /= scale[1];
862
863 // Compute XZ and YZ shears, orthogonalize 3rd row
864 skew[1] = row1.dot(row2);
865 row2.combine(row0, 1.0, -skew[1]);
866 skew[2] = row1.dot(row2);
867 row2.combine(row1, 1.0, -skew[2]);
868
869 // Next, get Z scale and normalize 3rd row.
870 scale[2] = row2.vectorLength();
871 row2.divide(scale[2]);
872 skew[1] /= scale[2];
873 skew[2] /= scale[2];
874
875 // At this point, the matrix (in rows) is orthonormal.
876 // Check for a coordinate system flip. If the determinant
877 // is -1, then negate the matrix and the scaling factors.
878 var pdum3 = new J3DIVector3(row1);
879 pdum3.cross(row2);
880 if (row0.dot(pdum3) < 0) {
881 for (i = 0; i < 3; i++) {
882 scale[i] *= -1;
883 row[0][i] *= -1;
884 row[1][i] *= -1;
885 row[2][i] *= -1;
886 }
887 }
888
889 // Now, get the rotations out
890 rotate[1] = Math.asin(-row0[2]);
891 if (Math.cos(rotate[1]) != 0) {
892 rotate[0] = Math.atan2(row1[2], row2[2]);
893 rotate[2] = Math.atan2(row0[1], row0[0]);
894 }
895 else {
896 rotate[0] = Math.atan2(-row2[0], row1[1]);
897 rotate[2] = 0;
898 }
899
900 // Convert rotations to degrees
901 var rad2deg = 180 / Math.PI;
902 rotate[0] *= rad2deg;
903 rotate[1] *= rad2deg;
904 rotate[2] *= rad2deg;
905
906 return true;
907 }
908
909 J3DIMatrix4.prototype._determinant2x2 = function(a, b, c, d)
910 {
911 return a * d - b * c;
912 }
913
914 J3DIMatrix4.prototype._determinant3x3 = function(a1, a2, a3, b1, b2, b3, c1, c2, c3)
915 {
916 return a1 * this._determinant2x2(b2, b3, c2, c3)
917 - b1 * this._determinant2x2(a2, a3, c2, c3)
918 + c1 * this._determinant2x2(a2, a3, b2, b3);
919 }
920
921 J3DIMatrix4.prototype._determinant4x4 = function()
922 {
923 var a1 = this.$matrix.m11;
924 var b1 = this.$matrix.m12;
925 var c1 = this.$matrix.m13;
926 var d1 = this.$matrix.m14;
927
928 var a2 = this.$matrix.m21;
929 var b2 = this.$matrix.m22;
930 var c2 = this.$matrix.m23;
931 var d2 = this.$matrix.m24;
932
933 var a3 = this.$matrix.m31;
934 var b3 = this.$matrix.m32;
935 var c3 = this.$matrix.m33;
936 var d3 = this.$matrix.m34;
937
938 var a4 = this.$matrix.m41;
939 var b4 = this.$matrix.m42;
940 var c4 = this.$matrix.m43;
941 var d4 = this.$matrix.m44;
942
943 return a1 * this._determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4)
944 - b1 * this._determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4)
945 + c1 * this._determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4)
946 - d1 * this._determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
947 }
948
949
950
951
952 J3DIMatrix4.prototype._makeAdjoint = function()
953 {
954 var a1 = this.$matrix.m11;
955 var b1 = this.$matrix.m12;
956 var c1 = this.$matrix.m13;
957 var d1 = this.$matrix.m14;
958
959 var a2 = this.$matrix.m21;
960 var b2 = this.$matrix.m22;
961 var c2 = this.$matrix.m23;
962 var d2 = this.$matrix.m24;
963
964 var a3 = this.$matrix.m31;
965 var b3 = this.$matrix.m32;
966 var c3 = this.$matrix.m33;
967 var d3 = this.$matrix.m34;
968
969 var a4 = this.$matrix.m41;
970 var b4 = this.$matrix.m42;
971 var c4 = this.$matrix.m43;
972 var d4 = this.$matrix.m44;
973
974 // Row column labeling reversed since we transpose rows & columns
975 this.$matrix.m11 = this._determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4);
976 this.$matrix.m21 = - this._determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4);
977 this.$matrix.m31 = this._determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4);
978 this.$matrix.m41 = - this._determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
979
980 this.$matrix.m12 = - this._determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4);
981 this.$matrix.m22 = this._determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4);
982 this.$matrix.m32 = - this._determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4);
983 this.$matrix.m42 = this._determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4);
984
985 this.$matrix.m13 = this._determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4);
986 this.$matrix.m23 = - this._determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4);
987 this.$matrix.m33 = this._determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4);
988 this.$matrix.m43 = - this._determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4);
989
990 this.$matrix.m14 = - this._determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3);
991 this.$matrix.m24 = this._determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3);
992 this.$matrix.m34 = - this._determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3);
993 this.$matrix.m44 = this._determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3);
994 }
995
996 //
997 // J3DIVector3
998 //
999 J3DIVector3 = function(x,y,z)
1000 {
1001 this.load(x,y,z);
1002 }
1003
1004 J3DIVector3.prototype.load = function(x,y,z)
1005 {
1006 if (typeof x == 'object' && "length" in x) {
1007 this[0] = x[0];
1008 this[1] = x[1];
1009 this[2] = x[2];
1010 }
1011 else if (typeof x == 'number') {
1012 this[0] = x;
1013 this[1] = y;
1014 this[2] = z;
1015 }
1016 else {
1017 this[0] = 0;
1018 this[1] = 0;
1019 this[2] = 0;
1020 }
1021 }
1022
1023 J3DIVector3.prototype.getAsArray = function()
1024 {
1025 return [ this[0], this[1], this[2] ];
1026 }
1027
1028 J3DIVector3.prototype.getAsFloat32Array = function()
1029 {
1030 return new Float32Array(this.getAsArray());
1031 }
1032
1033 J3DIVector3.prototype.vectorLength = function()
1034 {
1035 return Math.sqrt(this[0] * this[0] + this[1] * this[1] + this[2] * this[2]);
1036 }
1037
1038 J3DIVector3.prototype.divide = function(divisor)
1039 {
1040 this[0] /= divisor; this[1] /= divisor; this[2] /= divisor;
1041 }
1042
1043 J3DIVector3.prototype.cross = function(v)
1044 {
1045 this[0] = this[1] * v[2] - this[2] * v[1];
1046 this[1] = -this[0] * v[2] + this[2] * v[0];
1047 this[2] = this[0] * v[1] - this[1] * v[0];
1048 }
1049
1050 J3DIVector3.prototype.dot = function(v)
1051 {
1052 return this[0] * v[0] + this[1] * v[1] + this[2] * v[2];
1053 }
1054
1055 J3DIVector3.prototype.combine = function(v, ascl, bscl)
1056 {
1057 this[0] = (ascl * this[0]) + (bscl * v[0]);
1058 this[1] = (ascl * this[1]) + (bscl * v[1]);
1059 this[2] = (ascl * this[2]) + (bscl * v[2]);
1060 }
1061
1062 J3DIVector3.prototype.multVecMatrix = function(matrix)
1063 {
1064 var x = this[0];
1065 var y = this[1];
1066 var z = this[2];
1067
1068 this[0] = matrix.$matrix.m41 + x * matrix.$matrix.m11 + y * matrix.$matrix.m21 + z * matrix.$matrix.m31;
1069 this[1] = matrix.$matrix.m42 + x * matrix.$matrix.m12 + y * matrix.$matrix.m22 + z * matrix.$matrix.m32;
1070 this[2] = matrix.$matrix.m43 + x * matrix.$matrix.m13 + y * matrix.$matrix.m23 + z * matrix.$matrix.m33;
1071 var w = matrix.$matrix.m44 + x * matrix.$matrix.m14 + y * matrix.$matrix.m24 + z * matrix.$matrix.m34;
1072 if (w != 1 && w != 0) {
1073 this[0] /= w;
1074 this[1] /= w;
1075 this[2] /= w;
1076 }
1077 }
1078
1079 J3DIVector3.prototype.toString = function()
1080 {
1081 return "["+this[0]+","+this[1]+","+this[2]+"]";
1082 }