sawine@2
|
1 |
/*
|
sawine@2
|
2 |
CanvasMatrix4 class
|
sawine@2
|
3 |
|
sawine@2
|
4 |
This class implements a 4x4 matrix. It has functions which
|
sawine@2
|
5 |
duplicate the functionality of the OpenGL matrix stack and
|
sawine@2
|
6 |
glut functions.
|
sawine@2
|
7 |
|
sawine@2
|
8 |
IDL:
|
sawine@2
|
9 |
|
sawine@2
|
10 |
[
|
sawine@2
|
11 |
Constructor(in CanvasMatrix4 matrix), // copy passed matrix into new CanvasMatrix4
|
sawine@2
|
12 |
Constructor(in sequence<float> array) // create new CanvasMatrix4 with 16 floats (row major)
|
sawine@2
|
13 |
Constructor() // create new CanvasMatrix4 with identity matrix
|
sawine@2
|
14 |
]
|
sawine@2
|
15 |
interface CanvasMatrix4 {
|
sawine@2
|
16 |
attribute float m11;
|
sawine@2
|
17 |
attribute float m12;
|
sawine@2
|
18 |
attribute float m13;
|
sawine@2
|
19 |
attribute float m14;
|
sawine@2
|
20 |
attribute float m21;
|
sawine@2
|
21 |
attribute float m22;
|
sawine@2
|
22 |
attribute float m23;
|
sawine@2
|
23 |
attribute float m24;
|
sawine@2
|
24 |
attribute float m31;
|
sawine@2
|
25 |
attribute float m32;
|
sawine@2
|
26 |
attribute float m33;
|
sawine@2
|
27 |
attribute float m34;
|
sawine@2
|
28 |
attribute float m41;
|
sawine@2
|
29 |
attribute float m42;
|
sawine@2
|
30 |
attribute float m43;
|
sawine@2
|
31 |
attribute float m44;
|
sawine@2
|
32 |
|
sawine@2
|
33 |
void load(in CanvasMatrix4 matrix); // copy the values from the passed matrix
|
sawine@2
|
34 |
void load(in sequence<float> array); // copy 16 floats into the matrix
|
sawine@2
|
35 |
sequence<float> getAsArray(); // return the matrix as an array of 16 floats
|
sawine@2
|
36 |
WebGLFloatArray getAsCanvasFloatArray(); // return the matrix as a WebGLFloatArray with 16 values
|
sawine@2
|
37 |
void makeIdentity(); // replace the matrix with identity
|
sawine@2
|
38 |
void transpose(); // replace the matrix with its transpose
|
sawine@2
|
39 |
void invert(); // replace the matrix with its inverse
|
sawine@2
|
40 |
|
sawine@2
|
41 |
void translate(in float x, in float y, in float z); // multiply the matrix by passed translation values on the right
|
sawine@2
|
42 |
void scale(in float x, in float y, in float z); // multiply the matrix by passed scale values on the right
|
sawine@2
|
43 |
void rotate(in float angle, // multiply the matrix by passed rotation values on the right
|
sawine@2
|
44 |
in float x, in float y, in float z); // (angle is in degrees)
|
sawine@2
|
45 |
void multRight(in CanvasMatrix matrix); // multiply the matrix by the passed matrix on the right
|
sawine@2
|
46 |
void multLeft(in CanvasMatrix matrix); // multiply the matrix by the passed matrix on the left
|
sawine@2
|
47 |
void ortho(in float left, in float right, // multiply the matrix by the passed ortho values on the right
|
sawine@2
|
48 |
in float bottom, in float top,
|
sawine@2
|
49 |
in float near, in float far);
|
sawine@2
|
50 |
void frustum(in float left, in float right, // multiply the matrix by the passed frustum values on the right
|
sawine@2
|
51 |
in float bottom, in float top,
|
sawine@2
|
52 |
in float near, in float far);
|
sawine@2
|
53 |
void perspective(in float fovy, in float aspect, // multiply the matrix by the passed perspective values on the right
|
sawine@2
|
54 |
in float zNear, in float zFar);
|
sawine@2
|
55 |
void lookat(in float eyex, in float eyey, in float eyez, // multiply the matrix by the passed lookat
|
sawine@2
|
56 |
in float ctrx, in float ctry, in float ctrz, // values on the right
|
sawine@2
|
57 |
in float upx, in float upy, in float upz);
|
sawine@2
|
58 |
}
|
sawine@2
|
59 |
*/
|
sawine@2
|
60 |
|
sawine@2
|
61 |
CanvasMatrix4 = function(m)
|
sawine@2
|
62 |
{
|
sawine@2
|
63 |
if (typeof m == 'object') {
|
sawine@2
|
64 |
if ("length" in m && m.length >= 16) {
|
sawine@2
|
65 |
this.load(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13], m[14], m[15]);
|
sawine@2
|
66 |
return;
|
sawine@2
|
67 |
}
|
sawine@2
|
68 |
else if (m instanceof CanvasMatrix4) {
|
sawine@2
|
69 |
this.load(m);
|
sawine@2
|
70 |
return;
|
sawine@2
|
71 |
}
|
sawine@2
|
72 |
}
|
sawine@2
|
73 |
this.makeIdentity();
|
sawine@2
|
74 |
}
|
sawine@2
|
75 |
|
sawine@2
|
76 |
CanvasMatrix4.prototype.load = function()
|
sawine@2
|
77 |
{
|
sawine@2
|
78 |
if (arguments.length == 1 && typeof arguments[0] == 'object') {
|
sawine@2
|
79 |
var matrix = arguments[0];
|
sawine@2
|
80 |
|
sawine@2
|
81 |
if ("length" in matrix && matrix.length == 16) {
|
sawine@2
|
82 |
this.m11 = matrix[0];
|
sawine@2
|
83 |
this.m12 = matrix[1];
|
sawine@2
|
84 |
this.m13 = matrix[2];
|
sawine@2
|
85 |
this.m14 = matrix[3];
|
sawine@2
|
86 |
|
sawine@2
|
87 |
this.m21 = matrix[4];
|
sawine@2
|
88 |
this.m22 = matrix[5];
|
sawine@2
|
89 |
this.m23 = matrix[6];
|
sawine@2
|
90 |
this.m24 = matrix[7];
|
sawine@2
|
91 |
|
sawine@2
|
92 |
this.m31 = matrix[8];
|
sawine@2
|
93 |
this.m32 = matrix[9];
|
sawine@2
|
94 |
this.m33 = matrix[10];
|
sawine@2
|
95 |
this.m34 = matrix[11];
|
sawine@2
|
96 |
|
sawine@2
|
97 |
this.m41 = matrix[12];
|
sawine@2
|
98 |
this.m42 = matrix[13];
|
sawine@2
|
99 |
this.m43 = matrix[14];
|
sawine@2
|
100 |
this.m44 = matrix[15];
|
sawine@2
|
101 |
return;
|
sawine@2
|
102 |
}
|
sawine@2
|
103 |
|
sawine@2
|
104 |
if (arguments[0] instanceof CanvasMatrix4) {
|
sawine@2
|
105 |
|
sawine@2
|
106 |
this.m11 = matrix.m11;
|
sawine@2
|
107 |
this.m12 = matrix.m12;
|
sawine@2
|
108 |
this.m13 = matrix.m13;
|
sawine@2
|
109 |
this.m14 = matrix.m14;
|
sawine@2
|
110 |
|
sawine@2
|
111 |
this.m21 = matrix.m21;
|
sawine@2
|
112 |
this.m22 = matrix.m22;
|
sawine@2
|
113 |
this.m23 = matrix.m23;
|
sawine@2
|
114 |
this.m24 = matrix.m24;
|
sawine@2
|
115 |
|
sawine@2
|
116 |
this.m31 = matrix.m31;
|
sawine@2
|
117 |
this.m32 = matrix.m32;
|
sawine@2
|
118 |
this.m33 = matrix.m33;
|
sawine@2
|
119 |
this.m34 = matrix.m34;
|
sawine@2
|
120 |
|
sawine@2
|
121 |
this.m41 = matrix.m41;
|
sawine@2
|
122 |
this.m42 = matrix.m42;
|
sawine@2
|
123 |
this.m43 = matrix.m43;
|
sawine@2
|
124 |
this.m44 = matrix.m44;
|
sawine@2
|
125 |
return;
|
sawine@2
|
126 |
}
|
sawine@2
|
127 |
}
|
sawine@2
|
128 |
|
sawine@2
|
129 |
this.makeIdentity();
|
sawine@2
|
130 |
}
|
sawine@2
|
131 |
|
sawine@2
|
132 |
CanvasMatrix4.prototype.getAsArray = function()
|
sawine@2
|
133 |
{
|
sawine@2
|
134 |
return [
|
sawine@2
|
135 |
this.m11, this.m12, this.m13, this.m14,
|
sawine@2
|
136 |
this.m21, this.m22, this.m23, this.m24,
|
sawine@2
|
137 |
this.m31, this.m32, this.m33, this.m34,
|
sawine@2
|
138 |
this.m41, this.m42, this.m43, this.m44
|
sawine@2
|
139 |
];
|
sawine@2
|
140 |
}
|
sawine@2
|
141 |
|
sawine@2
|
142 |
CanvasMatrix4.prototype.getAsCanvasFloatArray = function()
|
sawine@2
|
143 |
{
|
sawine@2
|
144 |
return new WebGLFloatArray(this.getAsArray());
|
sawine@2
|
145 |
}
|
sawine@2
|
146 |
|
sawine@2
|
147 |
CanvasMatrix4.prototype.makeIdentity = function()
|
sawine@2
|
148 |
{
|
sawine@2
|
149 |
this.m11 = 1;
|
sawine@2
|
150 |
this.m12 = 0;
|
sawine@2
|
151 |
this.m13 = 0;
|
sawine@2
|
152 |
this.m14 = 0;
|
sawine@2
|
153 |
|
sawine@2
|
154 |
this.m21 = 0;
|
sawine@2
|
155 |
this.m22 = 1;
|
sawine@2
|
156 |
this.m23 = 0;
|
sawine@2
|
157 |
this.m24 = 0;
|
sawine@2
|
158 |
|
sawine@2
|
159 |
this.m31 = 0;
|
sawine@2
|
160 |
this.m32 = 0;
|
sawine@2
|
161 |
this.m33 = 1;
|
sawine@2
|
162 |
this.m34 = 0;
|
sawine@2
|
163 |
|
sawine@2
|
164 |
this.m41 = 0;
|
sawine@2
|
165 |
this.m42 = 0;
|
sawine@2
|
166 |
this.m43 = 0;
|
sawine@2
|
167 |
this.m44 = 1;
|
sawine@2
|
168 |
}
|
sawine@2
|
169 |
|
sawine@2
|
170 |
CanvasMatrix4.prototype.transpose = function()
|
sawine@2
|
171 |
{
|
sawine@2
|
172 |
var tmp = this.m12;
|
sawine@2
|
173 |
this.m12 = this.m21;
|
sawine@2
|
174 |
this.m21 = tmp;
|
sawine@2
|
175 |
|
sawine@2
|
176 |
tmp = this.m13;
|
sawine@2
|
177 |
this.m13 = this.m31;
|
sawine@2
|
178 |
this.m31 = tmp;
|
sawine@2
|
179 |
|
sawine@2
|
180 |
tmp = this.m14;
|
sawine@2
|
181 |
this.m14 = this.m41;
|
sawine@2
|
182 |
this.m41 = tmp;
|
sawine@2
|
183 |
|
sawine@2
|
184 |
tmp = this.m23;
|
sawine@2
|
185 |
this.m23 = this.m32;
|
sawine@2
|
186 |
this.m32 = tmp;
|
sawine@2
|
187 |
|
sawine@2
|
188 |
tmp = this.m24;
|
sawine@2
|
189 |
this.m24 = this.m42;
|
sawine@2
|
190 |
this.m42 = tmp;
|
sawine@2
|
191 |
|
sawine@2
|
192 |
tmp = this.m34;
|
sawine@2
|
193 |
this.m34 = this.m43;
|
sawine@2
|
194 |
this.m43 = tmp;
|
sawine@2
|
195 |
}
|
sawine@2
|
196 |
|
sawine@2
|
197 |
CanvasMatrix4.prototype.invert = function()
|
sawine@2
|
198 |
{
|
sawine@2
|
199 |
// Calculate the 4x4 determinant
|
sawine@2
|
200 |
// If the determinant is zero,
|
sawine@2
|
201 |
// then the inverse matrix is not unique.
|
sawine@2
|
202 |
var det = this._determinant4x4();
|
sawine@2
|
203 |
|
sawine@2
|
204 |
if (Math.abs(det) < 1e-8)
|
sawine@2
|
205 |
return null;
|
sawine@2
|
206 |
|
sawine@2
|
207 |
this._makeAdjoint();
|
sawine@2
|
208 |
|
sawine@2
|
209 |
// Scale the adjoint matrix to get the inverse
|
sawine@2
|
210 |
this.m11 /= det;
|
sawine@2
|
211 |
this.m12 /= det;
|
sawine@2
|
212 |
this.m13 /= det;
|
sawine@2
|
213 |
this.m14 /= det;
|
sawine@2
|
214 |
|
sawine@2
|
215 |
this.m21 /= det;
|
sawine@2
|
216 |
this.m22 /= det;
|
sawine@2
|
217 |
this.m23 /= det;
|
sawine@2
|
218 |
this.m24 /= det;
|
sawine@2
|
219 |
|
sawine@2
|
220 |
this.m31 /= det;
|
sawine@2
|
221 |
this.m32 /= det;
|
sawine@2
|
222 |
this.m33 /= det;
|
sawine@2
|
223 |
this.m34 /= det;
|
sawine@2
|
224 |
|
sawine@2
|
225 |
this.m41 /= det;
|
sawine@2
|
226 |
this.m42 /= det;
|
sawine@2
|
227 |
this.m43 /= det;
|
sawine@2
|
228 |
this.m44 /= det;
|
sawine@2
|
229 |
}
|
sawine@2
|
230 |
|
sawine@2
|
231 |
CanvasMatrix4.prototype.translate = function(x,y,z)
|
sawine@2
|
232 |
{
|
sawine@2
|
233 |
if (x == undefined)
|
sawine@2
|
234 |
x = 0;
|
sawine@2
|
235 |
if (y == undefined)
|
sawine@2
|
236 |
y = 0;
|
sawine@2
|
237 |
if (z == undefined)
|
sawine@2
|
238 |
z = 0;
|
sawine@2
|
239 |
|
sawine@2
|
240 |
var matrix = new CanvasMatrix4();
|
sawine@2
|
241 |
matrix.m41 = x;
|
sawine@2
|
242 |
matrix.m42 = y;
|
sawine@2
|
243 |
matrix.m43 = z;
|
sawine@2
|
244 |
|
sawine@2
|
245 |
this.multRight(matrix);
|
sawine@2
|
246 |
}
|
sawine@2
|
247 |
|
sawine@2
|
248 |
CanvasMatrix4.prototype.scale = function(x,y,z)
|
sawine@2
|
249 |
{
|
sawine@2
|
250 |
if (x == undefined)
|
sawine@2
|
251 |
x = 1;
|
sawine@2
|
252 |
if (z == undefined) {
|
sawine@2
|
253 |
if (y == undefined) {
|
sawine@2
|
254 |
y = x;
|
sawine@2
|
255 |
z = x;
|
sawine@2
|
256 |
}
|
sawine@2
|
257 |
else
|
sawine@2
|
258 |
z = 1;
|
sawine@2
|
259 |
}
|
sawine@2
|
260 |
else if (y == undefined)
|
sawine@2
|
261 |
y = x;
|
sawine@2
|
262 |
|
sawine@2
|
263 |
var matrix = new CanvasMatrix4();
|
sawine@2
|
264 |
matrix.m11 = x;
|
sawine@2
|
265 |
matrix.m22 = y;
|
sawine@2
|
266 |
matrix.m33 = z;
|
sawine@2
|
267 |
|
sawine@2
|
268 |
this.multRight(matrix);
|
sawine@2
|
269 |
}
|
sawine@2
|
270 |
|
sawine@2
|
271 |
CanvasMatrix4.prototype.rotate = function(angle,x,y,z)
|
sawine@2
|
272 |
{
|
sawine@2
|
273 |
// angles are in degrees. Switch to radians
|
sawine@2
|
274 |
angle = angle / 180 * Math.PI;
|
sawine@2
|
275 |
|
sawine@2
|
276 |
angle /= 2;
|
sawine@2
|
277 |
var sinA = Math.sin(angle);
|
sawine@2
|
278 |
var cosA = Math.cos(angle);
|
sawine@2
|
279 |
var sinA2 = sinA * sinA;
|
sawine@2
|
280 |
|
sawine@2
|
281 |
// normalize
|
sawine@2
|
282 |
var length = Math.sqrt(x * x + y * y + z * z);
|
sawine@2
|
283 |
if (length == 0) {
|
sawine@2
|
284 |
// bad vector, just use something reasonable
|
sawine@2
|
285 |
x = 0;
|
sawine@2
|
286 |
y = 0;
|
sawine@2
|
287 |
z = 1;
|
sawine@2
|
288 |
} else if (length != 1) {
|
sawine@2
|
289 |
x /= length;
|
sawine@2
|
290 |
y /= length;
|
sawine@2
|
291 |
z /= length;
|
sawine@2
|
292 |
}
|
sawine@2
|
293 |
|
sawine@2
|
294 |
var mat = new CanvasMatrix4();
|
sawine@2
|
295 |
|
sawine@2
|
296 |
// optimize case where axis is along major axis
|
sawine@2
|
297 |
if (x == 1 && y == 0 && z == 0) {
|
sawine@2
|
298 |
mat.m11 = 1;
|
sawine@2
|
299 |
mat.m12 = 0;
|
sawine@2
|
300 |
mat.m13 = 0;
|
sawine@2
|
301 |
mat.m21 = 0;
|
sawine@2
|
302 |
mat.m22 = 1 - 2 * sinA2;
|
sawine@2
|
303 |
mat.m23 = 2 * sinA * cosA;
|
sawine@2
|
304 |
mat.m31 = 0;
|
sawine@2
|
305 |
mat.m32 = -2 * sinA * cosA;
|
sawine@2
|
306 |
mat.m33 = 1 - 2 * sinA2;
|
sawine@2
|
307 |
mat.m14 = mat.m24 = mat.m34 = 0;
|
sawine@2
|
308 |
mat.m41 = mat.m42 = mat.m43 = 0;
|
sawine@2
|
309 |
mat.m44 = 1;
|
sawine@2
|
310 |
} else if (x == 0 && y == 1 && z == 0) {
|
sawine@2
|
311 |
mat.m11 = 1 - 2 * sinA2;
|
sawine@2
|
312 |
mat.m12 = 0;
|
sawine@2
|
313 |
mat.m13 = -2 * sinA * cosA;
|
sawine@2
|
314 |
mat.m21 = 0;
|
sawine@2
|
315 |
mat.m22 = 1;
|
sawine@2
|
316 |
mat.m23 = 0;
|
sawine@2
|
317 |
mat.m31 = 2 * sinA * cosA;
|
sawine@2
|
318 |
mat.m32 = 0;
|
sawine@2
|
319 |
mat.m33 = 1 - 2 * sinA2;
|
sawine@2
|
320 |
mat.m14 = mat.m24 = mat.m34 = 0;
|
sawine@2
|
321 |
mat.m41 = mat.m42 = mat.m43 = 0;
|
sawine@2
|
322 |
mat.m44 = 1;
|
sawine@2
|
323 |
} else if (x == 0 && y == 0 && z == 1) {
|
sawine@2
|
324 |
mat.m11 = 1 - 2 * sinA2;
|
sawine@2
|
325 |
mat.m12 = 2 * sinA * cosA;
|
sawine@2
|
326 |
mat.m13 = 0;
|
sawine@2
|
327 |
mat.m21 = -2 * sinA * cosA;
|
sawine@2
|
328 |
mat.m22 = 1 - 2 * sinA2;
|
sawine@2
|
329 |
mat.m23 = 0;
|
sawine@2
|
330 |
mat.m31 = 0;
|
sawine@2
|
331 |
mat.m32 = 0;
|
sawine@2
|
332 |
mat.m33 = 1;
|
sawine@2
|
333 |
mat.m14 = mat.m24 = mat.m34 = 0;
|
sawine@2
|
334 |
mat.m41 = mat.m42 = mat.m43 = 0;
|
sawine@2
|
335 |
mat.m44 = 1;
|
sawine@2
|
336 |
} else {
|
sawine@2
|
337 |
var x2 = x*x;
|
sawine@2
|
338 |
var y2 = y*y;
|
sawine@2
|
339 |
var z2 = z*z;
|
sawine@2
|
340 |
|
sawine@2
|
341 |
mat.m11 = 1 - 2 * (y2 + z2) * sinA2;
|
sawine@2
|
342 |
mat.m12 = 2 * (x * y * sinA2 + z * sinA * cosA);
|
sawine@2
|
343 |
mat.m13 = 2 * (x * z * sinA2 - y * sinA * cosA);
|
sawine@2
|
344 |
mat.m21 = 2 * (y * x * sinA2 - z * sinA * cosA);
|
sawine@2
|
345 |
mat.m22 = 1 - 2 * (z2 + x2) * sinA2;
|
sawine@2
|
346 |
mat.m23 = 2 * (y * z * sinA2 + x * sinA * cosA);
|
sawine@2
|
347 |
mat.m31 = 2 * (z * x * sinA2 + y * sinA * cosA);
|
sawine@2
|
348 |
mat.m32 = 2 * (z * y * sinA2 - x * sinA * cosA);
|
sawine@2
|
349 |
mat.m33 = 1 - 2 * (x2 + y2) * sinA2;
|
sawine@2
|
350 |
mat.m14 = mat.m24 = mat.m34 = 0;
|
sawine@2
|
351 |
mat.m41 = mat.m42 = mat.m43 = 0;
|
sawine@2
|
352 |
mat.m44 = 1;
|
sawine@2
|
353 |
}
|
sawine@2
|
354 |
this.multRight(mat);
|
sawine@2
|
355 |
}
|
sawine@2
|
356 |
|
sawine@2
|
357 |
CanvasMatrix4.prototype.multRight = function(mat)
|
sawine@2
|
358 |
{
|
sawine@2
|
359 |
var m11 = (this.m11 * mat.m11 + this.m12 * mat.m21
|
sawine@2
|
360 |
+ this.m13 * mat.m31 + this.m14 * mat.m41);
|
sawine@2
|
361 |
var m12 = (this.m11 * mat.m12 + this.m12 * mat.m22
|
sawine@2
|
362 |
+ this.m13 * mat.m32 + this.m14 * mat.m42);
|
sawine@2
|
363 |
var m13 = (this.m11 * mat.m13 + this.m12 * mat.m23
|
sawine@2
|
364 |
+ this.m13 * mat.m33 + this.m14 * mat.m43);
|
sawine@2
|
365 |
var m14 = (this.m11 * mat.m14 + this.m12 * mat.m24
|
sawine@2
|
366 |
+ this.m13 * mat.m34 + this.m14 * mat.m44);
|
sawine@2
|
367 |
|
sawine@2
|
368 |
var m21 = (this.m21 * mat.m11 + this.m22 * mat.m21
|
sawine@2
|
369 |
+ this.m23 * mat.m31 + this.m24 * mat.m41);
|
sawine@2
|
370 |
var m22 = (this.m21 * mat.m12 + this.m22 * mat.m22
|
sawine@2
|
371 |
+ this.m23 * mat.m32 + this.m24 * mat.m42);
|
sawine@2
|
372 |
var m23 = (this.m21 * mat.m13 + this.m22 * mat.m23
|
sawine@2
|
373 |
+ this.m23 * mat.m33 + this.m24 * mat.m43);
|
sawine@2
|
374 |
var m24 = (this.m21 * mat.m14 + this.m22 * mat.m24
|
sawine@2
|
375 |
+ this.m23 * mat.m34 + this.m24 * mat.m44);
|
sawine@2
|
376 |
|
sawine@2
|
377 |
var m31 = (this.m31 * mat.m11 + this.m32 * mat.m21
|
sawine@2
|
378 |
+ this.m33 * mat.m31 + this.m34 * mat.m41);
|
sawine@2
|
379 |
var m32 = (this.m31 * mat.m12 + this.m32 * mat.m22
|
sawine@2
|
380 |
+ this.m33 * mat.m32 + this.m34 * mat.m42);
|
sawine@2
|
381 |
var m33 = (this.m31 * mat.m13 + this.m32 * mat.m23
|
sawine@2
|
382 |
+ this.m33 * mat.m33 + this.m34 * mat.m43);
|
sawine@2
|
383 |
var m34 = (this.m31 * mat.m14 + this.m32 * mat.m24
|
sawine@2
|
384 |
+ this.m33 * mat.m34 + this.m34 * mat.m44);
|
sawine@2
|
385 |
|
sawine@2
|
386 |
var m41 = (this.m41 * mat.m11 + this.m42 * mat.m21
|
sawine@2
|
387 |
+ this.m43 * mat.m31 + this.m44 * mat.m41);
|
sawine@2
|
388 |
var m42 = (this.m41 * mat.m12 + this.m42 * mat.m22
|
sawine@2
|
389 |
+ this.m43 * mat.m32 + this.m44 * mat.m42);
|
sawine@2
|
390 |
var m43 = (this.m41 * mat.m13 + this.m42 * mat.m23
|
sawine@2
|
391 |
+ this.m43 * mat.m33 + this.m44 * mat.m43);
|
sawine@2
|
392 |
var m44 = (this.m41 * mat.m14 + this.m42 * mat.m24
|
sawine@2
|
393 |
+ this.m43 * mat.m34 + this.m44 * mat.m44);
|
sawine@2
|
394 |
|
sawine@2
|
395 |
this.m11 = m11;
|
sawine@2
|
396 |
this.m12 = m12;
|
sawine@2
|
397 |
this.m13 = m13;
|
sawine@2
|
398 |
this.m14 = m14;
|
sawine@2
|
399 |
|
sawine@2
|
400 |
this.m21 = m21;
|
sawine@2
|
401 |
this.m22 = m22;
|
sawine@2
|
402 |
this.m23 = m23;
|
sawine@2
|
403 |
this.m24 = m24;
|
sawine@2
|
404 |
|
sawine@2
|
405 |
this.m31 = m31;
|
sawine@2
|
406 |
this.m32 = m32;
|
sawine@2
|
407 |
this.m33 = m33;
|
sawine@2
|
408 |
this.m34 = m34;
|
sawine@2
|
409 |
|
sawine@2
|
410 |
this.m41 = m41;
|
sawine@2
|
411 |
this.m42 = m42;
|
sawine@2
|
412 |
this.m43 = m43;
|
sawine@2
|
413 |
this.m44 = m44;
|
sawine@2
|
414 |
}
|
sawine@2
|
415 |
|
sawine@2
|
416 |
CanvasMatrix4.prototype.multLeft = function(mat)
|
sawine@2
|
417 |
{
|
sawine@2
|
418 |
var m11 = (mat.m11 * this.m11 + mat.m12 * this.m21
|
sawine@2
|
419 |
+ mat.m13 * this.m31 + mat.m14 * this.m41);
|
sawine@2
|
420 |
var m12 = (mat.m11 * this.m12 + mat.m12 * this.m22
|
sawine@2
|
421 |
+ mat.m13 * this.m32 + mat.m14 * this.m42);
|
sawine@2
|
422 |
var m13 = (mat.m11 * this.m13 + mat.m12 * this.m23
|
sawine@2
|
423 |
+ mat.m13 * this.m33 + mat.m14 * this.m43);
|
sawine@2
|
424 |
var m14 = (mat.m11 * this.m14 + mat.m12 * this.m24
|
sawine@2
|
425 |
+ mat.m13 * this.m34 + mat.m14 * this.m44);
|
sawine@2
|
426 |
|
sawine@2
|
427 |
var m21 = (mat.m21 * this.m11 + mat.m22 * this.m21
|
sawine@2
|
428 |
+ mat.m23 * this.m31 + mat.m24 * this.m41);
|
sawine@2
|
429 |
var m22 = (mat.m21 * this.m12 + mat.m22 * this.m22
|
sawine@2
|
430 |
+ mat.m23 * this.m32 + mat.m24 * this.m42);
|
sawine@2
|
431 |
var m23 = (mat.m21 * this.m13 + mat.m22 * this.m23
|
sawine@2
|
432 |
+ mat.m23 * this.m33 + mat.m24 * this.m43);
|
sawine@2
|
433 |
var m24 = (mat.m21 * this.m14 + mat.m22 * this.m24
|
sawine@2
|
434 |
+ mat.m23 * this.m34 + mat.m24 * this.m44);
|
sawine@2
|
435 |
|
sawine@2
|
436 |
var m31 = (mat.m31 * this.m11 + mat.m32 * this.m21
|
sawine@2
|
437 |
+ mat.m33 * this.m31 + mat.m34 * this.m41);
|
sawine@2
|
438 |
var m32 = (mat.m31 * this.m12 + mat.m32 * this.m22
|
sawine@2
|
439 |
+ mat.m33 * this.m32 + mat.m34 * this.m42);
|
sawine@2
|
440 |
var m33 = (mat.m31 * this.m13 + mat.m32 * this.m23
|
sawine@2
|
441 |
+ mat.m33 * this.m33 + mat.m34 * this.m43);
|
sawine@2
|
442 |
var m34 = (mat.m31 * this.m14 + mat.m32 * this.m24
|
sawine@2
|
443 |
+ mat.m33 * this.m34 + mat.m34 * this.m44);
|
sawine@2
|
444 |
|
sawine@2
|
445 |
var m41 = (mat.m41 * this.m11 + mat.m42 * this.m21
|
sawine@2
|
446 |
+ mat.m43 * this.m31 + mat.m44 * this.m41);
|
sawine@2
|
447 |
var m42 = (mat.m41 * this.m12 + mat.m42 * this.m22
|
sawine@2
|
448 |
+ mat.m43 * this.m32 + mat.m44 * this.m42);
|
sawine@2
|
449 |
var m43 = (mat.m41 * this.m13 + mat.m42 * this.m23
|
sawine@2
|
450 |
+ mat.m43 * this.m33 + mat.m44 * this.m43);
|
sawine@2
|
451 |
var m44 = (mat.m41 * this.m14 + mat.m42 * this.m24
|
sawine@2
|
452 |
+ mat.m43 * this.m34 + mat.m44 * this.m44);
|
sawine@2
|
453 |
|
sawine@2
|
454 |
this.m11 = m11;
|
sawine@2
|
455 |
this.m12 = m12;
|
sawine@2
|
456 |
this.m13 = m13;
|
sawine@2
|
457 |
this.m14 = m14;
|
sawine@2
|
458 |
|
sawine@2
|
459 |
this.m21 = m21;
|
sawine@2
|
460 |
this.m22 = m22;
|
sawine@2
|
461 |
this.m23 = m23;
|
sawine@2
|
462 |
this.m24 = m24;
|
sawine@2
|
463 |
|
sawine@2
|
464 |
this.m31 = m31;
|
sawine@2
|
465 |
this.m32 = m32;
|
sawine@2
|
466 |
this.m33 = m33;
|
sawine@2
|
467 |
this.m34 = m34;
|
sawine@2
|
468 |
|
sawine@2
|
469 |
this.m41 = m41;
|
sawine@2
|
470 |
this.m42 = m42;
|
sawine@2
|
471 |
this.m43 = m43;
|
sawine@2
|
472 |
this.m44 = m44;
|
sawine@2
|
473 |
}
|
sawine@2
|
474 |
|
sawine@2
|
475 |
CanvasMatrix4.prototype.ortho = function(left, right, bottom, top, near, far)
|
sawine@2
|
476 |
{
|
sawine@2
|
477 |
var tx = (left + right) / (left - right);
|
sawine@2
|
478 |
var ty = (top + bottom) / (top - bottom);
|
sawine@2
|
479 |
var tz = (far + near) / (far - near);
|
sawine@2
|
480 |
|
sawine@2
|
481 |
var matrix = new CanvasMatrix4();
|
sawine@2
|
482 |
matrix.m11 = 2 / (left - right);
|
sawine@2
|
483 |
matrix.m12 = 0;
|
sawine@2
|
484 |
matrix.m13 = 0;
|
sawine@2
|
485 |
matrix.m14 = 0;
|
sawine@2
|
486 |
matrix.m21 = 0;
|
sawine@2
|
487 |
matrix.m22 = 2 / (top - bottom);
|
sawine@2
|
488 |
matrix.m23 = 0;
|
sawine@2
|
489 |
matrix.m24 = 0;
|
sawine@2
|
490 |
matrix.m31 = 0;
|
sawine@2
|
491 |
matrix.m32 = 0;
|
sawine@2
|
492 |
matrix.m33 = -2 / (far - near);
|
sawine@2
|
493 |
matrix.m34 = 0;
|
sawine@2
|
494 |
matrix.m41 = tx;
|
sawine@2
|
495 |
matrix.m42 = ty;
|
sawine@2
|
496 |
matrix.m43 = tz;
|
sawine@2
|
497 |
matrix.m44 = 1;
|
sawine@2
|
498 |
|
sawine@2
|
499 |
this.multRight(matrix);
|
sawine@2
|
500 |
}
|
sawine@2
|
501 |
|
sawine@2
|
502 |
CanvasMatrix4.prototype.frustum = function(left, right, bottom, top, near, far)
|
sawine@2
|
503 |
{
|
sawine@2
|
504 |
var matrix = new CanvasMatrix4();
|
sawine@2
|
505 |
var A = (right + left) / (right - left);
|
sawine@2
|
506 |
var B = (top + bottom) / (top - bottom);
|
sawine@2
|
507 |
var C = -(far + near) / (far - near);
|
sawine@2
|
508 |
var D = -(2 * far * near) / (far - near);
|
sawine@2
|
509 |
|
sawine@2
|
510 |
matrix.m11 = (2 * near) / (right - left);
|
sawine@2
|
511 |
matrix.m12 = 0;
|
sawine@2
|
512 |
matrix.m13 = 0;
|
sawine@2
|
513 |
matrix.m14 = 0;
|
sawine@2
|
514 |
|
sawine@2
|
515 |
matrix.m21 = 0;
|
sawine@2
|
516 |
matrix.m22 = 2 * near / (top - bottom);
|
sawine@2
|
517 |
matrix.m23 = 0;
|
sawine@2
|
518 |
matrix.m24 = 0;
|
sawine@2
|
519 |
|
sawine@2
|
520 |
matrix.m31 = A;
|
sawine@2
|
521 |
matrix.m32 = B;
|
sawine@2
|
522 |
matrix.m33 = C;
|
sawine@2
|
523 |
matrix.m34 = -1;
|
sawine@2
|
524 |
|
sawine@2
|
525 |
matrix.m41 = 0;
|
sawine@2
|
526 |
matrix.m42 = 0;
|
sawine@2
|
527 |
matrix.m43 = D;
|
sawine@2
|
528 |
matrix.m44 = 0;
|
sawine@2
|
529 |
|
sawine@2
|
530 |
this.multRight(matrix);
|
sawine@2
|
531 |
}
|
sawine@2
|
532 |
|
sawine@2
|
533 |
CanvasMatrix4.prototype.perspective = function(fovy, aspect, zNear, zFar)
|
sawine@2
|
534 |
{
|
sawine@2
|
535 |
var top = Math.tan(fovy * Math.PI / 360) * zNear;
|
sawine@2
|
536 |
var bottom = -top;
|
sawine@2
|
537 |
var left = aspect * bottom;
|
sawine@2
|
538 |
var right = aspect * top;
|
sawine@2
|
539 |
this.frustum(left, right, bottom, top, zNear, zFar);
|
sawine@2
|
540 |
}
|
sawine@2
|
541 |
|
sawine@2
|
542 |
CanvasMatrix4.prototype.lookat = function(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz)
|
sawine@2
|
543 |
{
|
sawine@2
|
544 |
var matrix = new CanvasMatrix4();
|
sawine@2
|
545 |
|
sawine@2
|
546 |
// Make rotation matrix
|
sawine@2
|
547 |
|
sawine@2
|
548 |
// Z vector
|
sawine@2
|
549 |
var zx = eyex - centerx;
|
sawine@2
|
550 |
var zy = eyey - centery;
|
sawine@2
|
551 |
var zz = eyez - centerz;
|
sawine@2
|
552 |
var mag = Math.sqrt(zx * zx + zy * zy + zz * zz);
|
sawine@2
|
553 |
if (mag) {
|
sawine@2
|
554 |
zx /= mag;
|
sawine@2
|
555 |
zy /= mag;
|
sawine@2
|
556 |
zz /= mag;
|
sawine@2
|
557 |
}
|
sawine@2
|
558 |
|
sawine@2
|
559 |
// Y vector
|
sawine@2
|
560 |
var yx = upx;
|
sawine@2
|
561 |
var yy = upy;
|
sawine@2
|
562 |
var yz = upz;
|
sawine@2
|
563 |
|
sawine@2
|
564 |
// X vector = Y cross Z
|
sawine@2
|
565 |
xx = yy * zz - yz * zy;
|
sawine@2
|
566 |
xy = -yx * zz + yz * zx;
|
sawine@2
|
567 |
xz = yx * zy - yy * zx;
|
sawine@2
|
568 |
|
sawine@2
|
569 |
// Recompute Y = Z cross X
|
sawine@2
|
570 |
yx = zy * xz - zz * xy;
|
sawine@2
|
571 |
yy = -zx * xz + zz * xx;
|
sawine@2
|
572 |
yx = zx * xy - zy * xx;
|
sawine@2
|
573 |
|
sawine@2
|
574 |
// cross product gives area of parallelogram, which is < 1.0 for
|
sawine@2
|
575 |
// non-perpendicular unit-length vectors; so normalize x, y here
|
sawine@2
|
576 |
|
sawine@2
|
577 |
mag = Math.sqrt(xx * xx + xy * xy + xz * xz);
|
sawine@2
|
578 |
if (mag) {
|
sawine@2
|
579 |
xx /= mag;
|
sawine@2
|
580 |
xy /= mag;
|
sawine@2
|
581 |
xz /= mag;
|
sawine@2
|
582 |
}
|
sawine@2
|
583 |
|
sawine@2
|
584 |
mag = Math.sqrt(yx * yx + yy * yy + yz * yz);
|
sawine@2
|
585 |
if (mag) {
|
sawine@2
|
586 |
yx /= mag;
|
sawine@2
|
587 |
yy /= mag;
|
sawine@2
|
588 |
yz /= mag;
|
sawine@2
|
589 |
}
|
sawine@2
|
590 |
|
sawine@2
|
591 |
matrix.m11 = xx;
|
sawine@2
|
592 |
matrix.m12 = xy;
|
sawine@2
|
593 |
matrix.m13 = xz;
|
sawine@2
|
594 |
matrix.m14 = 0;
|
sawine@2
|
595 |
|
sawine@2
|
596 |
matrix.m21 = yx;
|
sawine@2
|
597 |
matrix.m22 = yy;
|
sawine@2
|
598 |
matrix.m23 = yz;
|
sawine@2
|
599 |
matrix.m24 = 0;
|
sawine@2
|
600 |
|
sawine@2
|
601 |
matrix.m31 = zx;
|
sawine@2
|
602 |
matrix.m32 = zy;
|
sawine@2
|
603 |
matrix.m33 = zz;
|
sawine@2
|
604 |
matrix.m34 = 0;
|
sawine@2
|
605 |
|
sawine@2
|
606 |
matrix.m41 = 0;
|
sawine@2
|
607 |
matrix.m42 = 0;
|
sawine@2
|
608 |
matrix.m43 = 0;
|
sawine@2
|
609 |
matrix.m44 = 1;
|
sawine@2
|
610 |
matrix.translate(-eyex, -eyey, -eyez);
|
sawine@2
|
611 |
|
sawine@2
|
612 |
this.multRight(matrix);
|
sawine@2
|
613 |
}
|
sawine@2
|
614 |
|
sawine@2
|
615 |
// Support functions
|
sawine@2
|
616 |
CanvasMatrix4.prototype._determinant2x2 = function(a, b, c, d)
|
sawine@2
|
617 |
{
|
sawine@2
|
618 |
return a * d - b * c;
|
sawine@2
|
619 |
}
|
sawine@2
|
620 |
|
sawine@2
|
621 |
CanvasMatrix4.prototype._determinant3x3 = function(a1, a2, a3, b1, b2, b3, c1, c2, c3)
|
sawine@2
|
622 |
{
|
sawine@2
|
623 |
return a1 * this._determinant2x2(b2, b3, c2, c3)
|
sawine@2
|
624 |
- b1 * this._determinant2x2(a2, a3, c2, c3)
|
sawine@2
|
625 |
+ c1 * this._determinant2x2(a2, a3, b2, b3);
|
sawine@2
|
626 |
}
|
sawine@2
|
627 |
|
sawine@2
|
628 |
CanvasMatrix4.prototype._determinant4x4 = function()
|
sawine@2
|
629 |
{
|
sawine@2
|
630 |
var a1 = this.m11;
|
sawine@2
|
631 |
var b1 = this.m12;
|
sawine@2
|
632 |
var c1 = this.m13;
|
sawine@2
|
633 |
var d1 = this.m14;
|
sawine@2
|
634 |
|
sawine@2
|
635 |
var a2 = this.m21;
|
sawine@2
|
636 |
var b2 = this.m22;
|
sawine@2
|
637 |
var c2 = this.m23;
|
sawine@2
|
638 |
var d2 = this.m24;
|
sawine@2
|
639 |
|
sawine@2
|
640 |
var a3 = this.m31;
|
sawine@2
|
641 |
var b3 = this.m32;
|
sawine@2
|
642 |
var c3 = this.m33;
|
sawine@2
|
643 |
var d3 = this.m34;
|
sawine@2
|
644 |
|
sawine@2
|
645 |
var a4 = this.m41;
|
sawine@2
|
646 |
var b4 = this.m42;
|
sawine@2
|
647 |
var c4 = this.m43;
|
sawine@2
|
648 |
var d4 = this.m44;
|
sawine@2
|
649 |
|
sawine@2
|
650 |
return a1 * this._determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4)
|
sawine@2
|
651 |
- b1 * this._determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4)
|
sawine@2
|
652 |
+ c1 * this._determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4)
|
sawine@2
|
653 |
- d1 * this._determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
|
sawine@2
|
654 |
}
|
sawine@2
|
655 |
|
sawine@2
|
656 |
CanvasMatrix4.prototype._makeAdjoint = function()
|
sawine@2
|
657 |
{
|
sawine@2
|
658 |
var a1 = this.m11;
|
sawine@2
|
659 |
var b1 = this.m12;
|
sawine@2
|
660 |
var c1 = this.m13;
|
sawine@2
|
661 |
var d1 = this.m14;
|
sawine@2
|
662 |
|
sawine@2
|
663 |
var a2 = this.m21;
|
sawine@2
|
664 |
var b2 = this.m22;
|
sawine@2
|
665 |
var c2 = this.m23;
|
sawine@2
|
666 |
var d2 = this.m24;
|
sawine@2
|
667 |
|
sawine@2
|
668 |
var a3 = this.m31;
|
sawine@2
|
669 |
var b3 = this.m32;
|
sawine@2
|
670 |
var c3 = this.m33;
|
sawine@2
|
671 |
var d3 = this.m34;
|
sawine@2
|
672 |
|
sawine@2
|
673 |
var a4 = this.m41;
|
sawine@2
|
674 |
var b4 = this.m42;
|
sawine@2
|
675 |
var c4 = this.m43;
|
sawine@2
|
676 |
var d4 = this.m44;
|
sawine@2
|
677 |
|
sawine@2
|
678 |
// Row column labeling reversed since we transpose rows & columns
|
sawine@2
|
679 |
this.m11 = this._determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4);
|
sawine@2
|
680 |
this.m21 = - this._determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4);
|
sawine@2
|
681 |
this.m31 = this._determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4);
|
sawine@2
|
682 |
this.m41 = - this._determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
|
sawine@2
|
683 |
|
sawine@2
|
684 |
this.m12 = - this._determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4);
|
sawine@2
|
685 |
this.m22 = this._determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4);
|
sawine@2
|
686 |
this.m32 = - this._determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4);
|
sawine@2
|
687 |
this.m42 = this._determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4);
|
sawine@2
|
688 |
|
sawine@2
|
689 |
this.m13 = this._determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4);
|
sawine@2
|
690 |
this.m23 = - this._determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4);
|
sawine@2
|
691 |
this.m33 = this._determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4);
|
sawine@2
|
692 |
this.m43 = - this._determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4);
|
sawine@2
|
693 |
|
sawine@2
|
694 |
this.m14 = - this._determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3);
|
sawine@2
|
695 |
this.m24 = this._determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3);
|
sawine@2
|
696 |
this.m34 = - this._determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3);
|
sawine@2
|
697 |
this.m44 = this._determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3);
|
sawine@2
|
698 |
} |