diff --git a/cg/webgl/index.html b/cg/webgl/index.html
new file mode 100644
index 0000000..c98ce0e
--- /dev/null
+++ b/cg/webgl/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cg/webgl/m4.js b/cg/webgl/m4.js
new file mode 100644
index 0000000..5a628f6
--- /dev/null
+++ b/cg/webgl/m4.js
@@ -0,0 +1,1467 @@
+/*
+ * Copyright 2021 GFXFundamentals.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of GFXFundamentals. nor the names of his
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Various 3d math functions.
+ *
+ * @module webgl-3d-math
+ */
+(function(root, factory) { // eslint-disable-line
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define([], factory);
+ } else {
+ // Browser globals
+ root.m4 = factory();
+ }
+}(this, function() {
+ "use strict";
+
+ /**
+ * An array or typed array with 3 values.
+ * @typedef {number[]|TypedArray} Vector3
+ * @memberOf module:webgl-3d-math
+ */
+
+ /**
+ * An array or typed array with 4 values.
+ * @typedef {number[]|TypedArray} Vector4
+ * @memberOf module:webgl-3d-math
+ */
+
+ /**
+ * An array or typed array with 16 values.
+ * @typedef {number[]|TypedArray} Matrix4
+ * @memberOf module:webgl-3d-math
+ */
+
+
+ let MatType = Float32Array;
+
+ /**
+ * Sets the type this library creates for a Mat4
+ * @param {constructor} Ctor the constructor for the type. Either `Float32Array` or `Array`
+ * @return {constructor} previous constructor for Mat4
+ */
+ function setDefaultType(Ctor) {
+ const OldType = MatType;
+ MatType = Ctor;
+ return OldType;
+ }
+
+ /**
+ * Takes two 4-by-4 matrices, a and b, and computes the product in the order
+ * that pre-composes b with a. In other words, the matrix returned will
+ * transform by b first and then a. Note this is subtly different from just
+ * multiplying the matrices together. For given a and b, this function returns
+ * the same object in both row-major and column-major mode.
+ * @param {Matrix4} a A matrix.
+ * @param {Matrix4} b A matrix.
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ */
+ function multiply(a, b, dst) {
+ dst = dst || new MatType(16);
+ var b00 = b[0 * 4 + 0];
+ var b01 = b[0 * 4 + 1];
+ var b02 = b[0 * 4 + 2];
+ var b03 = b[0 * 4 + 3];
+ var b10 = b[1 * 4 + 0];
+ var b11 = b[1 * 4 + 1];
+ var b12 = b[1 * 4 + 2];
+ var b13 = b[1 * 4 + 3];
+ var b20 = b[2 * 4 + 0];
+ var b21 = b[2 * 4 + 1];
+ var b22 = b[2 * 4 + 2];
+ var b23 = b[2 * 4 + 3];
+ var b30 = b[3 * 4 + 0];
+ var b31 = b[3 * 4 + 1];
+ var b32 = b[3 * 4 + 2];
+ var b33 = b[3 * 4 + 3];
+ var a00 = a[0 * 4 + 0];
+ var a01 = a[0 * 4 + 1];
+ var a02 = a[0 * 4 + 2];
+ var a03 = a[0 * 4 + 3];
+ var a10 = a[1 * 4 + 0];
+ var a11 = a[1 * 4 + 1];
+ var a12 = a[1 * 4 + 2];
+ var a13 = a[1 * 4 + 3];
+ var a20 = a[2 * 4 + 0];
+ var a21 = a[2 * 4 + 1];
+ var a22 = a[2 * 4 + 2];
+ var a23 = a[2 * 4 + 3];
+ var a30 = a[3 * 4 + 0];
+ var a31 = a[3 * 4 + 1];
+ var a32 = a[3 * 4 + 2];
+ var a33 = a[3 * 4 + 3];
+ dst[ 0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30;
+ dst[ 1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31;
+ dst[ 2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32;
+ dst[ 3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33;
+ dst[ 4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30;
+ dst[ 5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31;
+ dst[ 6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32;
+ dst[ 7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33;
+ dst[ 8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30;
+ dst[ 9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31;
+ dst[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32;
+ dst[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33;
+ dst[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30;
+ dst[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31;
+ dst[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32;
+ dst[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33;
+ return dst;
+ }
+
+
+ /**
+ * adds 2 vectors3s
+ * @param {Vector3} a a
+ * @param {Vector3} b b
+ * @param {Vector3} dst optional vector3 to store result
+ * @return {Vector3} dst or new Vector3 if not provided
+ * @memberOf module:webgl-3d-math
+ */
+ function addVectors(a, b, dst) {
+ dst = dst || new MatType(3);
+ dst[0] = a[0] + b[0];
+ dst[1] = a[1] + b[1];
+ dst[2] = a[2] + b[2];
+ return dst;
+ }
+
+ /**
+ * subtracts 2 vectors3s
+ * @param {Vector3} a a
+ * @param {Vector3} b b
+ * @param {Vector3} dst optional vector3 to store result
+ * @return {Vector3} dst or new Vector3 if not provided
+ * @memberOf module:webgl-3d-math
+ */
+ function subtractVectors(a, b, dst) {
+ dst = dst || new MatType(3);
+ dst[0] = a[0] - b[0];
+ dst[1] = a[1] - b[1];
+ dst[2] = a[2] - b[2];
+ return dst;
+ }
+
+ /**
+ * scale vectors3
+ * @param {Vector3} v vector
+ * @param {Number} s scale
+ * @param {Vector3} dst optional vector3 to store result
+ * @return {Vector3} dst or new Vector3 if not provided
+ * @memberOf module:webgl-3d-math
+ */
+ function scaleVector(v, s, dst) {
+ dst = dst || new MatType(3);
+ dst[0] = v[0] * s;
+ dst[1] = v[1] * s;
+ dst[2] = v[2] * s;
+ return dst;
+ }
+
+ /**
+ * normalizes a vector.
+ * @param {Vector3} v vector to normalize
+ * @param {Vector3} dst optional vector3 to store result
+ * @return {Vector3} dst or new Vector3 if not provided
+ * @memberOf module:webgl-3d-math
+ */
+ function normalize(v, dst) {
+ dst = dst || new MatType(3);
+ var length = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+ // make sure we don't divide by 0.
+ if (length > 0.00001) {
+ dst[0] = v[0] / length;
+ dst[1] = v[1] / length;
+ dst[2] = v[2] / length;
+ }
+ return dst;
+ }
+
+ /**
+ * Computes the length of a vector
+ * @param {Vector3} v vector to take length of
+ * @return {number} length of vector
+ */
+ function length(v) {
+ return Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+ }
+
+ /**
+ * Computes the length squared of a vector
+ * @param {Vector3} v vector to take length of
+ * @return {number} length sqaured of vector
+ */
+ function lengthSq(v) {
+ return v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
+ }
+
+ /**
+ * Computes the cross product of 2 vectors3s
+ * @param {Vector3} a a
+ * @param {Vector3} b b
+ * @param {Vector3} dst optional vector3 to store result
+ * @return {Vector3} dst or new Vector3 if not provided
+ * @memberOf module:webgl-3d-math
+ */
+ function cross(a, b, dst) {
+ dst = dst || new MatType(3);
+ dst[0] = a[1] * b[2] - a[2] * b[1];
+ dst[1] = a[2] * b[0] - a[0] * b[2];
+ dst[2] = a[0] * b[1] - a[1] * b[0];
+ return dst;
+ }
+
+ /**
+ * Computes the dot product of two vectors; assumes both vectors have
+ * three entries.
+ * @param {Vector3} a Operand vector.
+ * @param {Vector3} b Operand vector.
+ * @return {number} dot product
+ * @memberOf module:webgl-3d-math
+ */
+ function dot(a, b) {
+ return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
+ }
+
+ /**
+ * Computes the distance squared between 2 points
+ * @param {Vector3} a
+ * @param {Vector3} b
+ * @return {number} distance squared between a and b
+ */
+ function distanceSq(a, b) {
+ const dx = a[0] - b[0];
+ const dy = a[1] - b[1];
+ const dz = a[2] - b[2];
+ return dx * dx + dy * dy + dz * dz;
+ }
+
+ /**
+ * Computes the distance between 2 points
+ * @param {Vector3} a
+ * @param {Vector3} b
+ * @return {number} distance between a and b
+ */
+ function distance(a, b) {
+ return Math.sqrt(distanceSq(a, b));
+ }
+
+ /**
+ * Makes an identity matrix.
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function identity(dst) {
+ dst = dst || new MatType(16);
+
+ dst[ 0] = 1;
+ dst[ 1] = 0;
+ dst[ 2] = 0;
+ dst[ 3] = 0;
+ dst[ 4] = 0;
+ dst[ 5] = 1;
+ dst[ 6] = 0;
+ dst[ 7] = 0;
+ dst[ 8] = 0;
+ dst[ 9] = 0;
+ dst[10] = 1;
+ dst[11] = 0;
+ dst[12] = 0;
+ dst[13] = 0;
+ dst[14] = 0;
+ dst[15] = 1;
+
+ return dst;
+ }
+
+ /**
+ * Transposes a matrix.
+ * @param {Matrix4} m matrix to transpose.
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function transpose(m, dst) {
+ dst = dst || new MatType(16);
+
+ dst[ 0] = m[0];
+ dst[ 1] = m[4];
+ dst[ 2] = m[8];
+ dst[ 3] = m[12];
+ dst[ 4] = m[1];
+ dst[ 5] = m[5];
+ dst[ 6] = m[9];
+ dst[ 7] = m[13];
+ dst[ 8] = m[2];
+ dst[ 9] = m[6];
+ dst[10] = m[10];
+ dst[11] = m[14];
+ dst[12] = m[3];
+ dst[13] = m[7];
+ dst[14] = m[11];
+ dst[15] = m[15];
+
+ return dst;
+ }
+
+ /**
+ * Creates a lookAt matrix.
+ * This is a world matrix for a camera. In other words it will transform
+ * from the origin to a place and orientation in the world. For a view
+ * matrix take the inverse of this.
+ * @param {Vector3} cameraPosition position of the camera
+ * @param {Vector3} target position of the target
+ * @param {Vector3} up direction
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function lookAt(cameraPosition, target, up, dst) {
+ dst = dst || new MatType(16);
+ var zAxis = normalize(
+ subtractVectors(cameraPosition, target));
+ var xAxis = normalize(cross(up, zAxis));
+ var yAxis = normalize(cross(zAxis, xAxis));
+
+ dst[ 0] = xAxis[0];
+ dst[ 1] = xAxis[1];
+ dst[ 2] = xAxis[2];
+ dst[ 3] = 0;
+ dst[ 4] = yAxis[0];
+ dst[ 5] = yAxis[1];
+ dst[ 6] = yAxis[2];
+ dst[ 7] = 0;
+ dst[ 8] = zAxis[0];
+ dst[ 9] = zAxis[1];
+ dst[10] = zAxis[2];
+ dst[11] = 0;
+ dst[12] = cameraPosition[0];
+ dst[13] = cameraPosition[1];
+ dst[14] = cameraPosition[2];
+ dst[15] = 1;
+
+ return dst;
+ }
+
+ /**
+ * Computes a 4-by-4 perspective transformation matrix given the angular height
+ * of the frustum, the aspect ratio, and the near and far clipping planes. The
+ * arguments define a frustum extending in the negative z direction. The given
+ * angle is the vertical angle of the frustum, and the horizontal angle is
+ * determined to produce the given aspect ratio. The arguments near and far are
+ * the distances to the near and far clipping planes. Note that near and far
+ * are not z coordinates, but rather they are distances along the negative
+ * z-axis. The matrix generated sends the viewing frustum to the unit box.
+ * We assume a unit box extending from -1 to 1 in the x and y dimensions and
+ * from -1 to 1 in the z dimension.
+ * @param {number} fieldOfViewInRadians field of view in y axis.
+ * @param {number} aspect aspect of viewport (width / height)
+ * @param {number} near near Z clipping plane
+ * @param {number} far far Z clipping plane
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function perspective(fieldOfViewInRadians, aspect, near, far, dst) {
+ dst = dst || new MatType(16);
+ var f = Math.tan(Math.PI * 0.5 - 0.5 * fieldOfViewInRadians);
+ var rangeInv = 1.0 / (near - far);
+
+ dst[ 0] = f / aspect;
+ dst[ 1] = 0;
+ dst[ 2] = 0;
+ dst[ 3] = 0;
+ dst[ 4] = 0;
+ dst[ 5] = f;
+ dst[ 6] = 0;
+ dst[ 7] = 0;
+ dst[ 8] = 0;
+ dst[ 9] = 0;
+ dst[10] = (near + far) * rangeInv;
+ dst[11] = -1;
+ dst[12] = 0;
+ dst[13] = 0;
+ dst[14] = near * far * rangeInv * 2;
+ dst[15] = 0;
+
+ return dst;
+ }
+
+ /**
+ * Computes a 4-by-4 orthographic projection matrix given the coordinates of the
+ * planes defining the axis-aligned, box-shaped viewing volume. The matrix
+ * generated sends that box to the unit box. Note that although left and right
+ * are x coordinates and bottom and top are y coordinates, near and far
+ * are not z coordinates, but rather they are distances along the negative
+ * z-axis. We assume a unit box extending from -1 to 1 in the x and y
+ * dimensions and from -1 to 1 in the z dimension.
+ * @param {number} left The x coordinate of the left plane of the box.
+ * @param {number} right The x coordinate of the right plane of the box.
+ * @param {number} bottom The y coordinate of the bottom plane of the box.
+ * @param {number} top The y coordinate of the right plane of the box.
+ * @param {number} near The negative z coordinate of the near plane of the box.
+ * @param {number} far The negative z coordinate of the far plane of the box.
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function orthographic(left, right, bottom, top, near, far, dst) {
+ dst = dst || new MatType(16);
+
+ dst[ 0] = 2 / (right - left);
+ dst[ 1] = 0;
+ dst[ 2] = 0;
+ dst[ 3] = 0;
+ dst[ 4] = 0;
+ dst[ 5] = 2 / (top - bottom);
+ dst[ 6] = 0;
+ dst[ 7] = 0;
+ dst[ 8] = 0;
+ dst[ 9] = 0;
+ dst[10] = 2 / (near - far);
+ dst[11] = 0;
+ dst[12] = (left + right) / (left - right);
+ dst[13] = (bottom + top) / (bottom - top);
+ dst[14] = (near + far) / (near - far);
+ dst[15] = 1;
+
+ return dst;
+ }
+
+ /**
+ * Computes a 4-by-4 perspective transformation matrix given the left, right,
+ * top, bottom, near and far clipping planes. The arguments define a frustum
+ * extending in the negative z direction. The arguments near and far are the
+ * distances to the near and far clipping planes. Note that near and far are not
+ * z coordinates, but rather they are distances along the negative z-axis. The
+ * matrix generated sends the viewing frustum to the unit box. We assume a unit
+ * box extending from -1 to 1 in the x and y dimensions and from -1 to 1 in the z
+ * dimension.
+ * @param {number} left The x coordinate of the left plane of the box.
+ * @param {number} right The x coordinate of the right plane of the box.
+ * @param {number} bottom The y coordinate of the bottom plane of the box.
+ * @param {number} top The y coordinate of the right plane of the box.
+ * @param {number} near The negative z coordinate of the near plane of the box.
+ * @param {number} far The negative z coordinate of the far plane of the box.
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function frustum(left, right, bottom, top, near, far, dst) {
+ dst = dst || new MatType(16);
+
+ var dx = right - left;
+ var dy = top - bottom;
+ var dz = far - near;
+
+ dst[ 0] = 2 * near / dx;
+ dst[ 1] = 0;
+ dst[ 2] = 0;
+ dst[ 3] = 0;
+ dst[ 4] = 0;
+ dst[ 5] = 2 * near / dy;
+ dst[ 6] = 0;
+ dst[ 7] = 0;
+ dst[ 8] = (left + right) / dx;
+ dst[ 9] = (top + bottom) / dy;
+ dst[10] = -(far + near) / dz;
+ dst[11] = -1;
+ dst[12] = 0;
+ dst[13] = 0;
+ dst[14] = -2 * near * far / dz;
+ dst[15] = 0;
+
+ return dst;
+ }
+
+ /**
+ * Makes a translation matrix
+ * @param {number} tx x translation.
+ * @param {number} ty y translation.
+ * @param {number} tz z translation.
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function translation(tx, ty, tz, dst) {
+ dst = dst || new MatType(16);
+
+ dst[ 0] = 1;
+ dst[ 1] = 0;
+ dst[ 2] = 0;
+ dst[ 3] = 0;
+ dst[ 4] = 0;
+ dst[ 5] = 1;
+ dst[ 6] = 0;
+ dst[ 7] = 0;
+ dst[ 8] = 0;
+ dst[ 9] = 0;
+ dst[10] = 1;
+ dst[11] = 0;
+ dst[12] = tx;
+ dst[13] = ty;
+ dst[14] = tz;
+ dst[15] = 1;
+
+ return dst;
+ }
+
+ /**
+ * Multiply by translation matrix.
+ * @param {Matrix4} m matrix to multiply
+ * @param {number} tx x translation.
+ * @param {number} ty y translation.
+ * @param {number} tz z translation.
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function translate(m, tx, ty, tz, dst) {
+ // This is the optimized version of
+ // return multiply(m, translation(tx, ty, tz), dst);
+ dst = dst || new MatType(16);
+
+ var m00 = m[0];
+ var m01 = m[1];
+ var m02 = m[2];
+ var m03 = m[3];
+ var m10 = m[1 * 4 + 0];
+ var m11 = m[1 * 4 + 1];
+ var m12 = m[1 * 4 + 2];
+ var m13 = m[1 * 4 + 3];
+ var m20 = m[2 * 4 + 0];
+ var m21 = m[2 * 4 + 1];
+ var m22 = m[2 * 4 + 2];
+ var m23 = m[2 * 4 + 3];
+ var m30 = m[3 * 4 + 0];
+ var m31 = m[3 * 4 + 1];
+ var m32 = m[3 * 4 + 2];
+ var m33 = m[3 * 4 + 3];
+
+ if (m !== dst) {
+ dst[ 0] = m00;
+ dst[ 1] = m01;
+ dst[ 2] = m02;
+ dst[ 3] = m03;
+ dst[ 4] = m10;
+ dst[ 5] = m11;
+ dst[ 6] = m12;
+ dst[ 7] = m13;
+ dst[ 8] = m20;
+ dst[ 9] = m21;
+ dst[10] = m22;
+ dst[11] = m23;
+ }
+
+ dst[12] = m00 * tx + m10 * ty + m20 * tz + m30;
+ dst[13] = m01 * tx + m11 * ty + m21 * tz + m31;
+ dst[14] = m02 * tx + m12 * ty + m22 * tz + m32;
+ dst[15] = m03 * tx + m13 * ty + m23 * tz + m33;
+
+ return dst;
+ }
+
+ /**
+ * Makes an x rotation matrix
+ * @param {number} angleInRadians amount to rotate
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function xRotation(angleInRadians, dst) {
+ dst = dst || new MatType(16);
+ var c = Math.cos(angleInRadians);
+ var s = Math.sin(angleInRadians);
+
+ dst[ 0] = 1;
+ dst[ 1] = 0;
+ dst[ 2] = 0;
+ dst[ 3] = 0;
+ dst[ 4] = 0;
+ dst[ 5] = c;
+ dst[ 6] = s;
+ dst[ 7] = 0;
+ dst[ 8] = 0;
+ dst[ 9] = -s;
+ dst[10] = c;
+ dst[11] = 0;
+ dst[12] = 0;
+ dst[13] = 0;
+ dst[14] = 0;
+ dst[15] = 1;
+
+ return dst;
+ }
+
+ /**
+ * Multiply by an x rotation matrix
+ * @param {Matrix4} m matrix to multiply
+ * @param {number} angleInRadians amount to rotate
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function xRotate(m, angleInRadians, dst) {
+ // this is the optimized version of
+ // return multiply(m, xRotation(angleInRadians), dst);
+ dst = dst || new MatType(16);
+
+ var m10 = m[4];
+ var m11 = m[5];
+ var m12 = m[6];
+ var m13 = m[7];
+ var m20 = m[8];
+ var m21 = m[9];
+ var m22 = m[10];
+ var m23 = m[11];
+ var c = Math.cos(angleInRadians);
+ var s = Math.sin(angleInRadians);
+
+ dst[4] = c * m10 + s * m20;
+ dst[5] = c * m11 + s * m21;
+ dst[6] = c * m12 + s * m22;
+ dst[7] = c * m13 + s * m23;
+ dst[8] = c * m20 - s * m10;
+ dst[9] = c * m21 - s * m11;
+ dst[10] = c * m22 - s * m12;
+ dst[11] = c * m23 - s * m13;
+
+ if (m !== dst) {
+ dst[ 0] = m[ 0];
+ dst[ 1] = m[ 1];
+ dst[ 2] = m[ 2];
+ dst[ 3] = m[ 3];
+ dst[12] = m[12];
+ dst[13] = m[13];
+ dst[14] = m[14];
+ dst[15] = m[15];
+ }
+
+ return dst;
+ }
+
+ /**
+ * Makes an y rotation matrix
+ * @param {number} angleInRadians amount to rotate
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function yRotation(angleInRadians, dst) {
+ dst = dst || new MatType(16);
+ var c = Math.cos(angleInRadians);
+ var s = Math.sin(angleInRadians);
+
+ dst[ 0] = c;
+ dst[ 1] = 0;
+ dst[ 2] = -s;
+ dst[ 3] = 0;
+ dst[ 4] = 0;
+ dst[ 5] = 1;
+ dst[ 6] = 0;
+ dst[ 7] = 0;
+ dst[ 8] = s;
+ dst[ 9] = 0;
+ dst[10] = c;
+ dst[11] = 0;
+ dst[12] = 0;
+ dst[13] = 0;
+ dst[14] = 0;
+ dst[15] = 1;
+
+ return dst;
+ }
+
+ /**
+ * Multiply by an y rotation matrix
+ * @param {Matrix4} m matrix to multiply
+ * @param {number} angleInRadians amount to rotate
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function yRotate(m, angleInRadians, dst) {
+ // this is the optimized version of
+ // return multiply(m, yRotation(angleInRadians), dst);
+ dst = dst || new MatType(16);
+
+ var m00 = m[0 * 4 + 0];
+ var m01 = m[0 * 4 + 1];
+ var m02 = m[0 * 4 + 2];
+ var m03 = m[0 * 4 + 3];
+ var m20 = m[2 * 4 + 0];
+ var m21 = m[2 * 4 + 1];
+ var m22 = m[2 * 4 + 2];
+ var m23 = m[2 * 4 + 3];
+ var c = Math.cos(angleInRadians);
+ var s = Math.sin(angleInRadians);
+
+ dst[ 0] = c * m00 - s * m20;
+ dst[ 1] = c * m01 - s * m21;
+ dst[ 2] = c * m02 - s * m22;
+ dst[ 3] = c * m03 - s * m23;
+ dst[ 8] = c * m20 + s * m00;
+ dst[ 9] = c * m21 + s * m01;
+ dst[10] = c * m22 + s * m02;
+ dst[11] = c * m23 + s * m03;
+
+ if (m !== dst) {
+ dst[ 4] = m[ 4];
+ dst[ 5] = m[ 5];
+ dst[ 6] = m[ 6];
+ dst[ 7] = m[ 7];
+ dst[12] = m[12];
+ dst[13] = m[13];
+ dst[14] = m[14];
+ dst[15] = m[15];
+ }
+
+ return dst;
+ }
+
+ /**
+ * Makes an z rotation matrix
+ * @param {number} angleInRadians amount to rotate
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function zRotation(angleInRadians, dst) {
+ dst = dst || new MatType(16);
+ var c = Math.cos(angleInRadians);
+ var s = Math.sin(angleInRadians);
+
+ dst[ 0] = c;
+ dst[ 1] = s;
+ dst[ 2] = 0;
+ dst[ 3] = 0;
+ dst[ 4] = -s;
+ dst[ 5] = c;
+ dst[ 6] = 0;
+ dst[ 7] = 0;
+ dst[ 8] = 0;
+ dst[ 9] = 0;
+ dst[10] = 1;
+ dst[11] = 0;
+ dst[12] = 0;
+ dst[13] = 0;
+ dst[14] = 0;
+ dst[15] = 1;
+
+ return dst;
+ }
+
+ /**
+ * Multiply by an z rotation matrix
+ * @param {Matrix4} m matrix to multiply
+ * @param {number} angleInRadians amount to rotate
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function zRotate(m, angleInRadians, dst) {
+ // This is the optimized version of
+ // return multiply(m, zRotation(angleInRadians), dst);
+ dst = dst || new MatType(16);
+
+ var m00 = m[0 * 4 + 0];
+ var m01 = m[0 * 4 + 1];
+ var m02 = m[0 * 4 + 2];
+ var m03 = m[0 * 4 + 3];
+ var m10 = m[1 * 4 + 0];
+ var m11 = m[1 * 4 + 1];
+ var m12 = m[1 * 4 + 2];
+ var m13 = m[1 * 4 + 3];
+ var c = Math.cos(angleInRadians);
+ var s = Math.sin(angleInRadians);
+
+ dst[ 0] = c * m00 + s * m10;
+ dst[ 1] = c * m01 + s * m11;
+ dst[ 2] = c * m02 + s * m12;
+ dst[ 3] = c * m03 + s * m13;
+ dst[ 4] = c * m10 - s * m00;
+ dst[ 5] = c * m11 - s * m01;
+ dst[ 6] = c * m12 - s * m02;
+ dst[ 7] = c * m13 - s * m03;
+
+ if (m !== dst) {
+ dst[ 8] = m[ 8];
+ dst[ 9] = m[ 9];
+ dst[10] = m[10];
+ dst[11] = m[11];
+ dst[12] = m[12];
+ dst[13] = m[13];
+ dst[14] = m[14];
+ dst[15] = m[15];
+ }
+
+ return dst;
+ }
+
+ /**
+ * Makes an rotation matrix around an arbitrary axis
+ * @param {Vector3} axis axis to rotate around
+ * @param {number} angleInRadians amount to rotate
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function axisRotation(axis, angleInRadians, dst) {
+ dst = dst || new MatType(16);
+
+ var x = axis[0];
+ var y = axis[1];
+ var z = axis[2];
+ var n = Math.sqrt(x * x + y * y + z * z);
+ x /= n;
+ y /= n;
+ z /= n;
+ var xx = x * x;
+ var yy = y * y;
+ var zz = z * z;
+ var c = Math.cos(angleInRadians);
+ var s = Math.sin(angleInRadians);
+ var oneMinusCosine = 1 - c;
+
+ dst[ 0] = xx + (1 - xx) * c;
+ dst[ 1] = x * y * oneMinusCosine + z * s;
+ dst[ 2] = x * z * oneMinusCosine - y * s;
+ dst[ 3] = 0;
+ dst[ 4] = x * y * oneMinusCosine - z * s;
+ dst[ 5] = yy + (1 - yy) * c;
+ dst[ 6] = y * z * oneMinusCosine + x * s;
+ dst[ 7] = 0;
+ dst[ 8] = x * z * oneMinusCosine + y * s;
+ dst[ 9] = y * z * oneMinusCosine - x * s;
+ dst[10] = zz + (1 - zz) * c;
+ dst[11] = 0;
+ dst[12] = 0;
+ dst[13] = 0;
+ dst[14] = 0;
+ dst[15] = 1;
+
+ return dst;
+ }
+
+ /**
+ * Multiply by an axis rotation matrix
+ * @param {Matrix4} m matrix to multiply
+ * @param {Vector3} axis axis to rotate around
+ * @param {number} angleInRadians amount to rotate
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function axisRotate(m, axis, angleInRadians, dst) {
+ // This is the optimized version of
+ // return multiply(m, axisRotation(axis, angleInRadians), dst);
+ dst = dst || new MatType(16);
+
+ var x = axis[0];
+ var y = axis[1];
+ var z = axis[2];
+ var n = Math.sqrt(x * x + y * y + z * z);
+ x /= n;
+ y /= n;
+ z /= n;
+ var xx = x * x;
+ var yy = y * y;
+ var zz = z * z;
+ var c = Math.cos(angleInRadians);
+ var s = Math.sin(angleInRadians);
+ var oneMinusCosine = 1 - c;
+
+ var r00 = xx + (1 - xx) * c;
+ var r01 = x * y * oneMinusCosine + z * s;
+ var r02 = x * z * oneMinusCosine - y * s;
+ var r10 = x * y * oneMinusCosine - z * s;
+ var r11 = yy + (1 - yy) * c;
+ var r12 = y * z * oneMinusCosine + x * s;
+ var r20 = x * z * oneMinusCosine + y * s;
+ var r21 = y * z * oneMinusCosine - x * s;
+ var r22 = zz + (1 - zz) * c;
+
+ var m00 = m[0];
+ var m01 = m[1];
+ var m02 = m[2];
+ var m03 = m[3];
+ var m10 = m[4];
+ var m11 = m[5];
+ var m12 = m[6];
+ var m13 = m[7];
+ var m20 = m[8];
+ var m21 = m[9];
+ var m22 = m[10];
+ var m23 = m[11];
+
+ dst[ 0] = r00 * m00 + r01 * m10 + r02 * m20;
+ dst[ 1] = r00 * m01 + r01 * m11 + r02 * m21;
+ dst[ 2] = r00 * m02 + r01 * m12 + r02 * m22;
+ dst[ 3] = r00 * m03 + r01 * m13 + r02 * m23;
+ dst[ 4] = r10 * m00 + r11 * m10 + r12 * m20;
+ dst[ 5] = r10 * m01 + r11 * m11 + r12 * m21;
+ dst[ 6] = r10 * m02 + r11 * m12 + r12 * m22;
+ dst[ 7] = r10 * m03 + r11 * m13 + r12 * m23;
+ dst[ 8] = r20 * m00 + r21 * m10 + r22 * m20;
+ dst[ 9] = r20 * m01 + r21 * m11 + r22 * m21;
+ dst[10] = r20 * m02 + r21 * m12 + r22 * m22;
+ dst[11] = r20 * m03 + r21 * m13 + r22 * m23;
+
+ if (m !== dst) {
+ dst[12] = m[12];
+ dst[13] = m[13];
+ dst[14] = m[14];
+ dst[15] = m[15];
+ }
+
+ return dst;
+ }
+
+ /**
+ * Makes a scale matrix
+ * @param {number} sx x scale.
+ * @param {number} sy y scale.
+ * @param {number} sz z scale.
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function scaling(sx, sy, sz, dst) {
+ dst = dst || new MatType(16);
+
+ dst[ 0] = sx;
+ dst[ 1] = 0;
+ dst[ 2] = 0;
+ dst[ 3] = 0;
+ dst[ 4] = 0;
+ dst[ 5] = sy;
+ dst[ 6] = 0;
+ dst[ 7] = 0;
+ dst[ 8] = 0;
+ dst[ 9] = 0;
+ dst[10] = sz;
+ dst[11] = 0;
+ dst[12] = 0;
+ dst[13] = 0;
+ dst[14] = 0;
+ dst[15] = 1;
+
+ return dst;
+ }
+
+ /**
+ * Multiply by a scaling matrix
+ * @param {Matrix4} m matrix to multiply
+ * @param {number} sx x scale.
+ * @param {number} sy y scale.
+ * @param {number} sz z scale.
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function scale(m, sx, sy, sz, dst) {
+ // This is the optimized version of
+ // return multiply(m, scaling(sx, sy, sz), dst);
+ dst = dst || new MatType(16);
+
+ dst[ 0] = sx * m[0 * 4 + 0];
+ dst[ 1] = sx * m[0 * 4 + 1];
+ dst[ 2] = sx * m[0 * 4 + 2];
+ dst[ 3] = sx * m[0 * 4 + 3];
+ dst[ 4] = sy * m[1 * 4 + 0];
+ dst[ 5] = sy * m[1 * 4 + 1];
+ dst[ 6] = sy * m[1 * 4 + 2];
+ dst[ 7] = sy * m[1 * 4 + 3];
+ dst[ 8] = sz * m[2 * 4 + 0];
+ dst[ 9] = sz * m[2 * 4 + 1];
+ dst[10] = sz * m[2 * 4 + 2];
+ dst[11] = sz * m[2 * 4 + 3];
+
+ if (m !== dst) {
+ dst[12] = m[12];
+ dst[13] = m[13];
+ dst[14] = m[14];
+ dst[15] = m[15];
+ }
+
+ return dst;
+ }
+
+ /**
+ * creates a matrix from translation, quaternion, scale
+ * @param {Number[]} translation [x, y, z] translation
+ * @param {Number[]} quaternion [x, y, z, z] quaternion rotation
+ * @param {Number[]} scale [x, y, z] scale
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ */
+ function compose(translation, quaternion, scale, dst) {
+ dst = dst || new MatType(16);
+
+ const x = quaternion[0];
+ const y = quaternion[1];
+ const z = quaternion[2];
+ const w = quaternion[3];
+
+ const x2 = x + x;
+ const y2 = y + y;
+ const z2 = z + z;
+
+ const xx = x * x2;
+ const xy = x * y2;
+ const xz = x * z2;
+
+ const yy = y * y2;
+ const yz = y * z2;
+ const zz = z * z2;
+
+ const wx = w * x2;
+ const wy = w * y2;
+ const wz = w * z2;
+
+ const sx = scale[0];
+ const sy = scale[1];
+ const sz = scale[2];
+
+ dst[0] = (1 - (yy + zz)) * sx;
+ dst[1] = (xy + wz) * sx;
+ dst[2] = (xz - wy) * sx;
+ dst[3] = 0;
+
+ dst[4] = (xy - wz) * sy;
+ dst[5] = (1 - (xx + zz)) * sy;
+ dst[6] = (yz + wx) * sy;
+ dst[7] = 0;
+
+ dst[ 8] = (xz + wy) * sz;
+ dst[ 9] = (yz - wx) * sz;
+ dst[10] = (1 - (xx + yy)) * sz;
+ dst[11] = 0;
+
+ dst[12] = translation[0];
+ dst[13] = translation[1];
+ dst[14] = translation[2];
+ dst[15] = 1;
+
+ return dst;
+ }
+
+ function quatFromRotationMatrix(m, dst) {
+ // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
+
+ // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
+ const m11 = m[0];
+ const m12 = m[4];
+ const m13 = m[8];
+ const m21 = m[1];
+ const m22 = m[5];
+ const m23 = m[9];
+ const m31 = m[2];
+ const m32 = m[6];
+ const m33 = m[10];
+
+ const trace = m11 + m22 + m33;
+
+ if (trace > 0) {
+ const s = 0.5 / Math.sqrt(trace + 1);
+ dst[3] = 0.25 / s;
+ dst[0] = (m32 - m23) * s;
+ dst[1] = (m13 - m31) * s;
+ dst[2] = (m21 - m12) * s;
+ } else if (m11 > m22 && m11 > m33) {
+ const s = 2 * Math.sqrt(1 + m11 - m22 - m33);
+ dst[3] = (m32 - m23) / s;
+ dst[0] = 0.25 * s;
+ dst[1] = (m12 + m21) / s;
+ dst[2] = (m13 + m31) / s;
+ } else if (m22 > m33) {
+ const s = 2 * Math.sqrt(1 + m22 - m11 - m33);
+ dst[3] = (m13 - m31) / s;
+ dst[0] = (m12 + m21) / s;
+ dst[1] = 0.25 * s;
+ dst[2] = (m23 + m32) / s;
+ } else {
+ const s = 2 * Math.sqrt(1 + m33 - m11 - m22);
+ dst[3] = (m21 - m12) / s;
+ dst[0] = (m13 + m31) / s;
+ dst[1] = (m23 + m32) / s;
+ dst[2] = 0.25 * s;
+ }
+ }
+
+ function decompose(mat, translation, quaternion, scale) {
+ let sx = m4.length(mat.slice(0, 3));
+ const sy = m4.length(mat.slice(4, 7));
+ const sz = m4.length(mat.slice(8, 11));
+
+ // if determinate is negative, we need to invert one scale
+ const det = determinate(mat);
+ if (det < 0) {
+ sx = -sx;
+ }
+
+ translation[0] = mat[12];
+ translation[1] = mat[13];
+ translation[2] = mat[14];
+
+ // scale the rotation part
+ const matrix = m4.copy(mat);
+
+ const invSX = 1 / sx;
+ const invSY = 1 / sy;
+ const invSZ = 1 / sz;
+
+ matrix[0] *= invSX;
+ matrix[1] *= invSX;
+ matrix[2] *= invSX;
+
+ matrix[4] *= invSY;
+ matrix[5] *= invSY;
+ matrix[6] *= invSY;
+
+ matrix[8] *= invSZ;
+ matrix[9] *= invSZ;
+ matrix[10] *= invSZ;
+
+ quatFromRotationMatrix(matrix, quaternion);
+
+ scale[0] = sx;
+ scale[1] = sy;
+ scale[2] = sz;
+ }
+
+ function determinate(m) {
+ var m00 = m[0 * 4 + 0];
+ var m01 = m[0 * 4 + 1];
+ var m02 = m[0 * 4 + 2];
+ var m03 = m[0 * 4 + 3];
+ var m10 = m[1 * 4 + 0];
+ var m11 = m[1 * 4 + 1];
+ var m12 = m[1 * 4 + 2];
+ var m13 = m[1 * 4 + 3];
+ var m20 = m[2 * 4 + 0];
+ var m21 = m[2 * 4 + 1];
+ var m22 = m[2 * 4 + 2];
+ var m23 = m[2 * 4 + 3];
+ var m30 = m[3 * 4 + 0];
+ var m31 = m[3 * 4 + 1];
+ var m32 = m[3 * 4 + 2];
+ var m33 = m[3 * 4 + 3];
+ var tmp_0 = m22 * m33;
+ var tmp_1 = m32 * m23;
+ var tmp_2 = m12 * m33;
+ var tmp_3 = m32 * m13;
+ var tmp_4 = m12 * m23;
+ var tmp_5 = m22 * m13;
+ var tmp_6 = m02 * m33;
+ var tmp_7 = m32 * m03;
+ var tmp_8 = m02 * m23;
+ var tmp_9 = m22 * m03;
+ var tmp_10 = m02 * m13;
+ var tmp_11 = m12 * m03;
+
+ var t0 = (tmp_0 * m11 + tmp_3 * m21 + tmp_4 * m31) -
+ (tmp_1 * m11 + tmp_2 * m21 + tmp_5 * m31);
+ var t1 = (tmp_1 * m01 + tmp_6 * m21 + tmp_9 * m31) -
+ (tmp_0 * m01 + tmp_7 * m21 + tmp_8 * m31);
+ var t2 = (tmp_2 * m01 + tmp_7 * m11 + tmp_10 * m31) -
+ (tmp_3 * m01 + tmp_6 * m11 + tmp_11 * m31);
+ var t3 = (tmp_5 * m01 + tmp_8 * m11 + tmp_11 * m21) -
+ (tmp_4 * m01 + tmp_9 * m11 + tmp_10 * m21);
+
+ return 1.0 / (m00 * t0 + m10 * t1 + m20 * t2 + m30 * t3);
+ }
+
+ /**
+ * Computes the inverse of a matrix.
+ * @param {Matrix4} m matrix to compute inverse of
+ * @param {Matrix4} [dst] optional matrix to store result
+ * @return {Matrix4} dst or a new matrix if none provided
+ * @memberOf module:webgl-3d-math
+ */
+ function inverse(m, dst) {
+ dst = dst || new MatType(16);
+ var m00 = m[0 * 4 + 0];
+ var m01 = m[0 * 4 + 1];
+ var m02 = m[0 * 4 + 2];
+ var m03 = m[0 * 4 + 3];
+ var m10 = m[1 * 4 + 0];
+ var m11 = m[1 * 4 + 1];
+ var m12 = m[1 * 4 + 2];
+ var m13 = m[1 * 4 + 3];
+ var m20 = m[2 * 4 + 0];
+ var m21 = m[2 * 4 + 1];
+ var m22 = m[2 * 4 + 2];
+ var m23 = m[2 * 4 + 3];
+ var m30 = m[3 * 4 + 0];
+ var m31 = m[3 * 4 + 1];
+ var m32 = m[3 * 4 + 2];
+ var m33 = m[3 * 4 + 3];
+ var tmp_0 = m22 * m33;
+ var tmp_1 = m32 * m23;
+ var tmp_2 = m12 * m33;
+ var tmp_3 = m32 * m13;
+ var tmp_4 = m12 * m23;
+ var tmp_5 = m22 * m13;
+ var tmp_6 = m02 * m33;
+ var tmp_7 = m32 * m03;
+ var tmp_8 = m02 * m23;
+ var tmp_9 = m22 * m03;
+ var tmp_10 = m02 * m13;
+ var tmp_11 = m12 * m03;
+ var tmp_12 = m20 * m31;
+ var tmp_13 = m30 * m21;
+ var tmp_14 = m10 * m31;
+ var tmp_15 = m30 * m11;
+ var tmp_16 = m10 * m21;
+ var tmp_17 = m20 * m11;
+ var tmp_18 = m00 * m31;
+ var tmp_19 = m30 * m01;
+ var tmp_20 = m00 * m21;
+ var tmp_21 = m20 * m01;
+ var tmp_22 = m00 * m11;
+ var tmp_23 = m10 * m01;
+
+ var t0 = (tmp_0 * m11 + tmp_3 * m21 + tmp_4 * m31) -
+ (tmp_1 * m11 + tmp_2 * m21 + tmp_5 * m31);
+ var t1 = (tmp_1 * m01 + tmp_6 * m21 + tmp_9 * m31) -
+ (tmp_0 * m01 + tmp_7 * m21 + tmp_8 * m31);
+ var t2 = (tmp_2 * m01 + tmp_7 * m11 + tmp_10 * m31) -
+ (tmp_3 * m01 + tmp_6 * m11 + tmp_11 * m31);
+ var t3 = (tmp_5 * m01 + tmp_8 * m11 + tmp_11 * m21) -
+ (tmp_4 * m01 + tmp_9 * m11 + tmp_10 * m21);
+
+ var d = 1.0 / (m00 * t0 + m10 * t1 + m20 * t2 + m30 * t3);
+
+ dst[0] = d * t0;
+ dst[1] = d * t1;
+ dst[2] = d * t2;
+ dst[3] = d * t3;
+ dst[4] = d * ((tmp_1 * m10 + tmp_2 * m20 + tmp_5 * m30) -
+ (tmp_0 * m10 + tmp_3 * m20 + tmp_4 * m30));
+ dst[5] = d * ((tmp_0 * m00 + tmp_7 * m20 + tmp_8 * m30) -
+ (tmp_1 * m00 + tmp_6 * m20 + tmp_9 * m30));
+ dst[6] = d * ((tmp_3 * m00 + tmp_6 * m10 + tmp_11 * m30) -
+ (tmp_2 * m00 + tmp_7 * m10 + tmp_10 * m30));
+ dst[7] = d * ((tmp_4 * m00 + tmp_9 * m10 + tmp_10 * m20) -
+ (tmp_5 * m00 + tmp_8 * m10 + tmp_11 * m20));
+ dst[8] = d * ((tmp_12 * m13 + tmp_15 * m23 + tmp_16 * m33) -
+ (tmp_13 * m13 + tmp_14 * m23 + tmp_17 * m33));
+ dst[9] = d * ((tmp_13 * m03 + tmp_18 * m23 + tmp_21 * m33) -
+ (tmp_12 * m03 + tmp_19 * m23 + tmp_20 * m33));
+ dst[10] = d * ((tmp_14 * m03 + tmp_19 * m13 + tmp_22 * m33) -
+ (tmp_15 * m03 + tmp_18 * m13 + tmp_23 * m33));
+ dst[11] = d * ((tmp_17 * m03 + tmp_20 * m13 + tmp_23 * m23) -
+ (tmp_16 * m03 + tmp_21 * m13 + tmp_22 * m23));
+ dst[12] = d * ((tmp_14 * m22 + tmp_17 * m32 + tmp_13 * m12) -
+ (tmp_16 * m32 + tmp_12 * m12 + tmp_15 * m22));
+ dst[13] = d * ((tmp_20 * m32 + tmp_12 * m02 + tmp_19 * m22) -
+ (tmp_18 * m22 + tmp_21 * m32 + tmp_13 * m02));
+ dst[14] = d * ((tmp_18 * m12 + tmp_23 * m32 + tmp_15 * m02) -
+ (tmp_22 * m32 + tmp_14 * m02 + tmp_19 * m12));
+ dst[15] = d * ((tmp_22 * m22 + tmp_16 * m02 + tmp_21 * m12) -
+ (tmp_20 * m12 + tmp_23 * m22 + tmp_17 * m02));
+
+ return dst;
+ }
+
+ /**
+ * Takes a matrix and a vector with 4 entries, transforms that vector by
+ * the matrix, and returns the result as a vector with 4 entries.
+ * @param {Matrix4} m The matrix.
+ * @param {Vector4} v The point in homogenous coordinates.
+ * @param {Vector4} dst optional vector4 to store result
+ * @return {Vector4} dst or new Vector4 if not provided
+ * @memberOf module:webgl-3d-math
+ */
+ function transformVector(m, v, dst) {
+ dst = dst || new MatType(4);
+ for (var i = 0; i < 4; ++i) {
+ dst[i] = 0.0;
+ for (var j = 0; j < 4; ++j) {
+ dst[i] += v[j] * m[j * 4 + i];
+ }
+ }
+ return dst;
+ }
+
+ /**
+ * Takes a 4-by-4 matrix and a vector with 3 entries,
+ * interprets the vector as a point, transforms that point by the matrix, and
+ * returns the result as a vector with 3 entries.
+ * @param {Matrix4} m The matrix.
+ * @param {Vector3} v The point.
+ * @param {Vector4} dst optional vector4 to store result
+ * @return {Vector4} dst or new Vector4 if not provided
+ * @memberOf module:webgl-3d-math
+ */
+ function transformPoint(m, v, dst) {
+ dst = dst || new MatType(3);
+ var v0 = v[0];
+ var v1 = v[1];
+ var v2 = v[2];
+ var d = v0 * m[0 * 4 + 3] + v1 * m[1 * 4 + 3] + v2 * m[2 * 4 + 3] + m[3 * 4 + 3];
+
+ dst[0] = (v0 * m[0 * 4 + 0] + v1 * m[1 * 4 + 0] + v2 * m[2 * 4 + 0] + m[3 * 4 + 0]) / d;
+ dst[1] = (v0 * m[0 * 4 + 1] + v1 * m[1 * 4 + 1] + v2 * m[2 * 4 + 1] + m[3 * 4 + 1]) / d;
+ dst[2] = (v0 * m[0 * 4 + 2] + v1 * m[1 * 4 + 2] + v2 * m[2 * 4 + 2] + m[3 * 4 + 2]) / d;
+
+ return dst;
+ }
+
+ /**
+ * Takes a 4-by-4 matrix and a vector with 3 entries, interprets the vector as a
+ * direction, transforms that direction by the matrix, and returns the result;
+ * assumes the transformation of 3-dimensional space represented by the matrix
+ * is parallel-preserving, i.e. any combination of rotation, scaling and
+ * translation, but not a perspective distortion. Returns a vector with 3
+ * entries.
+ * @param {Matrix4} m The matrix.
+ * @param {Vector3} v The direction.
+ * @param {Vector4} dst optional vector4 to store result
+ * @return {Vector4} dst or new Vector4 if not provided
+ * @memberOf module:webgl-3d-math
+ */
+ function transformDirection(m, v, dst) {
+ dst = dst || new MatType(3);
+
+ var v0 = v[0];
+ var v1 = v[1];
+ var v2 = v[2];
+
+ dst[0] = v0 * m[0 * 4 + 0] + v1 * m[1 * 4 + 0] + v2 * m[2 * 4 + 0];
+ dst[1] = v0 * m[0 * 4 + 1] + v1 * m[1 * 4 + 1] + v2 * m[2 * 4 + 1];
+ dst[2] = v0 * m[0 * 4 + 2] + v1 * m[1 * 4 + 2] + v2 * m[2 * 4 + 2];
+
+ return dst;
+ }
+
+ /**
+ * Takes a 4-by-4 matrix m and a vector v with 3 entries, interprets the vector
+ * as a normal to a surface, and computes a vector which is normal upon
+ * transforming that surface by the matrix. The effect of this function is the
+ * same as transforming v (as a direction) by the inverse-transpose of m. This
+ * function assumes the transformation of 3-dimensional space represented by the
+ * matrix is parallel-preserving, i.e. any combination of rotation, scaling and
+ * translation, but not a perspective distortion. Returns a vector with 3
+ * entries.
+ * @param {Matrix4} m The matrix.
+ * @param {Vector3} v The normal.
+ * @param {Vector3} [dst] The direction.
+ * @return {Vector3} The transformed direction.
+ * @memberOf module:webgl-3d-math
+ */
+ function transformNormal(m, v, dst) {
+ dst = dst || new MatType(3);
+ var mi = inverse(m);
+ var v0 = v[0];
+ var v1 = v[1];
+ var v2 = v[2];
+
+ dst[0] = v0 * mi[0 * 4 + 0] + v1 * mi[0 * 4 + 1] + v2 * mi[0 * 4 + 2];
+ dst[1] = v0 * mi[1 * 4 + 0] + v1 * mi[1 * 4 + 1] + v2 * mi[1 * 4 + 2];
+ dst[2] = v0 * mi[2 * 4 + 0] + v1 * mi[2 * 4 + 1] + v2 * mi[2 * 4 + 2];
+
+ return dst;
+ }
+
+ function copy(src, dst) {
+ dst = dst || new MatType(16);
+
+ dst[ 0] = src[ 0];
+ dst[ 1] = src[ 1];
+ dst[ 2] = src[ 2];
+ dst[ 3] = src[ 3];
+ dst[ 4] = src[ 4];
+ dst[ 5] = src[ 5];
+ dst[ 6] = src[ 6];
+ dst[ 7] = src[ 7];
+ dst[ 8] = src[ 8];
+ dst[ 9] = src[ 9];
+ dst[10] = src[10];
+ dst[11] = src[11];
+ dst[12] = src[12];
+ dst[13] = src[13];
+ dst[14] = src[14];
+ dst[15] = src[15];
+
+ return dst;
+ }
+
+ return {
+ copy: copy,
+ lookAt: lookAt,
+ addVectors: addVectors,
+ subtractVectors: subtractVectors,
+ scaleVector: scaleVector,
+ distance: distance,
+ distanceSq: distanceSq,
+ normalize: normalize,
+ compose: compose,
+ cross: cross,
+ decompose: decompose,
+ dot: dot,
+ identity: identity,
+ transpose: transpose,
+ length: length,
+ lengthSq: lengthSq,
+ orthographic: orthographic,
+ frustum: frustum,
+ perspective: perspective,
+ translation: translation,
+ translate: translate,
+ xRotation: xRotation,
+ yRotation: yRotation,
+ zRotation: zRotation,
+ xRotate: xRotate,
+ yRotate: yRotate,
+ zRotate: zRotate,
+ axisRotation: axisRotation,
+ axisRotate: axisRotate,
+ scaling: scaling,
+ scale: scale,
+ multiply: multiply,
+ inverse: inverse,
+ transformVector: transformVector,
+ transformPoint: transformPoint,
+ transformDirection: transformDirection,
+ transformNormal: transformNormal,
+ setDefaultType: setDefaultType,
+ };
+
+}));
+
+
diff --git a/cg/webgl/webgl.js b/cg/webgl/webgl.js
new file mode 100644
index 0000000..be5a222
--- /dev/null
+++ b/cg/webgl/webgl.js
@@ -0,0 +1,323 @@
+"use strict";
+
+const v3 = {
+ add: function (v1, v2) {
+ return [v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]];
+ },
+ normalize: function (v) {
+ return v3.scale(v, 1 / v3.norm(v));
+ },
+ norm: function (v) {
+ return Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2) + Math.pow(v[2], 2));
+ },
+ scale: function (v, f) {
+ return [v[0] * f, v[1] * f, v[2] * f];
+ },
+};
+
+function getGyroPermission(){
+ if(!DeviceOrientationEvent.requestPermission){
+ return Promise.resolve("granted")
+ }
+ else{
+ return DeviceOrientationEvent.requestPermission()
+ }
+}
+
+function createShader(gl, type, source) {
+ const shader = gl.createShader(type);
+ gl.shaderSource(shader, source);
+ gl.compileShader(shader);
+
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
+ throw new Error(gl.getShaderInfoLog(shader));
+ }
+
+ return shader;
+}
+
+function createProgram(gl, shaders) {
+ const program = gl.createProgram();
+ for (const shader of shaders) {
+ gl.attachShader(program, shader);
+ }
+ gl.linkProgram(program);
+
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
+ throw new Error(gl.getProgramInfoLog(program));
+ }
+
+ return program;
+}
+
+function initIsocahedron(vertices, elements) {
+ const t = 1 + Math.sqrt(5) / 2;
+
+ vertices.push(
+ v3.normalize([-1, t, 0]),
+ v3.normalize([1, t, 0]),
+ v3.normalize([-1, -t, 0]),
+ v3.normalize([1, -t, 0]),
+ v3.normalize([0, -1, t]),
+ v3.normalize([0, 1, t]),
+ v3.normalize([0, -1, -t]),
+ v3.normalize([0, 1, -t]),
+ v3.normalize([t, 0, -1]),
+ v3.normalize([t, 0, 1]),
+ v3.normalize([-t, 0, -1]),
+ v3.normalize([-t, 0, 1]),
+ );
+
+ elements.push(
+ 0, 11, 5,
+ 0, 5, 1,
+ 0, 1, 7,
+ 0, 7, 10,
+ 0, 10, 11,
+ 1, 5, 9,
+ 5, 11, 4,
+ 11, 10, 2,
+ 10, 7, 6,
+ 7, 1, 8,
+ 3, 9, 4,
+ 3, 4, 2,
+ 3, 2, 6,
+ 3, 6, 8,
+ 3, 8, 9,
+ 4, 9, 5,
+ 2, 4, 11,
+ 6, 2, 10,
+ 8, 6, 7,
+ 9, 8, 1,
+ );
+}
+
+function getMidpoint(vertices, midpoints, i0, i1) {
+ const k = `${i0}_${i1}`;
+ if (midpoints.has(k)) {
+ return vertices[midpoints[k]];
+ }
+
+ const p0 = vertices[i0];
+ const p1 = vertices[i1];
+
+ const midpoint = v3.normalize(v3.scale(v3.add(p0, p1), 0.5));
+ const midpointIndex = vertices.length;
+ midpoints.set(k, midpointIndex);
+ vertices.push(midpoint);
+ return midpointIndex;
+}
+
+function subdivideIsocahedron(vertices, elements, midpoints) {
+ const newElements = [];
+ for (let i = 0; i < elements.length; i += 3) {
+ const p0 = elements[i];
+ const p1 = elements[i + 1];
+ const p2 = elements[i + 2];
+ const m0 = getMidpoint(vertices, midpoints, p0, p1);
+ const m1 = getMidpoint(vertices, midpoints, p1, p2);
+ const m2 = getMidpoint(vertices, midpoints, p2, p0);
+
+ newElements.push(
+ m0, m1, m2,
+ p0, m0, m2,
+ p1, m1, m0,
+ p2, m2, m1
+ );
+ }
+ return newElements;
+}
+
+function generateIsocahedron() {
+ const r = 1;
+ const n = 3;
+ const tau = 2 * Math.PI;
+
+ const vertices = [];
+ const normals = [];
+ let elements = [];
+
+ initIsocahedron(vertices, elements);
+ const midpoints = new Map();
+ for (let i = 0; i < 1; i++) {
+ elements = subdivideIsocahedron(vertices, elements, midpoints);
+ }
+
+ return {
+ vertices: [].concat(...vertices),
+ // as we want to approximate a unit sphere, all the vertices are unit vectors
+ normals: [].concat(...vertices),
+ elements
+ };
+}
+
+const canvas = document.querySelector("#canvas");
+const gl = canvas.getContext("webgl");
+
+const vertexShader = createShader(gl, gl.VERTEX_SHADER, `
+ attribute vec4 a_position;
+ attribute vec3 a_normal;
+
+ uniform mat4 u_matrix;
+ uniform mat4 u_world;
+ uniform mat4 u_worldIT;
+ uniform vec3 u_light;
+ uniform vec3 u_camera;
+
+ varying vec3 v_normal;
+ varying vec3 v_surfaceToLight;
+ varying vec3 v_surfaceToView;
+ varying vec3 v_pos;
+
+ void main() {
+ gl_Position = u_matrix * a_position;
+ v_pos = a_position.rgb;
+ v_pos.r = abs(v_pos.r);
+ v_pos.g = abs(v_pos.g);
+ v_pos.b = abs(v_pos.b);
+
+ v_normal = mat3(u_worldIT) * a_normal;
+
+ vec3 surfaceWorldPos = (u_world * a_position).xyz;
+ v_surfaceToLight = u_light - surfaceWorldPos;
+
+ v_surfaceToView = u_camera - surfaceWorldPos;
+ }
+`);
+
+const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, `
+ precision highp float;
+
+ varying vec3 v_normal;
+ varying vec3 v_surfaceToLight;
+ varying vec3 v_surfaceToView;
+ varying vec3 v_pos;
+
+ void main() {
+ vec3 halfVector = normalize(normalize(v_surfaceToLight) + normalize(v_surfaceToView));
+
+ float ka = 0.3;
+ float kd = 0.8;
+ float ks = 0.6;
+ float gamma = 100.0;
+
+ gl_FragColor = vec4(v_pos, 1.0);
+ gl_FragColor.rgb *= ka + (kd * dot(normalize(v_normal), normalize(v_surfaceToLight)));
+ gl_FragColor.rgb += ks * pow(max(0.0, dot(normalize(v_normal), halfVector)), gamma);
+ }
+`);
+
+const program = createProgram(gl, [vertexShader, fragmentShader]);
+
+const {vertices, normals, elements} = generateIsocahedron();
+
+const positionBuffer = gl.createBuffer();
+gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)
+gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
+
+const normalBuffer = gl.createBuffer();
+gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
+gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW);
+
+const elementBuffer = gl.createBuffer();
+gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer);
+gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(elements), gl.STATIC_DRAW);
+
+gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
+
+gl.enable(gl.DEPTH_TEST);
+gl.enable(gl.CULL_FACE);
+
+const positionAttribLocation = gl.getAttribLocation(program, "a_position");
+const normalAttribLocation = gl.getAttribLocation(program, "a_normal");
+
+const matrixLocation = gl.getUniformLocation(program, "u_matrix");
+const worldMatrixLocation = gl.getUniformLocation(program, "u_world");
+const worldITMatrixLocation = gl.getUniformLocation(program, "u_worldIT");
+const lightVecLocation = gl.getUniformLocation(program, "u_light");
+const cameraVecLocation = gl.getUniformLocation(program, "u_camera");
+
+const aspectRatio = gl.canvas.width / gl.canvas.height;
+const zNear = 1;
+const zFar = 2000;
+
+const rotation = [0, 0, 0];
+
+gl.useProgram(program);
+
+gl.enableVertexAttribArray(positionAttribLocation);
+gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+gl.vertexAttribPointer(
+ positionAttribLocation,
+ 3, // element size
+ gl.FLOAT,
+ false, // normalize
+ 0, // stride
+ 0 // offset
+);
+
+gl.enableVertexAttribArray(normalAttribLocation);
+gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
+gl.vertexAttribPointer(normalAttribLocation, 3, gl.FLOAT, false, 0, 0);
+
+gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer);
+
+function drawScene () {
+ window.requestAnimationFrame(drawScene);
+
+ const t = performance.now() / 1000;
+
+ const lightPos = [10, 10, 30];
+ const projectionMatrix = m4.perspective(Math.PI / 180 * 60, aspectRatio, zNear, zFar);
+ const cameraPos = [0, 0, 30];
+ const target = [0, 0, 0];
+ const up = [0, 1, 0];
+ const cameraMatrix = m4.lookAt(cameraPos, target, up);
+ const viewMatrix = m4.inverse(cameraMatrix);
+ let worldMatrix = m4.identity();
+ worldMatrix = m4.xRotate(worldMatrix, rotation[0]);
+ worldMatrix = m4.yRotate(worldMatrix, rotation[1]);
+ worldMatrix = m4.zRotate(worldMatrix, rotation[2]);
+ worldMatrix = m4.scale(worldMatrix, 12, 12, 12);
+
+ const worldITMatrix = m4.transpose(m4.inverse(worldMatrix));
+ const viewProjectionMatrix = m4.multiply(projectionMatrix, viewMatrix);
+ const worldViewProjectionMatrix = m4.multiply(viewProjectionMatrix, worldMatrix);
+
+ /*
+ let matrix = projectionMatrix;
+ matrix = m4.translate(matrix, 0, 0, -30);
+ matrix = m4.xRotate(matrix, rotation[0]);
+ matrix = m4.yRotate(matrix, rotation[1]);
+ matrix = m4.zRotate(matrix, rotation[2]);
+ matrix = m4.scale(matrix, 10, 10, 10);
+ */
+ gl.uniformMatrix4fv(matrixLocation, false, worldViewProjectionMatrix);
+ gl.uniformMatrix4fv(worldMatrixLocation, false, worldMatrix);
+ gl.uniformMatrix4fv(worldITMatrixLocation, false, worldITMatrix);
+ gl.uniform3fv(lightVecLocation, lightPos);
+ gl.uniform3fv(cameraVecLocation, cameraPos);
+
+ gl.clearColor(0, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ gl.drawElements(
+ gl.TRIANGLES,
+ elements.length, // count
+ gl.UNSIGNED_SHORT,
+ 0, // offset
+ );
+}
+
+drawScene();
+
+canvas.addEventListener("click", e => {
+ getGyroPermission()
+ .then(response => {
+ window.addEventListener("deviceorientation", e => {
+ rotation[0] = 2 * (-e.beta / 180 * Math.PI);
+ rotation[1] = 2 * (-e.gamma / 180 * Math.PI);
+ rotation[2] = 2 * (-e.alpha / 180 * Math.PI + Math.PI / 2);
+ });
+ });
+});
diff --git a/gyro/AufnahmeLIna.mp3 b/gyro/AufnahmeLIna.mp3
new file mode 100644
index 0000000..67893cb
Binary files /dev/null and b/gyro/AufnahmeLIna.mp3 differ
diff --git a/gyro/Untitled-1.html b/gyro/Untitled-1.html
new file mode 100644
index 0000000..08ba0df
--- /dev/null
+++ b/gyro/Untitled-1.html
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+colles gyro dingens
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/gyro/blatters.mp3 b/gyro/blatters.mp3
new file mode 100644
index 0000000..a3e6542
Binary files /dev/null and b/gyro/blatters.mp3 differ
diff --git a/gyro/index.html b/gyro/index.html
new file mode 100644
index 0000000..c3982ca
--- /dev/null
+++ b/gyro/index.html
@@ -0,0 +1,26 @@
+
+
+
+Is it working?
+
+lalala
+
+
+