UNPKG

222 kBJavaScriptView Raw
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3 typeof define === 'function' && define.amd ? define(['exports'], factory) :
4 (global = global || self, factory(global.Ashes = {}));
5}(this, function (exports) { 'use strict';
6
7 class Texture {
8 constructor(rawImage, sampler = undefined, width = 2, height = 2, border = 0) {
9 this.channel = null;
10 this.isDirty = true;
11 this.glType = WebGL2RenderingContext.TEXTURE_2D;
12 this.isCubetex = false;
13 this.data = null;
14 this.level = 0;
15 this.internalformat = WebGL2RenderingContext.RGBA;
16 this.format = WebGL2RenderingContext.RGBA;
17 this.type = WebGL2RenderingContext.UNSIGNED_BYTE;
18 this.flipY = false;
19 this.sampler = new Sampler(sampler);
20 this.image = rawImage;
21 this.width = width;
22 this.height = height;
23 this.border = border;
24 if (rawImage && rawImage.length == 6) {
25 this.isCubetex = true;
26 this.glType = WebGL2RenderingContext.TEXTURE_CUBE_MAP;
27 }
28 }
29 static clone(origin) {
30 let temp = new Texture(origin.image, origin.sampler);
31 temp.sampler = origin.sampler;
32 temp.flipY = origin.flipY;
33 return temp;
34 }
35 static createTexture(gl, tex) {
36 if (tex.sampler.texture) { // if the texuter is already exist
37 gl.deleteTexture(tex.sampler.texture);
38 }
39 tex.sampler.texture = gl.createTexture();
40 gl.bindTexture(tex.glType, tex.sampler.texture);
41 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, tex.flipY ? 1 : 0);
42 if (tex.isCubetex) {
43 for (let i in this.cubetexOrder) {
44 gl.texImage2D(this.cubetexOrder[i], tex.level, tex.internalformat, tex.format, tex.type, tex.image[i]);
45 }
46 }
47 else {
48 if (tex.image) {
49 gl.texImage2D(tex.glType, tex.level, tex.internalformat, tex.format, tex.type, tex.image);
50 }
51 else { // Data texture
52 gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
53 gl.texImage2D(tex.glType, tex.level, tex.internalformat, tex.width, tex.height, tex.border, tex.format, tex.type, tex.data);
54 }
55 }
56 gl.texParameterf(tex.glType, gl.TEXTURE_WRAP_S, tex.sampler.wrapS);
57 gl.texParameterf(tex.glType, gl.TEXTURE_WRAP_T, tex.sampler.wrapT);
58 if (tex.sampler.minFilter == WebGL2RenderingContext.NEAREST_MIPMAP_NEAREST || tex.sampler.minFilter == WebGL2RenderingContext.NEAREST_MIPMAP_LINEAR || tex.sampler.minFilter == WebGL2RenderingContext.LINEAR_MIPMAP_NEAREST || tex.sampler.minFilter == WebGL2RenderingContext.LINEAR_MIPMAP_LINEAR) {
59 gl.generateMipmap(tex.glType);
60 }
61 else {
62 gl.texParameterf(tex.glType, gl.TEXTURE_MIN_FILTER, tex.sampler.minFilter);
63 gl.texParameterf(tex.glType, gl.TEXTURE_MAG_FILTER, tex.sampler.magFilter);
64 }
65 gl.bindTexture(tex.glType, null);
66 }
67 static unbindTexture(gl, tex) {
68 if (tex.channel != null) {
69 gl.activeTexture(this.texChannels[tex.channel]);
70 }
71 gl.bindTexture(tex.glType, null);
72 }
73 static bindTexture(gl, tex) {
74 if (tex.channel != null) {
75 gl.activeTexture(this.texChannels[tex.channel]);
76 }
77 if (tex.sampler.texture == null || (tex.isDirty && (tex.data || tex.image))) {
78 // Ignore texture belongs to framebuffer after created once
79 this.createTexture(gl, tex);
80 }
81 gl.bindTexture(tex.glType, tex.sampler.texture);
82 }
83 }
84 Texture.defaultData = new Uint8Array([
85 1, 1, 1, 1,
86 1, 0.5, 0.4, 1,
87 0.4, 0.5, 1, 1,
88 1, 1, 1, 1,
89 ].map(v => v * 255));
90 Texture.cubetexOrder = [
91 WebGL2RenderingContext.TEXTURE_CUBE_MAP_POSITIVE_X,
92 WebGL2RenderingContext.TEXTURE_CUBE_MAP_NEGATIVE_X,
93 WebGL2RenderingContext.TEXTURE_CUBE_MAP_POSITIVE_Y,
94 WebGL2RenderingContext.TEXTURE_CUBE_MAP_NEGATIVE_Y,
95 WebGL2RenderingContext.TEXTURE_CUBE_MAP_POSITIVE_Z,
96 WebGL2RenderingContext.TEXTURE_CUBE_MAP_NEGATIVE_Z,
97 ];
98 // Reduce GC
99 Texture.texChannels = [
100 WebGL2RenderingContext.TEXTURE0,
101 WebGL2RenderingContext.TEXTURE1,
102 WebGL2RenderingContext.TEXTURE2,
103 WebGL2RenderingContext.TEXTURE3,
104 WebGL2RenderingContext.TEXTURE4,
105 WebGL2RenderingContext.TEXTURE5,
106 WebGL2RenderingContext.TEXTURE6,
107 WebGL2RenderingContext.TEXTURE7,
108 ];
109 class Sampler {
110 constructor({ magFilter = WebGL2RenderingContext.NEAREST, minFilter = WebGL2RenderingContext.NEAREST, wrapS = 10497, wrapT = 10497, texture = null } = { magFilter: WebGL2RenderingContext.NEAREST, minFilter: WebGL2RenderingContext.NEAREST, wrapS: 10497, wrapT: 10497, texture: null }) {
111 this.texture = null;
112 this.magFilter = magFilter;
113 this.minFilter = minFilter;
114 this.wrapS = wrapS;
115 this.wrapT = wrapT;
116 this.texture = texture;
117 }
118 }
119
120 /**
121 * Common utilities
122 * @module glMatrix
123 */
124
125 // Configuration Constants
126 var EPSILON = 0.000001;
127 var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
128 var RANDOM = Math.random;
129
130 var degree = Math.PI / 180;
131
132 /**
133 * 3x3 Matrix
134 * @module mat3
135 */
136
137 /**
138 * Creates a new identity mat3
139 *
140 * @returns {mat3} a new 3x3 matrix
141 */
142 function create$2() {
143 var out = new ARRAY_TYPE(9);
144 if (ARRAY_TYPE != Float32Array) {
145 out[1] = 0;
146 out[2] = 0;
147 out[3] = 0;
148 out[5] = 0;
149 out[6] = 0;
150 out[7] = 0;
151 }
152 out[0] = 1;
153 out[4] = 1;
154 out[8] = 1;
155 return out;
156 }
157
158 /**
159 * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied.
160 * @module mat4
161 */
162
163 /**
164 * Creates a new identity mat4
165 *
166 * @returns {mat4} a new 4x4 matrix
167 */
168 function create$3() {
169 var out = new ARRAY_TYPE(16);
170 if (ARRAY_TYPE != Float32Array) {
171 out[1] = 0;
172 out[2] = 0;
173 out[3] = 0;
174 out[4] = 0;
175 out[6] = 0;
176 out[7] = 0;
177 out[8] = 0;
178 out[9] = 0;
179 out[11] = 0;
180 out[12] = 0;
181 out[13] = 0;
182 out[14] = 0;
183 }
184 out[0] = 1;
185 out[5] = 1;
186 out[10] = 1;
187 out[15] = 1;
188 return out;
189 }
190
191 /**
192 * Creates a new mat4 initialized with values from an existing matrix
193 *
194 * @param {mat4} a matrix to clone
195 * @returns {mat4} a new 4x4 matrix
196 */
197 function clone$3(a) {
198 var out = new ARRAY_TYPE(16);
199 out[0] = a[0];
200 out[1] = a[1];
201 out[2] = a[2];
202 out[3] = a[3];
203 out[4] = a[4];
204 out[5] = a[5];
205 out[6] = a[6];
206 out[7] = a[7];
207 out[8] = a[8];
208 out[9] = a[9];
209 out[10] = a[10];
210 out[11] = a[11];
211 out[12] = a[12];
212 out[13] = a[13];
213 out[14] = a[14];
214 out[15] = a[15];
215 return out;
216 }
217
218 /**
219 * Copy the values from one mat4 to another
220 *
221 * @param {mat4} out the receiving matrix
222 * @param {mat4} a the source matrix
223 * @returns {mat4} out
224 */
225 function copy$3(out, a) {
226 out[0] = a[0];
227 out[1] = a[1];
228 out[2] = a[2];
229 out[3] = a[3];
230 out[4] = a[4];
231 out[5] = a[5];
232 out[6] = a[6];
233 out[7] = a[7];
234 out[8] = a[8];
235 out[9] = a[9];
236 out[10] = a[10];
237 out[11] = a[11];
238 out[12] = a[12];
239 out[13] = a[13];
240 out[14] = a[14];
241 out[15] = a[15];
242 return out;
243 }
244
245 /**
246 * Create a new mat4 with the given values
247 *
248 * @param {Number} m00 Component in column 0, row 0 position (index 0)
249 * @param {Number} m01 Component in column 0, row 1 position (index 1)
250 * @param {Number} m02 Component in column 0, row 2 position (index 2)
251 * @param {Number} m03 Component in column 0, row 3 position (index 3)
252 * @param {Number} m10 Component in column 1, row 0 position (index 4)
253 * @param {Number} m11 Component in column 1, row 1 position (index 5)
254 * @param {Number} m12 Component in column 1, row 2 position (index 6)
255 * @param {Number} m13 Component in column 1, row 3 position (index 7)
256 * @param {Number} m20 Component in column 2, row 0 position (index 8)
257 * @param {Number} m21 Component in column 2, row 1 position (index 9)
258 * @param {Number} m22 Component in column 2, row 2 position (index 10)
259 * @param {Number} m23 Component in column 2, row 3 position (index 11)
260 * @param {Number} m30 Component in column 3, row 0 position (index 12)
261 * @param {Number} m31 Component in column 3, row 1 position (index 13)
262 * @param {Number} m32 Component in column 3, row 2 position (index 14)
263 * @param {Number} m33 Component in column 3, row 3 position (index 15)
264 * @returns {mat4} A new mat4
265 */
266 function fromValues$3(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
267 var out = new ARRAY_TYPE(16);
268 out[0] = m00;
269 out[1] = m01;
270 out[2] = m02;
271 out[3] = m03;
272 out[4] = m10;
273 out[5] = m11;
274 out[6] = m12;
275 out[7] = m13;
276 out[8] = m20;
277 out[9] = m21;
278 out[10] = m22;
279 out[11] = m23;
280 out[12] = m30;
281 out[13] = m31;
282 out[14] = m32;
283 out[15] = m33;
284 return out;
285 }
286
287 /**
288 * Set the components of a mat4 to the given values
289 *
290 * @param {mat4} out the receiving matrix
291 * @param {Number} m00 Component in column 0, row 0 position (index 0)
292 * @param {Number} m01 Component in column 0, row 1 position (index 1)
293 * @param {Number} m02 Component in column 0, row 2 position (index 2)
294 * @param {Number} m03 Component in column 0, row 3 position (index 3)
295 * @param {Number} m10 Component in column 1, row 0 position (index 4)
296 * @param {Number} m11 Component in column 1, row 1 position (index 5)
297 * @param {Number} m12 Component in column 1, row 2 position (index 6)
298 * @param {Number} m13 Component in column 1, row 3 position (index 7)
299 * @param {Number} m20 Component in column 2, row 0 position (index 8)
300 * @param {Number} m21 Component in column 2, row 1 position (index 9)
301 * @param {Number} m22 Component in column 2, row 2 position (index 10)
302 * @param {Number} m23 Component in column 2, row 3 position (index 11)
303 * @param {Number} m30 Component in column 3, row 0 position (index 12)
304 * @param {Number} m31 Component in column 3, row 1 position (index 13)
305 * @param {Number} m32 Component in column 3, row 2 position (index 14)
306 * @param {Number} m33 Component in column 3, row 3 position (index 15)
307 * @returns {mat4} out
308 */
309 function set$3(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
310 out[0] = m00;
311 out[1] = m01;
312 out[2] = m02;
313 out[3] = m03;
314 out[4] = m10;
315 out[5] = m11;
316 out[6] = m12;
317 out[7] = m13;
318 out[8] = m20;
319 out[9] = m21;
320 out[10] = m22;
321 out[11] = m23;
322 out[12] = m30;
323 out[13] = m31;
324 out[14] = m32;
325 out[15] = m33;
326 return out;
327 }
328
329 /**
330 * Set a mat4 to the identity matrix
331 *
332 * @param {mat4} out the receiving matrix
333 * @returns {mat4} out
334 */
335 function identity$3(out) {
336 out[0] = 1;
337 out[1] = 0;
338 out[2] = 0;
339 out[3] = 0;
340 out[4] = 0;
341 out[5] = 1;
342 out[6] = 0;
343 out[7] = 0;
344 out[8] = 0;
345 out[9] = 0;
346 out[10] = 1;
347 out[11] = 0;
348 out[12] = 0;
349 out[13] = 0;
350 out[14] = 0;
351 out[15] = 1;
352 return out;
353 }
354
355 /**
356 * Transpose the values of a mat4
357 *
358 * @param {mat4} out the receiving matrix
359 * @param {mat4} a the source matrix
360 * @returns {mat4} out
361 */
362 function transpose$2(out, a) {
363 // If we are transposing ourselves we can skip a few steps but have to cache some values
364 if (out === a) {
365 var a01 = a[1],
366 a02 = a[2],
367 a03 = a[3];
368 var a12 = a[6],
369 a13 = a[7];
370 var a23 = a[11];
371
372 out[1] = a[4];
373 out[2] = a[8];
374 out[3] = a[12];
375 out[4] = a01;
376 out[6] = a[9];
377 out[7] = a[13];
378 out[8] = a02;
379 out[9] = a12;
380 out[11] = a[14];
381 out[12] = a03;
382 out[13] = a13;
383 out[14] = a23;
384 } else {
385 out[0] = a[0];
386 out[1] = a[4];
387 out[2] = a[8];
388 out[3] = a[12];
389 out[4] = a[1];
390 out[5] = a[5];
391 out[6] = a[9];
392 out[7] = a[13];
393 out[8] = a[2];
394 out[9] = a[6];
395 out[10] = a[10];
396 out[11] = a[14];
397 out[12] = a[3];
398 out[13] = a[7];
399 out[14] = a[11];
400 out[15] = a[15];
401 }
402
403 return out;
404 }
405
406 /**
407 * Inverts a mat4
408 *
409 * @param {mat4} out the receiving matrix
410 * @param {mat4} a the source matrix
411 * @returns {mat4} out
412 */
413 function invert$3(out, a) {
414 var a00 = a[0],
415 a01 = a[1],
416 a02 = a[2],
417 a03 = a[3];
418 var a10 = a[4],
419 a11 = a[5],
420 a12 = a[6],
421 a13 = a[7];
422 var a20 = a[8],
423 a21 = a[9],
424 a22 = a[10],
425 a23 = a[11];
426 var a30 = a[12],
427 a31 = a[13],
428 a32 = a[14],
429 a33 = a[15];
430
431 var b00 = a00 * a11 - a01 * a10;
432 var b01 = a00 * a12 - a02 * a10;
433 var b02 = a00 * a13 - a03 * a10;
434 var b03 = a01 * a12 - a02 * a11;
435 var b04 = a01 * a13 - a03 * a11;
436 var b05 = a02 * a13 - a03 * a12;
437 var b06 = a20 * a31 - a21 * a30;
438 var b07 = a20 * a32 - a22 * a30;
439 var b08 = a20 * a33 - a23 * a30;
440 var b09 = a21 * a32 - a22 * a31;
441 var b10 = a21 * a33 - a23 * a31;
442 var b11 = a22 * a33 - a23 * a32;
443
444 // Calculate the determinant
445 var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
446
447 if (!det) {
448 return null;
449 }
450 det = 1.0 / det;
451
452 out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
453 out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
454 out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
455 out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
456 out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
457 out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
458 out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
459 out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
460 out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
461 out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
462 out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
463 out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
464 out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
465 out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
466 out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
467 out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
468
469 return out;
470 }
471
472 /**
473 * Calculates the adjugate of a mat4
474 *
475 * @param {mat4} out the receiving matrix
476 * @param {mat4} a the source matrix
477 * @returns {mat4} out
478 */
479 function adjoint$2(out, a) {
480 var a00 = a[0],
481 a01 = a[1],
482 a02 = a[2],
483 a03 = a[3];
484 var a10 = a[4],
485 a11 = a[5],
486 a12 = a[6],
487 a13 = a[7];
488 var a20 = a[8],
489 a21 = a[9],
490 a22 = a[10],
491 a23 = a[11];
492 var a30 = a[12],
493 a31 = a[13],
494 a32 = a[14],
495 a33 = a[15];
496
497 out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
498 out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
499 out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
500 out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
501 out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
502 out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
503 out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
504 out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
505 out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
506 out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
507 out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
508 out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
509 out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
510 out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
511 out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
512 out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
513 return out;
514 }
515
516 /**
517 * Calculates the determinant of a mat4
518 *
519 * @param {mat4} a the source matrix
520 * @returns {Number} determinant of a
521 */
522 function determinant$3(a) {
523 var a00 = a[0],
524 a01 = a[1],
525 a02 = a[2],
526 a03 = a[3];
527 var a10 = a[4],
528 a11 = a[5],
529 a12 = a[6],
530 a13 = a[7];
531 var a20 = a[8],
532 a21 = a[9],
533 a22 = a[10],
534 a23 = a[11];
535 var a30 = a[12],
536 a31 = a[13],
537 a32 = a[14],
538 a33 = a[15];
539
540 var b00 = a00 * a11 - a01 * a10;
541 var b01 = a00 * a12 - a02 * a10;
542 var b02 = a00 * a13 - a03 * a10;
543 var b03 = a01 * a12 - a02 * a11;
544 var b04 = a01 * a13 - a03 * a11;
545 var b05 = a02 * a13 - a03 * a12;
546 var b06 = a20 * a31 - a21 * a30;
547 var b07 = a20 * a32 - a22 * a30;
548 var b08 = a20 * a33 - a23 * a30;
549 var b09 = a21 * a32 - a22 * a31;
550 var b10 = a21 * a33 - a23 * a31;
551 var b11 = a22 * a33 - a23 * a32;
552
553 // Calculate the determinant
554 return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
555 }
556
557 /**
558 * Multiplies two mat4s
559 *
560 * @param {mat4} out the receiving matrix
561 * @param {mat4} a the first operand
562 * @param {mat4} b the second operand
563 * @returns {mat4} out
564 */
565 function multiply$3(out, a, b) {
566 var a00 = a[0],
567 a01 = a[1],
568 a02 = a[2],
569 a03 = a[3];
570 var a10 = a[4],
571 a11 = a[5],
572 a12 = a[6],
573 a13 = a[7];
574 var a20 = a[8],
575 a21 = a[9],
576 a22 = a[10],
577 a23 = a[11];
578 var a30 = a[12],
579 a31 = a[13],
580 a32 = a[14],
581 a33 = a[15];
582
583 // Cache only the current line of the second matrix
584 var b0 = b[0],
585 b1 = b[1],
586 b2 = b[2],
587 b3 = b[3];
588 out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
589 out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
590 out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
591 out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
592
593 b0 = b[4];b1 = b[5];b2 = b[6];b3 = b[7];
594 out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
595 out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
596 out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
597 out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
598
599 b0 = b[8];b1 = b[9];b2 = b[10];b3 = b[11];
600 out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
601 out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
602 out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
603 out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
604
605 b0 = b[12];b1 = b[13];b2 = b[14];b3 = b[15];
606 out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
607 out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
608 out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
609 out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
610 return out;
611 }
612
613 /**
614 * Translate a mat4 by the given vector
615 *
616 * @param {mat4} out the receiving matrix
617 * @param {mat4} a the matrix to translate
618 * @param {vec3} v vector to translate by
619 * @returns {mat4} out
620 */
621 function translate$2(out, a, v) {
622 var x = v[0],
623 y = v[1],
624 z = v[2];
625 var a00 = void 0,
626 a01 = void 0,
627 a02 = void 0,
628 a03 = void 0;
629 var a10 = void 0,
630 a11 = void 0,
631 a12 = void 0,
632 a13 = void 0;
633 var a20 = void 0,
634 a21 = void 0,
635 a22 = void 0,
636 a23 = void 0;
637
638 if (a === out) {
639 out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
640 out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
641 out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
642 out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
643 } else {
644 a00 = a[0];a01 = a[1];a02 = a[2];a03 = a[3];
645 a10 = a[4];a11 = a[5];a12 = a[6];a13 = a[7];
646 a20 = a[8];a21 = a[9];a22 = a[10];a23 = a[11];
647
648 out[0] = a00;out[1] = a01;out[2] = a02;out[3] = a03;
649 out[4] = a10;out[5] = a11;out[6] = a12;out[7] = a13;
650 out[8] = a20;out[9] = a21;out[10] = a22;out[11] = a23;
651
652 out[12] = a00 * x + a10 * y + a20 * z + a[12];
653 out[13] = a01 * x + a11 * y + a21 * z + a[13];
654 out[14] = a02 * x + a12 * y + a22 * z + a[14];
655 out[15] = a03 * x + a13 * y + a23 * z + a[15];
656 }
657
658 return out;
659 }
660
661 /**
662 * Scales the mat4 by the dimensions in the given vec3 not using vectorization
663 *
664 * @param {mat4} out the receiving matrix
665 * @param {mat4} a the matrix to scale
666 * @param {vec3} v the vec3 to scale the matrix by
667 * @returns {mat4} out
668 **/
669 function scale$3(out, a, v) {
670 var x = v[0],
671 y = v[1],
672 z = v[2];
673
674 out[0] = a[0] * x;
675 out[1] = a[1] * x;
676 out[2] = a[2] * x;
677 out[3] = a[3] * x;
678 out[4] = a[4] * y;
679 out[5] = a[5] * y;
680 out[6] = a[6] * y;
681 out[7] = a[7] * y;
682 out[8] = a[8] * z;
683 out[9] = a[9] * z;
684 out[10] = a[10] * z;
685 out[11] = a[11] * z;
686 out[12] = a[12];
687 out[13] = a[13];
688 out[14] = a[14];
689 out[15] = a[15];
690 return out;
691 }
692
693 /**
694 * Rotates a mat4 by the given angle around the given axis
695 *
696 * @param {mat4} out the receiving matrix
697 * @param {mat4} a the matrix to rotate
698 * @param {Number} rad the angle to rotate the matrix by
699 * @param {vec3} axis the axis to rotate around
700 * @returns {mat4} out
701 */
702 function rotate$3(out, a, rad, axis) {
703 var x = axis[0],
704 y = axis[1],
705 z = axis[2];
706 var len = Math.sqrt(x * x + y * y + z * z);
707 var s = void 0,
708 c = void 0,
709 t = void 0;
710 var a00 = void 0,
711 a01 = void 0,
712 a02 = void 0,
713 a03 = void 0;
714 var a10 = void 0,
715 a11 = void 0,
716 a12 = void 0,
717 a13 = void 0;
718 var a20 = void 0,
719 a21 = void 0,
720 a22 = void 0,
721 a23 = void 0;
722 var b00 = void 0,
723 b01 = void 0,
724 b02 = void 0;
725 var b10 = void 0,
726 b11 = void 0,
727 b12 = void 0;
728 var b20 = void 0,
729 b21 = void 0,
730 b22 = void 0;
731
732 if (len < EPSILON) {
733 return null;
734 }
735
736 len = 1 / len;
737 x *= len;
738 y *= len;
739 z *= len;
740
741 s = Math.sin(rad);
742 c = Math.cos(rad);
743 t = 1 - c;
744
745 a00 = a[0];a01 = a[1];a02 = a[2];a03 = a[3];
746 a10 = a[4];a11 = a[5];a12 = a[6];a13 = a[7];
747 a20 = a[8];a21 = a[9];a22 = a[10];a23 = a[11];
748
749 // Construct the elements of the rotation matrix
750 b00 = x * x * t + c;b01 = y * x * t + z * s;b02 = z * x * t - y * s;
751 b10 = x * y * t - z * s;b11 = y * y * t + c;b12 = z * y * t + x * s;
752 b20 = x * z * t + y * s;b21 = y * z * t - x * s;b22 = z * z * t + c;
753
754 // Perform rotation-specific matrix multiplication
755 out[0] = a00 * b00 + a10 * b01 + a20 * b02;
756 out[1] = a01 * b00 + a11 * b01 + a21 * b02;
757 out[2] = a02 * b00 + a12 * b01 + a22 * b02;
758 out[3] = a03 * b00 + a13 * b01 + a23 * b02;
759 out[4] = a00 * b10 + a10 * b11 + a20 * b12;
760 out[5] = a01 * b10 + a11 * b11 + a21 * b12;
761 out[6] = a02 * b10 + a12 * b11 + a22 * b12;
762 out[7] = a03 * b10 + a13 * b11 + a23 * b12;
763 out[8] = a00 * b20 + a10 * b21 + a20 * b22;
764 out[9] = a01 * b20 + a11 * b21 + a21 * b22;
765 out[10] = a02 * b20 + a12 * b21 + a22 * b22;
766 out[11] = a03 * b20 + a13 * b21 + a23 * b22;
767
768 if (a !== out) {
769 // If the source and destination differ, copy the unchanged last row
770 out[12] = a[12];
771 out[13] = a[13];
772 out[14] = a[14];
773 out[15] = a[15];
774 }
775 return out;
776 }
777
778 /**
779 * Rotates a matrix by the given angle around the X axis
780 *
781 * @param {mat4} out the receiving matrix
782 * @param {mat4} a the matrix to rotate
783 * @param {Number} rad the angle to rotate the matrix by
784 * @returns {mat4} out
785 */
786 function rotateX(out, a, rad) {
787 var s = Math.sin(rad);
788 var c = Math.cos(rad);
789 var a10 = a[4];
790 var a11 = a[5];
791 var a12 = a[6];
792 var a13 = a[7];
793 var a20 = a[8];
794 var a21 = a[9];
795 var a22 = a[10];
796 var a23 = a[11];
797
798 if (a !== out) {
799 // If the source and destination differ, copy the unchanged rows
800 out[0] = a[0];
801 out[1] = a[1];
802 out[2] = a[2];
803 out[3] = a[3];
804 out[12] = a[12];
805 out[13] = a[13];
806 out[14] = a[14];
807 out[15] = a[15];
808 }
809
810 // Perform axis-specific matrix multiplication
811 out[4] = a10 * c + a20 * s;
812 out[5] = a11 * c + a21 * s;
813 out[6] = a12 * c + a22 * s;
814 out[7] = a13 * c + a23 * s;
815 out[8] = a20 * c - a10 * s;
816 out[9] = a21 * c - a11 * s;
817 out[10] = a22 * c - a12 * s;
818 out[11] = a23 * c - a13 * s;
819 return out;
820 }
821
822 /**
823 * Rotates a matrix by the given angle around the Y axis
824 *
825 * @param {mat4} out the receiving matrix
826 * @param {mat4} a the matrix to rotate
827 * @param {Number} rad the angle to rotate the matrix by
828 * @returns {mat4} out
829 */
830 function rotateY(out, a, rad) {
831 var s = Math.sin(rad);
832 var c = Math.cos(rad);
833 var a00 = a[0];
834 var a01 = a[1];
835 var a02 = a[2];
836 var a03 = a[3];
837 var a20 = a[8];
838 var a21 = a[9];
839 var a22 = a[10];
840 var a23 = a[11];
841
842 if (a !== out) {
843 // If the source and destination differ, copy the unchanged rows
844 out[4] = a[4];
845 out[5] = a[5];
846 out[6] = a[6];
847 out[7] = a[7];
848 out[12] = a[12];
849 out[13] = a[13];
850 out[14] = a[14];
851 out[15] = a[15];
852 }
853
854 // Perform axis-specific matrix multiplication
855 out[0] = a00 * c - a20 * s;
856 out[1] = a01 * c - a21 * s;
857 out[2] = a02 * c - a22 * s;
858 out[3] = a03 * c - a23 * s;
859 out[8] = a00 * s + a20 * c;
860 out[9] = a01 * s + a21 * c;
861 out[10] = a02 * s + a22 * c;
862 out[11] = a03 * s + a23 * c;
863 return out;
864 }
865
866 /**
867 * Rotates a matrix by the given angle around the Z axis
868 *
869 * @param {mat4} out the receiving matrix
870 * @param {mat4} a the matrix to rotate
871 * @param {Number} rad the angle to rotate the matrix by
872 * @returns {mat4} out
873 */
874 function rotateZ(out, a, rad) {
875 var s = Math.sin(rad);
876 var c = Math.cos(rad);
877 var a00 = a[0];
878 var a01 = a[1];
879 var a02 = a[2];
880 var a03 = a[3];
881 var a10 = a[4];
882 var a11 = a[5];
883 var a12 = a[6];
884 var a13 = a[7];
885
886 if (a !== out) {
887 // If the source and destination differ, copy the unchanged last row
888 out[8] = a[8];
889 out[9] = a[9];
890 out[10] = a[10];
891 out[11] = a[11];
892 out[12] = a[12];
893 out[13] = a[13];
894 out[14] = a[14];
895 out[15] = a[15];
896 }
897
898 // Perform axis-specific matrix multiplication
899 out[0] = a00 * c + a10 * s;
900 out[1] = a01 * c + a11 * s;
901 out[2] = a02 * c + a12 * s;
902 out[3] = a03 * c + a13 * s;
903 out[4] = a10 * c - a00 * s;
904 out[5] = a11 * c - a01 * s;
905 out[6] = a12 * c - a02 * s;
906 out[7] = a13 * c - a03 * s;
907 return out;
908 }
909
910 /**
911 * Creates a matrix from a vector translation
912 * This is equivalent to (but much faster than):
913 *
914 * mat4.identity(dest);
915 * mat4.translate(dest, dest, vec);
916 *
917 * @param {mat4} out mat4 receiving operation result
918 * @param {vec3} v Translation vector
919 * @returns {mat4} out
920 */
921 function fromTranslation$2(out, v) {
922 out[0] = 1;
923 out[1] = 0;
924 out[2] = 0;
925 out[3] = 0;
926 out[4] = 0;
927 out[5] = 1;
928 out[6] = 0;
929 out[7] = 0;
930 out[8] = 0;
931 out[9] = 0;
932 out[10] = 1;
933 out[11] = 0;
934 out[12] = v[0];
935 out[13] = v[1];
936 out[14] = v[2];
937 out[15] = 1;
938 return out;
939 }
940
941 /**
942 * Creates a matrix from a vector scaling
943 * This is equivalent to (but much faster than):
944 *
945 * mat4.identity(dest);
946 * mat4.scale(dest, dest, vec);
947 *
948 * @param {mat4} out mat4 receiving operation result
949 * @param {vec3} v Scaling vector
950 * @returns {mat4} out
951 */
952 function fromScaling$3(out, v) {
953 out[0] = v[0];
954 out[1] = 0;
955 out[2] = 0;
956 out[3] = 0;
957 out[4] = 0;
958 out[5] = v[1];
959 out[6] = 0;
960 out[7] = 0;
961 out[8] = 0;
962 out[9] = 0;
963 out[10] = v[2];
964 out[11] = 0;
965 out[12] = 0;
966 out[13] = 0;
967 out[14] = 0;
968 out[15] = 1;
969 return out;
970 }
971
972 /**
973 * Creates a matrix from a given angle around a given axis
974 * This is equivalent to (but much faster than):
975 *
976 * mat4.identity(dest);
977 * mat4.rotate(dest, dest, rad, axis);
978 *
979 * @param {mat4} out mat4 receiving operation result
980 * @param {Number} rad the angle to rotate the matrix by
981 * @param {vec3} axis the axis to rotate around
982 * @returns {mat4} out
983 */
984 function fromRotation$3(out, rad, axis) {
985 var x = axis[0],
986 y = axis[1],
987 z = axis[2];
988 var len = Math.sqrt(x * x + y * y + z * z);
989 var s = void 0,
990 c = void 0,
991 t = void 0;
992
993 if (len < EPSILON) {
994 return null;
995 }
996
997 len = 1 / len;
998 x *= len;
999 y *= len;
1000 z *= len;
1001
1002 s = Math.sin(rad);
1003 c = Math.cos(rad);
1004 t = 1 - c;
1005
1006 // Perform rotation-specific matrix multiplication
1007 out[0] = x * x * t + c;
1008 out[1] = y * x * t + z * s;
1009 out[2] = z * x * t - y * s;
1010 out[3] = 0;
1011 out[4] = x * y * t - z * s;
1012 out[5] = y * y * t + c;
1013 out[6] = z * y * t + x * s;
1014 out[7] = 0;
1015 out[8] = x * z * t + y * s;
1016 out[9] = y * z * t - x * s;
1017 out[10] = z * z * t + c;
1018 out[11] = 0;
1019 out[12] = 0;
1020 out[13] = 0;
1021 out[14] = 0;
1022 out[15] = 1;
1023 return out;
1024 }
1025
1026 /**
1027 * Creates a matrix from the given angle around the X axis
1028 * This is equivalent to (but much faster than):
1029 *
1030 * mat4.identity(dest);
1031 * mat4.rotateX(dest, dest, rad);
1032 *
1033 * @param {mat4} out mat4 receiving operation result
1034 * @param {Number} rad the angle to rotate the matrix by
1035 * @returns {mat4} out
1036 */
1037 function fromXRotation(out, rad) {
1038 var s = Math.sin(rad);
1039 var c = Math.cos(rad);
1040
1041 // Perform axis-specific matrix multiplication
1042 out[0] = 1;
1043 out[1] = 0;
1044 out[2] = 0;
1045 out[3] = 0;
1046 out[4] = 0;
1047 out[5] = c;
1048 out[6] = s;
1049 out[7] = 0;
1050 out[8] = 0;
1051 out[9] = -s;
1052 out[10] = c;
1053 out[11] = 0;
1054 out[12] = 0;
1055 out[13] = 0;
1056 out[14] = 0;
1057 out[15] = 1;
1058 return out;
1059 }
1060
1061 /**
1062 * Creates a matrix from the given angle around the Y axis
1063 * This is equivalent to (but much faster than):
1064 *
1065 * mat4.identity(dest);
1066 * mat4.rotateY(dest, dest, rad);
1067 *
1068 * @param {mat4} out mat4 receiving operation result
1069 * @param {Number} rad the angle to rotate the matrix by
1070 * @returns {mat4} out
1071 */
1072 function fromYRotation(out, rad) {
1073 var s = Math.sin(rad);
1074 var c = Math.cos(rad);
1075
1076 // Perform axis-specific matrix multiplication
1077 out[0] = c;
1078 out[1] = 0;
1079 out[2] = -s;
1080 out[3] = 0;
1081 out[4] = 0;
1082 out[5] = 1;
1083 out[6] = 0;
1084 out[7] = 0;
1085 out[8] = s;
1086 out[9] = 0;
1087 out[10] = c;
1088 out[11] = 0;
1089 out[12] = 0;
1090 out[13] = 0;
1091 out[14] = 0;
1092 out[15] = 1;
1093 return out;
1094 }
1095
1096 /**
1097 * Creates a matrix from the given angle around the Z axis
1098 * This is equivalent to (but much faster than):
1099 *
1100 * mat4.identity(dest);
1101 * mat4.rotateZ(dest, dest, rad);
1102 *
1103 * @param {mat4} out mat4 receiving operation result
1104 * @param {Number} rad the angle to rotate the matrix by
1105 * @returns {mat4} out
1106 */
1107 function fromZRotation(out, rad) {
1108 var s = Math.sin(rad);
1109 var c = Math.cos(rad);
1110
1111 // Perform axis-specific matrix multiplication
1112 out[0] = c;
1113 out[1] = s;
1114 out[2] = 0;
1115 out[3] = 0;
1116 out[4] = -s;
1117 out[5] = c;
1118 out[6] = 0;
1119 out[7] = 0;
1120 out[8] = 0;
1121 out[9] = 0;
1122 out[10] = 1;
1123 out[11] = 0;
1124 out[12] = 0;
1125 out[13] = 0;
1126 out[14] = 0;
1127 out[15] = 1;
1128 return out;
1129 }
1130
1131 /**
1132 * Creates a matrix from a quaternion rotation and vector translation
1133 * This is equivalent to (but much faster than):
1134 *
1135 * mat4.identity(dest);
1136 * mat4.translate(dest, vec);
1137 * let quatMat = mat4.create();
1138 * quat4.toMat4(quat, quatMat);
1139 * mat4.multiply(dest, quatMat);
1140 *
1141 * @param {mat4} out mat4 receiving operation result
1142 * @param {quat4} q Rotation quaternion
1143 * @param {vec3} v Translation vector
1144 * @returns {mat4} out
1145 */
1146 function fromRotationTranslation(out, q, v) {
1147 // Quaternion math
1148 var x = q[0],
1149 y = q[1],
1150 z = q[2],
1151 w = q[3];
1152 var x2 = x + x;
1153 var y2 = y + y;
1154 var z2 = z + z;
1155
1156 var xx = x * x2;
1157 var xy = x * y2;
1158 var xz = x * z2;
1159 var yy = y * y2;
1160 var yz = y * z2;
1161 var zz = z * z2;
1162 var wx = w * x2;
1163 var wy = w * y2;
1164 var wz = w * z2;
1165
1166 out[0] = 1 - (yy + zz);
1167 out[1] = xy + wz;
1168 out[2] = xz - wy;
1169 out[3] = 0;
1170 out[4] = xy - wz;
1171 out[5] = 1 - (xx + zz);
1172 out[6] = yz + wx;
1173 out[7] = 0;
1174 out[8] = xz + wy;
1175 out[9] = yz - wx;
1176 out[10] = 1 - (xx + yy);
1177 out[11] = 0;
1178 out[12] = v[0];
1179 out[13] = v[1];
1180 out[14] = v[2];
1181 out[15] = 1;
1182
1183 return out;
1184 }
1185
1186 /**
1187 * Creates a new mat4 from a dual quat.
1188 *
1189 * @param {mat4} out Matrix
1190 * @param {quat2} a Dual Quaternion
1191 * @returns {mat4} mat4 receiving operation result
1192 */
1193 function fromQuat2(out, a) {
1194 var translation = new ARRAY_TYPE(3);
1195 var bx = -a[0],
1196 by = -a[1],
1197 bz = -a[2],
1198 bw = a[3],
1199 ax = a[4],
1200 ay = a[5],
1201 az = a[6],
1202 aw = a[7];
1203
1204 var magnitude = bx * bx + by * by + bz * bz + bw * bw;
1205 //Only scale if it makes sense
1206 if (magnitude > 0) {
1207 translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;
1208 translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;
1209 translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;
1210 } else {
1211 translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
1212 translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
1213 translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
1214 }
1215 fromRotationTranslation(out, a, translation);
1216 return out;
1217 }
1218
1219 /**
1220 * Returns the translation vector component of a transformation
1221 * matrix. If a matrix is built with fromRotationTranslation,
1222 * the returned vector will be the same as the translation vector
1223 * originally supplied.
1224 * @param {vec3} out Vector to receive translation component
1225 * @param {mat4} mat Matrix to be decomposed (input)
1226 * @return {vec3} out
1227 */
1228 function getTranslation(out, mat) {
1229 out[0] = mat[12];
1230 out[1] = mat[13];
1231 out[2] = mat[14];
1232
1233 return out;
1234 }
1235
1236 /**
1237 * Returns the scaling factor component of a transformation
1238 * matrix. If a matrix is built with fromRotationTranslationScale
1239 * with a normalized Quaternion paramter, the returned vector will be
1240 * the same as the scaling vector
1241 * originally supplied.
1242 * @param {vec3} out Vector to receive scaling factor component
1243 * @param {mat4} mat Matrix to be decomposed (input)
1244 * @return {vec3} out
1245 */
1246 function getScaling(out, mat) {
1247 var m11 = mat[0];
1248 var m12 = mat[1];
1249 var m13 = mat[2];
1250 var m21 = mat[4];
1251 var m22 = mat[5];
1252 var m23 = mat[6];
1253 var m31 = mat[8];
1254 var m32 = mat[9];
1255 var m33 = mat[10];
1256
1257 out[0] = Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13);
1258 out[1] = Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23);
1259 out[2] = Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33);
1260
1261 return out;
1262 }
1263
1264 /**
1265 * Returns a quaternion representing the rotational component
1266 * of a transformation matrix. If a matrix is built with
1267 * fromRotationTranslation, the returned quaternion will be the
1268 * same as the quaternion originally supplied.
1269 * @param {quat} out Quaternion to receive the rotation component
1270 * @param {mat4} mat Matrix to be decomposed (input)
1271 * @return {quat} out
1272 */
1273 function getRotation(out, mat) {
1274 // Algorithm taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
1275 var trace = mat[0] + mat[5] + mat[10];
1276 var S = 0;
1277
1278 if (trace > 0) {
1279 S = Math.sqrt(trace + 1.0) * 2;
1280 out[3] = 0.25 * S;
1281 out[0] = (mat[6] - mat[9]) / S;
1282 out[1] = (mat[8] - mat[2]) / S;
1283 out[2] = (mat[1] - mat[4]) / S;
1284 } else if (mat[0] > mat[5] && mat[0] > mat[10]) {
1285 S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2;
1286 out[3] = (mat[6] - mat[9]) / S;
1287 out[0] = 0.25 * S;
1288 out[1] = (mat[1] + mat[4]) / S;
1289 out[2] = (mat[8] + mat[2]) / S;
1290 } else if (mat[5] > mat[10]) {
1291 S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2;
1292 out[3] = (mat[8] - mat[2]) / S;
1293 out[0] = (mat[1] + mat[4]) / S;
1294 out[1] = 0.25 * S;
1295 out[2] = (mat[6] + mat[9]) / S;
1296 } else {
1297 S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2;
1298 out[3] = (mat[1] - mat[4]) / S;
1299 out[0] = (mat[8] + mat[2]) / S;
1300 out[1] = (mat[6] + mat[9]) / S;
1301 out[2] = 0.25 * S;
1302 }
1303
1304 return out;
1305 }
1306
1307 /**
1308 * Creates a matrix from a quaternion rotation, vector translation and vector scale
1309 * This is equivalent to (but much faster than):
1310 *
1311 * mat4.identity(dest);
1312 * mat4.translate(dest, vec);
1313 * let quatMat = mat4.create();
1314 * quat4.toMat4(quat, quatMat);
1315 * mat4.multiply(dest, quatMat);
1316 * mat4.scale(dest, scale)
1317 *
1318 * @param {mat4} out mat4 receiving operation result
1319 * @param {quat4} q Rotation quaternion
1320 * @param {vec3} v Translation vector
1321 * @param {vec3} s Scaling vector
1322 * @returns {mat4} out
1323 */
1324 function fromRotationTranslationScale(out, q, v, s) {
1325 // Quaternion math
1326 var x = q[0],
1327 y = q[1],
1328 z = q[2],
1329 w = q[3];
1330 var x2 = x + x;
1331 var y2 = y + y;
1332 var z2 = z + z;
1333
1334 var xx = x * x2;
1335 var xy = x * y2;
1336 var xz = x * z2;
1337 var yy = y * y2;
1338 var yz = y * z2;
1339 var zz = z * z2;
1340 var wx = w * x2;
1341 var wy = w * y2;
1342 var wz = w * z2;
1343 var sx = s[0];
1344 var sy = s[1];
1345 var sz = s[2];
1346
1347 out[0] = (1 - (yy + zz)) * sx;
1348 out[1] = (xy + wz) * sx;
1349 out[2] = (xz - wy) * sx;
1350 out[3] = 0;
1351 out[4] = (xy - wz) * sy;
1352 out[5] = (1 - (xx + zz)) * sy;
1353 out[6] = (yz + wx) * sy;
1354 out[7] = 0;
1355 out[8] = (xz + wy) * sz;
1356 out[9] = (yz - wx) * sz;
1357 out[10] = (1 - (xx + yy)) * sz;
1358 out[11] = 0;
1359 out[12] = v[0];
1360 out[13] = v[1];
1361 out[14] = v[2];
1362 out[15] = 1;
1363
1364 return out;
1365 }
1366
1367 /**
1368 * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
1369 * This is equivalent to (but much faster than):
1370 *
1371 * mat4.identity(dest);
1372 * mat4.translate(dest, vec);
1373 * mat4.translate(dest, origin);
1374 * let quatMat = mat4.create();
1375 * quat4.toMat4(quat, quatMat);
1376 * mat4.multiply(dest, quatMat);
1377 * mat4.scale(dest, scale)
1378 * mat4.translate(dest, negativeOrigin);
1379 *
1380 * @param {mat4} out mat4 receiving operation result
1381 * @param {quat4} q Rotation quaternion
1382 * @param {vec3} v Translation vector
1383 * @param {vec3} s Scaling vector
1384 * @param {vec3} o The origin vector around which to scale and rotate
1385 * @returns {mat4} out
1386 */
1387 function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
1388 // Quaternion math
1389 var x = q[0],
1390 y = q[1],
1391 z = q[2],
1392 w = q[3];
1393 var x2 = x + x;
1394 var y2 = y + y;
1395 var z2 = z + z;
1396
1397 var xx = x * x2;
1398 var xy = x * y2;
1399 var xz = x * z2;
1400 var yy = y * y2;
1401 var yz = y * z2;
1402 var zz = z * z2;
1403 var wx = w * x2;
1404 var wy = w * y2;
1405 var wz = w * z2;
1406
1407 var sx = s[0];
1408 var sy = s[1];
1409 var sz = s[2];
1410
1411 var ox = o[0];
1412 var oy = o[1];
1413 var oz = o[2];
1414
1415 var out0 = (1 - (yy + zz)) * sx;
1416 var out1 = (xy + wz) * sx;
1417 var out2 = (xz - wy) * sx;
1418 var out4 = (xy - wz) * sy;
1419 var out5 = (1 - (xx + zz)) * sy;
1420 var out6 = (yz + wx) * sy;
1421 var out8 = (xz + wy) * sz;
1422 var out9 = (yz - wx) * sz;
1423 var out10 = (1 - (xx + yy)) * sz;
1424
1425 out[0] = out0;
1426 out[1] = out1;
1427 out[2] = out2;
1428 out[3] = 0;
1429 out[4] = out4;
1430 out[5] = out5;
1431 out[6] = out6;
1432 out[7] = 0;
1433 out[8] = out8;
1434 out[9] = out9;
1435 out[10] = out10;
1436 out[11] = 0;
1437 out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);
1438 out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);
1439 out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);
1440 out[15] = 1;
1441
1442 return out;
1443 }
1444
1445 /**
1446 * Calculates a 4x4 matrix from the given quaternion
1447 *
1448 * @param {mat4} out mat4 receiving operation result
1449 * @param {quat} q Quaternion to create matrix from
1450 *
1451 * @returns {mat4} out
1452 */
1453 function fromQuat$1(out, q) {
1454 var x = q[0],
1455 y = q[1],
1456 z = q[2],
1457 w = q[3];
1458 var x2 = x + x;
1459 var y2 = y + y;
1460 var z2 = z + z;
1461
1462 var xx = x * x2;
1463 var yx = y * x2;
1464 var yy = y * y2;
1465 var zx = z * x2;
1466 var zy = z * y2;
1467 var zz = z * z2;
1468 var wx = w * x2;
1469 var wy = w * y2;
1470 var wz = w * z2;
1471
1472 out[0] = 1 - yy - zz;
1473 out[1] = yx + wz;
1474 out[2] = zx - wy;
1475 out[3] = 0;
1476
1477 out[4] = yx - wz;
1478 out[5] = 1 - xx - zz;
1479 out[6] = zy + wx;
1480 out[7] = 0;
1481
1482 out[8] = zx + wy;
1483 out[9] = zy - wx;
1484 out[10] = 1 - xx - yy;
1485 out[11] = 0;
1486
1487 out[12] = 0;
1488 out[13] = 0;
1489 out[14] = 0;
1490 out[15] = 1;
1491
1492 return out;
1493 }
1494
1495 /**
1496 * Generates a frustum matrix with the given bounds
1497 *
1498 * @param {mat4} out mat4 frustum matrix will be written into
1499 * @param {Number} left Left bound of the frustum
1500 * @param {Number} right Right bound of the frustum
1501 * @param {Number} bottom Bottom bound of the frustum
1502 * @param {Number} top Top bound of the frustum
1503 * @param {Number} near Near bound of the frustum
1504 * @param {Number} far Far bound of the frustum
1505 * @returns {mat4} out
1506 */
1507 function frustum(out, left, right, bottom, top, near, far) {
1508 var rl = 1 / (right - left);
1509 var tb = 1 / (top - bottom);
1510 var nf = 1 / (near - far);
1511 out[0] = near * 2 * rl;
1512 out[1] = 0;
1513 out[2] = 0;
1514 out[3] = 0;
1515 out[4] = 0;
1516 out[5] = near * 2 * tb;
1517 out[6] = 0;
1518 out[7] = 0;
1519 out[8] = (right + left) * rl;
1520 out[9] = (top + bottom) * tb;
1521 out[10] = (far + near) * nf;
1522 out[11] = -1;
1523 out[12] = 0;
1524 out[13] = 0;
1525 out[14] = far * near * 2 * nf;
1526 out[15] = 0;
1527 return out;
1528 }
1529
1530 /**
1531 * Generates a perspective projection matrix with the given bounds.
1532 * Passing null/undefined/no value for far will generate infinite projection matrix.
1533 *
1534 * @param {mat4} out mat4 frustum matrix will be written into
1535 * @param {number} fovy Vertical field of view in radians
1536 * @param {number} aspect Aspect ratio. typically viewport width/height
1537 * @param {number} near Near bound of the frustum
1538 * @param {number} far Far bound of the frustum, can be null or Infinity
1539 * @returns {mat4} out
1540 */
1541 function perspective(out, fovy, aspect, near, far) {
1542 var f = 1.0 / Math.tan(fovy / 2),
1543 nf = void 0;
1544 out[0] = f / aspect;
1545 out[1] = 0;
1546 out[2] = 0;
1547 out[3] = 0;
1548 out[4] = 0;
1549 out[5] = f;
1550 out[6] = 0;
1551 out[7] = 0;
1552 out[8] = 0;
1553 out[9] = 0;
1554 out[11] = -1;
1555 out[12] = 0;
1556 out[13] = 0;
1557 out[15] = 0;
1558 if (far != null && far !== Infinity) {
1559 nf = 1 / (near - far);
1560 out[10] = (far + near) * nf;
1561 out[14] = 2 * far * near * nf;
1562 } else {
1563 out[10] = -1;
1564 out[14] = -2 * near;
1565 }
1566 return out;
1567 }
1568
1569 /**
1570 * Generates a perspective projection matrix with the given field of view.
1571 * This is primarily useful for generating projection matrices to be used
1572 * with the still experiemental WebVR API.
1573 *
1574 * @param {mat4} out mat4 frustum matrix will be written into
1575 * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
1576 * @param {number} near Near bound of the frustum
1577 * @param {number} far Far bound of the frustum
1578 * @returns {mat4} out
1579 */
1580 function perspectiveFromFieldOfView(out, fov, near, far) {
1581 var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
1582 var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
1583 var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
1584 var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
1585 var xScale = 2.0 / (leftTan + rightTan);
1586 var yScale = 2.0 / (upTan + downTan);
1587
1588 out[0] = xScale;
1589 out[1] = 0.0;
1590 out[2] = 0.0;
1591 out[3] = 0.0;
1592 out[4] = 0.0;
1593 out[5] = yScale;
1594 out[6] = 0.0;
1595 out[7] = 0.0;
1596 out[8] = -((leftTan - rightTan) * xScale * 0.5);
1597 out[9] = (upTan - downTan) * yScale * 0.5;
1598 out[10] = far / (near - far);
1599 out[11] = -1.0;
1600 out[12] = 0.0;
1601 out[13] = 0.0;
1602 out[14] = far * near / (near - far);
1603 out[15] = 0.0;
1604 return out;
1605 }
1606
1607 /**
1608 * Generates a orthogonal projection matrix with the given bounds
1609 *
1610 * @param {mat4} out mat4 frustum matrix will be written into
1611 * @param {number} left Left bound of the frustum
1612 * @param {number} right Right bound of the frustum
1613 * @param {number} bottom Bottom bound of the frustum
1614 * @param {number} top Top bound of the frustum
1615 * @param {number} near Near bound of the frustum
1616 * @param {number} far Far bound of the frustum
1617 * @returns {mat4} out
1618 */
1619 function ortho(out, left, right, bottom, top, near, far) {
1620 var lr = 1 / (left - right);
1621 var bt = 1 / (bottom - top);
1622 var nf = 1 / (near - far);
1623 out[0] = -2 * lr;
1624 out[1] = 0;
1625 out[2] = 0;
1626 out[3] = 0;
1627 out[4] = 0;
1628 out[5] = -2 * bt;
1629 out[6] = 0;
1630 out[7] = 0;
1631 out[8] = 0;
1632 out[9] = 0;
1633 out[10] = 2 * nf;
1634 out[11] = 0;
1635 out[12] = (left + right) * lr;
1636 out[13] = (top + bottom) * bt;
1637 out[14] = (far + near) * nf;
1638 out[15] = 1;
1639 return out;
1640 }
1641
1642 /**
1643 * Generates a look-at matrix with the given eye position, focal point, and up axis.
1644 * If you want a matrix that actually makes an object look at another object, you should use targetTo instead.
1645 *
1646 * @param {mat4} out mat4 frustum matrix will be written into
1647 * @param {vec3} eye Position of the viewer
1648 * @param {vec3} center Point the viewer is looking at
1649 * @param {vec3} up vec3 pointing up
1650 * @returns {mat4} out
1651 */
1652 function lookAt(out, eye, center, up) {
1653 var x0 = void 0,
1654 x1 = void 0,
1655 x2 = void 0,
1656 y0 = void 0,
1657 y1 = void 0,
1658 y2 = void 0,
1659 z0 = void 0,
1660 z1 = void 0,
1661 z2 = void 0,
1662 len = void 0;
1663 var eyex = eye[0];
1664 var eyey = eye[1];
1665 var eyez = eye[2];
1666 var upx = up[0];
1667 var upy = up[1];
1668 var upz = up[2];
1669 var centerx = center[0];
1670 var centery = center[1];
1671 var centerz = center[2];
1672
1673 if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) {
1674 return identity$3(out);
1675 }
1676
1677 z0 = eyex - centerx;
1678 z1 = eyey - centery;
1679 z2 = eyez - centerz;
1680
1681 len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
1682 z0 *= len;
1683 z1 *= len;
1684 z2 *= len;
1685
1686 x0 = upy * z2 - upz * z1;
1687 x1 = upz * z0 - upx * z2;
1688 x2 = upx * z1 - upy * z0;
1689 len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
1690 if (!len) {
1691 x0 = 0;
1692 x1 = 0;
1693 x2 = 0;
1694 } else {
1695 len = 1 / len;
1696 x0 *= len;
1697 x1 *= len;
1698 x2 *= len;
1699 }
1700
1701 y0 = z1 * x2 - z2 * x1;
1702 y1 = z2 * x0 - z0 * x2;
1703 y2 = z0 * x1 - z1 * x0;
1704
1705 len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
1706 if (!len) {
1707 y0 = 0;
1708 y1 = 0;
1709 y2 = 0;
1710 } else {
1711 len = 1 / len;
1712 y0 *= len;
1713 y1 *= len;
1714 y2 *= len;
1715 }
1716
1717 out[0] = x0;
1718 out[1] = y0;
1719 out[2] = z0;
1720 out[3] = 0;
1721 out[4] = x1;
1722 out[5] = y1;
1723 out[6] = z1;
1724 out[7] = 0;
1725 out[8] = x2;
1726 out[9] = y2;
1727 out[10] = z2;
1728 out[11] = 0;
1729 out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
1730 out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
1731 out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
1732 out[15] = 1;
1733
1734 return out;
1735 }
1736
1737 /**
1738 * Generates a matrix that makes something look at something else.
1739 *
1740 * @param {mat4} out mat4 frustum matrix will be written into
1741 * @param {vec3} eye Position of the viewer
1742 * @param {vec3} center Point the viewer is looking at
1743 * @param {vec3} up vec3 pointing up
1744 * @returns {mat4} out
1745 */
1746 function targetTo(out, eye, target, up) {
1747 var eyex = eye[0],
1748 eyey = eye[1],
1749 eyez = eye[2],
1750 upx = up[0],
1751 upy = up[1],
1752 upz = up[2];
1753
1754 var z0 = eyex - target[0],
1755 z1 = eyey - target[1],
1756 z2 = eyez - target[2];
1757
1758 var len = z0 * z0 + z1 * z1 + z2 * z2;
1759 if (len > 0) {
1760 len = 1 / Math.sqrt(len);
1761 z0 *= len;
1762 z1 *= len;
1763 z2 *= len;
1764 }
1765
1766 var x0 = upy * z2 - upz * z1,
1767 x1 = upz * z0 - upx * z2,
1768 x2 = upx * z1 - upy * z0;
1769
1770 len = x0 * x0 + x1 * x1 + x2 * x2;
1771 if (len > 0) {
1772 len = 1 / Math.sqrt(len);
1773 x0 *= len;
1774 x1 *= len;
1775 x2 *= len;
1776 }
1777
1778 out[0] = x0;
1779 out[1] = x1;
1780 out[2] = x2;
1781 out[3] = 0;
1782 out[4] = z1 * x2 - z2 * x1;
1783 out[5] = z2 * x0 - z0 * x2;
1784 out[6] = z0 * x1 - z1 * x0;
1785 out[7] = 0;
1786 out[8] = z0;
1787 out[9] = z1;
1788 out[10] = z2;
1789 out[11] = 0;
1790 out[12] = eyex;
1791 out[13] = eyey;
1792 out[14] = eyez;
1793 out[15] = 1;
1794 return out;
1795 }
1796 /**
1797 * Returns a string representation of a mat4
1798 *
1799 * @param {mat4} a matrix to represent as a string
1800 * @returns {String} string representation of the matrix
1801 */
1802 function str$3(a) {
1803 return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
1804 }
1805
1806 /**
1807 * Returns Frobenius norm of a mat4
1808 *
1809 * @param {mat4} a the matrix to calculate Frobenius norm of
1810 * @returns {Number} Frobenius norm
1811 */
1812 function frob$3(a) {
1813 return Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2));
1814 }
1815
1816 /**
1817 * Adds two mat4's
1818 *
1819 * @param {mat4} out the receiving matrix
1820 * @param {mat4} a the first operand
1821 * @param {mat4} b the second operand
1822 * @returns {mat4} out
1823 */
1824 function add$3(out, a, b) {
1825 out[0] = a[0] + b[0];
1826 out[1] = a[1] + b[1];
1827 out[2] = a[2] + b[2];
1828 out[3] = a[3] + b[3];
1829 out[4] = a[4] + b[4];
1830 out[5] = a[5] + b[5];
1831 out[6] = a[6] + b[6];
1832 out[7] = a[7] + b[7];
1833 out[8] = a[8] + b[8];
1834 out[9] = a[9] + b[9];
1835 out[10] = a[10] + b[10];
1836 out[11] = a[11] + b[11];
1837 out[12] = a[12] + b[12];
1838 out[13] = a[13] + b[13];
1839 out[14] = a[14] + b[14];
1840 out[15] = a[15] + b[15];
1841 return out;
1842 }
1843
1844 /**
1845 * Subtracts matrix b from matrix a
1846 *
1847 * @param {mat4} out the receiving matrix
1848 * @param {mat4} a the first operand
1849 * @param {mat4} b the second operand
1850 * @returns {mat4} out
1851 */
1852 function subtract$3(out, a, b) {
1853 out[0] = a[0] - b[0];
1854 out[1] = a[1] - b[1];
1855 out[2] = a[2] - b[2];
1856 out[3] = a[3] - b[3];
1857 out[4] = a[4] - b[4];
1858 out[5] = a[5] - b[5];
1859 out[6] = a[6] - b[6];
1860 out[7] = a[7] - b[7];
1861 out[8] = a[8] - b[8];
1862 out[9] = a[9] - b[9];
1863 out[10] = a[10] - b[10];
1864 out[11] = a[11] - b[11];
1865 out[12] = a[12] - b[12];
1866 out[13] = a[13] - b[13];
1867 out[14] = a[14] - b[14];
1868 out[15] = a[15] - b[15];
1869 return out;
1870 }
1871
1872 /**
1873 * Multiply each element of the matrix by a scalar.
1874 *
1875 * @param {mat4} out the receiving matrix
1876 * @param {mat4} a the matrix to scale
1877 * @param {Number} b amount to scale the matrix's elements by
1878 * @returns {mat4} out
1879 */
1880 function multiplyScalar$3(out, a, b) {
1881 out[0] = a[0] * b;
1882 out[1] = a[1] * b;
1883 out[2] = a[2] * b;
1884 out[3] = a[3] * b;
1885 out[4] = a[4] * b;
1886 out[5] = a[5] * b;
1887 out[6] = a[6] * b;
1888 out[7] = a[7] * b;
1889 out[8] = a[8] * b;
1890 out[9] = a[9] * b;
1891 out[10] = a[10] * b;
1892 out[11] = a[11] * b;
1893 out[12] = a[12] * b;
1894 out[13] = a[13] * b;
1895 out[14] = a[14] * b;
1896 out[15] = a[15] * b;
1897 return out;
1898 }
1899
1900 /**
1901 * Adds two mat4's after multiplying each element of the second operand by a scalar value.
1902 *
1903 * @param {mat4} out the receiving vector
1904 * @param {mat4} a the first operand
1905 * @param {mat4} b the second operand
1906 * @param {Number} scale the amount to scale b's elements by before adding
1907 * @returns {mat4} out
1908 */
1909 function multiplyScalarAndAdd$3(out, a, b, scale) {
1910 out[0] = a[0] + b[0] * scale;
1911 out[1] = a[1] + b[1] * scale;
1912 out[2] = a[2] + b[2] * scale;
1913 out[3] = a[3] + b[3] * scale;
1914 out[4] = a[4] + b[4] * scale;
1915 out[5] = a[5] + b[5] * scale;
1916 out[6] = a[6] + b[6] * scale;
1917 out[7] = a[7] + b[7] * scale;
1918 out[8] = a[8] + b[8] * scale;
1919 out[9] = a[9] + b[9] * scale;
1920 out[10] = a[10] + b[10] * scale;
1921 out[11] = a[11] + b[11] * scale;
1922 out[12] = a[12] + b[12] * scale;
1923 out[13] = a[13] + b[13] * scale;
1924 out[14] = a[14] + b[14] * scale;
1925 out[15] = a[15] + b[15] * scale;
1926 return out;
1927 }
1928
1929 /**
1930 * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
1931 *
1932 * @param {mat4} a The first matrix.
1933 * @param {mat4} b The second matrix.
1934 * @returns {Boolean} True if the matrices are equal, false otherwise.
1935 */
1936 function exactEquals$3(a, b) {
1937 return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
1938 }
1939
1940 /**
1941 * Returns whether or not the matrices have approximately the same elements in the same position.
1942 *
1943 * @param {mat4} a The first matrix.
1944 * @param {mat4} b The second matrix.
1945 * @returns {Boolean} True if the matrices are equal, false otherwise.
1946 */
1947 function equals$4(a, b) {
1948 var a0 = a[0],
1949 a1 = a[1],
1950 a2 = a[2],
1951 a3 = a[3];
1952 var a4 = a[4],
1953 a5 = a[5],
1954 a6 = a[6],
1955 a7 = a[7];
1956 var a8 = a[8],
1957 a9 = a[9],
1958 a10 = a[10],
1959 a11 = a[11];
1960 var a12 = a[12],
1961 a13 = a[13],
1962 a14 = a[14],
1963 a15 = a[15];
1964
1965 var b0 = b[0],
1966 b1 = b[1],
1967 b2 = b[2],
1968 b3 = b[3];
1969 var b4 = b[4],
1970 b5 = b[5],
1971 b6 = b[6],
1972 b7 = b[7];
1973 var b8 = b[8],
1974 b9 = b[9],
1975 b10 = b[10],
1976 b11 = b[11];
1977 var b12 = b[12],
1978 b13 = b[13],
1979 b14 = b[14],
1980 b15 = b[15];
1981
1982 return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15));
1983 }
1984
1985 /**
1986 * Alias for {@link mat4.multiply}
1987 * @function
1988 */
1989 var mul$3 = multiply$3;
1990
1991 /**
1992 * Alias for {@link mat4.subtract}
1993 * @function
1994 */
1995 var sub$3 = subtract$3;
1996
1997 var mat4 = /*#__PURE__*/Object.freeze({
1998 create: create$3,
1999 clone: clone$3,
2000 copy: copy$3,
2001 fromValues: fromValues$3,
2002 set: set$3,
2003 identity: identity$3,
2004 transpose: transpose$2,
2005 invert: invert$3,
2006 adjoint: adjoint$2,
2007 determinant: determinant$3,
2008 multiply: multiply$3,
2009 translate: translate$2,
2010 scale: scale$3,
2011 rotate: rotate$3,
2012 rotateX: rotateX,
2013 rotateY: rotateY,
2014 rotateZ: rotateZ,
2015 fromTranslation: fromTranslation$2,
2016 fromScaling: fromScaling$3,
2017 fromRotation: fromRotation$3,
2018 fromXRotation: fromXRotation,
2019 fromYRotation: fromYRotation,
2020 fromZRotation: fromZRotation,
2021 fromRotationTranslation: fromRotationTranslation,
2022 fromQuat2: fromQuat2,
2023 getTranslation: getTranslation,
2024 getScaling: getScaling,
2025 getRotation: getRotation,
2026 fromRotationTranslationScale: fromRotationTranslationScale,
2027 fromRotationTranslationScaleOrigin: fromRotationTranslationScaleOrigin,
2028 fromQuat: fromQuat$1,
2029 frustum: frustum,
2030 perspective: perspective,
2031 perspectiveFromFieldOfView: perspectiveFromFieldOfView,
2032 ortho: ortho,
2033 lookAt: lookAt,
2034 targetTo: targetTo,
2035 str: str$3,
2036 frob: frob$3,
2037 add: add$3,
2038 subtract: subtract$3,
2039 multiplyScalar: multiplyScalar$3,
2040 multiplyScalarAndAdd: multiplyScalarAndAdd$3,
2041 exactEquals: exactEquals$3,
2042 equals: equals$4,
2043 mul: mul$3,
2044 sub: sub$3
2045 });
2046
2047 /**
2048 * 3 Dimensional Vector
2049 * @module vec3
2050 */
2051
2052 /**
2053 * Creates a new, empty vec3
2054 *
2055 * @returns {vec3} a new 3D vector
2056 */
2057 function create$4() {
2058 var out = new ARRAY_TYPE(3);
2059 if (ARRAY_TYPE != Float32Array) {
2060 out[0] = 0;
2061 out[1] = 0;
2062 out[2] = 0;
2063 }
2064 return out;
2065 }
2066
2067 /**
2068 * Creates a new vec3 initialized with values from an existing vector
2069 *
2070 * @param {vec3} a vector to clone
2071 * @returns {vec3} a new 3D vector
2072 */
2073 function clone$4(a) {
2074 var out = new ARRAY_TYPE(3);
2075 out[0] = a[0];
2076 out[1] = a[1];
2077 out[2] = a[2];
2078 return out;
2079 }
2080
2081 /**
2082 * Calculates the length of a vec3
2083 *
2084 * @param {vec3} a vector to calculate length of
2085 * @returns {Number} length of a
2086 */
2087 function length(a) {
2088 var x = a[0];
2089 var y = a[1];
2090 var z = a[2];
2091 return Math.sqrt(x * x + y * y + z * z);
2092 }
2093
2094 /**
2095 * Creates a new vec3 initialized with the given values
2096 *
2097 * @param {Number} x X component
2098 * @param {Number} y Y component
2099 * @param {Number} z Z component
2100 * @returns {vec3} a new 3D vector
2101 */
2102 function fromValues$4(x, y, z) {
2103 var out = new ARRAY_TYPE(3);
2104 out[0] = x;
2105 out[1] = y;
2106 out[2] = z;
2107 return out;
2108 }
2109
2110 /**
2111 * Copy the values from one vec3 to another
2112 *
2113 * @param {vec3} out the receiving vector
2114 * @param {vec3} a the source vector
2115 * @returns {vec3} out
2116 */
2117 function copy$4(out, a) {
2118 out[0] = a[0];
2119 out[1] = a[1];
2120 out[2] = a[2];
2121 return out;
2122 }
2123
2124 /**
2125 * Set the components of a vec3 to the given values
2126 *
2127 * @param {vec3} out the receiving vector
2128 * @param {Number} x X component
2129 * @param {Number} y Y component
2130 * @param {Number} z Z component
2131 * @returns {vec3} out
2132 */
2133 function set$4(out, x, y, z) {
2134 out[0] = x;
2135 out[1] = y;
2136 out[2] = z;
2137 return out;
2138 }
2139
2140 /**
2141 * Adds two vec3's
2142 *
2143 * @param {vec3} out the receiving vector
2144 * @param {vec3} a the first operand
2145 * @param {vec3} b the second operand
2146 * @returns {vec3} out
2147 */
2148 function add$4(out, a, b) {
2149 out[0] = a[0] + b[0];
2150 out[1] = a[1] + b[1];
2151 out[2] = a[2] + b[2];
2152 return out;
2153 }
2154
2155 /**
2156 * Subtracts vector b from vector a
2157 *
2158 * @param {vec3} out the receiving vector
2159 * @param {vec3} a the first operand
2160 * @param {vec3} b the second operand
2161 * @returns {vec3} out
2162 */
2163 function subtract$4(out, a, b) {
2164 out[0] = a[0] - b[0];
2165 out[1] = a[1] - b[1];
2166 out[2] = a[2] - b[2];
2167 return out;
2168 }
2169
2170 /**
2171 * Multiplies two vec3's
2172 *
2173 * @param {vec3} out the receiving vector
2174 * @param {vec3} a the first operand
2175 * @param {vec3} b the second operand
2176 * @returns {vec3} out
2177 */
2178 function multiply$4(out, a, b) {
2179 out[0] = a[0] * b[0];
2180 out[1] = a[1] * b[1];
2181 out[2] = a[2] * b[2];
2182 return out;
2183 }
2184
2185 /**
2186 * Divides two vec3's
2187 *
2188 * @param {vec3} out the receiving vector
2189 * @param {vec3} a the first operand
2190 * @param {vec3} b the second operand
2191 * @returns {vec3} out
2192 */
2193 function divide(out, a, b) {
2194 out[0] = a[0] / b[0];
2195 out[1] = a[1] / b[1];
2196 out[2] = a[2] / b[2];
2197 return out;
2198 }
2199
2200 /**
2201 * Math.ceil the components of a vec3
2202 *
2203 * @param {vec3} out the receiving vector
2204 * @param {vec3} a vector to ceil
2205 * @returns {vec3} out
2206 */
2207 function ceil(out, a) {
2208 out[0] = Math.ceil(a[0]);
2209 out[1] = Math.ceil(a[1]);
2210 out[2] = Math.ceil(a[2]);
2211 return out;
2212 }
2213
2214 /**
2215 * Math.floor the components of a vec3
2216 *
2217 * @param {vec3} out the receiving vector
2218 * @param {vec3} a vector to floor
2219 * @returns {vec3} out
2220 */
2221 function floor(out, a) {
2222 out[0] = Math.floor(a[0]);
2223 out[1] = Math.floor(a[1]);
2224 out[2] = Math.floor(a[2]);
2225 return out;
2226 }
2227
2228 /**
2229 * Returns the minimum of two vec3's
2230 *
2231 * @param {vec3} out the receiving vector
2232 * @param {vec3} a the first operand
2233 * @param {vec3} b the second operand
2234 * @returns {vec3} out
2235 */
2236 function min(out, a, b) {
2237 out[0] = Math.min(a[0], b[0]);
2238 out[1] = Math.min(a[1], b[1]);
2239 out[2] = Math.min(a[2], b[2]);
2240 return out;
2241 }
2242
2243 /**
2244 * Returns the maximum of two vec3's
2245 *
2246 * @param {vec3} out the receiving vector
2247 * @param {vec3} a the first operand
2248 * @param {vec3} b the second operand
2249 * @returns {vec3} out
2250 */
2251 function max(out, a, b) {
2252 out[0] = Math.max(a[0], b[0]);
2253 out[1] = Math.max(a[1], b[1]);
2254 out[2] = Math.max(a[2], b[2]);
2255 return out;
2256 }
2257
2258 /**
2259 * Math.round the components of a vec3
2260 *
2261 * @param {vec3} out the receiving vector
2262 * @param {vec3} a vector to round
2263 * @returns {vec3} out
2264 */
2265 function round(out, a) {
2266 out[0] = Math.round(a[0]);
2267 out[1] = Math.round(a[1]);
2268 out[2] = Math.round(a[2]);
2269 return out;
2270 }
2271
2272 /**
2273 * Scales a vec3 by a scalar number
2274 *
2275 * @param {vec3} out the receiving vector
2276 * @param {vec3} a the vector to scale
2277 * @param {Number} b amount to scale the vector by
2278 * @returns {vec3} out
2279 */
2280 function scale$4(out, a, b) {
2281 out[0] = a[0] * b;
2282 out[1] = a[1] * b;
2283 out[2] = a[2] * b;
2284 return out;
2285 }
2286
2287 /**
2288 * Adds two vec3's after scaling the second operand by a scalar value
2289 *
2290 * @param {vec3} out the receiving vector
2291 * @param {vec3} a the first operand
2292 * @param {vec3} b the second operand
2293 * @param {Number} scale the amount to scale b by before adding
2294 * @returns {vec3} out
2295 */
2296 function scaleAndAdd(out, a, b, scale) {
2297 out[0] = a[0] + b[0] * scale;
2298 out[1] = a[1] + b[1] * scale;
2299 out[2] = a[2] + b[2] * scale;
2300 return out;
2301 }
2302
2303 /**
2304 * Calculates the euclidian distance between two vec3's
2305 *
2306 * @param {vec3} a the first operand
2307 * @param {vec3} b the second operand
2308 * @returns {Number} distance between a and b
2309 */
2310 function distance(a, b) {
2311 var x = b[0] - a[0];
2312 var y = b[1] - a[1];
2313 var z = b[2] - a[2];
2314 return Math.sqrt(x * x + y * y + z * z);
2315 }
2316
2317 /**
2318 * Calculates the squared euclidian distance between two vec3's
2319 *
2320 * @param {vec3} a the first operand
2321 * @param {vec3} b the second operand
2322 * @returns {Number} squared distance between a and b
2323 */
2324 function squaredDistance(a, b) {
2325 var x = b[0] - a[0];
2326 var y = b[1] - a[1];
2327 var z = b[2] - a[2];
2328 return x * x + y * y + z * z;
2329 }
2330
2331 /**
2332 * Calculates the squared length of a vec3
2333 *
2334 * @param {vec3} a vector to calculate squared length of
2335 * @returns {Number} squared length of a
2336 */
2337 function squaredLength(a) {
2338 var x = a[0];
2339 var y = a[1];
2340 var z = a[2];
2341 return x * x + y * y + z * z;
2342 }
2343
2344 /**
2345 * Negates the components of a vec3
2346 *
2347 * @param {vec3} out the receiving vector
2348 * @param {vec3} a vector to negate
2349 * @returns {vec3} out
2350 */
2351 function negate(out, a) {
2352 out[0] = -a[0];
2353 out[1] = -a[1];
2354 out[2] = -a[2];
2355 return out;
2356 }
2357
2358 /**
2359 * Returns the inverse of the components of a vec3
2360 *
2361 * @param {vec3} out the receiving vector
2362 * @param {vec3} a vector to invert
2363 * @returns {vec3} out
2364 */
2365 function inverse(out, a) {
2366 out[0] = 1.0 / a[0];
2367 out[1] = 1.0 / a[1];
2368 out[2] = 1.0 / a[2];
2369 return out;
2370 }
2371
2372 /**
2373 * Normalize a vec3
2374 *
2375 * @param {vec3} out the receiving vector
2376 * @param {vec3} a vector to normalize
2377 * @returns {vec3} out
2378 */
2379 function normalize(out, a) {
2380 var x = a[0];
2381 var y = a[1];
2382 var z = a[2];
2383 var len = x * x + y * y + z * z;
2384 if (len > 0) {
2385 //TODO: evaluate use of glm_invsqrt here?
2386 len = 1 / Math.sqrt(len);
2387 out[0] = a[0] * len;
2388 out[1] = a[1] * len;
2389 out[2] = a[2] * len;
2390 }
2391 return out;
2392 }
2393
2394 /**
2395 * Calculates the dot product of two vec3's
2396 *
2397 * @param {vec3} a the first operand
2398 * @param {vec3} b the second operand
2399 * @returns {Number} dot product of a and b
2400 */
2401 function dot(a, b) {
2402 return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
2403 }
2404
2405 /**
2406 * Computes the cross product of two vec3's
2407 *
2408 * @param {vec3} out the receiving vector
2409 * @param {vec3} a the first operand
2410 * @param {vec3} b the second operand
2411 * @returns {vec3} out
2412 */
2413 function cross(out, a, b) {
2414 var ax = a[0],
2415 ay = a[1],
2416 az = a[2];
2417 var bx = b[0],
2418 by = b[1],
2419 bz = b[2];
2420
2421 out[0] = ay * bz - az * by;
2422 out[1] = az * bx - ax * bz;
2423 out[2] = ax * by - ay * bx;
2424 return out;
2425 }
2426
2427 /**
2428 * Performs a linear interpolation between two vec3's
2429 *
2430 * @param {vec3} out the receiving vector
2431 * @param {vec3} a the first operand
2432 * @param {vec3} b the second operand
2433 * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
2434 * @returns {vec3} out
2435 */
2436 function lerp(out, a, b, t) {
2437 var ax = a[0];
2438 var ay = a[1];
2439 var az = a[2];
2440 out[0] = ax + t * (b[0] - ax);
2441 out[1] = ay + t * (b[1] - ay);
2442 out[2] = az + t * (b[2] - az);
2443 return out;
2444 }
2445
2446 /**
2447 * Performs a hermite interpolation with two control points
2448 *
2449 * @param {vec3} out the receiving vector
2450 * @param {vec3} a the first operand
2451 * @param {vec3} b the second operand
2452 * @param {vec3} c the third operand
2453 * @param {vec3} d the fourth operand
2454 * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
2455 * @returns {vec3} out
2456 */
2457 function hermite(out, a, b, c, d, t) {
2458 var factorTimes2 = t * t;
2459 var factor1 = factorTimes2 * (2 * t - 3) + 1;
2460 var factor2 = factorTimes2 * (t - 2) + t;
2461 var factor3 = factorTimes2 * (t - 1);
2462 var factor4 = factorTimes2 * (3 - 2 * t);
2463
2464 out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
2465 out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
2466 out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
2467
2468 return out;
2469 }
2470
2471 /**
2472 * Performs a bezier interpolation with two control points
2473 *
2474 * @param {vec3} out the receiving vector
2475 * @param {vec3} a the first operand
2476 * @param {vec3} b the second operand
2477 * @param {vec3} c the third operand
2478 * @param {vec3} d the fourth operand
2479 * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
2480 * @returns {vec3} out
2481 */
2482 function bezier(out, a, b, c, d, t) {
2483 var inverseFactor = 1 - t;
2484 var inverseFactorTimesTwo = inverseFactor * inverseFactor;
2485 var factorTimes2 = t * t;
2486 var factor1 = inverseFactorTimesTwo * inverseFactor;
2487 var factor2 = 3 * t * inverseFactorTimesTwo;
2488 var factor3 = 3 * factorTimes2 * inverseFactor;
2489 var factor4 = factorTimes2 * t;
2490
2491 out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
2492 out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
2493 out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
2494
2495 return out;
2496 }
2497
2498 /**
2499 * Generates a random vector with the given scale
2500 *
2501 * @param {vec3} out the receiving vector
2502 * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
2503 * @returns {vec3} out
2504 */
2505 function random(out, scale) {
2506 scale = scale || 1.0;
2507
2508 var r = RANDOM() * 2.0 * Math.PI;
2509 var z = RANDOM() * 2.0 - 1.0;
2510 var zScale = Math.sqrt(1.0 - z * z) * scale;
2511
2512 out[0] = Math.cos(r) * zScale;
2513 out[1] = Math.sin(r) * zScale;
2514 out[2] = z * scale;
2515 return out;
2516 }
2517
2518 /**
2519 * Transforms the vec3 with a mat4.
2520 * 4th vector component is implicitly '1'
2521 *
2522 * @param {vec3} out the receiving vector
2523 * @param {vec3} a the vector to transform
2524 * @param {mat4} m matrix to transform with
2525 * @returns {vec3} out
2526 */
2527 function transformMat4(out, a, m) {
2528 var x = a[0],
2529 y = a[1],
2530 z = a[2];
2531 var w = m[3] * x + m[7] * y + m[11] * z + m[15];
2532 w = w || 1.0;
2533 out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
2534 out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
2535 out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
2536 return out;
2537 }
2538
2539 /**
2540 * Transforms the vec3 with a mat3.
2541 *
2542 * @param {vec3} out the receiving vector
2543 * @param {vec3} a the vector to transform
2544 * @param {mat3} m the 3x3 matrix to transform with
2545 * @returns {vec3} out
2546 */
2547 function transformMat3(out, a, m) {
2548 var x = a[0],
2549 y = a[1],
2550 z = a[2];
2551 out[0] = x * m[0] + y * m[3] + z * m[6];
2552 out[1] = x * m[1] + y * m[4] + z * m[7];
2553 out[2] = x * m[2] + y * m[5] + z * m[8];
2554 return out;
2555 }
2556
2557 /**
2558 * Transforms the vec3 with a quat
2559 * Can also be used for dual quaternions. (Multiply it with the real part)
2560 *
2561 * @param {vec3} out the receiving vector
2562 * @param {vec3} a the vector to transform
2563 * @param {quat} q quaternion to transform with
2564 * @returns {vec3} out
2565 */
2566 function transformQuat(out, a, q) {
2567 // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed
2568 var qx = q[0],
2569 qy = q[1],
2570 qz = q[2],
2571 qw = q[3];
2572 var x = a[0],
2573 y = a[1],
2574 z = a[2];
2575 // var qvec = [qx, qy, qz];
2576 // var uv = vec3.cross([], qvec, a);
2577 var uvx = qy * z - qz * y,
2578 uvy = qz * x - qx * z,
2579 uvz = qx * y - qy * x;
2580 // var uuv = vec3.cross([], qvec, uv);
2581 var uuvx = qy * uvz - qz * uvy,
2582 uuvy = qz * uvx - qx * uvz,
2583 uuvz = qx * uvy - qy * uvx;
2584 // vec3.scale(uv, uv, 2 * w);
2585 var w2 = qw * 2;
2586 uvx *= w2;
2587 uvy *= w2;
2588 uvz *= w2;
2589 // vec3.scale(uuv, uuv, 2);
2590 uuvx *= 2;
2591 uuvy *= 2;
2592 uuvz *= 2;
2593 // return vec3.add(out, a, vec3.add(out, uv, uuv));
2594 out[0] = x + uvx + uuvx;
2595 out[1] = y + uvy + uuvy;
2596 out[2] = z + uvz + uuvz;
2597 return out;
2598 }
2599
2600 /**
2601 * Rotate a 3D vector around the x-axis
2602 * @param {vec3} out The receiving vec3
2603 * @param {vec3} a The vec3 point to rotate
2604 * @param {vec3} b The origin of the rotation
2605 * @param {Number} c The angle of rotation
2606 * @returns {vec3} out
2607 */
2608 function rotateX$1(out, a, b, c) {
2609 var p = [],
2610 r = [];
2611 //Translate point to the origin
2612 p[0] = a[0] - b[0];
2613 p[1] = a[1] - b[1];
2614 p[2] = a[2] - b[2];
2615
2616 //perform rotation
2617 r[0] = p[0];
2618 r[1] = p[1] * Math.cos(c) - p[2] * Math.sin(c);
2619 r[2] = p[1] * Math.sin(c) + p[2] * Math.cos(c);
2620
2621 //translate to correct position
2622 out[0] = r[0] + b[0];
2623 out[1] = r[1] + b[1];
2624 out[2] = r[2] + b[2];
2625
2626 return out;
2627 }
2628
2629 /**
2630 * Rotate a 3D vector around the y-axis
2631 * @param {vec3} out The receiving vec3
2632 * @param {vec3} a The vec3 point to rotate
2633 * @param {vec3} b The origin of the rotation
2634 * @param {Number} c The angle of rotation
2635 * @returns {vec3} out
2636 */
2637 function rotateY$1(out, a, b, c) {
2638 var p = [],
2639 r = [];
2640 //Translate point to the origin
2641 p[0] = a[0] - b[0];
2642 p[1] = a[1] - b[1];
2643 p[2] = a[2] - b[2];
2644
2645 //perform rotation
2646 r[0] = p[2] * Math.sin(c) + p[0] * Math.cos(c);
2647 r[1] = p[1];
2648 r[2] = p[2] * Math.cos(c) - p[0] * Math.sin(c);
2649
2650 //translate to correct position
2651 out[0] = r[0] + b[0];
2652 out[1] = r[1] + b[1];
2653 out[2] = r[2] + b[2];
2654
2655 return out;
2656 }
2657
2658 /**
2659 * Rotate a 3D vector around the z-axis
2660 * @param {vec3} out The receiving vec3
2661 * @param {vec3} a The vec3 point to rotate
2662 * @param {vec3} b The origin of the rotation
2663 * @param {Number} c The angle of rotation
2664 * @returns {vec3} out
2665 */
2666 function rotateZ$1(out, a, b, c) {
2667 var p = [],
2668 r = [];
2669 //Translate point to the origin
2670 p[0] = a[0] - b[0];
2671 p[1] = a[1] - b[1];
2672 p[2] = a[2] - b[2];
2673
2674 //perform rotation
2675 r[0] = p[0] * Math.cos(c) - p[1] * Math.sin(c);
2676 r[1] = p[0] * Math.sin(c) + p[1] * Math.cos(c);
2677 r[2] = p[2];
2678
2679 //translate to correct position
2680 out[0] = r[0] + b[0];
2681 out[1] = r[1] + b[1];
2682 out[2] = r[2] + b[2];
2683
2684 return out;
2685 }
2686
2687 /**
2688 * Get the angle between two 3D vectors
2689 * @param {vec3} a The first operand
2690 * @param {vec3} b The second operand
2691 * @returns {Number} The angle in radians
2692 */
2693 function angle(a, b) {
2694 var tempA = fromValues$4(a[0], a[1], a[2]);
2695 var tempB = fromValues$4(b[0], b[1], b[2]);
2696
2697 normalize(tempA, tempA);
2698 normalize(tempB, tempB);
2699
2700 var cosine = dot(tempA, tempB);
2701
2702 if (cosine > 1.0) {
2703 return 0;
2704 } else if (cosine < -1.0) {
2705 return Math.PI;
2706 } else {
2707 return Math.acos(cosine);
2708 }
2709 }
2710
2711 /**
2712 * Returns a string representation of a vector
2713 *
2714 * @param {vec3} a vector to represent as a string
2715 * @returns {String} string representation of the vector
2716 */
2717 function str$4(a) {
2718 return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
2719 }
2720
2721 /**
2722 * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
2723 *
2724 * @param {vec3} a The first vector.
2725 * @param {vec3} b The second vector.
2726 * @returns {Boolean} True if the vectors are equal, false otherwise.
2727 */
2728 function exactEquals$4(a, b) {
2729 return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
2730 }
2731
2732 /**
2733 * Returns whether or not the vectors have approximately the same elements in the same position.
2734 *
2735 * @param {vec3} a The first vector.
2736 * @param {vec3} b The second vector.
2737 * @returns {Boolean} True if the vectors are equal, false otherwise.
2738 */
2739 function equals$5(a, b) {
2740 var a0 = a[0],
2741 a1 = a[1],
2742 a2 = a[2];
2743 var b0 = b[0],
2744 b1 = b[1],
2745 b2 = b[2];
2746 return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2));
2747 }
2748
2749 /**
2750 * Alias for {@link vec3.subtract}
2751 * @function
2752 */
2753 var sub$4 = subtract$4;
2754
2755 /**
2756 * Alias for {@link vec3.multiply}
2757 * @function
2758 */
2759 var mul$4 = multiply$4;
2760
2761 /**
2762 * Alias for {@link vec3.divide}
2763 * @function
2764 */
2765 var div = divide;
2766
2767 /**
2768 * Alias for {@link vec3.distance}
2769 * @function
2770 */
2771 var dist = distance;
2772
2773 /**
2774 * Alias for {@link vec3.squaredDistance}
2775 * @function
2776 */
2777 var sqrDist = squaredDistance;
2778
2779 /**
2780 * Alias for {@link vec3.length}
2781 * @function
2782 */
2783 var len = length;
2784
2785 /**
2786 * Alias for {@link vec3.squaredLength}
2787 * @function
2788 */
2789 var sqrLen = squaredLength;
2790
2791 /**
2792 * Perform some operation over an array of vec3s.
2793 *
2794 * @param {Array} a the array of vectors to iterate over
2795 * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
2796 * @param {Number} offset Number of elements to skip at the beginning of the array
2797 * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
2798 * @param {Function} fn Function to call for each vector in the array
2799 * @param {Object} [arg] additional argument to pass to fn
2800 * @returns {Array} a
2801 * @function
2802 */
2803 var forEach = function () {
2804 var vec = create$4();
2805
2806 return function (a, stride, offset, count, fn, arg) {
2807 var i = void 0,
2808 l = void 0;
2809 if (!stride) {
2810 stride = 3;
2811 }
2812
2813 if (!offset) {
2814 offset = 0;
2815 }
2816
2817 if (count) {
2818 l = Math.min(count * stride + offset, a.length);
2819 } else {
2820 l = a.length;
2821 }
2822
2823 for (i = offset; i < l; i += stride) {
2824 vec[0] = a[i];vec[1] = a[i + 1];vec[2] = a[i + 2];
2825 fn(vec, vec, arg);
2826 a[i] = vec[0];a[i + 1] = vec[1];a[i + 2] = vec[2];
2827 }
2828
2829 return a;
2830 };
2831 }();
2832
2833 var vec3 = /*#__PURE__*/Object.freeze({
2834 create: create$4,
2835 clone: clone$4,
2836 length: length,
2837 fromValues: fromValues$4,
2838 copy: copy$4,
2839 set: set$4,
2840 add: add$4,
2841 subtract: subtract$4,
2842 multiply: multiply$4,
2843 divide: divide,
2844 ceil: ceil,
2845 floor: floor,
2846 min: min,
2847 max: max,
2848 round: round,
2849 scale: scale$4,
2850 scaleAndAdd: scaleAndAdd,
2851 distance: distance,
2852 squaredDistance: squaredDistance,
2853 squaredLength: squaredLength,
2854 negate: negate,
2855 inverse: inverse,
2856 normalize: normalize,
2857 dot: dot,
2858 cross: cross,
2859 lerp: lerp,
2860 hermite: hermite,
2861 bezier: bezier,
2862 random: random,
2863 transformMat4: transformMat4,
2864 transformMat3: transformMat3,
2865 transformQuat: transformQuat,
2866 rotateX: rotateX$1,
2867 rotateY: rotateY$1,
2868 rotateZ: rotateZ$1,
2869 angle: angle,
2870 str: str$4,
2871 exactEquals: exactEquals$4,
2872 equals: equals$5,
2873 sub: sub$4,
2874 mul: mul$4,
2875 div: div,
2876 dist: dist,
2877 sqrDist: sqrDist,
2878 len: len,
2879 sqrLen: sqrLen,
2880 forEach: forEach
2881 });
2882
2883 /**
2884 * 4 Dimensional Vector
2885 * @module vec4
2886 */
2887
2888 /**
2889 * Creates a new, empty vec4
2890 *
2891 * @returns {vec4} a new 4D vector
2892 */
2893 function create$5() {
2894 var out = new ARRAY_TYPE(4);
2895 if (ARRAY_TYPE != Float32Array) {
2896 out[0] = 0;
2897 out[1] = 0;
2898 out[2] = 0;
2899 out[3] = 0;
2900 }
2901 return out;
2902 }
2903
2904 /**
2905 * Creates a new vec4 initialized with values from an existing vector
2906 *
2907 * @param {vec4} a vector to clone
2908 * @returns {vec4} a new 4D vector
2909 */
2910 function clone$5(a) {
2911 var out = new ARRAY_TYPE(4);
2912 out[0] = a[0];
2913 out[1] = a[1];
2914 out[2] = a[2];
2915 out[3] = a[3];
2916 return out;
2917 }
2918
2919 /**
2920 * Creates a new vec4 initialized with the given values
2921 *
2922 * @param {Number} x X component
2923 * @param {Number} y Y component
2924 * @param {Number} z Z component
2925 * @param {Number} w W component
2926 * @returns {vec4} a new 4D vector
2927 */
2928 function fromValues$5(x, y, z, w) {
2929 var out = new ARRAY_TYPE(4);
2930 out[0] = x;
2931 out[1] = y;
2932 out[2] = z;
2933 out[3] = w;
2934 return out;
2935 }
2936
2937 /**
2938 * Copy the values from one vec4 to another
2939 *
2940 * @param {vec4} out the receiving vector
2941 * @param {vec4} a the source vector
2942 * @returns {vec4} out
2943 */
2944 function copy$5(out, a) {
2945 out[0] = a[0];
2946 out[1] = a[1];
2947 out[2] = a[2];
2948 out[3] = a[3];
2949 return out;
2950 }
2951
2952 /**
2953 * Set the components of a vec4 to the given values
2954 *
2955 * @param {vec4} out the receiving vector
2956 * @param {Number} x X component
2957 * @param {Number} y Y component
2958 * @param {Number} z Z component
2959 * @param {Number} w W component
2960 * @returns {vec4} out
2961 */
2962 function set$5(out, x, y, z, w) {
2963 out[0] = x;
2964 out[1] = y;
2965 out[2] = z;
2966 out[3] = w;
2967 return out;
2968 }
2969
2970 /**
2971 * Adds two vec4's
2972 *
2973 * @param {vec4} out the receiving vector
2974 * @param {vec4} a the first operand
2975 * @param {vec4} b the second operand
2976 * @returns {vec4} out
2977 */
2978 function add$5(out, a, b) {
2979 out[0] = a[0] + b[0];
2980 out[1] = a[1] + b[1];
2981 out[2] = a[2] + b[2];
2982 out[3] = a[3] + b[3];
2983 return out;
2984 }
2985
2986 /**
2987 * Subtracts vector b from vector a
2988 *
2989 * @param {vec4} out the receiving vector
2990 * @param {vec4} a the first operand
2991 * @param {vec4} b the second operand
2992 * @returns {vec4} out
2993 */
2994 function subtract$5(out, a, b) {
2995 out[0] = a[0] - b[0];
2996 out[1] = a[1] - b[1];
2997 out[2] = a[2] - b[2];
2998 out[3] = a[3] - b[3];
2999 return out;
3000 }
3001
3002 /**
3003 * Multiplies two vec4's
3004 *
3005 * @param {vec4} out the receiving vector
3006 * @param {vec4} a the first operand
3007 * @param {vec4} b the second operand
3008 * @returns {vec4} out
3009 */
3010 function multiply$5(out, a, b) {
3011 out[0] = a[0] * b[0];
3012 out[1] = a[1] * b[1];
3013 out[2] = a[2] * b[2];
3014 out[3] = a[3] * b[3];
3015 return out;
3016 }
3017
3018 /**
3019 * Divides two vec4's
3020 *
3021 * @param {vec4} out the receiving vector
3022 * @param {vec4} a the first operand
3023 * @param {vec4} b the second operand
3024 * @returns {vec4} out
3025 */
3026 function divide$1(out, a, b) {
3027 out[0] = a[0] / b[0];
3028 out[1] = a[1] / b[1];
3029 out[2] = a[2] / b[2];
3030 out[3] = a[3] / b[3];
3031 return out;
3032 }
3033
3034 /**
3035 * Math.ceil the components of a vec4
3036 *
3037 * @param {vec4} out the receiving vector
3038 * @param {vec4} a vector to ceil
3039 * @returns {vec4} out
3040 */
3041 function ceil$1(out, a) {
3042 out[0] = Math.ceil(a[0]);
3043 out[1] = Math.ceil(a[1]);
3044 out[2] = Math.ceil(a[2]);
3045 out[3] = Math.ceil(a[3]);
3046 return out;
3047 }
3048
3049 /**
3050 * Math.floor the components of a vec4
3051 *
3052 * @param {vec4} out the receiving vector
3053 * @param {vec4} a vector to floor
3054 * @returns {vec4} out
3055 */
3056 function floor$1(out, a) {
3057 out[0] = Math.floor(a[0]);
3058 out[1] = Math.floor(a[1]);
3059 out[2] = Math.floor(a[2]);
3060 out[3] = Math.floor(a[3]);
3061 return out;
3062 }
3063
3064 /**
3065 * Returns the minimum of two vec4's
3066 *
3067 * @param {vec4} out the receiving vector
3068 * @param {vec4} a the first operand
3069 * @param {vec4} b the second operand
3070 * @returns {vec4} out
3071 */
3072 function min$1(out, a, b) {
3073 out[0] = Math.min(a[0], b[0]);
3074 out[1] = Math.min(a[1], b[1]);
3075 out[2] = Math.min(a[2], b[2]);
3076 out[3] = Math.min(a[3], b[3]);
3077 return out;
3078 }
3079
3080 /**
3081 * Returns the maximum of two vec4's
3082 *
3083 * @param {vec4} out the receiving vector
3084 * @param {vec4} a the first operand
3085 * @param {vec4} b the second operand
3086 * @returns {vec4} out
3087 */
3088 function max$1(out, a, b) {
3089 out[0] = Math.max(a[0], b[0]);
3090 out[1] = Math.max(a[1], b[1]);
3091 out[2] = Math.max(a[2], b[2]);
3092 out[3] = Math.max(a[3], b[3]);
3093 return out;
3094 }
3095
3096 /**
3097 * Math.round the components of a vec4
3098 *
3099 * @param {vec4} out the receiving vector
3100 * @param {vec4} a vector to round
3101 * @returns {vec4} out
3102 */
3103 function round$1(out, a) {
3104 out[0] = Math.round(a[0]);
3105 out[1] = Math.round(a[1]);
3106 out[2] = Math.round(a[2]);
3107 out[3] = Math.round(a[3]);
3108 return out;
3109 }
3110
3111 /**
3112 * Scales a vec4 by a scalar number
3113 *
3114 * @param {vec4} out the receiving vector
3115 * @param {vec4} a the vector to scale
3116 * @param {Number} b amount to scale the vector by
3117 * @returns {vec4} out
3118 */
3119 function scale$5(out, a, b) {
3120 out[0] = a[0] * b;
3121 out[1] = a[1] * b;
3122 out[2] = a[2] * b;
3123 out[3] = a[3] * b;
3124 return out;
3125 }
3126
3127 /**
3128 * Adds two vec4's after scaling the second operand by a scalar value
3129 *
3130 * @param {vec4} out the receiving vector
3131 * @param {vec4} a the first operand
3132 * @param {vec4} b the second operand
3133 * @param {Number} scale the amount to scale b by before adding
3134 * @returns {vec4} out
3135 */
3136 function scaleAndAdd$1(out, a, b, scale) {
3137 out[0] = a[0] + b[0] * scale;
3138 out[1] = a[1] + b[1] * scale;
3139 out[2] = a[2] + b[2] * scale;
3140 out[3] = a[3] + b[3] * scale;
3141 return out;
3142 }
3143
3144 /**
3145 * Calculates the euclidian distance between two vec4's
3146 *
3147 * @param {vec4} a the first operand
3148 * @param {vec4} b the second operand
3149 * @returns {Number} distance between a and b
3150 */
3151 function distance$1(a, b) {
3152 var x = b[0] - a[0];
3153 var y = b[1] - a[1];
3154 var z = b[2] - a[2];
3155 var w = b[3] - a[3];
3156 return Math.sqrt(x * x + y * y + z * z + w * w);
3157 }
3158
3159 /**
3160 * Calculates the squared euclidian distance between two vec4's
3161 *
3162 * @param {vec4} a the first operand
3163 * @param {vec4} b the second operand
3164 * @returns {Number} squared distance between a and b
3165 */
3166 function squaredDistance$1(a, b) {
3167 var x = b[0] - a[0];
3168 var y = b[1] - a[1];
3169 var z = b[2] - a[2];
3170 var w = b[3] - a[3];
3171 return x * x + y * y + z * z + w * w;
3172 }
3173
3174 /**
3175 * Calculates the length of a vec4
3176 *
3177 * @param {vec4} a vector to calculate length of
3178 * @returns {Number} length of a
3179 */
3180 function length$1(a) {
3181 var x = a[0];
3182 var y = a[1];
3183 var z = a[2];
3184 var w = a[3];
3185 return Math.sqrt(x * x + y * y + z * z + w * w);
3186 }
3187
3188 /**
3189 * Calculates the squared length of a vec4
3190 *
3191 * @param {vec4} a vector to calculate squared length of
3192 * @returns {Number} squared length of a
3193 */
3194 function squaredLength$1(a) {
3195 var x = a[0];
3196 var y = a[1];
3197 var z = a[2];
3198 var w = a[3];
3199 return x * x + y * y + z * z + w * w;
3200 }
3201
3202 /**
3203 * Negates the components of a vec4
3204 *
3205 * @param {vec4} out the receiving vector
3206 * @param {vec4} a vector to negate
3207 * @returns {vec4} out
3208 */
3209 function negate$1(out, a) {
3210 out[0] = -a[0];
3211 out[1] = -a[1];
3212 out[2] = -a[2];
3213 out[3] = -a[3];
3214 return out;
3215 }
3216
3217 /**
3218 * Returns the inverse of the components of a vec4
3219 *
3220 * @param {vec4} out the receiving vector
3221 * @param {vec4} a vector to invert
3222 * @returns {vec4} out
3223 */
3224 function inverse$1(out, a) {
3225 out[0] = 1.0 / a[0];
3226 out[1] = 1.0 / a[1];
3227 out[2] = 1.0 / a[2];
3228 out[3] = 1.0 / a[3];
3229 return out;
3230 }
3231
3232 /**
3233 * Normalize a vec4
3234 *
3235 * @param {vec4} out the receiving vector
3236 * @param {vec4} a vector to normalize
3237 * @returns {vec4} out
3238 */
3239 function normalize$1(out, a) {
3240 var x = a[0];
3241 var y = a[1];
3242 var z = a[2];
3243 var w = a[3];
3244 var len = x * x + y * y + z * z + w * w;
3245 if (len > 0) {
3246 len = 1 / Math.sqrt(len);
3247 out[0] = x * len;
3248 out[1] = y * len;
3249 out[2] = z * len;
3250 out[3] = w * len;
3251 }
3252 return out;
3253 }
3254
3255 /**
3256 * Calculates the dot product of two vec4's
3257 *
3258 * @param {vec4} a the first operand
3259 * @param {vec4} b the second operand
3260 * @returns {Number} dot product of a and b
3261 */
3262 function dot$1(a, b) {
3263 return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
3264 }
3265
3266 /**
3267 * Performs a linear interpolation between two vec4's
3268 *
3269 * @param {vec4} out the receiving vector
3270 * @param {vec4} a the first operand
3271 * @param {vec4} b the second operand
3272 * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
3273 * @returns {vec4} out
3274 */
3275 function lerp$1(out, a, b, t) {
3276 var ax = a[0];
3277 var ay = a[1];
3278 var az = a[2];
3279 var aw = a[3];
3280 out[0] = ax + t * (b[0] - ax);
3281 out[1] = ay + t * (b[1] - ay);
3282 out[2] = az + t * (b[2] - az);
3283 out[3] = aw + t * (b[3] - aw);
3284 return out;
3285 }
3286
3287 /**
3288 * Generates a random vector with the given scale
3289 *
3290 * @param {vec4} out the receiving vector
3291 * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
3292 * @returns {vec4} out
3293 */
3294 function random$1(out, scale) {
3295 scale = scale || 1.0;
3296
3297 // Marsaglia, George. Choosing a Point from the Surface of a
3298 // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646.
3299 // http://projecteuclid.org/euclid.aoms/1177692644;
3300 var v1, v2, v3, v4;
3301 var s1, s2;
3302 do {
3303 v1 = RANDOM() * 2 - 1;
3304 v2 = RANDOM() * 2 - 1;
3305 s1 = v1 * v1 + v2 * v2;
3306 } while (s1 >= 1);
3307 do {
3308 v3 = RANDOM() * 2 - 1;
3309 v4 = RANDOM() * 2 - 1;
3310 s2 = v3 * v3 + v4 * v4;
3311 } while (s2 >= 1);
3312
3313 var d = Math.sqrt((1 - s1) / s2);
3314 out[0] = scale * v1;
3315 out[1] = scale * v2;
3316 out[2] = scale * v3 * d;
3317 out[3] = scale * v4 * d;
3318 return out;
3319 }
3320
3321 /**
3322 * Transforms the vec4 with a mat4.
3323 *
3324 * @param {vec4} out the receiving vector
3325 * @param {vec4} a the vector to transform
3326 * @param {mat4} m matrix to transform with
3327 * @returns {vec4} out
3328 */
3329 function transformMat4$1(out, a, m) {
3330 var x = a[0],
3331 y = a[1],
3332 z = a[2],
3333 w = a[3];
3334 out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
3335 out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
3336 out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
3337 out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
3338 return out;
3339 }
3340
3341 /**
3342 * Transforms the vec4 with a quat
3343 *
3344 * @param {vec4} out the receiving vector
3345 * @param {vec4} a the vector to transform
3346 * @param {quat} q quaternion to transform with
3347 * @returns {vec4} out
3348 */
3349 function transformQuat$1(out, a, q) {
3350 var x = a[0],
3351 y = a[1],
3352 z = a[2];
3353 var qx = q[0],
3354 qy = q[1],
3355 qz = q[2],
3356 qw = q[3];
3357
3358 // calculate quat * vec
3359 var ix = qw * x + qy * z - qz * y;
3360 var iy = qw * y + qz * x - qx * z;
3361 var iz = qw * z + qx * y - qy * x;
3362 var iw = -qx * x - qy * y - qz * z;
3363
3364 // calculate result * inverse quat
3365 out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
3366 out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
3367 out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
3368 out[3] = a[3];
3369 return out;
3370 }
3371
3372 /**
3373 * Returns a string representation of a vector
3374 *
3375 * @param {vec4} a vector to represent as a string
3376 * @returns {String} string representation of the vector
3377 */
3378 function str$5(a) {
3379 return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
3380 }
3381
3382 /**
3383 * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
3384 *
3385 * @param {vec4} a The first vector.
3386 * @param {vec4} b The second vector.
3387 * @returns {Boolean} True if the vectors are equal, false otherwise.
3388 */
3389 function exactEquals$5(a, b) {
3390 return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
3391 }
3392
3393 /**
3394 * Returns whether or not the vectors have approximately the same elements in the same position.
3395 *
3396 * @param {vec4} a The first vector.
3397 * @param {vec4} b The second vector.
3398 * @returns {Boolean} True if the vectors are equal, false otherwise.
3399 */
3400 function equals$6(a, b) {
3401 var a0 = a[0],
3402 a1 = a[1],
3403 a2 = a[2],
3404 a3 = a[3];
3405 var b0 = b[0],
3406 b1 = b[1],
3407 b2 = b[2],
3408 b3 = b[3];
3409 return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
3410 }
3411
3412 /**
3413 * Alias for {@link vec4.subtract}
3414 * @function
3415 */
3416 var sub$5 = subtract$5;
3417
3418 /**
3419 * Alias for {@link vec4.multiply}
3420 * @function
3421 */
3422 var mul$5 = multiply$5;
3423
3424 /**
3425 * Alias for {@link vec4.divide}
3426 * @function
3427 */
3428 var div$1 = divide$1;
3429
3430 /**
3431 * Alias for {@link vec4.distance}
3432 * @function
3433 */
3434 var dist$1 = distance$1;
3435
3436 /**
3437 * Alias for {@link vec4.squaredDistance}
3438 * @function
3439 */
3440 var sqrDist$1 = squaredDistance$1;
3441
3442 /**
3443 * Alias for {@link vec4.length}
3444 * @function
3445 */
3446 var len$1 = length$1;
3447
3448 /**
3449 * Alias for {@link vec4.squaredLength}
3450 * @function
3451 */
3452 var sqrLen$1 = squaredLength$1;
3453
3454 /**
3455 * Perform some operation over an array of vec4s.
3456 *
3457 * @param {Array} a the array of vectors to iterate over
3458 * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
3459 * @param {Number} offset Number of elements to skip at the beginning of the array
3460 * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
3461 * @param {Function} fn Function to call for each vector in the array
3462 * @param {Object} [arg] additional argument to pass to fn
3463 * @returns {Array} a
3464 * @function
3465 */
3466 var forEach$1 = function () {
3467 var vec = create$5();
3468
3469 return function (a, stride, offset, count, fn, arg) {
3470 var i = void 0,
3471 l = void 0;
3472 if (!stride) {
3473 stride = 4;
3474 }
3475
3476 if (!offset) {
3477 offset = 0;
3478 }
3479
3480 if (count) {
3481 l = Math.min(count * stride + offset, a.length);
3482 } else {
3483 l = a.length;
3484 }
3485
3486 for (i = offset; i < l; i += stride) {
3487 vec[0] = a[i];vec[1] = a[i + 1];vec[2] = a[i + 2];vec[3] = a[i + 3];
3488 fn(vec, vec, arg);
3489 a[i] = vec[0];a[i + 1] = vec[1];a[i + 2] = vec[2];a[i + 3] = vec[3];
3490 }
3491
3492 return a;
3493 };
3494 }();
3495
3496 var vec4 = /*#__PURE__*/Object.freeze({
3497 create: create$5,
3498 clone: clone$5,
3499 fromValues: fromValues$5,
3500 copy: copy$5,
3501 set: set$5,
3502 add: add$5,
3503 subtract: subtract$5,
3504 multiply: multiply$5,
3505 divide: divide$1,
3506 ceil: ceil$1,
3507 floor: floor$1,
3508 min: min$1,
3509 max: max$1,
3510 round: round$1,
3511 scale: scale$5,
3512 scaleAndAdd: scaleAndAdd$1,
3513 distance: distance$1,
3514 squaredDistance: squaredDistance$1,
3515 length: length$1,
3516 squaredLength: squaredLength$1,
3517 negate: negate$1,
3518 inverse: inverse$1,
3519 normalize: normalize$1,
3520 dot: dot$1,
3521 lerp: lerp$1,
3522 random: random$1,
3523 transformMat4: transformMat4$1,
3524 transformQuat: transformQuat$1,
3525 str: str$5,
3526 exactEquals: exactEquals$5,
3527 equals: equals$6,
3528 sub: sub$5,
3529 mul: mul$5,
3530 div: div$1,
3531 dist: dist$1,
3532 sqrDist: sqrDist$1,
3533 len: len$1,
3534 sqrLen: sqrLen$1,
3535 forEach: forEach$1
3536 });
3537
3538 /**
3539 * Quaternion
3540 * @module quat
3541 */
3542
3543 /**
3544 * Creates a new identity quat
3545 *
3546 * @returns {quat} a new quaternion
3547 */
3548 function create$6() {
3549 var out = new ARRAY_TYPE(4);
3550 if (ARRAY_TYPE != Float32Array) {
3551 out[0] = 0;
3552 out[1] = 0;
3553 out[2] = 0;
3554 }
3555 out[3] = 1;
3556 return out;
3557 }
3558
3559 /**
3560 * Set a quat to the identity quaternion
3561 *
3562 * @param {quat} out the receiving quaternion
3563 * @returns {quat} out
3564 */
3565 function identity$4(out) {
3566 out[0] = 0;
3567 out[1] = 0;
3568 out[2] = 0;
3569 out[3] = 1;
3570 return out;
3571 }
3572
3573 /**
3574 * Sets a quat from the given angle and rotation axis,
3575 * then returns it.
3576 *
3577 * @param {quat} out the receiving quaternion
3578 * @param {vec3} axis the axis around which to rotate
3579 * @param {Number} rad the angle in radians
3580 * @returns {quat} out
3581 **/
3582 function setAxisAngle(out, axis, rad) {
3583 rad = rad * 0.5;
3584 var s = Math.sin(rad);
3585 out[0] = s * axis[0];
3586 out[1] = s * axis[1];
3587 out[2] = s * axis[2];
3588 out[3] = Math.cos(rad);
3589 return out;
3590 }
3591
3592 /**
3593 * Gets the rotation axis and angle for a given
3594 * quaternion. If a quaternion is created with
3595 * setAxisAngle, this method will return the same
3596 * values as providied in the original parameter list
3597 * OR functionally equivalent values.
3598 * Example: The quaternion formed by axis [0, 0, 1] and
3599 * angle -90 is the same as the quaternion formed by
3600 * [0, 0, 1] and 270. This method favors the latter.
3601 * @param {vec3} out_axis Vector receiving the axis of rotation
3602 * @param {quat} q Quaternion to be decomposed
3603 * @return {Number} Angle, in radians, of the rotation
3604 */
3605 function getAxisAngle(out_axis, q) {
3606 var rad = Math.acos(q[3]) * 2.0;
3607 var s = Math.sin(rad / 2.0);
3608 if (s > EPSILON) {
3609 out_axis[0] = q[0] / s;
3610 out_axis[1] = q[1] / s;
3611 out_axis[2] = q[2] / s;
3612 } else {
3613 // If s is zero, return any axis (no rotation - axis does not matter)
3614 out_axis[0] = 1;
3615 out_axis[1] = 0;
3616 out_axis[2] = 0;
3617 }
3618 return rad;
3619 }
3620
3621 /**
3622 * Multiplies two quat's
3623 *
3624 * @param {quat} out the receiving quaternion
3625 * @param {quat} a the first operand
3626 * @param {quat} b the second operand
3627 * @returns {quat} out
3628 */
3629 function multiply$6(out, a, b) {
3630 var ax = a[0],
3631 ay = a[1],
3632 az = a[2],
3633 aw = a[3];
3634 var bx = b[0],
3635 by = b[1],
3636 bz = b[2],
3637 bw = b[3];
3638
3639 out[0] = ax * bw + aw * bx + ay * bz - az * by;
3640 out[1] = ay * bw + aw * by + az * bx - ax * bz;
3641 out[2] = az * bw + aw * bz + ax * by - ay * bx;
3642 out[3] = aw * bw - ax * bx - ay * by - az * bz;
3643 return out;
3644 }
3645
3646 /**
3647 * Rotates a quaternion by the given angle about the X axis
3648 *
3649 * @param {quat} out quat receiving operation result
3650 * @param {quat} a quat to rotate
3651 * @param {number} rad angle (in radians) to rotate
3652 * @returns {quat} out
3653 */
3654 function rotateX$2(out, a, rad) {
3655 rad *= 0.5;
3656
3657 var ax = a[0],
3658 ay = a[1],
3659 az = a[2],
3660 aw = a[3];
3661 var bx = Math.sin(rad),
3662 bw = Math.cos(rad);
3663
3664 out[0] = ax * bw + aw * bx;
3665 out[1] = ay * bw + az * bx;
3666 out[2] = az * bw - ay * bx;
3667 out[3] = aw * bw - ax * bx;
3668 return out;
3669 }
3670
3671 /**
3672 * Rotates a quaternion by the given angle about the Y axis
3673 *
3674 * @param {quat} out quat receiving operation result
3675 * @param {quat} a quat to rotate
3676 * @param {number} rad angle (in radians) to rotate
3677 * @returns {quat} out
3678 */
3679 function rotateY$2(out, a, rad) {
3680 rad *= 0.5;
3681
3682 var ax = a[0],
3683 ay = a[1],
3684 az = a[2],
3685 aw = a[3];
3686 var by = Math.sin(rad),
3687 bw = Math.cos(rad);
3688
3689 out[0] = ax * bw - az * by;
3690 out[1] = ay * bw + aw * by;
3691 out[2] = az * bw + ax * by;
3692 out[3] = aw * bw - ay * by;
3693 return out;
3694 }
3695
3696 /**
3697 * Rotates a quaternion by the given angle about the Z axis
3698 *
3699 * @param {quat} out quat receiving operation result
3700 * @param {quat} a quat to rotate
3701 * @param {number} rad angle (in radians) to rotate
3702 * @returns {quat} out
3703 */
3704 function rotateZ$2(out, a, rad) {
3705 rad *= 0.5;
3706
3707 var ax = a[0],
3708 ay = a[1],
3709 az = a[2],
3710 aw = a[3];
3711 var bz = Math.sin(rad),
3712 bw = Math.cos(rad);
3713
3714 out[0] = ax * bw + ay * bz;
3715 out[1] = ay * bw - ax * bz;
3716 out[2] = az * bw + aw * bz;
3717 out[3] = aw * bw - az * bz;
3718 return out;
3719 }
3720
3721 /**
3722 * Calculates the W component of a quat from the X, Y, and Z components.
3723 * Assumes that quaternion is 1 unit in length.
3724 * Any existing W component will be ignored.
3725 *
3726 * @param {quat} out the receiving quaternion
3727 * @param {quat} a quat to calculate W component of
3728 * @returns {quat} out
3729 */
3730 function calculateW(out, a) {
3731 var x = a[0],
3732 y = a[1],
3733 z = a[2];
3734
3735 out[0] = x;
3736 out[1] = y;
3737 out[2] = z;
3738 out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
3739 return out;
3740 }
3741
3742 /**
3743 * Performs a spherical linear interpolation between two quat
3744 *
3745 * @param {quat} out the receiving quaternion
3746 * @param {quat} a the first operand
3747 * @param {quat} b the second operand
3748 * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
3749 * @returns {quat} out
3750 */
3751 function slerp(out, a, b, t) {
3752 // benchmarks:
3753 // http://jsperf.com/quaternion-slerp-implementations
3754 var ax = a[0],
3755 ay = a[1],
3756 az = a[2],
3757 aw = a[3];
3758 var bx = b[0],
3759 by = b[1],
3760 bz = b[2],
3761 bw = b[3];
3762
3763 var omega = void 0,
3764 cosom = void 0,
3765 sinom = void 0,
3766 scale0 = void 0,
3767 scale1 = void 0;
3768
3769 // calc cosine
3770 cosom = ax * bx + ay * by + az * bz + aw * bw;
3771 // adjust signs (if necessary)
3772 if (cosom < 0.0) {
3773 cosom = -cosom;
3774 bx = -bx;
3775 by = -by;
3776 bz = -bz;
3777 bw = -bw;
3778 }
3779 // calculate coefficients
3780 if (1.0 - cosom > EPSILON) {
3781 // standard case (slerp)
3782 omega = Math.acos(cosom);
3783 sinom = Math.sin(omega);
3784 scale0 = Math.sin((1.0 - t) * omega) / sinom;
3785 scale1 = Math.sin(t * omega) / sinom;
3786 } else {
3787 // "from" and "to" quaternions are very close
3788 // ... so we can do a linear interpolation
3789 scale0 = 1.0 - t;
3790 scale1 = t;
3791 }
3792 // calculate final values
3793 out[0] = scale0 * ax + scale1 * bx;
3794 out[1] = scale0 * ay + scale1 * by;
3795 out[2] = scale0 * az + scale1 * bz;
3796 out[3] = scale0 * aw + scale1 * bw;
3797
3798 return out;
3799 }
3800
3801 /**
3802 * Generates a random quaternion
3803 *
3804 * @param {quat} out the receiving quaternion
3805 * @returns {quat} out
3806 */
3807 function random$2(out) {
3808 // Implementation of http://planning.cs.uiuc.edu/node198.html
3809 // TODO: Calling random 3 times is probably not the fastest solution
3810 var u1 = RANDOM();
3811 var u2 = RANDOM();
3812 var u3 = RANDOM();
3813
3814 var sqrt1MinusU1 = Math.sqrt(1 - u1);
3815 var sqrtU1 = Math.sqrt(u1);
3816
3817 out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2);
3818 out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2);
3819 out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3);
3820 out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3);
3821 return out;
3822 }
3823
3824 /**
3825 * Calculates the inverse of a quat
3826 *
3827 * @param {quat} out the receiving quaternion
3828 * @param {quat} a quat to calculate inverse of
3829 * @returns {quat} out
3830 */
3831 function invert$4(out, a) {
3832 var a0 = a[0],
3833 a1 = a[1],
3834 a2 = a[2],
3835 a3 = a[3];
3836 var dot$$1 = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
3837 var invDot = dot$$1 ? 1.0 / dot$$1 : 0;
3838
3839 // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
3840
3841 out[0] = -a0 * invDot;
3842 out[1] = -a1 * invDot;
3843 out[2] = -a2 * invDot;
3844 out[3] = a3 * invDot;
3845 return out;
3846 }
3847
3848 /**
3849 * Calculates the conjugate of a quat
3850 * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
3851 *
3852 * @param {quat} out the receiving quaternion
3853 * @param {quat} a quat to calculate conjugate of
3854 * @returns {quat} out
3855 */
3856 function conjugate(out, a) {
3857 out[0] = -a[0];
3858 out[1] = -a[1];
3859 out[2] = -a[2];
3860 out[3] = a[3];
3861 return out;
3862 }
3863
3864 /**
3865 * Creates a quaternion from the given 3x3 rotation matrix.
3866 *
3867 * NOTE: The resultant quaternion is not normalized, so you should be sure
3868 * to renormalize the quaternion yourself where necessary.
3869 *
3870 * @param {quat} out the receiving quaternion
3871 * @param {mat3} m rotation matrix
3872 * @returns {quat} out
3873 * @function
3874 */
3875 function fromMat3(out, m) {
3876 // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
3877 // article "Quaternion Calculus and Fast Animation".
3878 var fTrace = m[0] + m[4] + m[8];
3879 var fRoot = void 0;
3880
3881 if (fTrace > 0.0) {
3882 // |w| > 1/2, may as well choose w > 1/2
3883 fRoot = Math.sqrt(fTrace + 1.0); // 2w
3884 out[3] = 0.5 * fRoot;
3885 fRoot = 0.5 / fRoot; // 1/(4w)
3886 out[0] = (m[5] - m[7]) * fRoot;
3887 out[1] = (m[6] - m[2]) * fRoot;
3888 out[2] = (m[1] - m[3]) * fRoot;
3889 } else {
3890 // |w| <= 1/2
3891 var i = 0;
3892 if (m[4] > m[0]) i = 1;
3893 if (m[8] > m[i * 3 + i]) i = 2;
3894 var j = (i + 1) % 3;
3895 var k = (i + 2) % 3;
3896
3897 fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);
3898 out[i] = 0.5 * fRoot;
3899 fRoot = 0.5 / fRoot;
3900 out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
3901 out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
3902 out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
3903 }
3904
3905 return out;
3906 }
3907
3908 /**
3909 * Creates a quaternion from the given euler angle x, y, z.
3910 *
3911 * @param {quat} out the receiving quaternion
3912 * @param {x} Angle to rotate around X axis in degrees.
3913 * @param {y} Angle to rotate around Y axis in degrees.
3914 * @param {z} Angle to rotate around Z axis in degrees.
3915 * @returns {quat} out
3916 * @function
3917 */
3918 function fromEuler(out, x, y, z) {
3919 var halfToRad = 0.5 * Math.PI / 180.0;
3920 x *= halfToRad;
3921 y *= halfToRad;
3922 z *= halfToRad;
3923
3924 var sx = Math.sin(x);
3925 var cx = Math.cos(x);
3926 var sy = Math.sin(y);
3927 var cy = Math.cos(y);
3928 var sz = Math.sin(z);
3929 var cz = Math.cos(z);
3930
3931 out[0] = sx * cy * cz - cx * sy * sz;
3932 out[1] = cx * sy * cz + sx * cy * sz;
3933 out[2] = cx * cy * sz - sx * sy * cz;
3934 out[3] = cx * cy * cz + sx * sy * sz;
3935
3936 return out;
3937 }
3938
3939 /**
3940 * Returns a string representation of a quatenion
3941 *
3942 * @param {quat} a vector to represent as a string
3943 * @returns {String} string representation of the vector
3944 */
3945 function str$6(a) {
3946 return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
3947 }
3948
3949 /**
3950 * Creates a new quat initialized with values from an existing quaternion
3951 *
3952 * @param {quat} a quaternion to clone
3953 * @returns {quat} a new quaternion
3954 * @function
3955 */
3956 var clone$6 = clone$5;
3957
3958 /**
3959 * Creates a new quat initialized with the given values
3960 *
3961 * @param {Number} x X component
3962 * @param {Number} y Y component
3963 * @param {Number} z Z component
3964 * @param {Number} w W component
3965 * @returns {quat} a new quaternion
3966 * @function
3967 */
3968 var fromValues$6 = fromValues$5;
3969
3970 /**
3971 * Copy the values from one quat to another
3972 *
3973 * @param {quat} out the receiving quaternion
3974 * @param {quat} a the source quaternion
3975 * @returns {quat} out
3976 * @function
3977 */
3978 var copy$6 = copy$5;
3979
3980 /**
3981 * Set the components of a quat to the given values
3982 *
3983 * @param {quat} out the receiving quaternion
3984 * @param {Number} x X component
3985 * @param {Number} y Y component
3986 * @param {Number} z Z component
3987 * @param {Number} w W component
3988 * @returns {quat} out
3989 * @function
3990 */
3991 var set$6 = set$5;
3992
3993 /**
3994 * Adds two quat's
3995 *
3996 * @param {quat} out the receiving quaternion
3997 * @param {quat} a the first operand
3998 * @param {quat} b the second operand
3999 * @returns {quat} out
4000 * @function
4001 */
4002 var add$6 = add$5;
4003
4004 /**
4005 * Alias for {@link quat.multiply}
4006 * @function
4007 */
4008 var mul$6 = multiply$6;
4009
4010 /**
4011 * Scales a quat by a scalar number
4012 *
4013 * @param {quat} out the receiving vector
4014 * @param {quat} a the vector to scale
4015 * @param {Number} b amount to scale the vector by
4016 * @returns {quat} out
4017 * @function
4018 */
4019 var scale$6 = scale$5;
4020
4021 /**
4022 * Calculates the dot product of two quat's
4023 *
4024 * @param {quat} a the first operand
4025 * @param {quat} b the second operand
4026 * @returns {Number} dot product of a and b
4027 * @function
4028 */
4029 var dot$2 = dot$1;
4030
4031 /**
4032 * Performs a linear interpolation between two quat's
4033 *
4034 * @param {quat} out the receiving quaternion
4035 * @param {quat} a the first operand
4036 * @param {quat} b the second operand
4037 * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
4038 * @returns {quat} out
4039 * @function
4040 */
4041 var lerp$2 = lerp$1;
4042
4043 /**
4044 * Calculates the length of a quat
4045 *
4046 * @param {quat} a vector to calculate length of
4047 * @returns {Number} length of a
4048 */
4049 var length$2 = length$1;
4050
4051 /**
4052 * Alias for {@link quat.length}
4053 * @function
4054 */
4055 var len$2 = length$2;
4056
4057 /**
4058 * Calculates the squared length of a quat
4059 *
4060 * @param {quat} a vector to calculate squared length of
4061 * @returns {Number} squared length of a
4062 * @function
4063 */
4064 var squaredLength$2 = squaredLength$1;
4065
4066 /**
4067 * Alias for {@link quat.squaredLength}
4068 * @function
4069 */
4070 var sqrLen$2 = squaredLength$2;
4071
4072 /**
4073 * Normalize a quat
4074 *
4075 * @param {quat} out the receiving quaternion
4076 * @param {quat} a quaternion to normalize
4077 * @returns {quat} out
4078 * @function
4079 */
4080 var normalize$2 = normalize$1;
4081
4082 /**
4083 * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
4084 *
4085 * @param {quat} a The first quaternion.
4086 * @param {quat} b The second quaternion.
4087 * @returns {Boolean} True if the vectors are equal, false otherwise.
4088 */
4089 var exactEquals$6 = exactEquals$5;
4090
4091 /**
4092 * Returns whether or not the quaternions have approximately the same elements in the same position.
4093 *
4094 * @param {quat} a The first vector.
4095 * @param {quat} b The second vector.
4096 * @returns {Boolean} True if the vectors are equal, false otherwise.
4097 */
4098 var equals$7 = equals$6;
4099
4100 /**
4101 * Sets a quaternion to represent the shortest rotation from one
4102 * vector to another.
4103 *
4104 * Both vectors are assumed to be unit length.
4105 *
4106 * @param {quat} out the receiving quaternion.
4107 * @param {vec3} a the initial vector
4108 * @param {vec3} b the destination vector
4109 * @returns {quat} out
4110 */
4111 var rotationTo = function () {
4112 var tmpvec3 = create$4();
4113 var xUnitVec3 = fromValues$4(1, 0, 0);
4114 var yUnitVec3 = fromValues$4(0, 1, 0);
4115
4116 return function (out, a, b) {
4117 var dot$$1 = dot(a, b);
4118 if (dot$$1 < -0.999999) {
4119 cross(tmpvec3, xUnitVec3, a);
4120 if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a);
4121 normalize(tmpvec3, tmpvec3);
4122 setAxisAngle(out, tmpvec3, Math.PI);
4123 return out;
4124 } else if (dot$$1 > 0.999999) {
4125 out[0] = 0;
4126 out[1] = 0;
4127 out[2] = 0;
4128 out[3] = 1;
4129 return out;
4130 } else {
4131 cross(tmpvec3, a, b);
4132 out[0] = tmpvec3[0];
4133 out[1] = tmpvec3[1];
4134 out[2] = tmpvec3[2];
4135 out[3] = 1 + dot$$1;
4136 return normalize$2(out, out);
4137 }
4138 };
4139 }();
4140
4141 /**
4142 * Performs a spherical linear interpolation with two control points
4143 *
4144 * @param {quat} out the receiving quaternion
4145 * @param {quat} a the first operand
4146 * @param {quat} b the second operand
4147 * @param {quat} c the third operand
4148 * @param {quat} d the fourth operand
4149 * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
4150 * @returns {quat} out
4151 */
4152 var sqlerp = function () {
4153 var temp1 = create$6();
4154 var temp2 = create$6();
4155
4156 return function (out, a, b, c, d, t) {
4157 slerp(temp1, a, d, t);
4158 slerp(temp2, b, c, t);
4159 slerp(out, temp1, temp2, 2 * t * (1 - t));
4160
4161 return out;
4162 };
4163 }();
4164
4165 /**
4166 * Sets the specified quaternion with values corresponding to the given
4167 * axes. Each axis is a vec3 and is expected to be unit length and
4168 * perpendicular to all other specified axes.
4169 *
4170 * @param {vec3} view the vector representing the viewing direction
4171 * @param {vec3} right the vector representing the local "right" direction
4172 * @param {vec3} up the vector representing the local "up" direction
4173 * @returns {quat} out
4174 */
4175 var setAxes = function () {
4176 var matr = create$2();
4177
4178 return function (out, view, right, up) {
4179 matr[0] = right[0];
4180 matr[3] = right[1];
4181 matr[6] = right[2];
4182
4183 matr[1] = up[0];
4184 matr[4] = up[1];
4185 matr[7] = up[2];
4186
4187 matr[2] = -view[0];
4188 matr[5] = -view[1];
4189 matr[8] = -view[2];
4190
4191 return normalize$2(out, fromMat3(out, matr));
4192 };
4193 }();
4194
4195 var quat = /*#__PURE__*/Object.freeze({
4196 create: create$6,
4197 identity: identity$4,
4198 setAxisAngle: setAxisAngle,
4199 getAxisAngle: getAxisAngle,
4200 multiply: multiply$6,
4201 rotateX: rotateX$2,
4202 rotateY: rotateY$2,
4203 rotateZ: rotateZ$2,
4204 calculateW: calculateW,
4205 slerp: slerp,
4206 random: random$2,
4207 invert: invert$4,
4208 conjugate: conjugate,
4209 fromMat3: fromMat3,
4210 fromEuler: fromEuler,
4211 str: str$6,
4212 clone: clone$6,
4213 fromValues: fromValues$6,
4214 copy: copy$6,
4215 set: set$6,
4216 add: add$6,
4217 mul: mul$6,
4218 scale: scale$6,
4219 dot: dot$2,
4220 lerp: lerp$2,
4221 length: length$2,
4222 len: len$2,
4223 squaredLength: squaredLength$2,
4224 sqrLen: sqrLen$2,
4225 normalize: normalize$2,
4226 exactEquals: exactEquals$6,
4227 equals: equals$7,
4228 rotationTo: rotationTo,
4229 sqlerp: sqlerp,
4230 setAxes: setAxes
4231 });
4232
4233 /**
4234 * 2 Dimensional Vector
4235 * @module vec2
4236 */
4237
4238 /**
4239 * Creates a new, empty vec2
4240 *
4241 * @returns {vec2} a new 2D vector
4242 */
4243 function create$8() {
4244 var out = new ARRAY_TYPE(2);
4245 if (ARRAY_TYPE != Float32Array) {
4246 out[0] = 0;
4247 out[1] = 0;
4248 }
4249 return out;
4250 }
4251
4252 /**
4253 * Perform some operation over an array of vec2s.
4254 *
4255 * @param {Array} a the array of vectors to iterate over
4256 * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
4257 * @param {Number} offset Number of elements to skip at the beginning of the array
4258 * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
4259 * @param {Function} fn Function to call for each vector in the array
4260 * @param {Object} [arg] additional argument to pass to fn
4261 * @returns {Array} a
4262 * @function
4263 */
4264 var forEach$2 = function () {
4265 var vec = create$8();
4266
4267 return function (a, stride, offset, count, fn, arg) {
4268 var i = void 0,
4269 l = void 0;
4270 if (!stride) {
4271 stride = 2;
4272 }
4273
4274 if (!offset) {
4275 offset = 0;
4276 }
4277
4278 if (count) {
4279 l = Math.min(count * stride + offset, a.length);
4280 } else {
4281 l = a.length;
4282 }
4283
4284 for (i = offset; i < l; i += stride) {
4285 vec[0] = a[i];vec[1] = a[i + 1];
4286 fn(vec, vec, arg);
4287 a[i] = vec[0];a[i + 1] = vec[1];
4288 }
4289
4290 return a;
4291 };
4292 }();
4293
4294 class Mesh {
4295 constructor(attributes, indices, mode = WebGL2RenderingContext.TRIANGLES) {
4296 this.attributes = attributes;
4297 if (indices) {
4298 this.indices = indices;
4299 // Ensure current buffer type is exist, considering the target value is not required at glTF
4300 this.indices.bufferView.target = WebGL2RenderingContext.ELEMENT_ARRAY_BUFFER;
4301 }
4302 this.mode = mode;
4303 }
4304 static bindAccessorsVBO(target, gl, locationList) {
4305 for (let acc of target.attributes) {
4306 // Ignore indeces
4307 let loc = locationList[acc.attribute];
4308 if (acc.attribute && loc != undefined) {
4309 bufferView.bindBuffer(acc.bufferView, gl);
4310 gl.enableVertexAttribArray(loc);
4311 let offset = acc.byteOffset;
4312 gl.vertexAttribPointer(loc, acc.size, acc.componentType, acc.normalized, acc.bufferView.byteStride, offset);
4313 }
4314 else {
4315 console.warn(`Attribute '${acc.attribute}' doesn't support in this material!`);
4316 }
4317 }
4318 }
4319 static drawElements(target, gl) {
4320 let acc = target.indices;
4321 gl.drawElements(target.mode, acc.count, acc.componentType, acc.byteOffset);
4322 }
4323 static drawArrays(target, gl) {
4324 gl.drawArrays(target.mode, 0, target.attributes[0].count);
4325 }
4326 static drawcall(target, gl) {
4327 if (target.indices) {
4328 bufferView.bindBuffer(target.indices.bufferView, gl);
4329 this.drawElements(target, gl);
4330 }
4331 else {
4332 this.drawArrays(target, gl);
4333 }
4334 }
4335 static preComputeTangent(mesh) {
4336 // http://www.opengl-tutorial.org/cn/intermediate-tutorials/tutorial-13-normal-mapping/
4337 // https://learnopengl-cn.readthedocs.io/zh/latest/05%20Advanced%20Lighting/04%20Normal%20Mapping/
4338 let indices = mesh.indices;
4339 let atts = {};
4340 for (let acc of mesh.attributes) {
4341 if (acc.attribute != 'POSITION' && acc.attribute != 'TEXCOORD_0')
4342 continue;
4343 let data = Accessor.newFloat32Array(acc);
4344 let chunks = Accessor.getSubChunks(acc, data);
4345 atts['_' + acc.attribute] = data;
4346 atts[acc.attribute] = chunks;
4347 if (acc.attribute == 'POSITION') {
4348 atts['_TANGENT'] = new Float32Array(data.length);
4349 atts['TANGENT'] = Accessor.getSubChunks(acc, atts['_TANGENT']);
4350 }
4351 }
4352 if (indices) { // element
4353 atts['i'] = Accessor.newUint16Array(indices);
4354 }
4355 else { // array
4356 atts['i'] = atts['POSITION'].map((e, i) => i);
4357 }
4358 let pos = atts['POSITION'];
4359 let uv = atts['TEXCOORD_0'];
4360 let ind = atts['i'];
4361 let tangent = atts['TANGENT'];
4362 // Temp
4363 let edge1 = create$4();
4364 let edge2 = create$4();
4365 let duv1 = create$8();
4366 let duv2 = create$8();
4367 for (let i = 0, l = ind.length; i < l; i += 3) {
4368 let i0 = ind[i];
4369 let i1 = ind[i + 1];
4370 let i2 = ind[i + 2];
4371 let p1 = pos[i0];
4372 let p2 = pos[i1];
4373 let p3 = pos[i2];
4374 let uv1 = uv[i0];
4375 let uv2 = uv[i1];
4376 let uv3 = uv[i2];
4377 sub$4(edge1, p2, p1);
4378 sub$4(edge2, p3, p1);
4379 sub$4(duv1, uv2, uv1);
4380 sub$4(duv2, uv3, uv1);
4381 let tan = tangent[i0];
4382 let f = 1.0 / (duv1[0] * duv2[1] - duv2[0] * duv1[1]);
4383 tan[0] = f * (duv2[1] * edge1[0] - duv1[1] * edge2[0]);
4384 tan[1] = f * (duv2[1] * edge1[1] - duv1[1] * edge2[1]);
4385 tan[2] = f * (duv2[1] * edge1[2] - duv1[1] * edge2[2]);
4386 normalize(tan, tan);
4387 copy$4(tangent[i1], tan);
4388 copy$4(tangent[i2], tan);
4389 }
4390 let tangentBuffer = new bufferView();
4391 tangentBuffer.dataView = atts['_TANGENT'];
4392 mesh.attributes.push(new Accessor({
4393 bufferView: tangentBuffer,
4394 byteOffset: 0,
4395 componentType: 5126,
4396 count: tangent.length,
4397 type: 'VEC3',
4398 }, 'TANGENT'));
4399 // return atts;
4400 }
4401 }
4402 class Accessor {
4403 constructor({ bufferView, byteOffset = 0, componentType, normalized = false, count, type, max: max$$1 = [], min: min$$1 = [] }, name = '') {
4404 this.attribute = name;
4405 this.bufferView = bufferView;
4406 this.byteOffset = byteOffset;
4407 this.componentType = componentType;
4408 this.normalized = normalized;
4409 this.count = count;
4410 this.max = max$$1;
4411 this.min = min$$1;
4412 this.size = Accessor.types[type];
4413 this.data = Accessor.getData(this);
4414 }
4415 static newFloat32Array(acc) {
4416 return new Float32Array(acc.bufferView.rawBuffer, acc.byteOffset + acc.bufferView.byteOffset, acc.size * acc.count);
4417 }
4418 static getSubChunks(acc, data) {
4419 let blocks = [];
4420 for (let i = 0; i < acc.count; i++) {
4421 let offset = i * acc.size;
4422 blocks.push(data.subarray(offset, offset + acc.size));
4423 }
4424 return blocks;
4425 }
4426 static getFloat32Blocks(acc) {
4427 return this.getSubChunks(acc, Accessor.newFloat32Array(acc));
4428 }
4429 static newUint16Array(acc) {
4430 return new Uint16Array(acc.bufferView.rawBuffer, acc.byteOffset + acc.bufferView.byteOffset, acc.size * acc.count);
4431 }
4432 static getUint16Blocks(acc) {
4433 return this.getSubChunks(acc, Accessor.newUint16Array(acc));
4434 }
4435 static getData(acc) {
4436 if (acc.size > 1) {
4437 return this.getFloat32Blocks(acc);
4438 }
4439 return this.newUint16Array(acc);
4440 }
4441 }
4442 Accessor.types = {
4443 "SCALAR": 1,
4444 'VEC1': 1,
4445 'VEC2': 2,
4446 'VEC3': 3,
4447 'VEC4': 4,
4448 "MAT2": 4,
4449 "MAT3": 9,
4450 "MAT4": 16,
4451 };
4452 class bufferView {
4453 constructor(rawData, { byteOffset = 0, byteLength = 0, byteStride = 0, target = 34962 } = {}) {
4454 this.buffer = null;
4455 this.rawBuffer = rawData;
4456 this.byteOffset = byteOffset;
4457 this.byteLength = byteLength;
4458 this.byteStride = byteStride;
4459 if (rawData)
4460 this.dataView = new DataView(rawData, this.byteOffset, this.byteLength);
4461 this.target = target;
4462 }
4463 static updateBuffer(bView, gl, usage = WebGL2RenderingContext.STATIC_DRAW) {
4464 if (bView.buffer) {
4465 gl.deleteBuffer(bView.buffer);
4466 }
4467 bView.buffer = gl.createBuffer();
4468 gl.bindBuffer(bView.target, bView.buffer);
4469 gl.bufferData(bView.target, bView.dataView, usage);
4470 }
4471 static bindBuffer(bView, gl) {
4472 if (!bView.buffer) {
4473 this.updateBuffer(bView, gl);
4474 }
4475 gl.bindBuffer(bView.target, bView.buffer);
4476 }
4477 }
4478
4479 var basic_vs = "attribute vec3 POSITION;attribute vec2 TEXCOORD_0;varying vec2 uv;varying vec4 pos;void main(){uv=TEXCOORD_0;vec4 position=vec4(POSITION,1);pos=position;gl_Position=position;}";
4480
4481 var basic_fs = "precision mediump float;uniform sampler2D base;varying vec2 uv;varying vec4 pos;void main(){gl_FragColor=texture2D(base,uv);}";
4482
4483 var stylize_vs = "attribute vec3 POSITION;attribute vec3 NORMAL;attribute vec2 TEXCOORD_0;attribute vec2 TEXCOORD_1;attribute vec4 TANGENT;\n#ifdef COLOR_0_SIZE_3\nattribute vec3 COLOR_0;\n#elif defined(COLOR_0_SIZE_4)\nattribute vec4 COLOR_0;\n#endif\n#ifdef HAS_SKINS\n#ifndef JOINT_AMOUNT\n#define JOINT_AMOUNT 200\n#endif\nattribute vec4 JOINTS_0;attribute vec4 WEIGHTS_0;uniform mat4 jointMat[JOINT_AMOUNT];\n#endif\nuniform mat4 M;uniform mat4 VP;uniform mat4 nM;varying vec3 normal;varying vec2 uv;varying vec2 uv1;varying vec3 pos;varying vec4 vColor;varying mat3 TBN;void main(){uv=TEXCOORD_0;uv1=TEXCOORD_1;vec3 skinedNormal=NORMAL;vec4 position=vec4(POSITION,1);\n#ifdef HAS_SKINS\nmat4 skinMat=WEIGHTS_0.x*jointMat[int(JOINTS_0.x)]+WEIGHTS_0.y*jointMat[int(JOINTS_0.y)]+WEIGHTS_0.z*jointMat[int(JOINTS_0.z)]+WEIGHTS_0.w*jointMat[int(JOINTS_0.w)];position=M*skinMat*position;skinedNormal=(skinMat*vec4(skinedNormal,0)).xyz;\n#else\nposition=M*position;\n#endif\nnormal=normalize((nM*vec4(skinedNormal,0)).xyz);vec3 tangent=normalize(vec3(nM*vec4(TANGENT.xyz,0)));vec3 bitangent=cross(normal,tangent)*TANGENT.w;TBN=mat3(tangent,bitangent,normal);\n#ifdef COLOR_0_SIZE_3\nvColor=vec4(COLOR_0,1);\n#elif defined(COLOR_0_SIZE_4)\nvColor=COLOR_0;\n#endif\npos=position.xyz/position.w;gl_Position=VP*position;}";
4484
4485 var stylize_fs = "precision mediump float;\n#define PI 3.14159265358979\n#define GAMMA 2.2\nvarying vec3 normal;varying vec2 uv;varying vec2 uv1;varying vec3 pos;varying vec4 vColor;varying mat3 TBN;uniform sampler2D brdfLUT;\n#ifdef HAS_EMISSIVE_MAP\n#ifndef emissiveTexture_uv\n#define emissiveTexture_uv uv\n#endif\nuniform sampler2D emissiveTexture;\n#endif\n#ifdef HAS_NORMAL_MAP\n#ifndef normalTexture_uv\n#define normalTexture_uv uv\n#endif\nuniform sampler2D normalTexture;\n#endif\n#ifdef HAS_BASECOLOR_MAP\n#ifndef baseColorTexture_uv\n#define baseColorTexture_uv uv\n#endif\nuniform sampler2D baseColorTexture;\n#endif\n#ifdef HAS_METALLIC_ROUGHNESS_MAP\n#ifndef metallicRoughnessTexture_uv\n#define metallicRoughnessTexture_uv uv\n#endif\nuniform sampler2D metallicRoughnessTexture;\n#endif\n#ifdef HAS_AO_MAP\n#ifndef occlusionTexture_uv\n#define occlusionTexture_uv uv\n#endif\nuniform sampler2D occlusionTexture;\n#endif\n#ifdef HAS_ENV_MAP\nuniform samplerCube env;\n#endif\nuniform vec3 u_Camera;vec4 sRGBtoLINEAR(vec4 color){return vec4(pow(color.rgb,vec3(GAMMA)),color.a);}vec4 LINEARtoSRGB(vec4 color){return vec4(pow(color.rgb,vec3(1.0/GAMMA)),color.a);}vec3 F_Schlick(float VoH,vec3 F0){return F0+(vec3(1)-F0)*pow(1.0-VoH,5.0);}vec3 F_UE4(float VoH,vec3 F0){return F0+(vec3(1.0)-F0)*pow(2.0,(-5.55473*VoH-6.98316)*VoH);}float G_CookTorrance(float NoV,float NoH,float VoH,float NoL){return min(min(2.0*NoV*NoH/VoH,2.0*NoL*NoH/VoH),1.0);}float G_UE4(float NoV,float NoH,float VoH,float NoL,float roughness){float k=(roughness+1.0)*(roughness+1.0)/8.0;float l=NoL/(NoL*(1.0-k)+k);float v=NoV/(NoV*(1.0-k)+k);return l*v;}float D_GGX(float a,float NoH){a=a*a;float f=NoH*NoH*(a-1.0)+1.0;return a/(PI*f*f);}struct coreData{vec3 diffuse;vec3 f0;vec3 N;vec3 V;vec3 R;float NoV;float metallic;float roughness;float alphaRoughness;};vec3 lightContrib(vec3 lightDir,coreData core){vec3 L=normalize(lightDir);vec3 H=normalize(core.V+L);float NoL=clamp(dot(core.N,L),0.001,1.0);float NoH=clamp(dot(core.N,H),0.0,1.0);float LoH=clamp(dot(L,H),0.0,1.0);float VoH=clamp(dot(core.V,H),0.0,1.0);vec3 F=F_Schlick(VoH,core.f0);float G=G_UE4(core.NoV,NoH,VoH,NoL,core.roughness);float D=D_GGX(core.alphaRoughness,NoH);vec3 specContrib=F*G*D/(4.0*NoL*core.NoV);vec3 diffuseContrib=(1.0-F)*core.diffuse*(1.0-core.metallic);vec3 color=NoL*(diffuseContrib+specContrib);return color;}void main(){\n#ifdef HAS_EMISSIVE_MAP\nvec4 em=sRGBtoLINEAR(texture2D(emissiveTexture,emissiveTexture_uv));\n#endif\n#ifdef HAS_BASECOLOR_MAP\nvec4 base=sRGBtoLINEAR(texture2D(baseColorTexture,baseColorTexture_uv));\n#else\nvec4 base=vec4(1);\n#endif\n#if defined(COLOR_0_SIZE_3) || defined(COLOR_0_SIZE_4)\nbase*=vColor;\n#endif\n#ifdef BASECOLOR_FACTOR\nbase*=BASECOLOR_FACTOR;\n#endif\n#ifdef HAS_METALLIC_ROUGHNESS_MAP\nvec3 rm=texture2D(metallicRoughnessTexture,metallicRoughnessTexture_uv).rgb;\n#else\nvec3 rm=vec3(0,0.7,0);\n#endif\n#ifdef HAS_AO_MAP\nvec4 ao=texture2D(occlusionTexture,occlusionTexture_uv);\n#endif\n#ifdef HAS_NORMAL_MAP\nvec3 normalAddation=texture2D(normalTexture,normalTexture_uv).rgb*2.0-1.0;vec3 N=normalize(TBN*normalAddation);\n#else\nvec3 N=normalize(normal);\n#endif\nvec3 V=normalize(u_Camera-pos);float NoV=clamp(abs(dot(N,V)),0.001,1.0);vec3 R=-normalize(reflect(V,N));float roughness=clamp(rm.g,0.04,1.0);\n#ifdef ROUGHNESS_FACTOR\nroughness*=ROUGHNESS_FACTOR;\n#endif\nfloat alphaRoughness=roughness*roughness;float metallic=clamp(rm.b,0.0,1.0);\n#ifdef METALLIC_FACTOR\nmetallic*=METALLIC_FACTOR;\n#endif\nvec3 f0=vec3(0.04);f0=mix(f0,base.xyz,metallic);vec3 diffuse=base.rgb*(vec3(1)-f0);diffuse*=1.0-metallic;diffuse/=PI;coreData core=coreData(diffuse,f0,N,V,R,NoV,metallic,roughness,alphaRoughness);vec3 color;\n#ifdef HAS_ENV_MAP\nvec3 brdf=sRGBtoLINEAR(texture2D(brdfLUT,vec2(NoV,1.0-alphaRoughness))).rgb;vec3 IBLcolor=sRGBtoLINEAR(textureCube(env,R)).rgb;vec3 IBLspecular=1.0*IBLcolor*(f0*brdf.x+brdf.y);color+=IBLspecular;\n#endif\ncolor+=lightContrib(vec3(2,5,2),core)*vec3(2);color+=lightContrib(vec3(1,1,5),core)*vec3(1.0,0.8902,0.6902)*4.0;color+=lightContrib(vec3(-5,3,-5),core)*vec3(0.6431,0.9176,1.0);\n#ifdef HAS_EMISSIVE_MAP\ncolor+=em.rgb;\n#endif\n#ifdef BLEND\ngl_FragColor=LINEARtoSRGB(vec4(color,base.a));\n#elif defined(MASK)\n#ifndef ALPHA_CUTOFF\n#define ALPHA_CUTOFF 0.5\n#endif\nif(base.a<ALPHA_CUTOFF)discard;gl_FragColor=LINEARtoSRGB(vec4(color,1));\n#else\ngl_FragColor=LINEARtoSRGB(vec4(color,1));\n#endif\n}";
4486
4487 var vignetting_vs = "attribute vec3 POSITION;varying vec2 uv;varying vec2 pos;void main(){vec4 position=vec4(POSITION,1);pos=position.xy;uv=pos+1.*0.5;gl_Position=position;}";
4488
4489 var vignetting_fs = "precision mediump float;uniform sampler2D base;varying vec2 uv;varying vec2 pos;void main(){float mask=1.-dot(pos,pos)*FACTOR;mask=clamp(.5+(mask-.5)*HARDNESS,0.,1.);vec4 color=texture2D(base,uv);gl_FragColor=mix(vec4(vec3(0),1),color,mask);}";
4490
4491 let glsl = {
4492 basic: {
4493 vs: basic_vs,
4494 fs: basic_fs,
4495 },
4496 sylize: {
4497 vs: stylize_vs,
4498 fs: stylize_fs,
4499 },
4500 vignetting: {
4501 vs: vignetting_vs,
4502 fs: vignetting_fs,
4503 },
4504 };
4505
4506 class Shader {
4507 constructor(vertCode = glsl.basic.vs, fragCode = glsl.basic.fs, macros = {}) {
4508 this.isDirty = true; // Shader sources status
4509 this.vertexSource = vertCode;
4510 this.fragmentSource = fragCode;
4511 this.macros = macros;
4512 }
4513 static clone(shader) {
4514 let temp = new Shader(shader.vertexSource, shader.fragmentSource);
4515 temp.macros = Object.assign({}, shader.macros);
4516 return temp;
4517 }
4518 static buildProgram(shader, ctx) {
4519 shader.isDirty = false;
4520 // if(!this.isDirty) return;
4521 // If current program needs recompile
4522 shader.ctx = ctx;
4523 // prepare macros
4524 this.macros = '';
4525 for (let macro in shader.macros) {
4526 this.macros += `\n#define ${macro} ${shader.macros[macro]}\n`;
4527 }
4528 // if WebGL shader is already exist, then dispose them
4529 if (shader.vertex) { // Vertex shader
4530 shader.ctx.deleteShader(shader.vertex);
4531 }
4532 shader.vertex = Shader.compileShader(shader.ctx, shader.ctx.VERTEX_SHADER, this.macros + shader.vertexSource);
4533 if (shader.fragment) { // Fragment shader
4534 shader.ctx.deleteShader(shader.fragment);
4535 }
4536 shader.fragment = Shader.compileShader(shader.ctx, shader.ctx.FRAGMENT_SHADER, this.macros + shader.fragmentSource);
4537 if (!shader.vertex || !shader.fragment) {
4538 return;
4539 }
4540 if (shader.program) { // Shader Program
4541 shader.ctx.deleteProgram(shader.program);
4542 }
4543 shader.program = Shader.createShaderProgram(shader.ctx, shader.vertex, shader.fragment);
4544 // Pickup details
4545 shader.attributes = Shader.pickupActiveAttributes(shader.ctx, shader.program);
4546 shader.uniforms = Shader.pickupActiveUniforms(shader.ctx, shader.program);
4547 }
4548 static updateUniform(shader) {
4549 let gl = shader.ctx;
4550 for (let k in shader.uniforms) {
4551 let uni = shader.uniforms[k];
4552 if (uni.value != null && uni.isDirty) {
4553 uni.isDirty = false;
4554 if (uni.argLength == 3) {
4555 gl[uni.setter](uni.location, false, uni.value);
4556 }
4557 else {
4558 gl[uni.setter](uni.location, uni.value);
4559 }
4560 }
4561 }
4562 }
4563 static pickupActiveAttributes(ctx, shader) {
4564 const amount = ctx.getProgramParameter(shader, ctx.ACTIVE_ATTRIBUTES);
4565 let attributes = {};
4566 for (let i = 0; i < amount; i++) {
4567 const { name } = ctx.getActiveAttrib(shader, i);
4568 const location = ctx.getAttribLocation(shader, name);
4569 attributes[name] = location;
4570 }
4571 return attributes;
4572 }
4573 static pickupActiveUniforms(gl, shader) {
4574 const amount = gl.getProgramParameter(shader, gl.ACTIVE_UNIFORMS);
4575 let uniforms = {};
4576 for (let i = 0; i < amount; i++) {
4577 const { name, type } = gl.getActiveUniform(shader, i);
4578 const location = gl.getUniformLocation(shader, name);
4579 const setter = Uniform.getUnifSetter(type);
4580 let length = gl[setter].length;
4581 if (length == 0) { // prototype was modified by debugging tools
4582 length = Uniform.getUnifArgLenght(type);
4583 }
4584 uniforms[name] = new Uniform(location, type, setter, length);
4585 }
4586 return uniforms;
4587 }
4588 static compileShader(gl, type, code) {
4589 let shader = gl.createShader(type);
4590 gl.shaderSource(shader, code);
4591 gl.compileShader(shader);
4592 if (gl.getShaderParameter(shader, gl.COMPILE_STATUS) === true) {
4593 return shader;
4594 }
4595 console.warn(gl.getShaderInfoLog(shader));
4596 gl.deleteShader(shader);
4597 }
4598 static createShaderProgram(gl, vertexShader, fragmentShader) {
4599 let program = gl.createProgram();
4600 gl.attachShader(program, vertexShader);
4601 gl.attachShader(program, fragmentShader);
4602 gl.linkProgram(program);
4603 if (gl.getProgramParameter(program, gl.LINK_STATUS)) {
4604 return program;
4605 }
4606 console.warn(gl.getProgramInfoLog(program));
4607 // Dispose
4608 gl.deleteProgram(program);
4609 gl.deleteShader(vertexShader);
4610 gl.deleteShader(fragmentShader);
4611 }
4612 }
4613 Shader.macros = ''; // Reduce GC?
4614 class Uniform {
4615 constructor(location, type, setter, argLength) {
4616 this.value = null; // empty texture channel must be null
4617 this.isDirty = false;
4618 this.location = location;
4619 this.type = type;
4620 this.setter = setter;
4621 this.argLength = argLength;
4622 }
4623 static getUnifSetter(type) {
4624 switch (type) {
4625 case WebGLRenderingContext.FLOAT:
4626 return 'uniform1f';
4627 case WebGLRenderingContext.FLOAT_VEC2:
4628 return 'uniform2f';
4629 case WebGLRenderingContext.FLOAT_VEC3:
4630 return 'uniform3fv';
4631 case WebGLRenderingContext.FLOAT_VEC4:
4632 return 'uniform4f';
4633 case WebGLRenderingContext.INT:
4634 return 'uniform1i';
4635 case WebGLRenderingContext.INT_VEC2:
4636 return 'uniform2i';
4637 case WebGLRenderingContext.INT_VEC3:
4638 return 'uniform3i';
4639 case WebGLRenderingContext.INT_VEC4:
4640 return 'uniform4i';
4641 // case WebGLRenderingContext.BOOL:
4642 // return WebGLRenderingContext.uniform1f;
4643 // case WebGLRenderingContext.BOOL_VEC2:
4644 // return WebGLRenderingContext.uniform1f;
4645 // case WebGLRenderingContext.BOOL_VEC3:
4646 // return WebGLRenderingContext.uniform1f;
4647 // case WebGLRenderingContext.BOOL_VEC4:
4648 // return WebGLRenderingContext.uniform1f;
4649 case WebGLRenderingContext.FLOAT_MAT2:
4650 return 'uniformMatrix2fv';
4651 case WebGLRenderingContext.FLOAT_MAT3:
4652 return 'uniformMatrix3fv';
4653 case WebGLRenderingContext.FLOAT_MAT4:
4654 return 'uniformMatrix4fv';
4655 case WebGLRenderingContext.SAMPLER_2D:
4656 return 'uniform1i';
4657 case WebGLRenderingContext.SAMPLER_CUBE:
4658 return 'uniform1i';
4659 }
4660 }
4661 static getUnifArgLenght(type) {
4662 switch (type) {
4663 case WebGLRenderingContext.FLOAT:
4664 case WebGLRenderingContext.FLOAT_VEC2:
4665 case WebGLRenderingContext.FLOAT_VEC3:
4666 case WebGLRenderingContext.FLOAT_VEC4:
4667 case WebGLRenderingContext.INT:
4668 case WebGLRenderingContext.INT_VEC2:
4669 case WebGLRenderingContext.INT_VEC3:
4670 case WebGLRenderingContext.INT_VEC4:
4671 case WebGLRenderingContext.SAMPLER_2D:
4672 case WebGLRenderingContext.SAMPLER_CUBE:
4673 return 2;
4674 // case WebGLRenderingContext.BOOL:
4675 // case WebGLRenderingContext.BOOL_VEC2:
4676 // case WebGLRenderingContext.BOOL_VEC3:
4677 // case WebGLRenderingContext.BOOL_VEC4:
4678 case WebGLRenderingContext.FLOAT_MAT2:
4679 case WebGLRenderingContext.FLOAT_MAT3:
4680 case WebGLRenderingContext.FLOAT_MAT4:
4681 return 3; // (location, transpose, value)
4682 }
4683 }
4684 }
4685
4686 var RenderQueue;
4687 (function (RenderQueue) {
4688 RenderQueue[RenderQueue["Opaque"] = 0] = "Opaque";
4689 RenderQueue[RenderQueue["Blend"] = 1] = "Blend";
4690 })(RenderQueue || (RenderQueue = {}));
4691 class Material {
4692 constructor(shader, name = null, doubleSided = false) {
4693 this.isDirty = true;
4694 // textures: Texture[] = [];
4695 this.textures = new Map();
4696 this.queue = RenderQueue.Opaque;
4697 this.shader = Shader.clone(shader);
4698 this.name = name;
4699 this.shader.macros['SHADER_NAME'] = name;
4700 this.doubleSided = doubleSided;
4701 }
4702 static clone(mat) {
4703 return new Material(mat.shader, mat.name, mat.doubleSided);
4704 }
4705 static useMaterial(mat, ctx) {
4706 if (mat.shader.isDirty) {
4707 // Update Shader
4708 Shader.buildProgram(mat.shader, ctx);
4709 }
4710 ctx.useProgram(mat.shader.program);
4711 }
4712 static setUniform(mat, key, value) {
4713 if (mat.shader.uniforms[key] == null) {
4714 // console.warn(`${key} doesn't found!`);
4715 return;
4716 }
4717 mat.shader.uniforms[key].value = value;
4718 mat.shader.uniforms[key].isDirty = true;
4719 mat.isDirty = true;
4720 }
4721 static updateUniform(mat, ctx) {
4722 if (mat.shader.isDirty) {
4723 Shader.buildProgram(mat.shader, ctx);
4724 this.useMaterial(mat, ctx);
4725 }
4726 Shader.updateUniform(mat.shader);
4727 mat.isDirty = false;
4728 }
4729 static bindAllTextures(mat, ctx, force = false) {
4730 if (mat.textures.size == 0) ;
4731 for (let [uniform, tex] of mat.textures) {
4732 Texture.bindTexture(ctx, tex);
4733 if (tex.isDirty || force) {
4734 Material.setUniform(mat, uniform, tex.channel);
4735 tex.isDirty = false;
4736 }
4737 }
4738 }
4739 static unbindAllTextures(mat, ctx) {
4740 for (let [, tex] of mat.textures) {
4741 Texture.unbindTexture(ctx, tex);
4742 }
4743 }
4744 static setTexture(mat, name, tex) {
4745 if (mat.textures.has(name)) {
4746 tex.channel = mat.textures.get(name).channel;
4747 }
4748 else {
4749 tex.channel = mat.textures.size;
4750 }
4751 mat.textures.set(name, tex);
4752 mat.isDirty = true;
4753 tex.isDirty = true;
4754 }
4755 }
4756 Material.SHADER_PATH = 'res/shader/';
4757
4758 class EntityMgr {
4759 static create(name = null, pure = false) {
4760 this.hasNewMember = true;
4761 let gameObject = document.createElement(this.entityTag);
4762 if (name) {
4763 gameObject.dataset.name = name;
4764 gameObject.textContent = name;
4765 }
4766 gameObject.components = {};
4767 if (this.getDefaultComponent && !pure)
4768 this.addComponent(gameObject, this.getDefaultComponent());
4769 // Alias
4770 gameObject['addComponent'] = (comp) => this.addComponent(gameObject, comp);
4771 // Debug envent
4772 gameObject.addEventListener('pointerdown', e => {
4773 console.log('\t|-' + gameObject.dataset.name);
4774 console.log(gameObject.components);
4775 let trans = gameObject.components.Transform;
4776 // toggle visible
4777 if (trans != null) {
4778 trans.isVisible = !trans.isVisible;
4779 }
4780 e.stopPropagation();
4781 });
4782 return gameObject;
4783 }
4784 static clone(entity) {
4785 let temp = this.create(entity.dataset.name, true);
4786 this.addComponent(temp, this.cloneMethods['_Transform'](entity.components.Transform));
4787 for (let comp in entity.components) {
4788 if (this.cloneMethods[comp]) {
4789 this.addComponent(temp, this.cloneMethods[comp](entity.components[comp]));
4790 }
4791 }
4792 for (let i = 0; i < entity.childElementCount; i++) {
4793 temp.appendChild(this.clone(entity.children[i]));
4794 }
4795 return temp;
4796 }
4797 static find(selector, root = document) {
4798 let nodes = Array.from(root.querySelectorAll(selector)); // convert NodeList to Array
4799 return nodes;
4800 }
4801 static getComponents(componentName) {
4802 return this.find(`${this.entityTag}[${componentName.toLowerCase()}]`).map(({ components }) => components[componentName]);
4803 }
4804 static getEntites(deps, root = document) {
4805 return this.find(`${this.entityTag}[${deps.join('][')}]`, root);
4806 }
4807 static addComponent(entity, component) {
4808 this.hasNewMember = true;
4809 let componentName = component.constructor.name;
4810 entity.components[componentName] = component;
4811 entity.setAttribute(componentName, '');
4812 component.entity = entity;
4813 return component;
4814 }
4815 }
4816 EntityMgr.entityTag = 'ash-entity';
4817 EntityMgr.hasNewMember = false;
4818 EntityMgr.cloneMethods = {};
4819
4820 class ComponentSystem {
4821 }
4822
4823 class System {
4824 static loop() {
4825 for (let name in this.sysQueue) {
4826 let sys = this.sysQueue[name];
4827 if (EntityMgr.hasNewMember || sys.group.length == 0) {
4828 sys.group = EntityMgr.getEntites(sys.depends);
4829 }
4830 sys.onUpdate(this.deltaTime);
4831 }
4832 EntityMgr.hasNewMember = false;
4833 this.deltaTime = (Date.now() - this.lastTime) / 1000;
4834 this.lastTime = Date.now();
4835 if (!this.isStoped)
4836 requestAnimationFrame(this.loop.bind(this));
4837 }
4838 static start() {
4839 if (!this.isStoped)
4840 return;
4841 this.isStoped = false;
4842 this.loop();
4843 }
4844 static stop() {
4845 this.isStoped = true;
4846 }
4847 static registSystem(system) {
4848 this.sysQueue[system.depends.toString()] = system;
4849 }
4850 static getSystem(system) {
4851 return this.sysQueue[system.depends.toString()];
4852 }
4853 static removeSystem(system) {
4854 this.sysQueue[system.depends.toString()] = null;
4855 }
4856 }
4857 System.lastTime = 0;
4858 System.deltaTime = 0;
4859 System.isStoped = true;
4860 System.sysQueue = {};
4861 System.start();
4862
4863 class MeshRenderer {
4864 constructor(screen, mesh, material) {
4865 this.materials = [];
4866 this.isDirty = true;
4867 if (screen != null)
4868 this.SID = screen.id;
4869 this.mesh = mesh;
4870 // specify the length of each attribute, considering the vertices color could be or vec4
4871 // FIXME:
4872 for (let att of mesh.attributes) {
4873 material.shader.macros[`${att.attribute}_SIZE_${att.size}`] = '';
4874 }
4875 MeshRendererSystem.attachMaterial(this, material);
4876 }
4877 static clone(source) {
4878 let mr = new MeshRenderer(null, source.mesh);
4879 mr.SID = source.SID;
4880 for (let mat of source.materials) {
4881 MeshRendererSystem.attachMaterial(mr, mat);
4882 }
4883 return mr;
4884 }
4885 }
4886 EntityMgr.cloneMethods['MeshRenderer'] = MeshRenderer.clone;
4887 class MeshRendererSystem extends ComponentSystem {
4888 constructor() {
4889 super(...arguments);
4890 this.group = [];
4891 this.depends = [
4892 MeshRenderer.name
4893 ];
4894 // According those discussion below, having actors draw themselves is not a good design
4895 // https://gamedev.stackexchange.com/questions/50531/entity-component-based-engine-rendering-separation-from-logic
4896 // https://gamedev.stackexchange.com/questions/14133/should-actors-in-a-game-be-responsible-for-drawing-themselves/14138#14138
4897 }
4898 onUpdate() {
4899 // Before render
4900 for (let id in Screen.list) {
4901 let screen = Screen.list[id];
4902 if (screen.filters.length) {
4903 screen.capture.bind();
4904 screen.setViewport(screen.capture.width, screen.capture.height);
4905 }
4906 screen.clear();
4907 }
4908 for (let { components } of this.group) {
4909 MeshRendererSystem.render(components.MeshRenderer, RenderQueue.Opaque);
4910 }
4911 for (let { components } of this.group) {
4912 // TODO: handle multiple transparent objects
4913 MeshRendererSystem.render(components.MeshRenderer, RenderQueue.Blend);
4914 }
4915 // After render
4916 for (let id in Screen.list) {
4917 let screen = Screen.list[id];
4918 // post effects
4919 for (let [i, ft] of screen.filters.entries()) {
4920 if (ft.renderToScreen) {
4921 // Render to screen
4922 ft.bind(null);
4923 screen.setViewport();
4924 }
4925 else {
4926 ft.bind();
4927 screen.setViewport(ft.width, ft.height);
4928 screen.clear(); // clear current framebuffer
4929 }
4930 MeshRendererSystem.render(ft.meshRender);
4931 }
4932 // // Render to screen
4933 // let lastft = screen.filters[screen.filters.length-1];
4934 // lastft.bind(null);
4935 // screen.setViewport();
4936 // MeshRendererSystem.render(lastft.meshRender);
4937 }
4938 }
4939 static useMaterial(mr, index) {
4940 Material.useMaterial(mr.materials[index], Screen.list[mr.SID].gl);
4941 }
4942 static attachMaterial(mr, mat) {
4943 if (mr.SID == null)
4944 return;
4945 mr.materials.push(mat);
4946 Material.updateUniform(mat, Screen.list[mr.SID].gl); // the first time this material get context
4947 this.useMaterial(mr, 0);
4948 this.updateVAO(mr);
4949 }
4950 static bindVAO(mr, vao) {
4951 if (Screen.platform == 'iOS') {
4952 Mesh.bindAccessorsVBO(mr.mesh, Screen.list[mr.SID].gl, mr.materials[0].shader.attributes);
4953 }
4954 else {
4955 Screen.list[mr.SID].gl.bindVertexArray(vao);
4956 }
4957 }
4958 static updateVAO(mr) {
4959 if (mr.vao) {
4960 Screen.list[mr.SID].gl.deleteVertexArray(mr.vao);
4961 }
4962 mr.vao = Screen.list[mr.SID].gl.createVertexArray();
4963 this.bindVAO(mr, mr.vao);
4964 Mesh.bindAccessorsVBO(mr.mesh, Screen.list[mr.SID].gl, mr.materials[0].shader.attributes);
4965 this.bindVAO(mr, null);
4966 }
4967 static updateMaterial(target) {
4968 if (target.materials[0].isDirty) {
4969 Material.updateUniform(target.materials[0], Screen.list[target.SID].gl);
4970 }
4971 }
4972 static render(target, queue = RenderQueue.Opaque) {
4973 let screen = Screen.list[target.SID];
4974 let { gl, mainCamera } = screen;
4975 // Enable material
4976 let idShader = 0;
4977 const currentMat = target.materials[idShader];
4978 if (currentMat.queue != queue)
4979 return;
4980 let needsUpdateTexture = currentMat.shader.isDirty;
4981 this.useMaterial(target, idShader);
4982 if (currentMat.doubleSided) {
4983 gl.disable(gl.CULL_FACE);
4984 }
4985 else {
4986 gl.enable(gl.CULL_FACE);
4987 }
4988 if (target.entity) {
4989 if (!target.entity.components.Transform.isVisible)
4990 return;
4991 let trans = target.entity.components.Transform;
4992 if (mainCamera) {
4993 Material.setUniform(currentMat, 'VP', mainCamera.vp);
4994 Material.setUniform(currentMat, 'u_Camera', mainCamera.entity.components.Transform.worldPos);
4995 }
4996 Material.setUniform(currentMat, 'M', trans.worldMatrix);
4997 Material.setUniform(currentMat, 'nM', trans.worldNormalMatrix);
4998 if (trans.jointsMatrices) {
4999 Material.setUniform(currentMat, 'jointMat[0]', trans.jointsMatrices);
5000 }
5001 }
5002 // Update uniforms of material
5003 this.updateMaterial(target);
5004 // Bind all textures
5005 Material.bindAllTextures(currentMat, gl, needsUpdateTexture);
5006 // Bind Mesh
5007 this.bindVAO(target, target.vao); // Bind VAO
5008 // Drawcall
5009 Mesh.drawcall(target.mesh, gl);
5010 // Clean texture channels
5011 // Material.unbindAllTextures(currentMat, gl);
5012 }
5013 }
5014 System.registSystem(new MeshRendererSystem());
5015
5016 // Post effect
5017 class Filter {
5018 constructor(screen, shader, width = screen.pow2width, height = screen.pow2height) {
5019 this.color = [];
5020 this.depth = [];
5021 this.renderToScreen = true;
5022 this.ctx = screen.gl;
5023 this.screen = screen;
5024 this.width = width;
5025 this.height = height;
5026 // Create framebuffer
5027 this.buffer = this.ctx.createFramebuffer();
5028 this.output = this.attachTexture();
5029 this.mesh = new fill();
5030 this.material = new Material(shader);
5031 this.meshRender = new MeshRenderer(screen, this.mesh, this.material);
5032 }
5033 clone(screen = this.screen) {
5034 return new Filter(screen, Shader.clone(this.material.shader), this.width, this.height);
5035 }
5036 setInput(tex, channel = 'base') {
5037 this.input = tex;
5038 Material.setTexture(this.material, channel, tex);
5039 this.material.isDirty = true;
5040 }
5041 bind(target = this.buffer) {
5042 this.ctx.bindFramebuffer(WebGL2RenderingContext.FRAMEBUFFER, target);
5043 }
5044 attachTexture() {
5045 this.bind();
5046 let color = new Texture(null, Filter.sampleColor, this.width, this.height);
5047 Texture.createTexture(this.ctx, color);
5048 this.ctx.framebufferTexture2D(Filter.FRAMEBUFFER, Filter.COLOR_ATTACH_BASE + this.color.length, color.glType, color.sampler.texture, color.level);
5049 this.color.push(color);
5050 let depth = new Texture(null, Filter.sampleDepth, this.width, this.height);
5051 depth.internalformat = WebGL2RenderingContext.DEPTH_COMPONENT24;
5052 depth.format = WebGL2RenderingContext.DEPTH_COMPONENT;
5053 depth.type = WebGL2RenderingContext.UNSIGNED_INT;
5054 Texture.createTexture(this.ctx, depth);
5055 this.ctx.framebufferTexture2D(Filter.FRAMEBUFFER, Filter.DEPTH_ATTACHMENT, depth.glType, depth.sampler.texture, depth.level);
5056 this.depth.push(depth);
5057 this.bind(null);
5058 return color;
5059 }
5060 }
5061 Filter.sampleColor = {
5062 magFilter: WebGL2RenderingContext.LINEAR,
5063 minFilter: WebGL2RenderingContext.LINEAR,
5064 wrapS: WebGL2RenderingContext.CLAMP_TO_EDGE,
5065 wrapT: WebGL2RenderingContext.CLAMP_TO_EDGE,
5066 };
5067 Filter.sampleDepth = {
5068 magFilter: WebGL2RenderingContext.NEAREST,
5069 minFilter: WebGL2RenderingContext.NEAREST,
5070 wrapS: WebGL2RenderingContext.CLAMP_TO_EDGE,
5071 wrapT: WebGL2RenderingContext.CLAMP_TO_EDGE,
5072 };
5073 Filter.COLOR_ATTACH_BASE = WebGL2RenderingContext.COLOR_ATTACHMENT0;
5074 Filter.DEPTH_ATTACHMENT = WebGL2RenderingContext.DEPTH_ATTACHMENT;
5075 Filter.FRAMEBUFFER = WebGL2RenderingContext.FRAMEBUFFER;
5076 class fill extends Mesh {
5077 constructor() {
5078 let vert = new Float32Array([
5079 -1, 3, 0, -1, -1, 0, 3, -1, 0
5080 ]);
5081 let vbo = new bufferView(vert.buffer, {
5082 byteOffset: vert.byteOffset,
5083 byteLength: vert.byteLength,
5084 byteStride: 3 * 4,
5085 target: WebGL2RenderingContext.ARRAY_BUFFER
5086 });
5087 let position = new Accessor({
5088 bufferView: vbo,
5089 componentType: WebGL2RenderingContext.FLOAT,
5090 byteOffset: 0,
5091 type: "VEC3",
5092 count: 3
5093 }, 'POSITION');
5094 super([position]);
5095 }
5096 }
5097
5098 class Screen {
5099 constructor(selector) {
5100 this.filters = [];
5101 this.output = null;
5102 this.bgColor = [1, 1, 1, 1];
5103 this.id = selector;
5104 // Detect device
5105 if (navigator.userAgent.indexOf('iPhone') != -1 || navigator.userAgent.indexOf('iPad') != -1) {
5106 Screen.platform = 'iOS';
5107 }
5108 this.canvas = document.querySelector(selector);
5109 if (!this.canvas) {
5110 console.error('Canvas not found!');
5111 return;
5112 }
5113 this.gl = this.canvas.getContext('webgl2');
5114 if (!this.gl) {
5115 console.error('Get Context Failed');
5116 alert('Your browser do not support WebGL2');
5117 return;
5118 }
5119 // Regist current screen
5120 Screen.list[selector] = this;
5121 this.gl.enable(this.gl.DEPTH_TEST);
5122 this.gl.enable(this.gl.BLEND);
5123 this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);
5124 // this.ext = this.gl.getExtension('WEBGL_draw_buffers');
5125 this.setScreenSize(); // initial - full screen
5126 // initial capture
5127 this.pow2width = nearestPow2(this.width);
5128 this.pow2height = nearestPow2(this.height);
5129 this.capture = new Filter(this, new Shader(), this.pow2width, this.pow2height);
5130 this.capture.renderToScreen = false;
5131 // Bloom.initFilters(this)
5132 // this.attachFilter(new Vignetting(this));
5133 }
5134 setScreenSize(width = window.innerWidth, height = window.innerHeight) {
5135 let { devicePixelRatio } = window;
5136 console.log(devicePixelRatio);
5137 this.canvas.setAttribute('width', width * devicePixelRatio + '');
5138 this.canvas.setAttribute('height', height * devicePixelRatio + '');
5139 this.canvas.style.width = width + 'px';
5140 this.canvas.style.height = height + 'px';
5141 this.width = width * devicePixelRatio;
5142 this.height = height * devicePixelRatio;
5143 this.ratio = devicePixelRatio;
5144 this.setViewport();
5145 }
5146 setViewport(width = this.width, height = this.height) {
5147 this.gl.viewport(0, 0, width, height);
5148 }
5149 clear(r = this.bgColor[0], g = this.bgColor[1], b = this.bgColor[2], a = this.bgColor[3], mode = this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT) {
5150 this.gl.clearColor(r, g, b, a);
5151 this.gl.clear(mode);
5152 }
5153 attachFilter(ft) {
5154 if (this.output == null) {
5155 // filter head
5156 ft.setInput(this.capture.output);
5157 }
5158 else {
5159 // Attach to the filter chain
5160 this.output.renderToScreen = false;
5161 ft.setInput(this.output.output);
5162 }
5163 this.filters.push(ft);
5164 this.output = ft;
5165 }
5166 deleteFilter(index) {
5167 let target = this.filters[index];
5168 if (!target) {
5169 console.error('Filter does not exist!');
5170 return;
5171 }
5172 let prev = this.filters[index - 1] || this.capture;
5173 let next = this.filters[index + 1];
5174 if (next) {
5175 next.setInput(prev.output);
5176 }
5177 else {
5178 prev.renderToScreen = true;
5179 }
5180 this.filters.splice(index, 1);
5181 this.output = this.filters[this.filters.length - 1];
5182 }
5183 }
5184 Screen.list = {};
5185 Screen.platform = 'unknown';
5186 function nearestPow2(s) {
5187 let psize = 128;
5188 while (s > psize) {
5189 psize = psize << 1;
5190 }
5191 return psize;
5192 }
5193
5194 /*! *****************************************************************************
5195 Copyright (c) Microsoft Corporation. All rights reserved.
5196 Licensed under the Apache License, Version 2.0 (the "License"); you may not use
5197 this file except in compliance with the License. You may obtain a copy of the
5198 License at http://www.apache.org/licenses/LICENSE-2.0
5199
5200 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
5201 KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
5202 WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
5203 MERCHANTABLITY OR NON-INFRINGEMENT.
5204
5205 See the Apache Version 2.0 License for specific language governing permissions
5206 and limitations under the License.
5207 ***************************************************************************** */
5208
5209 function __awaiter(thisArg, _arguments, P, generator) {
5210 return new (P || (P = Promise))(function (resolve, reject) {
5211 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5212 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
5213 function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
5214 step((generator = generator.apply(thisArg, _arguments || [])).next());
5215 });
5216 }
5217
5218 class Transform {
5219 constructor() {
5220 this.worldPos = fromValues$4(0, 0, 0);
5221 this.translate = fromValues$4(0, 0, 0);
5222 this.rotate = fromValues$4(0, 0, 0);
5223 this.scale = fromValues$4(1, 1, 1);
5224 this.quaternion = fromValues$5(0, 0, 0, 1);
5225 // RTS
5226 this.localMatrix = create$3();
5227 this.worldMatrix = create$3();
5228 this.worldInverseMatrix = create$3();
5229 this.worldNormalMatrix = create$3();
5230 this.isVisible = true;
5231 this.isDirty = false;
5232 // RTS
5233 identity$3(this.localMatrix);
5234 identity$3(this.worldMatrix);
5235 }
5236 static clone(source) {
5237 let trans = new Transform();
5238 copy$4(trans.translate, source.translate);
5239 copy$4(trans.rotate, source.rotate);
5240 copy$4(trans.scale, source.scale);
5241 copy$5(trans.quaternion, source.quaternion);
5242 return trans;
5243 }
5244 }
5245 EntityMgr.getDefaultComponent = () => new Transform();
5246 EntityMgr.cloneMethods['_Transform'] = Transform.clone;
5247 class TransformSystem extends ComponentSystem {
5248 constructor() {
5249 super(...arguments);
5250 this.group = [];
5251 this.depends = [Transform.name];
5252 }
5253 onUpdate() {
5254 for (let { components } of this.group) {
5255 // if(trans.isDirty)
5256 TransformSystem.updateMatrix(components.Transform);
5257 }
5258 }
5259 static decomposeMatrix(trans, mat = trans.localMatrix) {
5260 // https://math.stackexchange.com/questions/237369/given-this-transformation-matrix-how-do-i-decompose-it-into-translation-rotati
5261 // Get scaling
5262 set$4(trans.translate, mat[0], mat[1], mat[2]); // temp
5263 let sx = len(trans.translate);
5264 set$4(trans.translate, mat[4], mat[5], mat[6]); // temp
5265 let sy = len(trans.translate);
5266 set$4(trans.translate, mat[8], mat[9], mat[10]); // temp
5267 let sz = len(trans.translate);
5268 set$4(trans.scale, sx, sy, sz);
5269 if (determinant$3(mat) < 0) {
5270 sx = -sx;
5271 }
5272 // Get translation
5273 set$4(trans.translate, mat[12], mat[13], mat[14]);
5274 mat[12] = mat[13] = mat[14] = 0;
5275 // Get rotation
5276 mat[0] /= sx;
5277 mat[1] /= sx;
5278 mat[2] /= sx;
5279 mat[4] /= sy;
5280 mat[5] /= sy;
5281 mat[6] /= sy;
5282 mat[8] /= sz;
5283 mat[9] /= sz;
5284 mat[10] /= sz;
5285 getRotation(trans.quaternion, mat);
5286 }
5287 static updateMatrix(trans) {
5288 trans.isDirty = false;
5289 // Calculate local matrix
5290 fromRotationTranslationScale(trans.localMatrix, trans.quaternion, trans.translate, trans.scale);
5291 invert$3(trans.worldInverseMatrix, trans.worldMatrix);
5292 transpose$2(trans.worldNormalMatrix, trans.worldInverseMatrix);
5293 // Calculate world matrix
5294 let parent = trans.entity.parentElement;
5295 if (parent != null && parent.components) {
5296 let world = parent.components.Transform;
5297 // if(world.isDirty) {
5298 // this.updateMatrix(world);
5299 // }
5300 // Update world matrix
5301 mul$3(trans.worldMatrix, world.worldMatrix, trans.localMatrix);
5302 // Update world position
5303 transformMat4(trans.worldPos, trans.translate, trans.worldMatrix);
5304 }
5305 else { // if current node is the root of world
5306 copy$3(trans.worldMatrix, trans.localMatrix);
5307 }
5308 }
5309 }
5310 System.registSystem(new TransformSystem());
5311 // (!) Circular dependency: src/ECS/system.ts -> src/ECS/entityMgr.ts -> src/transform.ts -> src/ECS/system.ts
5312
5313 class Skin {
5314 constructor() {
5315 // Inverse Bind pose Matrices
5316 this.ibm = [];
5317 this.jointMat = [];
5318 }
5319 }
5320 class SkinSystem extends ComponentSystem {
5321 constructor() {
5322 super(...arguments);
5323 this.group = [];
5324 this.depends = [
5325 Skin.name,
5326 ];
5327 }
5328 onUpdate() {
5329 for (let { components } of this.group) {
5330 let skin = components.Skin;
5331 // global transform of node that the mesh ss attached to
5332 let trans = components.Transform;
5333 for (let [i, joint] of skin.joints.entries()) {
5334 mul$3(skin.jointMat[i], joint.worldMatrix, skin.ibm[i]);
5335 mul$3(skin.jointMat[i], trans.worldInverseMatrix, skin.jointMat[i]);
5336 }
5337 // if(!skin.materials) {
5338 // skin.materials = [];
5339 // let materials: any = trans.entity.parentElement.querySelectorAll('ash-entity[Material]');
5340 // for(let entity of materials) {
5341 // let mat = entity.components.Material as Material;
5342 // // mat.shader.macros['HAS_SKINS'] = '';
5343 // mat.shader.macros['JOINT_AMOUNT'] = Math.min(skin.jointMat.length, 200);
5344 // mat.shader.isDirty = true;
5345 // skin.materials.push(mat);
5346 // }
5347 // }
5348 // update matrices
5349 // for(let mat of skin.materials) {
5350 // Material.setUniform(mat, 'jointMat[0]', skin.outputMat);
5351 // }
5352 // let materials: any = trans.entity.querySelectorAll('Material');
5353 // for(let mat of materials) {
5354 // Material.setUniform(mat, 'jointMat[0]', skin.outputMat);
5355 // }
5356 }
5357 }
5358 ;
5359 }
5360 System.registSystem(new SkinSystem());
5361
5362 class Animation {
5363 constructor() {
5364 this.channels = [];
5365 }
5366 static attachChannel(anim, chan) {
5367 anim.channels.push(chan);
5368 this.totalTime = Math.max(this.totalTime, chan.endTime);
5369 }
5370 }
5371 Animation.totalTime = 0;
5372 class AnimationChannel {
5373 constructor(pTarget, timeline, keyframe) {
5374 this.isLoop = true;
5375 this.pause = false;
5376 this.currentTime = 0;
5377 this.startTime = 0;
5378 this.endTime = 0;
5379 this.totalTime = 0;
5380 this.step = 0;
5381 this.speed = 1;
5382 this.channel = pTarget;
5383 this.timeline = Accessor.newFloat32Array(timeline);
5384 this.endTime = this.timeline[this.timeline.length - 1];
5385 this.keyframe = Accessor.getFloat32Blocks(keyframe);
5386 if (this.timeline.length != 1) {
5387 this.startTime = this.timeline[0];
5388 }
5389 else {
5390 this.currentTime = this.endTime;
5391 }
5392 }
5393 }
5394 class AnimationSystem extends ComponentSystem {
5395 constructor() {
5396 super(...arguments);
5397 this.group = [];
5398 this.depends = [
5399 Animation.name,
5400 ];
5401 }
5402 reset(anim) {
5403 anim.step = 0;
5404 anim.currentTime = 0;
5405 }
5406 static step(anim) {
5407 let rigLength = anim.channel.length;
5408 let prevKey = anim.step;
5409 let nextKey = prevKey + 1;
5410 let prevTime, prevFrame, nextTime, nextFrame;
5411 if (anim.timeline.length == 1) { // Single frame
5412 nextKey = 0;
5413 prevTime = 0;
5414 anim.pause = true;
5415 }
5416 else {
5417 prevTime = anim.timeline[prevKey];
5418 prevFrame = anim.keyframe[prevKey];
5419 }
5420 nextTime = anim.timeline[nextKey];
5421 nextFrame = anim.keyframe[nextKey];
5422 let scopeTime = nextTime - prevTime;
5423 // Confirm
5424 if (anim.currentTime < prevTime || anim.currentTime > nextTime) {
5425 console.error('Wrong step!', anim.currentTime, prevTime, nextTime);
5426 console.log(anim.timeline);
5427 return;
5428 }
5429 let interpolationValue = scopeTime
5430 ? (anim.currentTime - prevTime) / scopeTime
5431 : 1;
5432 switch (rigLength) {
5433 case 4:
5434 slerp(anim.channel, prevFrame || this.defaultQuat, nextFrame, interpolationValue);
5435 break;
5436 case 3:
5437 lerp(anim.channel, prevFrame || this.defaultVec3, nextFrame, interpolationValue);
5438 break;
5439 }
5440 }
5441 playStep(anim, dt) {
5442 if (!anim.pause) {
5443 if (anim.currentTime > Animation.totalTime) {
5444 this.reset(anim);
5445 if (!anim.isLoop) {
5446 anim.pause = true;
5447 // execute the last frame even already missed?
5448 // anim.currentTime = anim.endTime;
5449 console.log('stop');
5450 }
5451 return;
5452 }
5453 while (anim.currentTime > anim.timeline[anim.step + 1]) {
5454 anim.step++;
5455 }
5456 if (anim.currentTime > anim.startTime && anim.currentTime <= anim.endTime) {
5457 AnimationSystem.step(anim);
5458 }
5459 anim.currentTime += dt * anim.speed;
5460 }
5461 }
5462 onUpdate(dt) {
5463 for (let { components } of this.group) {
5464 if (dt > 0.016)
5465 dt = 0.016;
5466 let anim = components.Animation;
5467 for (let channel of anim.channels) {
5468 this.playStep(channel, dt);
5469 }
5470 }
5471 }
5472 ;
5473 }
5474 AnimationSystem.defaultQuat = create$6();
5475 AnimationSystem.defaultVec3 = create$4();
5476 System.registSystem(new AnimationSystem());
5477
5478 class gltfScene {
5479 constructor(gltf) {
5480 this.scene = EntityMgr.create('scene');
5481 this.gltf = gltf;
5482 // Materials
5483 // set default material if materials does not exist
5484 if (!gltf.materials) {
5485 gltf.materials = [{ name: 'Default_Material' }];
5486 }
5487 gltf.materials = gltf.materials.map(config => {
5488 let mat = new Material(gltf.commonShader, config.name, config.doubleSided);
5489 console.log(config);
5490 this.detectConfig(mat, config);
5491 Material.setTexture(mat, 'brdfLUT', Texture.clone(gltf.brdfLUT));
5492 if (gltf.hasEnvmap) {
5493 mat.shader.macros['HAS_ENV_MAP'] = '';
5494 Material.setTexture(mat, 'env', Texture.clone(gltf.envmap));
5495 }
5496 // if(gltf.skins) {
5497 // mat.shader.macros['HAS_SKINS'] = '';
5498 // }
5499 return mat;
5500 });
5501 // Set up all Vertexes
5502 gltf.accessors = gltf.accessors.map(acc => {
5503 let attr = new Accessor(acc);
5504 attr.bufferView = gltf.bufferViews[acc.bufferView];
5505 return attr;
5506 });
5507 // Create mesh
5508 gltf.meshes = gltf.meshes.map(mesh => {
5509 return mesh.primitives.map(meshData => {
5510 let { attributes, targets } = meshData;
5511 // Pick up attributes
5512 let accessors = [];
5513 for (let attr in attributes) {
5514 let acc = gltf.accessors[attributes[attr]];
5515 acc.attribute = attr; // Set attribute name
5516 accessors.push(acc);
5517 }
5518 // if(targets) {
5519 // for (let target of targets) {
5520 // for (let tar in target) {
5521 // let acc: Accessor = gltf.accessors[target[tar]];
5522 // acc.attribute = '_' + tar;
5523 // accessors.push(acc);
5524 // }
5525 // break;
5526 // }
5527 // }
5528 // Triangles
5529 let ebo = gltf.accessors[meshData.indices];
5530 let mf = new Mesh(accessors, ebo, meshData.mode);
5531 if (attributes.TANGENT == null && attributes.TEXCOORD_0 != null) {
5532 console.warn('Using computed tagent!');
5533 Mesh.preComputeTangent(mf);
5534 }
5535 let mat = gltf.materials[meshData.material || 0];
5536 if (attributes.JOINTS_0 != null) {
5537 mat.shader.macros['HAS_SKINS'] = '';
5538 }
5539 return [mf, mat];
5540 });
5541 });
5542 }
5543 assemble() {
5544 return __awaiter(this, void 0, void 0, function* () {
5545 // Create entity instance for each node
5546 let gltf = this.gltf;
5547 let { scene, scenes, nodes, skins, animations } = gltf;
5548 this.entities = yield Promise.all(gltf.nodes.map((node, index) => this.waitEntity(node, index)));
5549 if (skins) {
5550 skins = skins.map(skin => {
5551 skin.joints = skin.joints.map(jointIndex => this.entities[jointIndex].components.Transform);
5552 if (skin.entity == null) {
5553 return;
5554 }
5555 let skinComp = new Skin();
5556 // Set up releated materials
5557 skinComp.materials = skin.materials;
5558 skinComp.joints = skin.joints;
5559 let acc = gltf.accessors[skin.inverseBindMatrices];
5560 skinComp.ibm = Accessor.getFloat32Blocks(acc);
5561 skinComp.outputMat = new Float32Array(acc.count * acc.size);
5562 skinComp.jointMat = Accessor.getSubChunks(acc, skinComp.outputMat);
5563 // https://github.com/KhronosGroup/glTF/issues/1270
5564 // https://github.com/KhronosGroup/glTF/pull/1195
5565 // for (let mat of skin.materials) {
5566 // mat.shader.macros['JOINT_AMOUNT'] = Math.min(skin.joints.length, 200);
5567 // mat.shader.isDirty = true;
5568 // }
5569 for (let trans of skin.transforms) {
5570 trans.jointsMatrices = skinComp.outputMat;
5571 let mat = trans.entity.components.Material;
5572 mat.shader.macros['JOINT_AMOUNT'] = Math.min(skin.joints.length, 200);
5573 }
5574 if (skin.entity)
5575 skin.entity.addComponent(skinComp);
5576 return skinComp;
5577 });
5578 }
5579 if (animations) {
5580 for (let { channels, samplers } of animations) {
5581 for (let { sampler, target } of channels) {
5582 let e = this.entities[target.node];
5583 let trans = e.components.Transform;
5584 let controlChannel;
5585 switch (target.path) {
5586 case 'translation':
5587 controlChannel = trans.translate;
5588 break;
5589 case 'rotation':
5590 controlChannel = trans.quaternion;
5591 break;
5592 case 'scale':
5593 controlChannel = trans.scale;
5594 break;
5595 case 'weights':
5596 break;
5597 }
5598 if (controlChannel != null) {
5599 let { input, interpolation, output } = samplers[sampler];
5600 let timeline = gltf.accessors[input];
5601 let keyframe = gltf.accessors[output];
5602 if (e.components.Animation == null) {
5603 e.addComponent(new Animation());
5604 }
5605 let anim = e.components.Animation;
5606 Animation.attachChannel(anim, new AnimationChannel(controlChannel, timeline, keyframe));
5607 // console.log(anim);
5608 }
5609 }
5610 }
5611 }
5612 // assemble scene tree
5613 let roots = scenes[scene || 0].nodes;
5614 for (let r of roots) {
5615 let root = this.parseNode(r, nodes);
5616 this.scene.appendChild(root);
5617 }
5618 console.log(this);
5619 return this;
5620 });
5621 }
5622 waitEntity(node, index) {
5623 return new Promise((resolve, reject) => {
5624 setTimeout(() => {
5625 resolve(this.createEntity(node, index));
5626 }, 0);
5627 });
5628 }
5629 detectTexture(mat, texName, texInfo) {
5630 let { index, texCoord } = texInfo;
5631 let gltf = this.gltf;
5632 if (index != null) { // common texture
5633 Material.setTexture(mat, texName, Texture.clone(gltf.textures[index]));
5634 // Multi UV
5635 if (texCoord) { // > 0
5636 mat.shader.macros[`${texName}_uv`] = `uv${texCoord}`;
5637 }
5638 }
5639 }
5640 detectConfig(mat, config) {
5641 let shader = mat.shader;
5642 for (let key in config) {
5643 let value = config[key];
5644 // assueme current property is an texture info
5645 this.detectTexture(mat, key, value);
5646 switch (key) {
5647 // Textures
5648 case 'normalTexture':
5649 shader.macros['HAS_NORMAL_MAP'] = '';
5650 break;
5651 case 'occlusionTexture':
5652 shader.macros['HAS_AO_MAP'] = '';
5653 break;
5654 case 'baseColorTexture':
5655 shader.macros['HAS_BASECOLOR_MAP'] = '';
5656 break;
5657 case 'metallicRoughnessTexture':
5658 shader.macros['HAS_METALLIC_ROUGHNESS_MAP'] = '';
5659 break;
5660 case 'emissiveTexture':
5661 shader.macros['HAS_EMISSIVE_MAP'] = '';
5662 break;
5663 // Factors - pbrMetallicRoughness
5664 case 'baseColorFactor':
5665 shader.macros['BASECOLOR_FACTOR'] = `vec4(${value.join(',')})`;
5666 break;
5667 case 'metallicFactor':
5668 shader.macros['METALLIC_FACTOR'] = `float(${value})`;
5669 break;
5670 case 'roughnessFactor':
5671 shader.macros['ROUGHNESS_FACTOR'] = `float(${value})`;
5672 break;
5673 // Alpha Blend Mode
5674 case 'alphaMode':
5675 shader.macros[value] = '';
5676 if (value != 'OPAQUE') {
5677 mat.queue = RenderQueue.Blend;
5678 }
5679 break;
5680 case 'alphaCutoff':
5681 shader.macros['ALPHA_CUTOFF'] = `float(${value})`;
5682 break;
5683 case 'pbrMetallicRoughness':
5684 this.detectConfig(mat, value);
5685 break;
5686 }
5687 }
5688 }
5689 createEntity(node, index) {
5690 let { mesh, name, matrix, rotation, scale, translation, skin, camera } = node;
5691 name = name || 'node_' + index;
5692 let entity = EntityMgr.create(name);
5693 let trans = entity.components.Transform;
5694 if (matrix != null) {
5695 set$3(trans.localMatrix, ...matrix);
5696 TransformSystem.decomposeMatrix(trans);
5697 }
5698 else {
5699 if (rotation != null) {
5700 set$5(trans.quaternion, ...rotation);
5701 }
5702 if (scale != null) {
5703 set$4(trans.scale, ...scale);
5704 }
5705 if (translation != null) {
5706 set$4(trans.translate, ...translation);
5707 }
5708 }
5709 TransformSystem.updateMatrix(trans);
5710 let transCache = [];
5711 // let matCache = [];
5712 if (mesh != null) {
5713 let renderTarget = entity;
5714 let meshChunk = this.gltf.meshes[mesh];
5715 let hasSubnode = meshChunk.length - 1;
5716 for (let [i, meshData] of meshChunk.entries()) {
5717 let [mf, mat] = meshData;
5718 if (hasSubnode) {
5719 renderTarget = entity.appendChild(EntityMgr.create('subNode_' + i));
5720 }
5721 renderTarget.addComponent(mf);
5722 renderTarget.addComponent(mat);
5723 transCache.push(renderTarget.components.Transform);
5724 // matCache.push(mat);
5725 }
5726 }
5727 if (skin != null) {
5728 this.gltf.skins[skin].entity = entity;
5729 if (!this.gltf.skins[skin].transforms) {
5730 this.gltf.skins[skin].transforms = [];
5731 }
5732 this.gltf.skins[skin].transforms.push(...transCache);
5733 // this.gltf.skins[skin].materials = matCache;
5734 }
5735 if (camera != null) {
5736 entity.addComponent(this.gltf.cameras[camera]);
5737 }
5738 return entity;
5739 }
5740 parseNode(nodeIndex, nodeList) {
5741 let node = nodeList[nodeIndex];
5742 let entity = this.entities[nodeIndex];
5743 if (node.children) {
5744 for (let child of node.children) {
5745 entity.appendChild(this.parseNode(child, nodeList));
5746 }
5747 }
5748 return entity;
5749 }
5750 }
5751
5752 class Camera {
5753 constructor(aspect = 1, fov = 45, near = 0.1, far = 1000) {
5754 this.isDirty = true;
5755 this.aspect = aspect;
5756 this.fov = fov;
5757 this.near = near;
5758 this.far = far;
5759 this.projection = create$3();
5760 this.view = create$3();
5761 this.vp = create$3();
5762 this.up = fromValues$4(0, 1, 0);
5763 this.lookAt = create$4();
5764 Camera.updateProjectionMatrix(this);
5765 }
5766 static updateProjectionMatrix(cam) {
5767 perspective(cam.projection, cam.fov * Math.PI / 180.0, cam.aspect, cam.near, cam.far);
5768 }
5769 static updateViewMatrix(cam) {
5770 let trans = cam.entity.components.Transform;
5771 lookAt(cam.view, trans.translate, cam.lookAt, cam.up);
5772 mul$3(cam.view, cam.view, trans.worldInverseMatrix);
5773 mul$3(cam.vp, cam.projection, cam.view);
5774 }
5775 }
5776 class CameraSystem extends ComponentSystem {
5777 constructor() {
5778 super(...arguments);
5779 this.group = [];
5780 this.depends = [
5781 Camera.name
5782 ];
5783 }
5784 onUpdate() {
5785 for (let { components } of this.group) {
5786 let camera = components.Camera;
5787 // let trans = components.Transform as Transform;
5788 // if(camera.isDirty) {
5789 Camera.updateViewMatrix(camera);
5790 // TODO: multiple scenes with multiple cameras
5791 // let meshRenderers = EntityMgr.getComponents<MeshRenderer>(MeshRenderer.name);
5792 // for(let mr of meshRenderers) {
5793 // Material.setUniform(mr.materials[0], 'P', camera.projection);
5794 // Material.setUniform(mr.materials[0], 'V', camera.view);
5795 // Material.setUniform(mr.materials[0], 'u_Camera', trans.worldPos);
5796 // }
5797 // camera.isDirty = false;
5798 // }
5799 }
5800 }
5801 }
5802 System.registSystem(new CameraSystem());
5803
5804 class Asset {
5805 static addTask() {
5806 this.totalTask++;
5807 if (this.taskObserve)
5808 this.taskObserve(this.finishedTask, this.totalTask);
5809 }
5810 ;
5811 static finishTask() {
5812 this.finishedTask++;
5813 if (this.taskObserve)
5814 this.taskObserve(this.finishedTask, this.totalTask);
5815 }
5816 ;
5817 static loadImage(url) {
5818 return new Promise((resolve, reject) => {
5819 this.addTask();
5820 let image = new Image();
5821 image.crossOrigin = "anonymous";
5822 image.src = url;
5823 image.onload = () => {
5824 resolve(image);
5825 this.finishTask();
5826 };
5827 });
5828 }
5829 static loadBufferImage(buffer, mimeType) {
5830 return new Promise((resolve, reject) => {
5831 var blob = new Blob([buffer], { type: mimeType });
5832 var url = URL.createObjectURL(blob);
5833 let image = new Image();
5834 image.src = url;
5835 image.onload = () => {
5836 resolve(image);
5837 };
5838 });
5839 }
5840 static adjustDataUri(root, uri) {
5841 return uri.substr(0, 5) == "data:" ? uri : root + uri;
5842 }
5843 static glbParse(path) {
5844 return __awaiter(this, void 0, void 0, function* () {
5845 let json, bin = [];
5846 let glb = yield this.loadBuffer(path);
5847 let offset = 0;
5848 // HEADER
5849 let header = new Int32Array(glb, offset, 3);
5850 offset += 3 * 4;
5851 let [magic, version, length] = header;
5852 if (magic != this.glbMagic) {
5853 console.error('Magic number incorrect! - ' + header[0]);
5854 return;
5855 }
5856 while (offset < length) {
5857 let [chunkLength, chunkType] = new Int32Array(glb, offset, 2);
5858 offset += 2 * 4;
5859 let chunkData = glb.slice(offset, offset + chunkLength);
5860 switch (chunkType) {
5861 // JSON
5862 case 0x4E4F534A:
5863 json = JSON.parse(this.decoder.decode(chunkData));
5864 break;
5865 // BIN
5866 case 0x004E4942:
5867 bin.push(chunkData);
5868 break;
5869 }
5870 offset += chunkLength;
5871 }
5872 return {
5873 json: json,
5874 bin: bin
5875 };
5876 });
5877 }
5878 static loadGLTF(path, screen, envmap, shader = new Shader(glsl.sylize.vs, glsl.sylize.fs)) {
5879 return __awaiter(this, void 0, void 0, function* () {
5880 let gltf;
5881 // parse current path
5882 let root = path.split('/');
5883 let [filename, format] = root.pop().split('.');
5884 root = root.join('/') + '/';
5885 if (format == 'glb') {
5886 let glb = yield this.glbParse(path);
5887 gltf = glb.json;
5888 gltf.buffers = glb.bin;
5889 // BufferViews
5890 gltf.bufferViews = gltf.bufferViews.map(bv => new bufferView(gltf.buffers[bv.buffer], bv));
5891 if (gltf.images) {
5892 gltf.images = yield Promise.all(gltf.images.map(i => this.loadBufferImage(gltf.bufferViews[i.bufferView].dataView, i.mimeType)));
5893 }
5894 }
5895 else if (format == 'gltf') {
5896 // Load gltf
5897 gltf = yield (yield fetch(path)).json();
5898 // Download buffers
5899 gltf.buffers = yield Promise.all(gltf.buffers.map(({ uri }) => this.loadBuffer(this.adjustDataUri(root, uri))));
5900 // BufferViews
5901 gltf.bufferViews = gltf.bufferViews.map(bv => new bufferView(gltf.buffers[bv.buffer], bv));
5902 // then download images
5903 if (gltf.images) {
5904 gltf.images = yield Promise.all(gltf.images.map(({ uri }) => this.loadImage(this.adjustDataUri(root, uri))));
5905 }
5906 }
5907 else {
5908 console.error('Wrong file!');
5909 return;
5910 }
5911 // Camera components
5912 if (gltf.cameras) {
5913 gltf.cameras = gltf.cameras.map(cam => {
5914 if (cam.perspective) {
5915 // NOTE: Infinite perspective camera is not support yet
5916 let { aspectRatio, yfov, znear, zfar } = cam.perspective;
5917 let camera = new Camera(screen.width / screen.height, yfov * 180 / Math.PI, znear, zfar);
5918 camera.name = cam.name;
5919 return camera;
5920 }
5921 });
5922 }
5923 // Textures
5924 if (gltf.textures) {
5925 gltf.textures = gltf.textures.map(tex => {
5926 let { source, sampler } = tex;
5927 let currentSampler;
5928 if (gltf.samplers != null)
5929 currentSampler = gltf.samplers[sampler];
5930 let texture = new Texture(gltf.images[source], currentSampler);
5931 Texture.createTexture(screen.gl, texture);
5932 return texture;
5933 });
5934 }
5935 // Load shader
5936 gltf.commonShader = shader;
5937 // Load brdfLUT
5938 gltf.brdfLUT = yield this.loadTexture('https://raw.githubusercontent.com/KhronosGroup/glTF-WebGL-PBR/master/textures/brdfLUT.png', { minFilter: WebGL2RenderingContext.LINEAR });
5939 if (envmap != null) {
5940 gltf.hasEnvmap = true;
5941 gltf.envmap = envmap;
5942 }
5943 else {
5944 gltf.hasEnvmap = false;
5945 }
5946 // Parse scene
5947 let { scene } = yield new gltfScene(gltf).assemble();
5948 // Create meshRenders
5949 // filter mesh & material which meshRenderer required
5950 let renderTargets = EntityMgr.getEntites([Mesh.name, Material.name], scene);
5951 for (let entity of renderTargets) {
5952 let mesh = entity.components.Mesh;
5953 let material = entity.components.Material;
5954 if (material.name == 'outline') {
5955 entity.components.Transform.isVisible = false;
5956 }
5957 entity.addComponent(new MeshRenderer(screen, mesh, material));
5958 }
5959 return scene;
5960 });
5961 }
5962 static loadBuffer(bufferPath) {
5963 return __awaiter(this, void 0, void 0, function* () {
5964 this.addTask();
5965 let buffer = yield (yield fetch(bufferPath)).arrayBuffer();
5966 this.finishTask();
5967 return buffer;
5968 });
5969 }
5970 static LoadShaderProgram(url) {
5971 return __awaiter(this, void 0, void 0, function* () {
5972 url = Material.SHADER_PATH + url;
5973 let vertPath = url + '.vs.glsl';
5974 let fragPath = url + '.fs.glsl';
5975 let [vert, frag] = yield Promise.all([vertPath, fragPath].map(path => fetch(path).then(e => e.text())));
5976 // console.log(vert);
5977 // console.log(frag);
5978 return new Shader(vert, frag);
5979 });
5980 }
5981 static LoadMaterial(matName) {
5982 return __awaiter(this, void 0, void 0, function* () {
5983 this.addTask();
5984 let shader = yield this.LoadShaderProgram(matName);
5985 this.finishTask();
5986 return new Material(shader);
5987 });
5988 }
5989 static loadCubeimg(folder, format = 'jpg') {
5990 return __awaiter(this, void 0, void 0, function* () {
5991 return yield Promise.all(this.cubemapOrder.map(name => this.loadImage(folder + name + format)));
5992 });
5993 }
5994 static loadCubemap(folder, format = 'jpg') {
5995 return __awaiter(this, void 0, void 0, function* () {
5996 let rawImages = yield this.loadCubeimg(folder, format);
5997 return new Texture(rawImages);
5998 });
5999 }
6000 static loadTexture(url, option) {
6001 return __awaiter(this, void 0, void 0, function* () {
6002 let image = yield this.loadImage(url);
6003 return new Texture(image, option);
6004 });
6005 }
6006 }
6007 // static load(url, type: XMLHttpRequestResponseType = 'json') {
6008 // return new Promise((resolve, reject) => {
6009 // let xhr = new XMLHttpRequest();
6010 // xhr.open('GET', url);
6011 // xhr.responseType = type;
6012 // xhr.onload = function () {
6013 // if (this.status >= 200 && this.status < 300) {
6014 // resolve(xhr.response);
6015 // } else {
6016 // reject(xhr.statusText);
6017 // }
6018 // }
6019 // xhr.onerror = function () {
6020 // reject(xhr.statusText);
6021 // }
6022 // xhr.send();
6023 // });
6024 // }
6025 // Analyze
6026 Asset.totalTask = 0;
6027 Asset.finishedTask = 0;
6028 Asset.taskObserve = null;
6029 Asset.glbMagic = 0x46546C67;
6030 Asset.decoder = new TextDecoder();
6031 Asset.cubemapOrder = [
6032 'posx.',
6033 'negx.',
6034 'posy.',
6035 'negy.',
6036 'posz.',
6037 'negz.',
6038 ];
6039
6040 class QuadMesh extends Mesh {
6041 constructor() {
6042 let meshVBO = new Float32Array([
6043 -1, -1, 0, 0, 0, 0, 0, 1,
6044 1, -1, 0, 1, 0, 0, 0, 1,
6045 1, 1, 0, 1, 1, 0, 0, 1,
6046 -1, 1, 0, 0, 1, 0, 0, 1
6047 ]);
6048 let meshEBO = new Uint16Array([
6049 0, 1, 2,
6050 0, 2, 3
6051 ]);
6052 let vbo = new bufferView(meshVBO.buffer, {
6053 byteOffset: meshVBO.byteOffset,
6054 byteLength: meshVBO.byteLength,
6055 byteStride: 8 * 4,
6056 target: WebGL2RenderingContext.ARRAY_BUFFER
6057 });
6058 let ebo = new bufferView(meshEBO.buffer, {
6059 byteOffset: meshEBO.byteOffset,
6060 byteLength: meshEBO.byteLength,
6061 byteStride: 0,
6062 target: WebGL2RenderingContext.ELEMENT_ARRAY_BUFFER
6063 });
6064 let position = new Accessor({
6065 bufferView: vbo,
6066 componentType: WebGL2RenderingContext.FLOAT,
6067 byteOffset: 0,
6068 type: "VEC3",
6069 count: 4
6070 }, 'POSITION');
6071 let uv = new Accessor({
6072 bufferView: vbo,
6073 componentType: WebGL2RenderingContext.FLOAT,
6074 byteOffset: 3 * 4,
6075 type: "VEC2",
6076 count: 4
6077 }, 'TEXCOORD_0');
6078 let normal = new Accessor({
6079 bufferView: vbo,
6080 componentType: WebGL2RenderingContext.FLOAT,
6081 byteOffset: 5 * 4,
6082 type: "VEC3",
6083 count: 4
6084 }, 'NORMAL');
6085 let indices = new Accessor({
6086 bufferView: ebo,
6087 componentType: WebGL2RenderingContext.UNSIGNED_SHORT,
6088 byteOffset: 0,
6089 type: "SCALAR",
6090 count: 6
6091 });
6092 super([position, uv, normal], indices);
6093 }
6094 }
6095
6096 class Bloom {
6097 static initFilters(screen, threshold = 0.7, radius = 60, intensity = 1) {
6098 let macro;
6099 // threshold filter
6100 macro = {
6101 THRESHOLD: threshold
6102 };
6103 let blurSize = 128;
6104 let thresholdFilter = new Filter(screen, new Shader(threshold_vs, threshold_fs, macro), blurSize, blurSize);
6105 // Two pass gaussian blur
6106 let width = screen.width / screen.ratio;
6107 let height = screen.height / screen.ratio;
6108 radius *= screen.ratio;
6109 macro = {
6110 OFFSET: `vec2(${radius / width}, 0)`
6111 };
6112 let blur1 = new Filter(screen, new Shader(blurvs, blurfs, macro));
6113 macro = {
6114 OFFSET: `vec2(0, ${radius / height})`
6115 };
6116 let blur2 = new Filter(screen, new Shader(blurvs, blurfs, macro));
6117 // Combiand
6118 macro = {
6119 BLOOM_INTENSITY: `float(${intensity})`
6120 };
6121 let comb = new Filter(screen, new Shader(combine_vs, combine_fs, macro));
6122 if (screen.output) {
6123 comb.setInput(screen.output.output, 'originTex');
6124 }
6125 else {
6126 comb.setInput(screen.capture.output, 'originTex');
6127 }
6128 // Assemble
6129 // The first stage must be attach to screen
6130 screen.attachFilter(thresholdFilter);
6131 screen.attachFilter(blur1);
6132 screen.attachFilter(blur2);
6133 screen.attachFilter(comb);
6134 }
6135 }
6136 let threshold_vs = `
6137attribute vec3 POSITION;
6138attribute vec2 TEXCOORD_0;
6139
6140varying vec2 uv;
6141varying vec4 pos;
6142
6143void main() {
6144 uv = TEXCOORD_0;
6145 vec4 position = vec4(POSITION, 1);
6146 pos = position;
6147 gl_Position = position;
6148}
6149`;
6150 let threshold_fs = `
6151precision mediump float;
6152uniform sampler2D base;
6153
6154varying vec2 uv;
6155varying vec4 pos;
6156
6157
6158void main() {
6159 vec4 color = texture2D(base, uv);
6160 float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
6161 if(brightness < THRESHOLD) {
6162 color.r = color.g = color.b = 0.0;
6163 }
6164 gl_FragColor = color;
6165}
6166`;
6167 let blurvs = `
6168attribute vec3 POSITION;
6169attribute vec2 TEXCOORD_0;
6170
6171varying vec2 uv;
6172varying vec4 pos;
6173
6174void main() {
6175 uv = TEXCOORD_0;
6176 vec4 position = vec4(POSITION, 1);
6177 pos = position;
6178 gl_Position = position;
6179}
6180`;
6181 let blurfs = `
6182#define PI 3.1415926535898
6183precision mediump float;
6184uniform sampler2D base;
6185
6186varying vec2 uv;
6187varying vec4 pos;
6188
6189vec4 blur9() {
6190 vec4 color = vec4(0);
6191 vec2 direction = OFFSET;
6192 vec2 off1 = vec2(1.3846153846) * direction;
6193 vec2 off2 = vec2(3.2307692308) * direction;
6194 color += texture2D(base, uv) * 0.2270270270;
6195 color += texture2D(base, uv + off1) * 0.3162162162;
6196 color += texture2D(base, uv - off1) * 0.3162162162;
6197 color += texture2D(base, uv + off2) * 0.0702702703;
6198 color += texture2D(base, uv - off2) * 0.0702702703;
6199 return color;
6200}
6201vec4 gaussianBlur() {
6202 vec2 offset = OFFSET;
6203 float weight[5];
6204 weight[0] = 0.227027;
6205 weight[1] = 0.1945946;
6206 weight[2] = 0.1216216;
6207 weight[3] = 0.054054;
6208 weight[4] = 0.016216;
6209 vec4 color = vec4(0);
6210 for(int i = 0; i < 5; i++) {
6211 color += texture2D(base, uv + offset * float(i+1) ) * weight[i];
6212 color += texture2D(base, uv + offset * float(-i-1) ) * weight[i];
6213 }
6214 return color;
6215}
6216
6217float random(vec3 scale, float seed) {
6218 return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);
6219}
6220
6221// https://redcamel.github.io/RedGL2/example/postEffect/blur/RedPostEffect_BlurX.html
6222
6223vec4 noiseblur() {
6224 vec4 finalColor = vec4(0);
6225 vec2 delta;
6226 float total = 0.0;
6227 float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0);
6228 delta = OFFSET;
6229 for (float t = -10.0; t <= 10.0; t++) {
6230 float percent = (t + offset - 0.5) / 10.0;
6231 float weight = 1.0 - abs(percent);
6232 vec4 sample = texture2D(base, uv + delta * percent);
6233 sample.rgb *= sample.a;
6234 finalColor += sample * weight;
6235 total += weight;
6236 }
6237 finalColor /= total;
6238 return finalColor;
6239}
6240
6241void main() {
6242 // gl_FragColor = gaussianBlur();
6243 gl_FragColor = noiseblur();
6244 // gl_FragColor = blur9();
6245}
6246`;
6247 let combine_vs = `
6248attribute vec3 POSITION;
6249attribute vec2 TEXCOORD_0;
6250
6251varying vec2 uv;
6252varying vec4 pos;
6253
6254void main() {
6255 uv = TEXCOORD_0;
6256 vec4 position = vec4(POSITION, 1);
6257 pos = position;
6258 gl_Position = position;
6259}
6260`;
6261 let combine_fs = `
6262precision mediump float;
6263uniform sampler2D base;
6264uniform sampler2D originTex;
6265
6266varying vec2 uv;
6267varying vec4 pos;
6268
6269
6270void main() {
6271 vec4 origin = texture2D(originTex, uv);
6272 vec4 addition = texture2D(base, uv) * vec4(vec3(BLOOM_INTENSITY),1);
6273 gl_FragColor = origin + addition;
6274}
6275`;
6276
6277 class Vignetting extends Filter {
6278 constructor(screen, factor = 0.4, hardness = 1) {
6279 super(screen, new Shader(vig_vs, vig_fs, {
6280 FACTOR: `float(${factor})`,
6281 HARDNESS: `float(${hardness})`,
6282 }));
6283 }
6284 }
6285 // FIXME: texcoords
6286 let vig_vs = glsl.vignetting.vs;
6287 let vig_fs = glsl.vignetting.fs;
6288
6289 class OrbitControl {
6290 constructor(screen, target, pitch = 90, yaw = 90, speed = 0.2, damping = 0.92) {
6291 this.movement = create$4();
6292 this.unprojectMatrix = create$3();
6293 this.X = fromValues$4(1, 0, 0);
6294 this.Y = fromValues$4(0, 1, 0);
6295 this.Z = fromValues$4(0, 0, 1);
6296 this.vx = 0;
6297 this.vy = 0;
6298 this.vz = 0;
6299 // Damping stuff
6300 this.vyaw = 0;
6301 this.vpitch = 0;
6302 this.vscale = 0;
6303 this.threshold = 0.001;
6304 this.moveHandler = (e) => {
6305 let { movementX, movementY, buttons } = e;
6306 if (buttons == 2) ;
6307 else { // Rotate
6308 let deltaX = movementX * this.speed;
6309 let deltaY = -movementY * this.speed;
6310 this.vpitch += deltaY;
6311 this.vyaw += deltaX;
6312 }
6313 // OrbitControlSystem.updatePosition(this);
6314 };
6315 this.touchHandler = (() => {
6316 let lastX, lastY;
6317 return (e) => {
6318 let { pageX, pageY } = e.touches[0];
6319 if (lastX || lastY) {
6320 let dX = pageX - lastX;
6321 let dY = pageY - lastY;
6322 this.vpitch += -dY * this.speed;
6323 this.vyaw += dX * this.speed;
6324 }
6325 lastY = pageY;
6326 lastX = pageX;
6327 };
6328 });
6329 this.scrollHandler = ({ deltaY }) => {
6330 // vec3.scaleAndAdd(this.trans.translate, this.trans.translate, this.direction, deltaY);
6331 this.vscale += deltaY * this.speed * 0.01;
6332 // OrbitControlSystem.updatePosition(this);
6333 };
6334 this.orientationHandler = (e) => {
6335 // if (this.ctr_initial_m) {
6336 // const delX = e.gamma - this.ctr.x;
6337 // const delY = e.beta - this.ctr.y;
6338 // vx -= delX * 0.09;
6339 // vy -= delY * 0.09;
6340 // } else {
6341 // this.ctr_initial_m = true;
6342 // }
6343 // this.ctr.x = e.gamma;
6344 // this.ctr.y = e.beta;
6345 if (!this.lastalpha || !this.lastbeta) {
6346 this.lastalpha = e.alpha;
6347 this.lastbeta = e.beta;
6348 }
6349 let dalpha = e.alpha - this.lastalpha;
6350 let dbeta = e.beta - this.lastbeta;
6351 // this.vpitch += dbeta * this.speed;
6352 // this.vyaw += dgamma * this.speed;
6353 this.pitch = this.lastbeta + dbeta * 0.1;
6354 this.yaw = this.lastalpha + dalpha * 0.1;
6355 // this.pitch = e.beta;
6356 // this.yaw = e.alpha;
6357 };
6358 this.pitch = pitch;
6359 this.yaw = yaw;
6360 this.speed = speed;
6361 this.damping = damping;
6362 this.camera = target.components.Camera;
6363 this.trans = target.components.Transform;
6364 this.distance = distance(this.trans.translate, this.camera.lookAt);
6365 // EntityMgr.addComponent(target, this);
6366 // Regist current camera as main camera (backward compatibility)
6367 screen.mainCamera = this.camera;
6368 OrbitControl.bindEvents(screen.canvas, this);
6369 OrbitControlSystem.updatePosition(this);
6370 }
6371 static bindEvents(screen, controler) {
6372 screen.oncontextmenu = () => false;
6373 screen.addEventListener('mousedown', () => {
6374 screen.addEventListener('mousemove', controler.moveHandler);
6375 });
6376 screen.addEventListener('mouseup', () => {
6377 screen.removeEventListener('mousemove', controler.moveHandler);
6378 });
6379 screen.addEventListener('wheel', controler.scrollHandler);
6380 // Mobile device
6381 screen.addEventListener('touchstart', () => {
6382 let handler = controler.touchHandler();
6383 screen.addEventListener('touchmove', handler);
6384 screen.addEventListener('touchend', () => {
6385 screen.removeEventListener('touchmove', handler);
6386 });
6387 });
6388 screen.addEventListener('wheel', controler.scrollHandler);
6389 // try {
6390 // window.addEventListener("deviceorientation", controler.orientationHandler, false);
6391 // } catch (e) {
6392 // console.log(e);
6393 // }
6394 }
6395 }
6396 class OrbitControlSystem extends ComponentSystem {
6397 constructor() {
6398 super(...arguments);
6399 this.group = [];
6400 this.depends = [
6401 OrbitControl.name
6402 ];
6403 }
6404 onUpdate() {
6405 for (let { components } of this.group) {
6406 OrbitControlSystem.updatePosition(components.OrbitControl);
6407 }
6408 }
6409 static updatePosition(ctr) {
6410 if (Math.abs(ctr.vyaw) > ctr.threshold) {
6411 ctr.yaw += ctr.vyaw;
6412 ctr.vyaw *= ctr.damping;
6413 }
6414 if (Math.abs(ctr.vpitch) > ctr.threshold) {
6415 ctr.pitch += ctr.vpitch;
6416 ctr.vpitch *= ctr.damping;
6417 }
6418 if (Math.abs(ctr.vscale) > ctr.threshold) {
6419 ctr.distance += ctr.vscale;
6420 ctr.distance = Math.max(ctr.distance, 1.0);
6421 ctr.vscale *= ctr.damping;
6422 }
6423 ctr.pitch = Math.min(180, Math.max(0.01, ctr.pitch));
6424 // https://github.com/t01y/WebGL_Learning/blob/PBR/scripts/canvas.js#L752
6425 ctr.trans.translate[0] = ctr.camera.lookAt[0] + ctr.distance * Math.sin(ctr.pitch / 180 * Math.PI) * Math.cos(ctr.yaw / 180 * Math.PI);
6426 ctr.trans.translate[1] = ctr.camera.lookAt[1] + ctr.distance * Math.cos(ctr.pitch / 180 * Math.PI);
6427 ctr.trans.translate[2] = ctr.camera.lookAt[2] + ctr.distance * Math.sin(ctr.pitch / 180 * Math.PI) * Math.sin(ctr.yaw / 180 * Math.PI);
6428 ctr.camera.isDirty = true;
6429 // TODO: enhance
6430 TransformSystem.updateMatrix(ctr.trans);
6431 }
6432 }
6433 System.registSystem(new OrbitControlSystem());
6434
6435 // export { Example } from "./example";
6436
6437 exports.Screen = Screen;
6438 exports.Asset = Asset;
6439 exports.EntityMgr = EntityMgr;
6440 exports.ComponentSystem = ComponentSystem;
6441 exports.System = System;
6442 exports.vec3 = vec3;
6443 exports.vec4 = vec4;
6444 exports.mat4 = mat4;
6445 exports.quat = quat;
6446 exports.Texture = Texture;
6447 exports.Mesh = Mesh;
6448 exports.Accessor = Accessor;
6449 exports.bufferView = bufferView;
6450 exports.QuadMesh = QuadMesh;
6451 exports.Filter = Filter;
6452 exports.Shader = Shader;
6453 exports.Uniform = Uniform;
6454 exports.Bloom = Bloom;
6455 exports.Vignetting = Vignetting;
6456 exports.Transform = Transform;
6457 exports.Camera = Camera;
6458 exports.OrbitControl = OrbitControl;
6459 exports.Material = Material;
6460 exports.MeshRenderer = MeshRenderer;
6461 exports.Animation = Animation;
6462 exports.AnimationChannel = AnimationChannel;
6463 exports.Skin = Skin;
6464
6465 Object.defineProperty(exports, '__esModule', { value: true });
6466
6467}));