├── README.md ├── LICENSE ├── assets ├── js │ ├── texture.js │ ├── vbo.js │ ├── meshviewer.js │ ├── vao.js │ ├── primitives.js │ ├── glmanager.js │ ├── jsutils.js │ ├── camera.js │ ├── light.js │ ├── objects.js │ ├── vertex.js │ ├── shader.js │ ├── mesh.js │ └── objloader.js └── libs │ └── gl-matrix.js ├── .gitignore └── index.html /README.md: -------------------------------------------------------------------------------- 1 | # mesh-viewer-webgl 2 | mesh viewer in webgl 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 DKE 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /assets/js/texture.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // texture usage 3 | const TEXTURE_TYPE = { 4 | DIFFUSE: "DIFFUSE", 5 | SPECULAR: "SPECULAR", 6 | NORMAL: "NORMAL", 7 | HEIGHT: "HEIGHT", 8 | DISPLACEMENT: "DISPLACEMENT", 9 | AO: "AO", 10 | ROUGHNESS: "ROUGHNESS", 11 | ALBEDO: "ALBEDO", 12 | METALLIC: "METALLIC", 13 | }; 14 | 15 | class Texture { 16 | constructor(ttype = null, flag = null, name = null, id = null) { 17 | this._type = ttype; 18 | this._flag = flag; 19 | this._name = name; 20 | this._id = id; 21 | } 22 | get ttype() { 23 | if (this._type === null) { 24 | throw "texture type is null"; 25 | } 26 | return this._type; 27 | } 28 | get flag() { 29 | if (this._flag === null) { 30 | throw "texture flag is null"; 31 | } 32 | return this._flag; 33 | } 34 | get name() { 35 | if (this._name === null) { 36 | throw "texture name is null"; 37 | } 38 | return this._name; 39 | } 40 | get id() { 41 | if (this._id === null) { 42 | throw "texture id is null"; 43 | } 44 | return this._id; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /assets/js/vbo.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // vertex buffer object 4 | 5 | class VertexBufferObject { 6 | constructor(arr) { 7 | this._buffer_ptr = null; 8 | this._data = arr; 9 | this.set_triangle_data(); 10 | } 11 | set_triangle_data() { 12 | this._data = new Float32Array([ 13 | -0.5, -0.5, 0.0, 14 | 0.5, -0.5, 0.0, 15 | 0.0, 0.5, 0.0, 16 | ]); 17 | } 18 | set_cube_data() { 19 | this._data = cube_vertex_normal_texture["data"]; 20 | } 21 | get vbo() { 22 | if (this._buffer_ptr === null) { 23 | throw "vertex buffer object has not been initialized"; 24 | } 25 | return this._buffer_ptr; 26 | } 27 | get data() { 28 | if (this._data === null) { 29 | throw "there is no data associated to this buffer"; 30 | } 31 | return this._data; 32 | } 33 | set data(arr) { 34 | this._data = arr; 35 | } 36 | init(gl, arr) { 37 | this._buffer_ptr = gl.createBuffer(); 38 | this.data = arr; 39 | gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo); 40 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.data), 41 | gl.STATIC_DRAW); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /assets/js/meshviewer.js: -------------------------------------------------------------------------------- 1 | // mesh viewer scripts 2 | "use strict"; 3 | 4 | /** 5 | starts the webgl object using the associated canvas id 6 | */ 7 | 8 | class SceneManager { 9 | constructor() { 10 | this._gl_manager = null; 11 | this._shader = null; 12 | this.drawables = []; 13 | } 14 | clear() { 15 | this.drawables = []; 16 | } 17 | get gl() { 18 | if (this._gl_manager === null) { 19 | throw "gl manager is null"; 20 | } 21 | return this._gl_manager.gl; 22 | } 23 | set gl(glmanager) { 24 | this._gl_manager = glmanager; 25 | } 26 | 27 | get mShader() { 28 | if (this._shader === null) { 29 | throw "shader is null"; 30 | } 31 | return this._shader; 32 | } 33 | set mShader(s) { 34 | this._shader = s; 35 | } 36 | load_renderables(arr) { 37 | // 38 | let color = glMatrix.vec3.fromValues(0.2, 0.5, 0.5); 39 | let model = glMatrix.mat4.create(); 40 | } 41 | add_renderable(a) { 42 | this.drawables.push(a); 43 | } 44 | init(canvas_id, vs_id, fs_id) { 45 | this.gl = new GLManager(canvas_id); 46 | this.mShader = new ConstantColorShader(vs_id, fs_id); 47 | this.mShader.link_program(this.gl); 48 | } 49 | draw() { 50 | let gl = this.gl; 51 | this.mShader.activate(gl); 52 | 53 | for (const key in this.drawables) { 54 | this.drawables[key].draw(gl, this.mShader); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /assets/js/vao.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | class VertexArrayObject { 5 | constructor() { 6 | this._props = null; 7 | this._vao = null; 8 | } 9 | init(gl) { 10 | this._vao = gl.createVertexArray(); 11 | } 12 | get vao() { 13 | if (this._vao === null) { 14 | throw "vertex array object is null"; 15 | } 16 | return this._vao; 17 | } 18 | get props() { 19 | if (this._props === null) { 20 | throw "vertex array props is null"; 21 | } 22 | return this._props; 23 | 24 | } 25 | set_props(coord) { 26 | if (this._props === null) { 27 | this._props = {}; 28 | } 29 | this.props[coord["name"]] = coord; 30 | } 31 | set_prop_size(name, size) { 32 | this.props[name]["size"] = size; 33 | } 34 | set_prop_type(name, type) { 35 | this.props[name]["type"] = type; 36 | } 37 | set_prop_location(name, loc) { 38 | this.props[name]["location"] = loc; 39 | } 40 | 41 | enable(gl, vbo) { 42 | // 43 | gl.bindVertexArray(this.vao); 44 | 45 | // 46 | gl.bindBuffer(gl.ARRAY_BUFFER, vbo); 47 | // 48 | var offset = 0; 49 | for (const key in this.props) { 50 | let prop = this.props[key]; 51 | gl.vertexAttribPointer( 52 | prop["location"], // index 53 | prop["size"], // size 54 | prop["type"], // GLenum type 55 | false, // normalized 56 | prop["stride"], // GLsizei stride 57 | prop["offset"] // GLintptr offset 58 | ); 59 | gl.enableVertexAttribArray(prop["location"]); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /assets/js/primitives.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | class Triangle { 4 | constructor(v1 = null, v2 = null, v3 = null, index = null, normal = null) { 5 | this._v1 = v1; 6 | this._v2 = v2; 7 | this._v3 = v3; 8 | this._index = index; 9 | this._normal = normal; 10 | } 11 | get v1() { 12 | if (this._v1 === null) { 13 | throw "first vertex is null"; 14 | } 15 | return this._v1; 16 | } 17 | get v2() { 18 | if (this._v2 === null) { 19 | throw "second vertex is null"; 20 | } 21 | return this._v2; 22 | } 23 | get v3() { 24 | if (this._v3 === null) { 25 | throw "third vertex is null"; 26 | } 27 | return this._v3; 28 | } 29 | get index() { 30 | if (this._index === null) { 31 | throw "index is null"; 32 | } 33 | return this._index; 34 | } 35 | get face() { 36 | return this.index; 37 | } 38 | set normal(s) { 39 | if (!Array.isArray(s)) { 40 | throw "must be an array with 3 elements or vec3"; 41 | } 42 | this._normal = s; 43 | } 44 | get normal() { 45 | if (this._normal === null) { 46 | let edges = get_edges(); 47 | if (this.v1._normal === null) { 48 | this.v1.set_normal_from_triangle_edges(edges); 49 | } 50 | this.normal = this.v1.normal; 51 | this.v2._normal = this.v1.normal; 52 | this.v3._normal = this.v1.normal; 53 | } 54 | return this._normal; 55 | } 56 | get_edges() { 57 | let e2 = glMatrix.vec3.create(); 58 | glMatrix.vec3.subtract(e2, this.v2.pos, this.v1.pos); 59 | 60 | let e1 = glMatrix.vec3.create(); 61 | glMatrix.vec3.subtract(e1, this.v3.pos, this.v1.pos); 62 | 63 | let e3 = glMatrix.vec3.create(); 64 | glMatrix.vec3.subtract(e3, this.v3.pos, this.v2.pos); 65 | 66 | return [e1, e2, e3]; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /assets/js/glmanager.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // error check code 4 | 5 | 6 | class GLManager { 7 | constructor(canvas_id) { 8 | let cnvs = document.getElementById(canvas_id); 9 | let mgl = cnvs.getContext("webgl2") || cnvs.getContext("webgl"); 10 | if (mgl === null) { 11 | alert("Browser does not support webgl!"); 12 | } 13 | this.mGL = mgl; 14 | this.clear_canvas(glMatrix.vec4.fromValues(0, 0, 0, 1)); 15 | } 16 | get gl() { 17 | if (this.mGL === null) { 18 | throw "webgl instance is null"; 19 | } 20 | return this.mGL 21 | } 22 | clear_canvas(color) { 23 | this.gl.clearColor(color[0], color[1], color[2], color[3]); 24 | this.gl.clear(this.gl.COLOR_BUFFER_BIT); 25 | } 26 | } 27 | 28 | 29 | function check_error(gl) { 30 | let err = gl.getError(); 31 | if (err === gl.NO_ERROR) { 32 | return true; 33 | } else if (err === gl.INVALID_ENUM) { 34 | let mess = "An unacceptable value has been specified for an enumerated"; 35 | mess += " argument. The command is ignored and the error flag is set."; 36 | throw "INVALID_ENUM :: " + mess; 37 | } else if (err === gl.INVALID_VALUE) { 38 | let mess = "A numeric argument is out of range."; 39 | mess += " The command is ignored and the error flag is set."; 40 | throw "INVALID_VALUE :: " + mess; 41 | } else if (err === gl.INVALID_OPERATION) { 42 | let mess = "The specified command is not allowed for the current"; 43 | mess += " state. The command is ignored and the error flag is set."; 44 | throw "INVALID_OPERATION :: " + mess; 45 | } else if (err === gl.INVALID_FRAMEBUFFER_OPERATION) { 46 | let mess = "The currently bound framebuffer is not framebuffer complete"; 47 | mess += " when trying to render to or to read from it."; 48 | throw "INVALID_FRAMEBUFFER_OPERATION :: " + mess; 49 | } else if (err === gl.OUT_OF_MEMORY) { 50 | let mess = "Not enough memory is left to execute the command."; 51 | throw "OUT_OF_MEMORY :: " + mess; 52 | } else if (err === gl.CONTEXT_LOST_WEBGL) { 53 | let mess = "If the WebGL context is lost, this error is returned on "; 54 | mess += "the first call to getError. Afterwards and until the context"; 55 | mess += " has been restored, it returns gl.NO_ERROR."; 56 | throw "CONTEXT_LOST_WEBGL :: " + mess; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /assets/js/jsutils.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // utils 3 | function isIterable(val) { 4 | return Symbol.iterator in Object(val); 5 | } 6 | 7 | function check_type(val, expected_type) { 8 | if (expected_type === "iterable") { 9 | if (!isIterable(val)) { 10 | let vstr = val.toString(); 11 | throw "argument " + vstr + " must be of type " + expected_type; 12 | } 13 | } else if (typeof val !== expected_type) { 14 | let vstr = val.toString(); 15 | throw "argument " + vstr + " must be of type " + expected_type; 16 | } 17 | return true; 18 | } 19 | 20 | 21 | function first_token_fn(str, token, boolfn, pos = null) { 22 | let ival = 0; 23 | if (pos !== null) { 24 | ival = pos; 25 | } 26 | for (var index = ival; index < str.length; index++) { 27 | if (boolfn(str[index], token)) { 28 | return index; 29 | } 30 | } 31 | return -1; 32 | 33 | } 34 | 35 | function last_token_fn(str, token, boolfn, pos = null) { 36 | var last = -1; 37 | let ival = 0; 38 | if (pos !== null) { 39 | ival = pos; 40 | } 41 | for (var index = ival; index < str.length; index++) { 42 | 43 | if (boolfn(str[key], token)) { 44 | last = key; 45 | } 46 | } 47 | return last; 48 | } 49 | 50 | function first_not_of(str, token, pos = null) { 51 | return first_token_fn(str, token, (a, b) => { 52 | return a !== b; 53 | }, pos); 54 | } 55 | 56 | function first_of(str, token, pos = null) { 57 | return first_token_fn(str, token, (a, b) => { 58 | return a === b; 59 | }, pos); 60 | } 61 | 62 | function last_not_of(str, token, pos = null) { 63 | return last_token_fn(str, token, (a, b) => { 64 | return a !== b; 65 | }, pos); 66 | } 67 | 68 | function last_of(str, token, pos = null) { 69 | return last_token_fn(str, token, (a, b) => { 70 | return a === b; 71 | }, pos); 72 | } 73 | 74 | function tail_str(str) { 75 | let token_start = first_not_of(str, " \t"); 76 | let space_start = first_of(str, " \t", token_start); 77 | let tail_start = first_not_of(str, " \t", space_start); 78 | let tail_end = last_not_of(str, " \t"); 79 | if (tail_start !== -1 && tail_end !== -1) { 80 | return str.substring(tail_start, tail_end - tail_start + 1); 81 | } else if (tail_start !== -1) { 82 | return str.substring(tail_start); 83 | } 84 | return ""; 85 | } 86 | 87 | function firstToken(str) { 88 | if (str !== "") { 89 | let token_start = first_not_of(str, " \t"); 90 | let token_end = first_of(str, " \t", token_start); 91 | if (token_start != -1 && token_end != -1) { 92 | return str.substring(token_start, token_end - token_start); 93 | } else if (token_start != -1) { 94 | return str.substring(token_start); 95 | } 96 | } 97 | return ""; 98 | } 99 | -------------------------------------------------------------------------------- /assets/js/camera.js: -------------------------------------------------------------------------------- 1 | // camera object 2 | "use strict"; 3 | 4 | const CAMERA_MOVEMENT = { 5 | FORWARD: "FORWARD", 6 | BACKWARD: "BACKWARD", 7 | LEFT: "LEFT", 8 | RIGHT: "RIGHT" 9 | }; 10 | 11 | // default values for the camera 12 | const M_YAW = -90.0; 13 | const M_PITCH = 0.0; 14 | const M_SPEED = 2.5; 15 | const M_SENSITIVITY = 0.00001; 16 | const M_ZOOM = 45.0; 17 | 18 | class Camera { 19 | constructor(pos = glMatrix.vec3.fromValues(0.0, 0.0, 0.0), 20 | up = glMatrix.vec3.fromValues(0.0, 1.0, 0.0), 21 | yaw = M_YAW, pitch = M_PITCH, zoom = M_ZOOM, 22 | front = glMatrix.vec3.fromValues(0.0, 0.0, -1.0), 23 | speed = M_SPEED, sens = M_SENSITIVITY 24 | ) { 25 | this.pos = pos; 26 | this.front = front; 27 | this.worldUp = up; 28 | // euler angles 29 | this.yaw = yaw; 30 | this.pitch = pitch; 31 | 32 | // camera options 33 | this.movementSpeed = speed; 34 | this.mouseSensitivity = sens; 35 | this.zoom = zoom; 36 | this.update_camera_vectors(); 37 | } 38 | set_camera(posX, posY, posZ, upX, upY, upZ, 39 | yaw, pitch, front = glMatrix.vec3.fromValues(0.0, 0.0, -1.0), 40 | speed = M_SPEED, sens = M_SENSITIVITY, zoom = M_ZOOM) { 41 | this.pos = glMatrix.vec3.fromValues(posX, posY, posZ); 42 | this.worldUp = glMatrix.vec3.fromValues(upX, upY, upZ); 43 | this.yaw = yaw; 44 | this.pitch = pitch; 45 | this.movementSpeed = speed; 46 | this.mouseSensitivity = sens; 47 | this.zoom = zoom; 48 | this.update_camera_vectors(); 49 | } 50 | update_camera_vectors() { 51 | let front = glMatrix.vec3.create(); 52 | let rad_yaw = glMatrix.glMatrix.toRadian(this.yaw); 53 | let rad_pitch = glMatrix.glMatrix.toRadian(this.pitch); 54 | front[0] = Math.cos(rad_yaw) * Math.cos(rad_pitch); 55 | front[1] = Math.sin(rad_pitch); 56 | front[2] = Math.sin(rad_yaw) * Math.cos(rad_pitch); 57 | glMatrix.vec3.normalize(this.front, front); 58 | // 59 | // compute right 60 | let right = glMatrix.vec3.create(); 61 | glMatrix.vec3.cross(right, this.front, this.worldUp); 62 | this.right = glMatrix.vec3.create(); 63 | glMatrix.vec3.normalize(this.right, right); 64 | // 65 | // compute up 66 | let up = glMatrix.vec3.create(); 67 | glMatrix.vec3.cross(up, this.right, this.front); 68 | this.up = glMatrix.vec3.create(); 69 | glMatrix.vec3.normalize(this.up, up); 70 | } 71 | process_keyboard(movement, deltaTime) { 72 | let velocity = this.movementSpeed * deltaTime; 73 | let fvel = glMatrix.vec3.create(); 74 | let pos = glMatrix.vec3.create(); 75 | if (movement === CAMERA_MOVEMENT["FORWARD"]) { 76 | glMatrix.vec3.scale(fvel, this.front, velocity); 77 | console.log(fvel); 78 | glMatrix.vec3.add(pos, this.pos, fvel); 79 | this.pos = pos; 80 | } else if (movement === CAMERA_MOVEMENT["BACKWARD"]) { 81 | glMatrix.vec3.scale(fvel, this.front, velocity); 82 | glMatrix.vec3.subtract(pos, this.pos, fvel); 83 | this.pos = pos; 84 | } else if (movement === CAMERA_MOVEMENT["RIGHT"]) { 85 | glMatrix.vec3.scale(fvel, this.right, velocity); 86 | glMatrix.vec3.add(pos, this.pos, fvel); 87 | this.pos = pos; 88 | } else if (movement === CAMERA_MOVEMENT["LEFT"]) { 89 | glMatrix.vec3.scale(fvel, this.right, velocity); 90 | glMatrix.vec3.subtract(pos, this.pos, fvel); 91 | this.pos = pos; 92 | } 93 | } 94 | get_view_matrix() { 95 | let cpos = this.pos; 96 | let cfront = this.front; 97 | let cup = this.up; 98 | let front_pos = glMatrix.vec3.create(); 99 | glMatrix.vec3.add(front_pos, cpos, cfront); 100 | let view = glMatrix.mat4.create(); 101 | glMatrix.mat4.lookAt(view, cpos, front_pos, cup); 102 | return view; 103 | } 104 | 105 | process_keyboard_rotate(direction, deltaTime) { 106 | 107 | deltaTime *= this.movementSpeed; 108 | if (direction === CAMERA_MOVEMENT["FORWARD"]) { 109 | this.pitch += deltaTime; 110 | } else if (direction === CAMERA_MOVEMENT["BACKWARD"]) { 111 | this.pitch -= deltaTime; 112 | } else if (direction === CAMERA_MOVEMENT["RIGHT"]) { 113 | this.yaw += deltaTime; 114 | } else if (direction === CAMERA_MOVEMENT["LEFT"]) { 115 | this.yaw -= deltaTime; 116 | } 117 | this.update_camera_vectors(); 118 | } 119 | process_mouse_scroll(yoffset) { 120 | let zoom = this.zoom; 121 | 122 | if (this.zoom >= 1.0 && this.zoom <= 45.0) { 123 | this.zoom -= yoffset; 124 | } 125 | if (this.zoom <= 1.0) { 126 | this.zoom = 1.0; 127 | } 128 | if (this.zoom >= 45.0) { 129 | this.zoom = 45.0; 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /assets/js/light.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // light implementation 3 | 4 | const LYAW = -90.0; 5 | const LPITCH = 0.0; 6 | const LSPEED = 2.5; 7 | 8 | // 9 | 10 | const LIGHT_MOVEMENT = { 11 | L_FORWARD: "L_FORWARD", 12 | L_BACKWARD: "L_BACKWARD", 13 | L_LEFT: "L_LEFT", 14 | L_RIGHT: "L_RIGHT" 15 | }; 16 | 17 | class Light { 18 | constructor(lightColor) { 19 | this.emitColor = lightColor; 20 | } 21 | emitted(emits) { 22 | emits = this.emitColor; 23 | return true; 24 | } 25 | } 26 | 27 | class DirectionalLight extends Light { 28 | constructor(lightColor, wup, y = LYAW, p = LPITCH) { 29 | super(lightColor); 30 | this.yaw = y; 31 | this.pitch = p; 32 | this.worldUp = wup; 33 | this.front = null; 34 | this.right = null; 35 | this.up = null; 36 | this.updateDirection(); 37 | } 38 | 39 | setYaw(val) { 40 | this.yaw = val; 41 | this.updateDirection(); 42 | } 43 | setPitch(val) { 44 | this.pitch = val; 45 | this.updateDirection(); 46 | } 47 | updateDirection() { 48 | // 49 | let front = glMatrix.vec3.create(); 50 | let rad_yaw = glMatrix.toRadian(this.yaw); 51 | let rad_pitch = glMatrix.toRadian(this.pitch); 52 | front.x = Math.cos(rad_yaw) * Math.cos(rad_pitch); 53 | front.y = Math.sin(rad_pitch); 54 | front.z = Math.sin(rad_yaw) * Math.cos(rad_pitch); 55 | glMatrix.vec3.normalize(this.front, front); 56 | // 57 | // compute right 58 | let right = glMatrix.vec3.create(); 59 | glMatrix.vec3.normalize(this.right, 60 | glMatrix.vec3.cross(right, this.front, this.worldUp)); 61 | // 62 | // compute up 63 | let up = glMatrix.vec3.create(); 64 | glMatrix.vec3.normalize(this.up, 65 | glMatrix.vec3.cross(up, this.right, this.front)); 66 | } 67 | processKeyBoardRotate(direction, deltaTime) { 68 | 69 | deltaTime *= this.movementSpeed; 70 | if (direction === LIGHT_MOVEMENT["L_FORWARD"]) { 71 | this.pitch += deltaTime; 72 | } else if (direction === LIGHT_MOVEMENT["L_BACKWARD"]) { 73 | this.pitch -= deltaTime; 74 | } else if (direction === LIGHT_MOVEMENT["L_RIGHT"]) { 75 | this.yaw += deltaTime; 76 | } else if (direction === LIGHT_MOVEMENT["L_LEFT"]) { 77 | this.yaw -= deltaTime; 78 | } 79 | this.updateDirection(); 80 | } 81 | } 82 | 83 | class PointLight extends Light { 84 | constructor(lightColor, pos) { 85 | super(lightColor); 86 | this.pos = pos; 87 | } 88 | 89 | } 90 | 91 | class SpotLight { 92 | constructor(lightColor, pos, wup, y = LYAW, 93 | p = LPITCH, cutOffAngleDegree = 0.91, 94 | outerCut = 0.82, mspeed = LSPEED) { 95 | // 96 | this.cutOff = glMatrix.toRadian(cutOffAngleDegree); 97 | this.outerCutoff = outerCut; 98 | this.dirLight = new DirectionalLight(lightColor, wup, y, p); 99 | this.pointLight = new PointLight(lightColor, pos); 100 | this.movementSpeed = mspeed; 101 | } 102 | get_view_matrix() { 103 | let target = this.pointLight.pos + this.dirLight.front; 104 | let upvec = this.dirLight.up; 105 | let cameraDirection = glMatrix.vec3.create(); 106 | glMatrix.vec3.normalize(cameraDirection, this.pointLight.pos - target); 107 | let upv = glMatrix.vec3.create(); 108 | let right = glMatrix.vec3.create(); 109 | // 110 | glMatrix.vec3.normalize(right, 111 | glMatrix.vec3.cross(upv, upvec, cameraDirection) 112 | ); 113 | let realUp = glMatrix.vec3.create(); 114 | glMatrix.vec3.normalize(realUp, 115 | glMatrix.vec3.cross(glMatrix.vec3.create(), cameraDirection, right) 116 | ); 117 | // 118 | let trans = glMatrix.mat4.create(1.0); 119 | trans[3][0] = -this.pointLight.pos.x; 120 | trans[3][1] = -this.pointLight.pos.y; 121 | trans[3][2] = -this.pointLight.pos.z; 122 | 123 | // 124 | let rotation = glMatrix.mat4.create(1.0); 125 | rotation[0][0] = right.x; 126 | rotation[1][0] = right.y; 127 | rotation[2][0] = right.z; 128 | rotation[0][1] = realUp.x; 129 | rotation[1][1] = realUp.y; 130 | rotation[2][1] = realUp.z; 131 | rotation[0][2] = cameraDirection.x; 132 | rotation[1][2] = cameraDirection.y; 133 | rotation[2][2] = cameraDirection.z; 134 | return rotation * trans; 135 | } 136 | processKeyBoardRotate(direction, deltaTime) { 137 | this.dirLight.processKeyBoardRotate(direction, deltaTime); 138 | } 139 | process_keyboard(movement, deltaTime) { 140 | let velocity = this.movementSpeed * deltaTime; 141 | if (movement === LIGHT_MOVEMENT["L_FORWARD"]) { 142 | this.pointLight.pos += this.dirLight.front * velocity; 143 | } else if (movement === LIGHT_MOVEMENT["L_BACKWARD"]) { 144 | this.pointLight.pos -= this.dirLight.front * velocity; 145 | } else if (movement === LIGHT_MOVEMENT["L_RIGHT"]) { 146 | this.pointLight.pos += this.dirLight.right * velocity; 147 | } else if (movement === LIGHT_MOVEMENT["L_LEFT"]) { 148 | this.pointLight.pos -= this.dirLight.right * velocity; 149 | } 150 | } 151 | }; 152 | -------------------------------------------------------------------------------- /assets/js/objects.js: -------------------------------------------------------------------------------- 1 | // objects in ndc coordinates 2 | var cube_vertex_normal_texture = { 3 | "data": new Float32Array([ 4 | // back face 5 | -1.0, -1.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // bottom-let 6 | 1.0, 1.0, -1.0, 0.0, 0.0, -1.0, 1.0, 1.0, // top-right 7 | 1.0, -1.0, -1.0, 0.0, 0.0, -1.0, 1.0, 0.0, // bottom-right 8 | 1.0, 1.0, -1.0, 0.0, 0.0, -1.0, 1.0, 1.0, // top-right 9 | -1.0, -1.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // bottom-let 10 | -1.0, 1.0, -1.0, 0.0, 0.0, -1.0, 0.0, 1.0, // top-let 11 | // front face 12 | -1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // bottom-let 13 | 1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, // bottom-right 14 | 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, // top-right 15 | 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, // top-right 16 | -1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, // top-let 17 | -1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // bottom-let 18 | // left face 19 | -1.0, 1.0, 1.0, -1.0, 0.0, 0.0, 1.0, 0.0, // top-right 20 | -1.0, 1.0, -1.0, -1.0, 0.0, 0.0, 1.0, 1.0, // top-let 21 | -1.0, -1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 1.0, // bottom-let 22 | -1.0, -1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 1.0, // bottom-let 23 | -1.0, -1.0, 1.0, -1.0, 0.0, 0.0, 0.0, 0.0, // bottom-right 24 | -1.0, 1.0, 1.0, -1.0, 0.0, 0.0, 1.0, 0.0, // top-right 25 | // right face 26 | 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, // top-let 27 | 1.0, -1.0, -1.0, 1.0, 0.0, 0.0, 0.0, 1.0, // bottom-right 28 | 1.0, 1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0, // top-right 29 | 1.0, -1.0, -1.0, 1.0, 0.0, 0.0, 0.0, 1.0, // bottom-right 30 | 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, // top-let 31 | 1.0, -1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, // bottom-let 32 | // bottom face 33 | -1.0, -1.0, -1.0, 0.0, -1.0, 0.0, 0.0, 1.0, // top-right 34 | 1.0, -1.0, -1.0, 0.0, -1.0, 0.0, 1.0, 1.0, // top-let 35 | 1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, // bottom-let 36 | 1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, // bottom-let 37 | -1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, // bottom-right 38 | -1.0, -1.0, -1.0, 0.0, -1.0, 0.0, 0.0, 1.0, // top-right 39 | // top face 40 | -1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 0.0, 1.0, // top-let 41 | 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, // bottom-right 42 | 1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 1.0, // top-right 43 | 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, // bottom-right 44 | -1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 0.0, 1.0, // top-let 45 | -1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0 // bottom-let 46 | ]), 47 | "nb_triangles": 0, 48 | "vertices": [], 49 | "indices": [] 50 | }; 51 | cube_vertex_normal_texture["vertices"] = 52 | Vertex.from_arrays(cube_vertex_normal_texture["data"]); 53 | 54 | cube_vertex_normal_texture["nb_triangles"] = 55 | cube_vertex_normal_texture["vertices"].length / 3; 56 | for (var index = 0; index < cube_vertex_normal_texture["nb_triangles"]; index++) { 57 | cube_vertex_normal_texture["indices"].push(index); 58 | } 59 | 60 | // 61 | var cube_vertex_texture_normal = { 62 | "data": new Float32Array([ 63 | // back face 64 | -1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 0.0, -1.0, // bottom-let 65 | 1.0, 1.0, -1.0, 1.0, 1.0, 0.0, 0.0, -1.0, // top-right 66 | 1.0, -1.0, -1.0, 1.0, 0.0, 0.0, 0.0, -1.0, // bottom-right 67 | 1.0, 1.0, -1.0, 1.0, 1.0, 0.0, 0.0, -1.0, // top-right 68 | -1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 0.0, -1.0, // bottom-let 69 | -1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 0.0, -1.0, // top-let 70 | // front face 71 | -1.0, -1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, // bottom-let 72 | 1.0, -1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, // bottom-right 73 | 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, // top-right 74 | 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, // top-right 75 | -1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, // top-let 76 | -1.0, -1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, // bottom-let 77 | // left face 78 | -1.0, 1.0, 1.0, 1.0, 0.0, -1.0, 0.0, 0.0, // top-right 79 | -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 0.0, 0.0, // top-let 80 | -1.0, -1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 0.0, // bottom-let 81 | -1.0, -1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 0.0, // bottom-let 82 | -1.0, -1.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // bottom-right 83 | -1.0, 1.0, 1.0, 1.0, 0.0, -1.0, 0.0, 0.0, // top-right 84 | // right face 85 | 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, // top-let 86 | 1.0, -1.0, -1.0, 0.0, 1.0, 1.0, 0.0, 0.0, // bottom-right 87 | 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 0.0, 0.0, // top-right 88 | 1.0, -1.0, -1.0, 0.0, 1.0, 1.0, 0.0, 0.0, // bottom-right 89 | 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, // top-let 90 | 1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // bottom-let 91 | // bottom face 92 | -1.0, -1.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, // top-right 93 | 1.0, -1.0, -1.0, 1.0, 1.0, 0.0, -1.0, 0.0, // top-let 94 | 1.0, -1.0, 1.0, 1.0, 0.0, 0.0, -1.0, 0.0, // bottom-let 95 | 1.0, -1.0, 1.0, 1.0, 0.0, 0.0, -1.0, 0.0, // bottom-let 96 | -1.0, -1.0, 1.0, 0.0, 0.0, 0.0, -1.0, 0.0, // bottom-right 97 | -1.0, -1.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, // top-right 98 | // top face 99 | -1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 0.0, // top-let 100 | 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, // bottom-right 101 | 1.0, 1.0, -1.0, 1.0, 1.0, 0.0, 1.0, 0.0, // top-right 102 | 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, // bottom-right 103 | -1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 0.0, // top-let 104 | -1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0 // bottom-let 105 | ]), 106 | "nb_triangles": 0, 107 | "vertices": [], 108 | "indices": [] 109 | }; 110 | cube_vertex_texture_normal["vertices"] = 111 | Vertex.from_arrays(cube_vertex_texture_normal["data"]); 112 | 113 | cube_vertex_texture_normal["nb_triangles"] = 114 | cube_vertex_texture_normal["vertices"].length / 3; 115 | for (var index = 0; index < cube_vertex_texture_normal["nb_triangles"]; index++) { 116 | cube_vertex_texture_normal["indices"].push(index); 117 | } 118 | -------------------------------------------------------------------------------- /assets/js/vertex.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // vertex 3 | 4 | class Vertex { 5 | /** 6 | 7 | Vertex for in a 3d plane 8 | 9 | @param {vec3} pos - position of vertex 10 | @param {vec3} normal - normal of vertex 11 | @param {vec2} texcoord - texture coordinate of vertex 12 | @param {vec3} tan - tangent coordinate of vertex 13 | @param {vec3} bitan - bitangent coordinate of vertex 14 | */ 15 | constructor(pos = null, normal = null, texcoord = null, tan = null, bitan = null) { 16 | this._position = pos; 17 | this._normal = normal; 18 | this._texcoord = texcoord; 19 | this._tangent = tan; 20 | this._bitangent = bitan; 21 | } 22 | get pos() { 23 | if (this._position === null) { 24 | throw "position is null"; 25 | } 26 | return this._position; 27 | } 28 | get normal() { 29 | if (this._normal === null) { 30 | throw "normal is null"; 31 | } 32 | return this._normal; 33 | } 34 | get uv() { 35 | if (this._texcoord === null) { 36 | throw "texture coordinate is null"; 37 | } 38 | return this._texcoord; 39 | } 40 | get tan() { 41 | if (this._tangent === null) { 42 | throw "tangent coordinate is null"; 43 | } 44 | return this._tangent; 45 | } 46 | get bitan() { 47 | if (this._bitangent === null) { 48 | throw "bitangent coordinate is null"; 49 | } 50 | return this._bitangent; 51 | } 52 | /** 53 | to quad array, first position, and to uv (texture coordinate) 54 | 55 | @return {Float32Array} an array with 5 values 56 | */ 57 | to_quad() { 58 | return new Float32Array([ 59 | this.pos[0], 60 | this.pos[1], 61 | this.pos[2], 62 | this.uv[0], 63 | this.uv[1] 64 | ]); 65 | } 66 | /** 67 | * to quad array, first position, and to uv (texture coordinate) 68 | * 69 | * @return {Float32Array} an array with 8 values 70 | */ 71 | to_array() { 72 | let quad = this.to_quad(); 73 | let quads = []; 74 | for (const key in quad) { 75 | quads.push(quad[key]); 76 | } 77 | quads.push(this.normal[0]); 78 | quads.push(this.normal[1]); 79 | quads.push(this.normal[2]); 80 | return new Float32Array(quads); 81 | } 82 | /** 83 | * to quad array, first position, and to uv (texture coordinate) 84 | * 85 | * @return {Float32Array} an array with 14 values 86 | */ 87 | to_primitive() { 88 | let arr = this.to_array(); 89 | let lst = []; 90 | for (const key in arr) { 91 | lst.push(arr[key]); 92 | } 93 | 94 | lst.push(this.tan[0]); 95 | lst.push(this.tan[1]); 96 | lst.push(this.tan[2]); 97 | lst.push(this.bitan[0]); 98 | lst.push(this.bitan[1]); 99 | lst.push(this.bitan[2]); 100 | return new Float32Array(lst); 101 | } 102 | size() { 103 | let count = 0; 104 | let p = this._position; 105 | let n = this._normal; 106 | let t = this._texcoord; 107 | let tt = this._tangent; 108 | let bt = this._bitangent; 109 | if (p !== null) { 110 | count += 3; 111 | } 112 | if (n !== null) { 113 | count += 3; 114 | } 115 | if (t !== null) { 116 | count += 2; 117 | } 118 | if (tt !== null) { 119 | count += 3; 120 | } 121 | if (bt !== null) { 122 | count += 3; 123 | } 124 | return count; 125 | } 126 | to_list() { 127 | let s = this.size(); 128 | if (s === 5) { 129 | return this.to_quad(); 130 | } else if (s === 8) { 131 | return this.to_array(); 132 | } else if (s === 14) { 133 | return this.to_primitive(); 134 | } else { 135 | throw "unsupported size"; 136 | } 137 | } 138 | set_normal_from_triangle_edges(edges) { 139 | let edge1 = edges[0]; 140 | let edge2 = edges[1]; 141 | let n = glMatrix.vec3.create(); 142 | glMatrix.vec3.cross(n, edge1, edge2); 143 | let n1 = glMatrix.vec3.create(); 144 | glMatrix.vec3.normalize(n1, n); 145 | this._normal = n1; 146 | } 147 | set_tangent_values_from_triangle(tri) { 148 | let v1 = tri.v1; 149 | let v2 = tri.v2; 150 | let v3 = tri.v3; 151 | let edges = tri.get_edges(); 152 | let edge1 = edges[0]; 153 | let edge2 = edges[1]; 154 | 155 | let deltaUV1 = glMatrix.vec3.create(); 156 | glMatrix.vec3.subtract(deltaUV1, v2.uv, v1.uv); 157 | 158 | let deltaUV2 = glMatrix.vec3.create(); 159 | glMatrix.vec3.subtract(deltaUV2, v3.uv, v1.uv); 160 | 161 | let f = 1.0 / (deltaUV1[0] * deltaUV2[1] - deltaUV2[0] * deltaUV1[1]); 162 | 163 | let tangent1 = glMatrix.vec3.create(); 164 | let tangent2 = glMatrix.vec3.create(); 165 | 166 | tangent1[0] = f * (deltaUV2[1] * edge1[0] - deltaUV1[1] * edge2[0]); 167 | tangent1[1] = f * (deltaUV2[1] * edge1[1] - deltaUV1[1] * edge2[1]); 168 | tangent1[2] = f * (deltaUV2[1] * edge1[2] - deltaUV1[1] * edge2[2]); 169 | 170 | bitangent1[0] = f * (-deltaUV2[0] * edge1[0] + deltaUV1[0] * edge2[0]); 171 | bitangent1[1] = f * (-deltaUV2[0] * edge1[1] + deltaUV1[0] * edge2[1]); 172 | bitangent1[2] = f * (-deltaUV2[0] * edge1[2] + deltaUV1[0] * edge2[2]); 173 | this._tangent = tangent1; 174 | this._bitangent = bitangent1; 175 | } 176 | static from_quad(arr) { 177 | let v = new Vertex(); 178 | v._position = glMatrix.vec3.create(); 179 | v._texcoord = glMatrix.vec2.create(); 180 | v.pos[0] = arr[0]; 181 | v.pos[1] = arr[1]; 182 | v.pos[2] = arr[2]; 183 | v.uv[0] = arr[3]; 184 | v.uv[1] = arr[4]; 185 | return v; 186 | } 187 | static from_array(arr) { 188 | let v = Vertex.from_quad(arr); 189 | v._normal = glMatrix.vec3.create(); 190 | v.normal[0] = arr[5]; 191 | v.normal[1] = arr[6]; 192 | v.normal[2] = arr[7]; 193 | return v; 194 | } 195 | static from_primitive(arr) { 196 | let v = Vertex.from_array(arr); 197 | v._tangent = glMatrix.vec3.create(); 198 | v._bitangent = glMatrix.vec3.create(); 199 | v.tan[0] = arr[8]; 200 | v.tan[1] = arr[9]; 201 | v.tan[2] = arr[10]; 202 | v.bitan[0] = arr[11]; 203 | v.bitan[1] = arr[12]; 204 | v.bitan[2] = arr[13]; 205 | return v; 206 | } 207 | static is_arr_fit(arr, expected_nb_components) { 208 | if (!isIterable(arr)) { 209 | console.log(arr); 210 | console.log(typeof(arr)); 211 | throw "argument is not an iterable"; 212 | } 213 | let cond = arr.length % expected_nb_components === 0; 214 | if (!cond) { 215 | let m = expected_nb_components.toString(); 216 | throw "length of array must be a multiple of " + m; 217 | } 218 | 219 | } 220 | static from_values(arr, expected_nb_components, vertex_fn) { 221 | let vs = []; 222 | Vertex.is_arr_fit(arr, expected_nb_components); 223 | 224 | for (var i = 0; i < arr.length; i += expected_nb_components) { 225 | let values = []; 226 | for (var j = 0; j < expected_nb_components; j++) { 227 | let val = arr[i + j]; 228 | values.push(val); 229 | } 230 | let vtx = vertex_fn(values); 231 | vs.push(vtx); 232 | } 233 | return vs; 234 | } 235 | static from_quads(arr) { 236 | return Vertex.from_values( 237 | arr, 5, Vertex.from_quad 238 | ); 239 | } 240 | static from_arrays(arr) { 241 | return Vertex.from_values( 242 | arr, 8, Vertex.from_array 243 | ); 244 | } 245 | static from_primitives(arr) { 246 | return Vertex.from_values( 247 | arr, 14, Vertex.from_primitive 248 | ); 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /assets/js/shader.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // simple shader class 4 | 5 | // check the shader compilation 6 | function checkShaderCompilation(gl, shader) { 7 | let gbool = gl.getShaderParameter(shader, gl.COMPILE_STATUS); 8 | if (!gbool) { 9 | let mess = gl.getShaderInfoLog(shader); 10 | throw mess; 11 | } 12 | return gbool; 13 | } 14 | 15 | function checkShaderProgramCompilation(gl, program) { 16 | // check the program compilation 17 | let pstat = gl.getProgramParameter(program, gl.LINK_STATUS); 18 | if (!pstat) { 19 | let mess = gl.getProgramInfoLog(program); 20 | throw mess; 21 | } 22 | return pstat; 23 | } 24 | 25 | function getUniformLocation(gl, program, name) { 26 | let locVal = gl.getUniformLocation(program, name); 27 | if (locVal === null) { 28 | throw "no location is given for the uniform in the program"; 29 | } 30 | check_error(gl); 31 | return locVal; 32 | } 33 | 34 | class Shader { 35 | constructor(vs_id, fs_id) { 36 | // shader source [{"text": "", "type": ""}] 37 | this._shader_sources = null; 38 | this._shader_id = null; 39 | this.init_shader_sources_vs_fs(vs_id, fs_id); 40 | } 41 | init_shader_sources(arr) { 42 | for (const key in arr) { 43 | let source_id_type = arr[key]; 44 | let text = 45 | document.getElementById(source_id_type["id"]).text.trim(); 46 | let stype = source_id_type["type"]; 47 | this.set_shader_source(text, stype); 48 | } 49 | } 50 | init_shader_sources_vs_fs(vs_id, fs_id) { 51 | let arr = [{ 52 | "type": "FRAGMENT_SHADER", 53 | "id": fs_id 54 | }, { 55 | "type": "VERTEX_SHADER", 56 | "id": vs_id 57 | }]; 58 | this.init_shader_sources(arr); 59 | } 60 | get shader_sources() { 61 | if (this._shader_sources === null) { 62 | throw "shader sources are null"; 63 | } 64 | return this._shader_sources; 65 | } 66 | get_shader_source_by_type(stype) { 67 | for (const key in this.shader_sources) { 68 | let source = this.shader_sources[key]; 69 | if (source["type"] === stype) { 70 | return source["text"]; 71 | } 72 | } 73 | return null; 74 | } 75 | set_shader_source(stext, stype) { 76 | if (this._shader_sources === null) { 77 | this._shader_sources = []; 78 | } 79 | let st = this.get_shader_source_by_type(stype); 80 | if (st === null) { 81 | this.shader_sources.push({ 82 | "text": stext, 83 | "type": stype 84 | }); 85 | } else { 86 | throw "same type shader already exists among shader source"; 87 | } 88 | } 89 | get vs_text() { 90 | return this.get_shader_source_by_type("VERTEX_SHADER"); 91 | } 92 | get fs_text() { 93 | return this.get_shader_source_by_type("FRAGMENT_SHADER"); 94 | } 95 | get program_id() { 96 | if (this._shader_id === null) { 97 | throw "shader id is null"; 98 | } 99 | return this._shader_id; 100 | } 101 | load_shader(gl, shader_type, shader_txt) { 102 | check_error(gl); 103 | let compiled_shader = gl.createShader(shader_type); 104 | gl.shaderSource(compiled_shader, shader_txt); 105 | gl.compileShader(compiled_shader); 106 | checkShaderCompilation(gl, compiled_shader); 107 | check_error(gl); 108 | return compiled_shader; 109 | } 110 | activate(gl) { 111 | gl.useProgram(this.program_id); 112 | } 113 | 114 | link_program(gl) { 115 | this._shader_id = gl.createProgram(); 116 | let shaders = []; 117 | for (const key in this.shader_sources) { 118 | let source = this.shader_sources[key]; 119 | let text = source["text"]; 120 | var stype = null; 121 | if (source["type"] === "FRAGMENT_SHADER") { 122 | stype = gl.FRAGMENT_SHADER; 123 | } else if (source["type"] === "VERTEX_SHADER") { 124 | stype = gl.VERTEX_SHADER; 125 | } else { 126 | throw "unsupported shader type " + source["type"]; 127 | } 128 | let shader = this.load_shader(gl, stype, text); 129 | shaders.push(shader); 130 | } 131 | for (const key in shaders) { 132 | gl.attachShader(this.program_id, shaders[key]); 133 | } 134 | gl.linkProgram(this.program_id); 135 | checkShaderProgramCompilation(gl, this.program_id); 136 | } 137 | check_type(val, expected_type) { 138 | check_type(val, expected_type); 139 | } 140 | check_components(val, expected_nb_components) { 141 | let nc = expected_nb_components; 142 | if (typeof(val) === "object") { 143 | if (val.length === nc) { 144 | return true; 145 | } else { 146 | let mess = "expected number of components is " + nc.toString(); 147 | mess += " but you had provided an object of length: "; 148 | mess += val.length.toString(); 149 | throw mess; 150 | } 151 | } else { 152 | let m = "object " + val.toString() + " is not an array"; 153 | m += " type: " + typeof(val); 154 | m += " with length " + val.length.toString(); 155 | m += " number of components: " + 156 | expected_nb_components.toString(); 157 | throw m; 158 | } 159 | } 160 | set_int_uniform(gl, name, value) { 161 | this.check_type(value, "number") 162 | let uloc = getUniformLocation(gl, this.program_id, name); 163 | gl.uniform1i(uloc, value); 164 | } 165 | set_bool_uniform(gl, name, value) { 166 | this.check_type(value, "boolean") 167 | let uloc = getUniformLocation(gl, this.program_id, name); 168 | gl.uniform1i(uloc, Number(value)); 169 | } 170 | set_float_uniform(gl, name, value) { 171 | this.check_type(value, "number") 172 | let uloc = getUniformLocation(gl, this.program_id, name); 173 | gl.uniform1f(uloc, parseFloat(value)); 174 | } 175 | set_vec2_uniform(gl, name, value) { 176 | this.check_components(value, 2) 177 | let uloc = getUniformLocation(gl, this.program_id, name); 178 | gl.uniform2f(uloc, value[0], value[1]); 179 | } 180 | set_vec3_uniform(gl, name, value) { 181 | this.check_components(value, 3) 182 | let uloc = getUniformLocation(gl, this.program_id, name); 183 | gl.uniform3f(uloc, value[0], value[1], value[2]); 184 | } 185 | set_vec4_uniform(gl, name, value) { 186 | this.check_components(value, 4) 187 | let uloc = getUniformLocation(gl, this.program_id, name); 188 | gl.uniform4f(uloc, value[0], value[1], value[2], value[3]); 189 | } 190 | set_mat2_uniform(gl, name, value) { 191 | this.check_components(value, 4) 192 | let uloc = getUniformLocation(gl, this.program_id, name); 193 | gl.uniformMatrix2fv(uloc, false, value); 194 | } 195 | set_mat3_uniform(gl, name, value) { 196 | this.check_components(value, 9) 197 | let uloc = getUniformLocation(gl, this.program_id, name); 198 | gl.uniformMatrix3fv(uloc, false, value); 199 | } 200 | set_mat4_uniform(gl, name, value) { 201 | this.check_components(value, 16) 202 | let uloc = getUniformLocation(gl, this.program_id, name); 203 | gl.uniformMatrix4fv(uloc, false, value); 204 | } 205 | set_uniform(gl, name, udata, utype) { 206 | if (utype === "vec2") { 207 | this.set_vec2_uniform(gl, name, udata); 208 | } else if (utype === "vec3") { 209 | this.set_vec3_uniform(gl, name, udata); 210 | } else if (utype === "vec4") { 211 | this.set_vec4_uniform(gl, name, udata); 212 | } else if (utype === "mat2") { 213 | this.set_mat2_uniform(gl, name, udata); 214 | } else if (utype === "mat3") { 215 | this.set_mat3_uniform(gl, name, udata); 216 | } else if (utype === "mat4") { 217 | this.set_mat4_uniform(gl, name, udata); 218 | } else if (utype === "bool") { 219 | this.set_bool_uniform(gl, name, udata); 220 | } else if (utype === "int") { 221 | this.set_int_uniform(gl, name, udata); 222 | } else if (utype === "float") { 223 | this.set_float_uniform(gl, name, udata); 224 | } else { 225 | throw "unknown uniform type: " + utype; 226 | } 227 | } 228 | } 229 | 230 | class ConstantColorShader extends Shader { 231 | constructor(vs_id, fs_id) { 232 | super(vs_id, fs_id); 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /assets/js/mesh.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // mesh object 3 | 4 | class BaseMesh { 5 | constructor(gl, vertices = null, textures = null, indices = null, uniforms = null) { 6 | this._vertices = vertices; 7 | this._textures = textures; 8 | this._indices = indices; 9 | this._vao = null; 10 | this._vbo = null; 11 | this._uniforms = uniforms; 12 | } 13 | set uniforms(u) { 14 | this._uniforms = u; 15 | } 16 | set_uniform_prop(u) { 17 | if (this._uniforms === null) { 18 | this._uniforms = {}; 19 | } 20 | this._uniforms[u["name"]] = u; 21 | } 22 | get uniforms() { 23 | if (this._uniforms === null) { 24 | throw "uniforms for this renderable are null"; 25 | } 26 | return this._uniforms; 27 | } 28 | load_uniforms(gl, shaderProgram) { 29 | for (const uniform_name in this.uniforms) { 30 | // 31 | let udata = this.uniforms[uniform_name].data; 32 | let utype = this.uniforms[uniform_name].type; 33 | shaderProgram.set_uniform(gl, uniform_name, udata, utype); 34 | } 35 | } 36 | get vertices() { 37 | if (this._vertices === null) { 38 | throw "vertces are null"; 39 | } 40 | return this._vertices; 41 | } 42 | get textures() { 43 | if (this._textures === null) { 44 | throw "textures are null"; 45 | } 46 | return this._textures; 47 | } 48 | get indices() { 49 | if (this._indices === null) { 50 | throw "indices are null"; 51 | } 52 | return this._indices; 53 | } 54 | get vbo() { 55 | if (this._vbo === null) { 56 | throw "vertex buffer object null"; 57 | } 58 | return this._vbo; 59 | } 60 | get vao() { 61 | if (this._vao === null) { 62 | throw "vertex array object null"; 63 | } 64 | return this._vao; 65 | } 66 | to_vertex_array() { 67 | let arr = []; 68 | let vsize = this.vertices[0].size(); 69 | for (const index in this.vertices) { 70 | let vertex = this.vertices[index]; 71 | let size = vertex.size(); 72 | if (size !== vsize) { 73 | let mes = "vertex size is not correct for given vertex array"; 74 | mes += " this messes up stride for overall vertex array"; 75 | throw mes; 76 | } 77 | let lst = vertex.to_list(); 78 | for (const i in lst) { 79 | arr.push(lst[i]); 80 | } 81 | } 82 | return new Float32Array(arr); 83 | } 84 | set_vao_values(gl) { 85 | let lst = this.vertices[0].to_list(); 86 | let vsize = lst.byteLength; 87 | if (vsize >= 5) { 88 | // enable position 89 | gl.vertexAttribPointer(0, 3, gl.FLOAT, false, vsize, 0); 90 | gl.enableVertexAttribArray(0); 91 | 92 | let subarr = lst.subarray(0, 3); 93 | // enable uv coordinate 94 | gl.vertexAttribPointer(1, 2, gl.FLOAT, false, vsize, 95 | subarr.byteLength); 96 | gl.enableVertexAttribArray(1); 97 | } 98 | if (vsize >= 8) { 99 | let subarr = lst.subarray(0, 5); 100 | // set normals 101 | gl.vertexAttribPointer(2, 3, gl.FLOAT, false, vsize, 102 | subarr.byteLength); 103 | gl.enableVertexAttribArray(2); 104 | } 105 | if (vsize === 14) { 106 | // set tangent and bitangent 107 | let subarr = lst.subarray(0, 8); 108 | 109 | // set tangent 110 | gl.vertexAttribPointer(3, 3, gl.FLOAT, false, vsize, 111 | subarr.byteLength); 112 | gl.enableVertexAttribArray(3); 113 | 114 | subarr = lst.subarray(0, 11); 115 | // set bitangent 116 | gl.vertexAttribPointer(4, 3, gl.FLOAT, 117 | false, stride, 118 | subarr.byteLength 119 | ); 120 | gl.enableVertexAttribArray(4); 121 | } 122 | } 123 | /* 124 | map vertex attributes to shader 125 | */ 126 | map_vertex_attrib_to_shader(gl, shaderProgram) { 127 | let vsize = this.vertices[0].size(); 128 | if (vsize >= 5) { 129 | gl.bindAttribLocation(shaderProgram, 0, 'aPos'); 130 | gl.bindAttribLocation(shaderProgram, 1, 'aTexCoord'); 131 | } 132 | if (vsize >= 8) { 133 | // set normals 134 | gl.bindAttribLocation(shaderProgram, 2, 'aNormal'); 135 | } 136 | if (vsize === 14) { 137 | // set tangent and bitangent 138 | gl.bindAttribLocation(shaderProgram, 3, 'aTan'); 139 | gl.bindAttribLocation(shaderProgram, 4, 'aBiTan'); 140 | } 141 | //Set the attributes in the vertex shader to the same indices 142 | //Since the attribute indices have changed, we must re-link the shader 143 | //Note that this will reset all uniforms that were previously set. 144 | shaderProgram.link_program(gl); 145 | this.load_uniforms(gl, shaderProgram); 146 | } 147 | activate_textures(gl, shaderProgram) { 148 | // bind textures 149 | let diffuseNb = 1; 150 | let specularNb = 1; 151 | let normalNb = 1; 152 | let heightNb = 1; 153 | let dispNb = 1; 154 | let aoNb = 1; 155 | let roughNb = 1; 156 | let metalNb = 1; 157 | let albedoNb = 1; 158 | for (var i = 0; i < this.textures.length; i++) { 159 | let gflag = textures[i].flag; 160 | gl.activeTexture(gflag); 161 | let nb = null; 162 | let ttype = textures[i].type; 163 | let tname = textures[i].name; 164 | if (ttype === TEXTURE_TYPE["DIFFUSE"]) { 165 | diffuseNb++; 166 | nb = diffuseNb.toString(); 167 | } else if (ttype === TEXTURE_TYPE["SPECULAR"]) { 168 | specularNb++; 169 | nb = specularNb.toString(); 170 | } else if (ttype === TEXTURE_TYPE["NORMAL"]) { 171 | normalNb++; 172 | nb = normalNb.toString(); 173 | } else if (ttype === TEXTURE_TYPE["HEIGHT"]) { 174 | heightNb++; 175 | nb = heightNb.toString(); 176 | } else if (ttype === TEXTURE_TYPE["DISPLACEMENT"]) { 177 | dispNb++; 178 | nb = heightNb.toString(); 179 | } else if (ttype === TEXTURE_TYPE["AO"]) { 180 | aoNb++; 181 | nb = aoNb.toString(); 182 | } else if (ttype === TEXTURE_TYPE["ROUGHNESS"]) { 183 | roughNb++; 184 | nb = roughNb.toString(); 185 | } else if (ttype === TEXTURE_TYPE["ALBEDO"]) { 186 | albedoNb++; 187 | nb = albedoNb.toString(); 188 | } else if (ttype === TEXTURE_TYPE["METALLIC"]) { 189 | metalNb++; 190 | nb = metalNb.toString(); 191 | } 192 | shaderProgram.set_int_uniform(gl, tname + nb, i); 193 | gl.bindTexture(gl.TEXTURE_2D, textures[i].id); 194 | } 195 | } 196 | } 197 | 198 | class ArrayMesh extends BaseMesh { 199 | constructor(gl, vertices = null, textures = null, indices = null, uniforms = null) { 200 | super(gl, vertices, textures, indices, uniforms); 201 | this.setup_mesh(gl); 202 | } 203 | setup_mesh(gl) { 204 | // create object 205 | this._vao = gl.createVertexArray(); 206 | this._vbo = gl.createBuffer(); 207 | 208 | // bind vertex array object 209 | gl.bindVertexArray(this.vao); 210 | gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo); 211 | check_error(gl); 212 | 213 | // bind buffer data 214 | let arr = this.to_vertex_array(); 215 | gl.bufferData(gl.ARRAY_BUFFER, arr, gl.STATIC_DRAW); 216 | check_error(gl); 217 | 218 | // bind vao values 219 | this.set_vao_values(gl); 220 | check_error(gl); 221 | } 222 | draw(gl, shaderProgram) { 223 | // this.activate_textures(); 224 | shaderProgram.activate(gl); 225 | this.load_uniforms(gl, shaderProgram); 226 | gl.bindVertexArray(this.vao); 227 | 228 | gl.drawArrays(gl.TRIANGLES, 0, this.vertices.length); 229 | gl.bindVertexArray(null); 230 | gl.activeTexture(gl.TEXTURE0); 231 | 232 | } 233 | } 234 | 235 | class Mesh extends BaseMesh { 236 | constructor(gl, vertices = null, textures = null, indices = null, uniforms = null) { 237 | super(gl, vertices, textures, indices, uniforms); 238 | this._ebo = null; 239 | this.setup_mesh(gl); 240 | } 241 | 242 | get ebo() { 243 | if (this._ebo === null) { 244 | throw "element buffer object null"; 245 | } 246 | return this._ebo; 247 | } 248 | setup_mesh(gl) { 249 | // create object 250 | this._vao = gl.createVertexArray(); 251 | this._vbo = gl.createBuffer(); 252 | this._ebo = gl.createBuffer(); 253 | 254 | // bind vertex array object 255 | gl.bindVertexArray(this.vao); 256 | gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo); 257 | check_error(gl); 258 | 259 | // bind buffer data 260 | let arr = this.to_vertex_array(); 261 | gl.bufferData(gl.ARRAY_BUFFER, arr, gl.STATIC_DRAW); 262 | check_error(gl); 263 | 264 | // bind index buffer 265 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.ebo); 266 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); 267 | check_error(gl); 268 | 269 | // bind vao values 270 | this.set_vao_values(gl); 271 | check_error(gl); 272 | } 273 | draw(gl, shaderProgram) { 274 | // bind textures 275 | this.activate_textures(gl, shaderProgram); 276 | 277 | gl.bindVertexArray(this.vao); 278 | gl.drawElements(gl.TRIANGLES, this.indices.length, gl.UNSIGNED_INT, 0); 279 | 280 | // 281 | gl.bindVertexArray(null); 282 | gl.activeTexture(gl.TEXTURE0); 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 |
10 | 11 |
12 | 13 |
14 | 15 | 16 | 17 | 18 |
19 |
20 | 21 |
22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 44 | 58 | 68 | 89 | 174 | 175 | 306 | 307 | 308 | 309 | -------------------------------------------------------------------------------- /assets/js/objloader.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // my obj parser inspired from 3 | // https://github.com/Bly7/OBJ-Loader/blob/master/Source/OBJ_Loader.h 4 | 5 | // some utility functions 6 | 7 | // Projection Calculation of a onto b 8 | function ProjV3(a, b) { 9 | let bn = b / glMatrix.vec3.length(b); 10 | return bn * glMatrix.vec3.dot(a, bn); 11 | } 12 | 13 | function GenTriNormal(t1, t2, t3) { 14 | 15 | let u = t2 - t1; 16 | let v = t3 - t1; 17 | let norm = glMatrix.vec3.cross(u, v); 18 | return norm; 19 | } 20 | 21 | function SameSide(p1, p2, a, b) { 22 | let cp1 = glMatrix.vec3.cross(b - a, p1 - a); 23 | let cp2 = glMatrix.vec3.cross(b - a, p2 - a); 24 | 25 | if (glMatrix.vec3.dot(cp1, cp2) >= 0) { 26 | return true; 27 | } else { 28 | return false; 29 | } 30 | } 31 | 32 | function inTriangle(point, tri1, tri2, tri3) { 33 | let within_tri_prisim = SameSide(point, tri1, tri2, tri3) && SameSide(point, tri2, tri1, tri3) && 34 | SameSide(point, tri3, tri1, tri2); 35 | 36 | // If it isn't it will never be on the triangle 37 | if (!within_tri_prisim) { 38 | return false; 39 | } 40 | 41 | // Calulate Triangle's Normal 42 | let n = GenTriNormal(tri1, tri2, tri3); 43 | 44 | // Project the point onto this normal 45 | let proj = ProjV3(point, n); 46 | 47 | // If the distance from the triangle to the point is 0 48 | // it lies on the triangle 49 | if (glMatrix.vec3.length(proj) === 0) { 50 | return true; 51 | } else { 52 | return false; 53 | } 54 | } 55 | 56 | // 57 | 58 | 59 | class ObjMaterial { 60 | // Material Name 61 | _name = null; 62 | // Ambient Color 63 | _Ka = null; 64 | // Diffuse Color 65 | _Kd = null; 66 | // Specular Color 67 | _Ks = null; 68 | // Specular Exponent 69 | _Ns = null; 70 | // Optical Density 71 | _Ni = null; 72 | // Dissolve 73 | _d = null; 74 | // Illumination 75 | _illum = null; 76 | // Ambient Texture Map 77 | _map_Ka = null; 78 | // Diffuse Texture Map 79 | _map_Kd = null; 80 | // Specular Texture Map 81 | _map_Ks = null; 82 | // Specular Hightlight Map 83 | _map_Ns = null; 84 | // Alpha Texture Map 85 | _map_d = null; 86 | // Bump Map 87 | _map_bump = null; 88 | 89 | constructor() { 90 | this.Ns = 0.0; 91 | this.Ni = 0.0; 92 | this.d = 0.0; 93 | this.illum = 0; 94 | } 95 | get name() { 96 | if (this._name === null || typeof this._name !== "string") { 97 | throw "name is null or it is not a string"; 98 | } 99 | return this._name; 100 | } 101 | set name(s) { 102 | if (typeof s !== "string") { 103 | throw "argument is not a string"; 104 | } 105 | this._name = s; 106 | } 107 | get Ka() { 108 | if (this._Ka === null) { 109 | throw "Ka is null"; 110 | } 111 | return this._Ka; 112 | } 113 | get Kd() { 114 | if (this._Kd === null) { 115 | throw "Kd is null"; 116 | } 117 | return this._Kd; 118 | } 119 | get Ks() { 120 | if (this._Ks === null) { 121 | throw "Ks is null"; 122 | } 123 | return this._Ks; 124 | } 125 | get Ns() { 126 | if (this._Ns === null || typeof this._Ns !== "number") { 127 | throw "Ns is null or it is not a number"; 128 | } 129 | return this._Ns; 130 | } 131 | set Ns(s) { 132 | if (typeof s !== "number") { 133 | throw "argument is not a number"; 134 | } 135 | this._Ns = s; 136 | } 137 | 138 | get Ni() { 139 | if (this._Ni === null || typeof this._Ni !== "number") { 140 | throw "Ni is null or it is not a number"; 141 | } 142 | return this._Ni; 143 | } 144 | set Ni(s) { 145 | if (typeof s !== "number") { 146 | throw "argument is not a number"; 147 | } 148 | this._Ni = s; 149 | } 150 | get d() { 151 | if (this._d === null || typeof this._d !== "number") { 152 | throw "d is null or it is not a number"; 153 | } 154 | return this._d; 155 | } 156 | set d(s) { 157 | if (typeof s !== "number") { 158 | throw "argument is not a number"; 159 | } 160 | this._d = s; 161 | } 162 | get illum() { 163 | if (this._illum === null || typeof this._illum !== "number") { 164 | throw "illum is null or it is not a number"; 165 | } 166 | return this._illum; 167 | } 168 | set illum(s) { 169 | if (typeof s !== "number") { 170 | throw "argument is not a number"; 171 | } 172 | this._illum = s; 173 | } 174 | get map_Ka() { 175 | if (this._map_Ka === null || typeof this._map_Ka !== "string") { 176 | throw "map_Ka is null or it is not string"; 177 | } 178 | return this._map_Ka; 179 | } 180 | set map_Ka(s) { 181 | if (typeof s !== "string") { 182 | throw "argument is not a string"; 183 | } 184 | this._map_Ka = s; 185 | } 186 | get map_Kd() { 187 | if (this._map_Kd === null || typeof this._map_Kd !== "string") { 188 | throw "map_Kd is null or it is not string"; 189 | } 190 | return this._map_Kd; 191 | } 192 | set map_Kd(s) { 193 | if (typeof s !== "string") { 194 | throw "argument is not a string"; 195 | } 196 | this._map_Kd = s; 197 | } 198 | get map_Ks() { 199 | if (this._map_Ks === null || typeof this._map_Ks !== "string") { 200 | throw "map_Ks is null or it is not string"; 201 | } 202 | return this._map_Ks; 203 | } 204 | set map_Ks(s) { 205 | if (typeof s !== "string") { 206 | throw "argument is not a string"; 207 | } 208 | this._map_Ks = s; 209 | } 210 | get map_Ns() { 211 | if (this._map_Ns === null || typeof this._map_Na !== "string") { 212 | throw "map_Ns is null or it is not string"; 213 | } 214 | return this._map_Ns; 215 | } 216 | set map_Ns(s) { 217 | if (typeof s !== "string") { 218 | throw "argument is not a string"; 219 | } 220 | this._map_Ns = s; 221 | } 222 | get map_d() { 223 | if (this._map_d === null || typeof this._map_d !== "string") { 224 | throw "map_d is null or it is not string"; 225 | } 226 | return this._map_d; 227 | } 228 | set map_d(s) { 229 | if (typeof s !== "string") { 230 | throw "argument is not a string"; 231 | } 232 | this._map_d = s; 233 | } 234 | get map_bump() { 235 | if (this._map_bump === null || typeof this._map_bump !== "string") { 236 | throw "map_bump is null or it is not string"; 237 | } 238 | return this._map_bump; 239 | } 240 | set map_bump(s) { 241 | if (typeof s !== "string") { 242 | throw "argument is not a string"; 243 | } 244 | this._map_bump = s; 245 | } 246 | } 247 | 248 | class ObjMesh { 249 | constructor(vertices = null, indices = null) { 250 | this._vertices = vertices; 251 | this._indices = vertices; 252 | this._mesh_name = null; 253 | this._material = null; // ObjMaterial 254 | } 255 | set mesh_name(s) { 256 | this._mesh_name = s; 257 | } 258 | get mesh_name() { 259 | if (this._mesh_name === null) { 260 | throw "mesh name null"; 261 | } 262 | return this._mesh_name; 263 | } 264 | } 265 | 266 | class ObjLoader { 267 | constructor(obj_text) { 268 | this.text = obj_text 269 | } 270 | load_text() { 271 | let LoadedMeshes = []; 272 | let LoadedVertices = []; 273 | let LoadedIndices = []; 274 | let Positions = []; 275 | let TCoords = []; 276 | let Normals = []; 277 | 278 | let Vertices = []; 279 | let Indices = []; 280 | 281 | let MeshMatNames = []; 282 | 283 | let listening = false; 284 | let meshname = null; 285 | let tempmesh = null; 286 | 287 | // split text into lines 288 | var lines = this.text.split(/\r\n|\n\r|\n|\r/); 289 | for (const index in lines) { 290 | let line = lines[index]; 291 | let ftoken = firstToken(line); 292 | 293 | // Generate a Mesh Object or Prepare for an object to be created 294 | if (ftoken === "o" || ftoken === "g" || line[0] === "g") { 295 | if (!listening) { 296 | listening = true; 297 | if (ftoken === "o" || ftoken === "g") { 298 | meshname = tail_str(line); 299 | } else { 300 | meshname = "unnamed"; 301 | } 302 | } else { 303 | if (Vertices.length !== 0 && Indices.length !== 0) { 304 | 305 | // create mesh 306 | tempmesh = new ObjMesh(Vertices, Indices); 307 | tempmesh.mesh_name = meshname; 308 | 309 | // insert mesh 310 | LoadedMeshes.push(tempmesh); 311 | 312 | // Cleanup 313 | Vertices = []; 314 | Indices = []; 315 | meshname = null; 316 | 317 | meshname = tail_str(line); 318 | } else { 319 | // 320 | if (firstToken(line) === "o" || firstToken(line) === "g") { 321 | meshname = tail_str(curline); 322 | } else { 323 | meshname = "unnamed"; 324 | } 325 | } 326 | 327 | } 328 | } 329 | // Generate a Vertex Position 330 | if (firstToken(line) === "v") { 331 | let spos = []; 332 | let vpos = glMatrix.vec3.create(); 333 | let line_tail = tail_str(line); 334 | spos = line_tail.split(" "); 335 | glMatrix.vec3.set(vpos, parseFloat(spos[0]), 336 | parseFloat(spos[1]), 337 | parseFloat(spos[2])); 338 | 339 | Positions.push(vpos); 340 | } 341 | // Generate a Vertex Texture Coordinate 342 | if (firstToken(line) == "vt") { 343 | let vtex = glMatrix.vec2.create(); 344 | 345 | let line_tail = tail_str(line); 346 | let stex = line_tail.split(" "); 347 | 348 | glMatrix.vec2.set(vtex, parseFloat(stex[0]), 349 | parseFloat(stex[1])); 350 | 351 | TCoords.push(vtex); 352 | } 353 | // Generate a Vertex Normal; 354 | if (firstToken(line) == "vn") { 355 | let vnor = glMatrix.vec3.create(); 356 | 357 | let line_tail = tail_str(line); 358 | let snor = line_tail.split(" "); 359 | 360 | glMatrix.vec3.set(vnor, parseFloat(snor[0]), 361 | parseFloat(snor[1]), 362 | parseFloat(snor[2])); 363 | Normals.push(vnor); 364 | } 365 | //https://github.com/Bly7/OBJ-Loader/blob/03b06bf50bca2953a0ccd2d2ba373b27f46eecf2/Source/OBJ_Loader.h#L576 366 | // Generate a Face (vertices & indices) 367 | } 368 | } 369 | } 370 | -------------------------------------------------------------------------------- /assets/libs/gl-matrix.js: -------------------------------------------------------------------------------- 1 | /*! 2 | @fileoverview gl-matrix - High performance matrix and vector operations 3 | @author Brandon Jones 4 | @author Colin MacKenzie IV 5 | @version 3.3.0 6 | 7 | Copyright (c) 2015-2020, Brandon Jones, Colin MacKenzie IV. 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | 27 | */ 28 | !function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).glMatrix={})}(this,(function(t){"use strict";var n=1e-6,a="undefined"!=typeof Float32Array?Float32Array:Array,r=Math.random;var u=Math.PI/180;Math.hypot||(Math.hypot=function(){for(var t=0,n=arguments.length;n--;)t+=arguments[n]*arguments[n];return Math.sqrt(t)});var e=Object.freeze({__proto__:null,EPSILON:n,get ARRAY_TYPE(){return a},RANDOM:r,setMatrixArrayType:function(t){a=t},toRadian:function(t){return t*u},equals:function(t,a){return Math.abs(t-a)<=n*Math.max(1,Math.abs(t),Math.abs(a))}});function o(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],h=a[1],c=a[2],s=a[3];return t[0]=r*i+e*h,t[1]=u*i+o*h,t[2]=r*c+e*s,t[3]=u*c+o*s,t}function i(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t}var h=o,c=i,s=Object.freeze({__proto__:null,create:function(){var t=new a(4);return a!=Float32Array&&(t[1]=0,t[2]=0),t[0]=1,t[3]=1,t},clone:function(t){var n=new a(4);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t},fromValues:function(t,n,r,u){var e=new a(4);return e[0]=t,e[1]=n,e[2]=r,e[3]=u,e},set:function(t,n,a,r,u){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t},transpose:function(t,n){if(t===n){var a=n[1];t[1]=n[2],t[2]=a}else t[0]=n[0],t[1]=n[2],t[2]=n[1],t[3]=n[3];return t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*e-u*r;return o?(o=1/o,t[0]=e*o,t[1]=-r*o,t[2]=-u*o,t[3]=a*o,t):null},adjoint:function(t,n){var a=n[0];return t[0]=n[3],t[1]=-n[1],t[2]=-n[2],t[3]=a,t},determinant:function(t){return t[0]*t[3]-t[2]*t[1]},multiply:o,rotate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),h=Math.cos(a);return t[0]=r*h+e*i,t[1]=u*h+o*i,t[2]=r*-i+e*h,t[3]=u*-i+o*h,t},scale:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],h=a[1];return t[0]=r*i,t[1]=u*i,t[2]=e*h,t[3]=o*h,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=-a,t[3]=r,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=n[1],t},str:function(t){return"mat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3])},LDU:function(t,n,a,r){return t[2]=r[2]/r[0],a[0]=r[0],a[1]=r[1],a[3]=r[3]-t[2]*a[1],[t,n,a]},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t},subtract:i,exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=a[0],h=a[1],c=a[2],s=a[3];return Math.abs(r-i)<=n*Math.max(1,Math.abs(r),Math.abs(i))&&Math.abs(u-h)<=n*Math.max(1,Math.abs(u),Math.abs(h))&&Math.abs(e-c)<=n*Math.max(1,Math.abs(e),Math.abs(c))&&Math.abs(o-s)<=n*Math.max(1,Math.abs(o),Math.abs(s))},multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t},mul:h,sub:c});function M(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],h=n[5],c=a[0],s=a[1],M=a[2],f=a[3],l=a[4],v=a[5];return t[0]=r*c+e*s,t[1]=u*c+o*s,t[2]=r*M+e*f,t[3]=u*M+o*f,t[4]=r*l+e*v+i,t[5]=u*l+o*v+h,t}function f(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t}var l=M,v=f,b=Object.freeze({__proto__:null,create:function(){var t=new a(6);return a!=Float32Array&&(t[1]=0,t[2]=0,t[4]=0,t[5]=0),t[0]=1,t[3]=1,t},clone:function(t){var n=new a(6);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t},fromValues:function(t,n,r,u,e,o){var i=new a(6);return i[0]=t,i[1]=n,i[2]=r,i[3]=u,i[4]=e,i[5]=o,i},set:function(t,n,a,r,u,e,o){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],h=a*e-r*u;return h?(h=1/h,t[0]=e*h,t[1]=-r*h,t[2]=-u*h,t[3]=a*h,t[4]=(u*i-e*o)*h,t[5]=(r*o-a*i)*h,t):null},determinant:function(t){return t[0]*t[3]-t[1]*t[2]},multiply:M,rotate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],h=n[5],c=Math.sin(a),s=Math.cos(a);return t[0]=r*s+e*c,t[1]=u*s+o*c,t[2]=r*-c+e*s,t[3]=u*-c+o*s,t[4]=i,t[5]=h,t},scale:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],h=n[5],c=a[0],s=a[1];return t[0]=r*c,t[1]=u*c,t[2]=e*s,t[3]=o*s,t[4]=i,t[5]=h,t},translate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],h=n[5],c=a[0],s=a[1];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=r*c+e*s+i,t[5]=u*c+o*s+h,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=-a,t[3]=r,t[4]=0,t[5]=0,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=n[1],t[4]=0,t[5]=0,t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=n[0],t[5]=n[1],t},str:function(t){return"mat2d("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3],t[4],t[5],1)},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t},subtract:f,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],h=t[5],c=a[0],s=a[1],M=a[2],f=a[3],l=a[4],v=a[5];return Math.abs(r-c)<=n*Math.max(1,Math.abs(r),Math.abs(c))&&Math.abs(u-s)<=n*Math.max(1,Math.abs(u),Math.abs(s))&&Math.abs(e-M)<=n*Math.max(1,Math.abs(e),Math.abs(M))&&Math.abs(o-f)<=n*Math.max(1,Math.abs(o),Math.abs(f))&&Math.abs(i-l)<=n*Math.max(1,Math.abs(i),Math.abs(l))&&Math.abs(h-v)<=n*Math.max(1,Math.abs(h),Math.abs(v))},mul:l,sub:v});function m(){var t=new a(9);return a!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[5]=0,t[6]=0,t[7]=0),t[0]=1,t[4]=1,t[8]=1,t}function d(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=n[8],f=a[0],l=a[1],v=a[2],b=a[3],m=a[4],d=a[5],x=a[6],p=a[7],y=a[8];return t[0]=f*r+l*o+v*c,t[1]=f*u+l*i+v*s,t[2]=f*e+l*h+v*M,t[3]=b*r+m*o+d*c,t[4]=b*u+m*i+d*s,t[5]=b*e+m*h+d*M,t[6]=x*r+p*o+y*c,t[7]=x*u+p*i+y*s,t[8]=x*e+p*h+y*M,t}function x(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t[6]=n[6]-a[6],t[7]=n[7]-a[7],t[8]=n[8]-a[8],t}var p=d,y=x,q=Object.freeze({__proto__:null,create:m,fromMat4:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[4],t[4]=n[5],t[5]=n[6],t[6]=n[8],t[7]=n[9],t[8]=n[10],t},clone:function(t){var n=new a(9);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n[8]=t[8],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t},fromValues:function(t,n,r,u,e,o,i,h,c){var s=new a(9);return s[0]=t,s[1]=n,s[2]=r,s[3]=u,s[4]=e,s[5]=o,s[6]=i,s[7]=h,s[8]=c,s},set:function(t,n,a,r,u,e,o,i,h,c){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=h,t[8]=c,t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},transpose:function(t,n){if(t===n){var a=n[1],r=n[2],u=n[5];t[1]=n[3],t[2]=n[6],t[3]=a,t[5]=n[7],t[6]=r,t[7]=u}else t[0]=n[0],t[1]=n[3],t[2]=n[6],t[3]=n[1],t[4]=n[4],t[5]=n[7],t[6]=n[2],t[7]=n[5],t[8]=n[8];return t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],h=n[6],c=n[7],s=n[8],M=s*o-i*c,f=-s*e+i*h,l=c*e-o*h,v=a*M+r*f+u*l;return v?(v=1/v,t[0]=M*v,t[1]=(-s*r+u*c)*v,t[2]=(i*r-u*o)*v,t[3]=f*v,t[4]=(s*a-u*h)*v,t[5]=(-i*a+u*e)*v,t[6]=l*v,t[7]=(-c*a+r*h)*v,t[8]=(o*a-r*e)*v,t):null},adjoint:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],h=n[6],c=n[7],s=n[8];return t[0]=o*s-i*c,t[1]=u*c-r*s,t[2]=r*i-u*o,t[3]=i*h-e*s,t[4]=a*s-u*h,t[5]=u*e-a*i,t[6]=e*c-o*h,t[7]=r*h-a*c,t[8]=a*o-r*e,t},determinant:function(t){var n=t[0],a=t[1],r=t[2],u=t[3],e=t[4],o=t[5],i=t[6],h=t[7],c=t[8];return n*(c*e-o*h)+a*(-c*u+o*i)+r*(h*u-e*i)},multiply:d,translate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=n[8],f=a[0],l=a[1];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=i,t[5]=h,t[6]=f*r+l*o+c,t[7]=f*u+l*i+s,t[8]=f*e+l*h+M,t},rotate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=n[8],f=Math.sin(a),l=Math.cos(a);return t[0]=l*r+f*o,t[1]=l*u+f*i,t[2]=l*e+f*h,t[3]=l*o-f*r,t[4]=l*i-f*u,t[5]=l*h-f*e,t[6]=c,t[7]=s,t[8]=M,t},scale:function(t,n,a){var r=a[0],u=a[1];return t[0]=r*n[0],t[1]=r*n[1],t[2]=r*n[2],t[3]=u*n[3],t[4]=u*n[4],t[5]=u*n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=n[0],t[7]=n[1],t[8]=1,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=0,t[3]=-a,t[4]=r,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=0,t[4]=n[1],t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},fromMat2d:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=0,t[3]=n[2],t[4]=n[3],t[5]=0,t[6]=n[4],t[7]=n[5],t[8]=1,t},fromQuat:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a+a,i=r+r,h=u+u,c=a*o,s=r*o,M=r*i,f=u*o,l=u*i,v=u*h,b=e*o,m=e*i,d=e*h;return t[0]=1-M-v,t[3]=s-d,t[6]=f+m,t[1]=s+d,t[4]=1-c-v,t[7]=l-b,t[2]=f-m,t[5]=l+b,t[8]=1-c-M,t},normalFromMat4:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],h=n[6],c=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15],x=a*i-r*o,p=a*h-u*o,y=a*c-e*o,q=r*h-u*i,g=r*c-e*i,_=u*c-e*h,A=s*b-M*v,w=s*m-f*v,z=s*d-l*v,R=M*m-f*b,j=M*d-l*b,P=f*d-l*m,T=x*P-p*j+y*R+q*z-g*w+_*A;return T?(T=1/T,t[0]=(i*P-h*j+c*R)*T,t[1]=(h*z-o*P-c*w)*T,t[2]=(o*j-i*z+c*A)*T,t[3]=(u*j-r*P-e*R)*T,t[4]=(a*P-u*z+e*w)*T,t[5]=(r*z-a*j-e*A)*T,t[6]=(b*_-m*g+d*q)*T,t[7]=(m*y-v*_-d*p)*T,t[8]=(v*g-b*y+d*x)*T,t):null},projection:function(t,n,a){return t[0]=2/n,t[1]=0,t[2]=0,t[3]=0,t[4]=-2/a,t[5]=0,t[6]=-1,t[7]=1,t[8]=1,t},str:function(t){return"mat3("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8])},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t[8]=n[8]+a[8],t},subtract:x,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t[8]=n[8]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t[6]=n[6]+a[6]*r,t[7]=n[7]+a[7]*r,t[8]=n[8]+a[8]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]&&t[8]===n[8]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],h=t[5],c=t[6],s=t[7],M=t[8],f=a[0],l=a[1],v=a[2],b=a[3],m=a[4],d=a[5],x=a[6],p=a[7],y=a[8];return Math.abs(r-f)<=n*Math.max(1,Math.abs(r),Math.abs(f))&&Math.abs(u-l)<=n*Math.max(1,Math.abs(u),Math.abs(l))&&Math.abs(e-v)<=n*Math.max(1,Math.abs(e),Math.abs(v))&&Math.abs(o-b)<=n*Math.max(1,Math.abs(o),Math.abs(b))&&Math.abs(i-m)<=n*Math.max(1,Math.abs(i),Math.abs(m))&&Math.abs(h-d)<=n*Math.max(1,Math.abs(h),Math.abs(d))&&Math.abs(c-x)<=n*Math.max(1,Math.abs(c),Math.abs(x))&&Math.abs(s-p)<=n*Math.max(1,Math.abs(s),Math.abs(p))&&Math.abs(M-y)<=n*Math.max(1,Math.abs(M),Math.abs(y))},mul:p,sub:y});function g(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function _(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=n[8],f=n[9],l=n[10],v=n[11],b=n[12],m=n[13],d=n[14],x=n[15],p=a[0],y=a[1],q=a[2],g=a[3];return t[0]=p*r+y*i+q*M+g*b,t[1]=p*u+y*h+q*f+g*m,t[2]=p*e+y*c+q*l+g*d,t[3]=p*o+y*s+q*v+g*x,p=a[4],y=a[5],q=a[6],g=a[7],t[4]=p*r+y*i+q*M+g*b,t[5]=p*u+y*h+q*f+g*m,t[6]=p*e+y*c+q*l+g*d,t[7]=p*o+y*s+q*v+g*x,p=a[8],y=a[9],q=a[10],g=a[11],t[8]=p*r+y*i+q*M+g*b,t[9]=p*u+y*h+q*f+g*m,t[10]=p*e+y*c+q*l+g*d,t[11]=p*o+y*s+q*v+g*x,p=a[12],y=a[13],q=a[14],g=a[15],t[12]=p*r+y*i+q*M+g*b,t[13]=p*u+y*h+q*f+g*m,t[14]=p*e+y*c+q*l+g*d,t[15]=p*o+y*s+q*v+g*x,t}function A(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=r+r,h=u+u,c=e+e,s=r*i,M=r*h,f=r*c,l=u*h,v=u*c,b=e*c,m=o*i,d=o*h,x=o*c;return t[0]=1-(l+b),t[1]=M+x,t[2]=f-d,t[3]=0,t[4]=M-x,t[5]=1-(s+b),t[6]=v+m,t[7]=0,t[8]=f+d,t[9]=v-m,t[10]=1-(s+l),t[11]=0,t[12]=a[0],t[13]=a[1],t[14]=a[2],t[15]=1,t}function w(t,n){return t[0]=n[12],t[1]=n[13],t[2]=n[14],t}function z(t,n){var a=n[0],r=n[1],u=n[2],e=n[4],o=n[5],i=n[6],h=n[8],c=n[9],s=n[10];return t[0]=Math.hypot(a,r,u),t[1]=Math.hypot(e,o,i),t[2]=Math.hypot(h,c,s),t}function R(t,n){var r=new a(3);z(r,n);var u=1/r[0],e=1/r[1],o=1/r[2],i=n[0]*u,h=n[1]*e,c=n[2]*o,s=n[4]*u,M=n[5]*e,f=n[6]*o,l=n[8]*u,v=n[9]*e,b=n[10]*o,m=i+M+b,d=0;return m>0?(d=2*Math.sqrt(m+1),t[3]=.25*d,t[0]=(f-v)/d,t[1]=(l-c)/d,t[2]=(h-s)/d):i>M&&i>b?(d=2*Math.sqrt(1+i-M-b),t[3]=(f-v)/d,t[0]=.25*d,t[1]=(h+s)/d,t[2]=(l+c)/d):M>b?(d=2*Math.sqrt(1+M-i-b),t[3]=(l-c)/d,t[0]=(h+s)/d,t[1]=.25*d,t[2]=(f+v)/d):(d=2*Math.sqrt(1+b-i-M),t[3]=(h-s)/d,t[0]=(l+c)/d,t[1]=(f+v)/d,t[2]=.25*d),t}function j(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t[6]=n[6]-a[6],t[7]=n[7]-a[7],t[8]=n[8]-a[8],t[9]=n[9]-a[9],t[10]=n[10]-a[10],t[11]=n[11]-a[11],t[12]=n[12]-a[12],t[13]=n[13]-a[13],t[14]=n[14]-a[14],t[15]=n[15]-a[15],t}var P=_,T=j,S=Object.freeze({__proto__:null,create:function(){var t=new a(16);return a!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0),t[0]=1,t[5]=1,t[10]=1,t[15]=1,t},clone:function(t){var n=new a(16);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n[8]=t[8],n[9]=t[9],n[10]=t[10],n[11]=t[11],n[12]=t[12],n[13]=t[13],n[14]=t[14],n[15]=t[15],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],t},fromValues:function(t,n,r,u,e,o,i,h,c,s,M,f,l,v,b,m){var d=new a(16);return d[0]=t,d[1]=n,d[2]=r,d[3]=u,d[4]=e,d[5]=o,d[6]=i,d[7]=h,d[8]=c,d[9]=s,d[10]=M,d[11]=f,d[12]=l,d[13]=v,d[14]=b,d[15]=m,d},set:function(t,n,a,r,u,e,o,i,h,c,s,M,f,l,v,b,m){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=h,t[8]=c,t[9]=s,t[10]=M,t[11]=f,t[12]=l,t[13]=v,t[14]=b,t[15]=m,t},identity:g,transpose:function(t,n){if(t===n){var a=n[1],r=n[2],u=n[3],e=n[6],o=n[7],i=n[11];t[1]=n[4],t[2]=n[8],t[3]=n[12],t[4]=a,t[6]=n[9],t[7]=n[13],t[8]=r,t[9]=e,t[11]=n[14],t[12]=u,t[13]=o,t[14]=i}else t[0]=n[0],t[1]=n[4],t[2]=n[8],t[3]=n[12],t[4]=n[1],t[5]=n[5],t[6]=n[9],t[7]=n[13],t[8]=n[2],t[9]=n[6],t[10]=n[10],t[11]=n[14],t[12]=n[3],t[13]=n[7],t[14]=n[11],t[15]=n[15];return t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],h=n[6],c=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15],x=a*i-r*o,p=a*h-u*o,y=a*c-e*o,q=r*h-u*i,g=r*c-e*i,_=u*c-e*h,A=s*b-M*v,w=s*m-f*v,z=s*d-l*v,R=M*m-f*b,j=M*d-l*b,P=f*d-l*m,T=x*P-p*j+y*R+q*z-g*w+_*A;return T?(T=1/T,t[0]=(i*P-h*j+c*R)*T,t[1]=(u*j-r*P-e*R)*T,t[2]=(b*_-m*g+d*q)*T,t[3]=(f*g-M*_-l*q)*T,t[4]=(h*z-o*P-c*w)*T,t[5]=(a*P-u*z+e*w)*T,t[6]=(m*y-v*_-d*p)*T,t[7]=(s*_-f*y+l*p)*T,t[8]=(o*j-i*z+c*A)*T,t[9]=(r*z-a*j-e*A)*T,t[10]=(v*g-b*y+d*x)*T,t[11]=(M*y-s*g-l*x)*T,t[12]=(i*w-o*R-h*A)*T,t[13]=(a*R-r*w+u*A)*T,t[14]=(b*p-v*q-m*x)*T,t[15]=(s*q-M*p+f*x)*T,t):null},adjoint:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],h=n[6],c=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15],x=a*i-r*o,p=a*h-u*o,y=a*c-e*o,q=r*h-u*i,g=r*c-e*i,_=u*c-e*h,A=s*b-M*v,w=s*m-f*v,z=s*d-l*v,R=M*m-f*b,j=M*d-l*b,P=f*d-l*m;return t[0]=i*P-h*j+c*R,t[1]=u*j-r*P-e*R,t[2]=b*_-m*g+d*q,t[3]=f*g-M*_-l*q,t[4]=h*z-o*P-c*w,t[5]=a*P-u*z+e*w,t[6]=m*y-v*_-d*p,t[7]=s*_-f*y+l*p,t[8]=o*j-i*z+c*A,t[9]=r*z-a*j-e*A,t[10]=v*g-b*y+d*x,t[11]=M*y-s*g-l*x,t[12]=i*w-o*R-h*A,t[13]=a*R-r*w+u*A,t[14]=b*p-v*q-m*x,t[15]=s*q-M*p+f*x,t},determinant:function(t){var n=t[0],a=t[1],r=t[2],u=t[3],e=t[4],o=t[5],i=t[6],h=t[7],c=t[8],s=t[9],M=t[10],f=t[11],l=t[12],v=t[13],b=t[14],m=n*o-a*e,d=n*i-r*e,x=a*i-r*o,p=c*v-s*l,y=c*b-M*l,q=s*b-M*v;return h*(n*q-a*y+r*p)-u*(e*q-o*y+i*p)+t[15]*(c*x-s*d+M*m)-f*(l*x-v*d+b*m)},multiply:_,translate:function(t,n,a){var r,u,e,o,i,h,c,s,M,f,l,v,b=a[0],m=a[1],d=a[2];return n===t?(t[12]=n[0]*b+n[4]*m+n[8]*d+n[12],t[13]=n[1]*b+n[5]*m+n[9]*d+n[13],t[14]=n[2]*b+n[6]*m+n[10]*d+n[14],t[15]=n[3]*b+n[7]*m+n[11]*d+n[15]):(r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=n[8],f=n[9],l=n[10],v=n[11],t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=i,t[5]=h,t[6]=c,t[7]=s,t[8]=M,t[9]=f,t[10]=l,t[11]=v,t[12]=r*b+i*m+M*d+n[12],t[13]=u*b+h*m+f*d+n[13],t[14]=e*b+c*m+l*d+n[14],t[15]=o*b+s*m+v*d+n[15]),t},scale:function(t,n,a){var r=a[0],u=a[1],e=a[2];return t[0]=n[0]*r,t[1]=n[1]*r,t[2]=n[2]*r,t[3]=n[3]*r,t[4]=n[4]*u,t[5]=n[5]*u,t[6]=n[6]*u,t[7]=n[7]*u,t[8]=n[8]*e,t[9]=n[9]*e,t[10]=n[10]*e,t[11]=n[11]*e,t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],t},rotate:function(t,a,r,u){var e,o,i,h,c,s,M,f,l,v,b,m,d,x,p,y,q,g,_,A,w,z,R,j,P=u[0],T=u[1],S=u[2],E=Math.hypot(P,T,S);return E0?(r[0]=2*(h*i+M*u+c*o-s*e)/f,r[1]=2*(c*i+M*e+s*u-h*o)/f,r[2]=2*(s*i+M*o+h*e-c*u)/f):(r[0]=2*(h*i+M*u+c*o-s*e),r[1]=2*(c*i+M*e+s*u-h*o),r[2]=2*(s*i+M*o+h*e-c*u)),A(t,n,r),t},getTranslation:w,getScaling:z,getRotation:R,decompose:function(t,n,a,r){n[0]=r[12],n[1]=r[13],n[2]=r[14];var u=r[0],e=r[1],o=r[2],i=r[4],h=r[5],c=r[6],s=r[8],M=r[9],f=r[10];a[0]=Math.hypot(u,e,o),a[1]=Math.hypot(i,h,c),a[2]=Math.hypot(s,M,f);var l=1/a[0],v=1/a[1],b=1/a[2],m=u*l,d=e*v,x=o*b,p=i*l,y=h*v,q=c*b,g=s*l,_=M*v,A=f*b,w=m+y+A,z=0;return w>0?(z=2*Math.sqrt(w+1),t[3]=.25*z,t[0]=(q-_)/z,t[1]=(g-x)/z,t[2]=(d-p)/z):m>y&&m>A?(z=2*Math.sqrt(1+m-y-A),t[3]=(q-_)/z,t[0]=.25*z,t[1]=(d+p)/z,t[2]=(g+x)/z):y>A?(z=2*Math.sqrt(1+y-m-A),t[3]=(g-x)/z,t[0]=(d+p)/z,t[1]=.25*z,t[2]=(q+_)/z):(z=2*Math.sqrt(1+A-m-y),t[3]=(d-p)/z,t[0]=(g+x)/z,t[1]=(q+_)/z,t[2]=.25*z),t},fromRotationTranslationScale:function(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=n[3],h=u+u,c=e+e,s=o+o,M=u*h,f=u*c,l=u*s,v=e*c,b=e*s,m=o*s,d=i*h,x=i*c,p=i*s,y=r[0],q=r[1],g=r[2];return t[0]=(1-(v+m))*y,t[1]=(f+p)*y,t[2]=(l-x)*y,t[3]=0,t[4]=(f-p)*q,t[5]=(1-(M+m))*q,t[6]=(b+d)*q,t[7]=0,t[8]=(l+x)*g,t[9]=(b-d)*g,t[10]=(1-(M+v))*g,t[11]=0,t[12]=a[0],t[13]=a[1],t[14]=a[2],t[15]=1,t},fromRotationTranslationScaleOrigin:function(t,n,a,r,u){var e=n[0],o=n[1],i=n[2],h=n[3],c=e+e,s=o+o,M=i+i,f=e*c,l=e*s,v=e*M,b=o*s,m=o*M,d=i*M,x=h*c,p=h*s,y=h*M,q=r[0],g=r[1],_=r[2],A=u[0],w=u[1],z=u[2],R=(1-(b+d))*q,j=(l+y)*q,P=(v-p)*q,T=(l-y)*g,S=(1-(f+d))*g,E=(m+x)*g,O=(v+p)*_,D=(m-x)*_,F=(1-(f+b))*_;return t[0]=R,t[1]=j,t[2]=P,t[3]=0,t[4]=T,t[5]=S,t[6]=E,t[7]=0,t[8]=O,t[9]=D,t[10]=F,t[11]=0,t[12]=a[0]+A-(R*A+T*w+O*z),t[13]=a[1]+w-(j*A+S*w+D*z),t[14]=a[2]+z-(P*A+E*w+F*z),t[15]=1,t},fromQuat:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a+a,i=r+r,h=u+u,c=a*o,s=r*o,M=r*i,f=u*o,l=u*i,v=u*h,b=e*o,m=e*i,d=e*h;return t[0]=1-M-v,t[1]=s+d,t[2]=f-m,t[3]=0,t[4]=s-d,t[5]=1-c-v,t[6]=l+b,t[7]=0,t[8]=f+m,t[9]=l-b,t[10]=1-c-M,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},frustum:function(t,n,a,r,u,e,o){var i=1/(a-n),h=1/(u-r),c=1/(e-o);return t[0]=2*e*i,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=2*e*h,t[6]=0,t[7]=0,t[8]=(a+n)*i,t[9]=(u+r)*h,t[10]=(o+e)*c,t[11]=-1,t[12]=0,t[13]=0,t[14]=o*e*2*c,t[15]=0,t},perspective:function(t,n,a,r,u){var e,o=1/Math.tan(n/2);return t[0]=o/a,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=o,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=-1,t[12]=0,t[13]=0,t[15]=0,null!=u&&u!==1/0?(e=1/(r-u),t[10]=(u+r)*e,t[14]=2*u*r*e):(t[10]=-1,t[14]=-2*r),t},perspectiveFromFieldOfView:function(t,n,a,r){var u=Math.tan(n.upDegrees*Math.PI/180),e=Math.tan(n.downDegrees*Math.PI/180),o=Math.tan(n.leftDegrees*Math.PI/180),i=Math.tan(n.rightDegrees*Math.PI/180),h=2/(o+i),c=2/(u+e);return t[0]=h,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=c,t[6]=0,t[7]=0,t[8]=-(o-i)*h*.5,t[9]=(u-e)*c*.5,t[10]=r/(a-r),t[11]=-1,t[12]=0,t[13]=0,t[14]=r*a/(a-r),t[15]=0,t},ortho:function(t,n,a,r,u,e,o){var i=1/(n-a),h=1/(r-u),c=1/(e-o);return t[0]=-2*i,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=-2*h,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=2*c,t[11]=0,t[12]=(n+a)*i,t[13]=(u+r)*h,t[14]=(o+e)*c,t[15]=1,t},lookAt:function(t,a,r,u){var e,o,i,h,c,s,M,f,l,v,b=a[0],m=a[1],d=a[2],x=u[0],p=u[1],y=u[2],q=r[0],_=r[1],A=r[2];return Math.abs(b-q)0&&(s*=l=1/Math.sqrt(l),M*=l,f*=l);var v=h*f-c*M,b=c*s-i*f,m=i*M-h*s;return(l=v*v+b*b+m*m)>0&&(v*=l=1/Math.sqrt(l),b*=l,m*=l),t[0]=v,t[1]=b,t[2]=m,t[3]=0,t[4]=M*m-f*b,t[5]=f*v-s*m,t[6]=s*b-M*v,t[7]=0,t[8]=s,t[9]=M,t[10]=f,t[11]=0,t[12]=u,t[13]=e,t[14]=o,t[15]=1,t},str:function(t){return"mat4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+", "+t[9]+", "+t[10]+", "+t[11]+", "+t[12]+", "+t[13]+", "+t[14]+", "+t[15]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15])},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t[8]=n[8]+a[8],t[9]=n[9]+a[9],t[10]=n[10]+a[10],t[11]=n[11]+a[11],t[12]=n[12]+a[12],t[13]=n[13]+a[13],t[14]=n[14]+a[14],t[15]=n[15]+a[15],t},subtract:j,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t[8]=n[8]*a,t[9]=n[9]*a,t[10]=n[10]*a,t[11]=n[11]*a,t[12]=n[12]*a,t[13]=n[13]*a,t[14]=n[14]*a,t[15]=n[15]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t[6]=n[6]+a[6]*r,t[7]=n[7]+a[7]*r,t[8]=n[8]+a[8]*r,t[9]=n[9]+a[9]*r,t[10]=n[10]+a[10]*r,t[11]=n[11]+a[11]*r,t[12]=n[12]+a[12]*r,t[13]=n[13]+a[13]*r,t[14]=n[14]+a[14]*r,t[15]=n[15]+a[15]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]&&t[8]===n[8]&&t[9]===n[9]&&t[10]===n[10]&&t[11]===n[11]&&t[12]===n[12]&&t[13]===n[13]&&t[14]===n[14]&&t[15]===n[15]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],h=t[5],c=t[6],s=t[7],M=t[8],f=t[9],l=t[10],v=t[11],b=t[12],m=t[13],d=t[14],x=t[15],p=a[0],y=a[1],q=a[2],g=a[3],_=a[4],A=a[5],w=a[6],z=a[7],R=a[8],j=a[9],P=a[10],T=a[11],S=a[12],E=a[13],O=a[14],D=a[15];return Math.abs(r-p)<=n*Math.max(1,Math.abs(r),Math.abs(p))&&Math.abs(u-y)<=n*Math.max(1,Math.abs(u),Math.abs(y))&&Math.abs(e-q)<=n*Math.max(1,Math.abs(e),Math.abs(q))&&Math.abs(o-g)<=n*Math.max(1,Math.abs(o),Math.abs(g))&&Math.abs(i-_)<=n*Math.max(1,Math.abs(i),Math.abs(_))&&Math.abs(h-A)<=n*Math.max(1,Math.abs(h),Math.abs(A))&&Math.abs(c-w)<=n*Math.max(1,Math.abs(c),Math.abs(w))&&Math.abs(s-z)<=n*Math.max(1,Math.abs(s),Math.abs(z))&&Math.abs(M-R)<=n*Math.max(1,Math.abs(M),Math.abs(R))&&Math.abs(f-j)<=n*Math.max(1,Math.abs(f),Math.abs(j))&&Math.abs(l-P)<=n*Math.max(1,Math.abs(l),Math.abs(P))&&Math.abs(v-T)<=n*Math.max(1,Math.abs(v),Math.abs(T))&&Math.abs(b-S)<=n*Math.max(1,Math.abs(b),Math.abs(S))&&Math.abs(m-E)<=n*Math.max(1,Math.abs(m),Math.abs(E))&&Math.abs(d-O)<=n*Math.max(1,Math.abs(d),Math.abs(O))&&Math.abs(x-D)<=n*Math.max(1,Math.abs(x),Math.abs(D))},mul:P,sub:T});function E(){var t=new a(3);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t}function O(t){var n=t[0],a=t[1],r=t[2];return Math.hypot(n,a,r)}function D(t,n,r){var u=new a(3);return u[0]=t,u[1]=n,u[2]=r,u}function F(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t}function I(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t[2]=n[2]*a[2],t}function L(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t[2]=n[2]/a[2],t}function V(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2];return Math.hypot(a,r,u)}function Q(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2];return a*a+r*r+u*u}function Y(t){var n=t[0],a=t[1],r=t[2];return n*n+a*a+r*r}function k(t,n){var a=n[0],r=n[1],u=n[2],e=a*a+r*r+u*u;return e>0&&(e=1/Math.sqrt(e)),t[0]=n[0]*e,t[1]=n[1]*e,t[2]=n[2]*e,t}function X(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function Z(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[0],i=a[1],h=a[2];return t[0]=u*h-e*i,t[1]=e*o-r*h,t[2]=r*i-u*o,t}var B,N=F,C=I,U=L,W=V,G=Q,H=O,J=Y,K=(B=E(),function(t,n,a,r,u,e){var o,i;for(n||(n=3),a||(a=0),i=r?Math.min(r*n+a,t.length):t.length,o=a;o0&&(o=1/Math.sqrt(o)),t[0]=a*o,t[1]=r*o,t[2]=u*o,t[3]=e*o,t}function bt(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]+t[3]*n[3]}function mt(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=n[3];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t[2]=o+r*(a[2]-o),t[3]=i+r*(a[3]-i),t}function dt(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]}function xt(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=a[0],h=a[1],c=a[2],s=a[3];return Math.abs(r-i)<=n*Math.max(1,Math.abs(r),Math.abs(i))&&Math.abs(u-h)<=n*Math.max(1,Math.abs(u),Math.abs(h))&&Math.abs(e-c)<=n*Math.max(1,Math.abs(e),Math.abs(c))&&Math.abs(o-s)<=n*Math.max(1,Math.abs(o),Math.abs(s))}var pt=ot,yt=it,qt=ht,gt=st,_t=Mt,At=ft,wt=lt,zt=function(){var t=tt();return function(n,a,r,u,e,o){var i,h;for(a||(a=4),r||(r=0),h=u?Math.min(u*a+r,n.length):n.length,i=r;i=1);do{h=(e=2*r()-1)*e+(o=2*r()-1)*o}while(h>=1);var c=Math.sqrt((1-i)/h);return t[0]=n*a,t[1]=n*u,t[2]=n*e*c,t[3]=n*o*c,t},transformMat4:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3];return t[0]=a[0]*r+a[4]*u+a[8]*e+a[12]*o,t[1]=a[1]*r+a[5]*u+a[9]*e+a[13]*o,t[2]=a[2]*r+a[6]*u+a[10]*e+a[14]*o,t[3]=a[3]*r+a[7]*u+a[11]*e+a[15]*o,t},transformQuat:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[0],i=a[1],h=a[2],c=a[3],s=c*r+i*e-h*u,M=c*u+h*r-o*e,f=c*e+o*u-i*r,l=-o*r-i*u-h*e;return t[0]=s*c+l*-o+M*-h-f*-i,t[1]=M*c+l*-i+f*-o-s*-h,t[2]=f*c+l*-h+s*-i-M*-o,t[3]=n[3],t},zero:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=0,t},str:function(t){return"vec4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},exactEquals:dt,equals:xt,sub:pt,mul:yt,div:qt,dist:gt,sqrDist:_t,len:At,sqrLen:wt,forEach:zt});function jt(){var t=new a(4);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t[3]=1,t}function Pt(t,n,a){a*=.5;var r=Math.sin(a);return t[0]=r*n[0],t[1]=r*n[1],t[2]=r*n[2],t[3]=Math.cos(a),t}function Tt(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],h=a[1],c=a[2],s=a[3];return t[0]=r*s+o*i+u*c-e*h,t[1]=u*s+o*h+e*i-r*c,t[2]=e*s+o*c+r*h-u*i,t[3]=o*s-r*i-u*h-e*c,t}function St(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),h=Math.cos(a);return t[0]=r*h+o*i,t[1]=u*h+e*i,t[2]=e*h-u*i,t[3]=o*h-r*i,t}function Et(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),h=Math.cos(a);return t[0]=r*h-e*i,t[1]=u*h+o*i,t[2]=e*h+r*i,t[3]=o*h-u*i,t}function Ot(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),h=Math.cos(a);return t[0]=r*h+u*i,t[1]=u*h-r*i,t[2]=e*h+o*i,t[3]=o*h-e*i,t}function Dt(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=Math.sqrt(a*a+r*r+u*u),i=Math.exp(e),h=o>0?i*Math.sin(o)/o:0;return t[0]=a*h,t[1]=r*h,t[2]=u*h,t[3]=i*Math.cos(o),t}function Ft(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=Math.sqrt(a*a+r*r+u*u),i=o>0?Math.atan2(o,e)/o:0;return t[0]=a*i,t[1]=r*i,t[2]=u*i,t[3]=.5*Math.log(a*a+r*r+u*u+e*e),t}function It(t,a,r,u){var e,o,i,h,c,s=a[0],M=a[1],f=a[2],l=a[3],v=r[0],b=r[1],m=r[2],d=r[3];return(o=s*v+M*b+f*m+l*d)<0&&(o=-o,v=-v,b=-b,m=-m,d=-d),1-o>n?(e=Math.acos(o),i=Math.sin(e),h=Math.sin((1-u)*e)/i,c=Math.sin(u*e)/i):(h=1-u,c=u),t[0]=h*s+c*v,t[1]=h*M+c*b,t[2]=h*f+c*m,t[3]=h*l+c*d,t}function Lt(t,n){var a,r=n[0]+n[4]+n[8];if(r>0)a=Math.sqrt(r+1),t[3]=.5*a,a=.5/a,t[0]=(n[5]-n[7])*a,t[1]=(n[6]-n[2])*a,t[2]=(n[1]-n[3])*a;else{var u=0;n[4]>n[0]&&(u=1),n[8]>n[3*u+u]&&(u=2);var e=(u+1)%3,o=(u+2)%3;a=Math.sqrt(n[3*u+u]-n[3*e+e]-n[3*o+o]+1),t[u]=.5*a,a=.5/a,t[3]=(n[3*e+o]-n[3*o+e])*a,t[e]=(n[3*e+u]+n[3*u+e])*a,t[o]=(n[3*o+u]+n[3*u+o])*a}return t}var Vt,Qt,Yt,kt,Xt,Zt,Bt=nt,Nt=at,Ct=rt,Ut=ut,Wt=et,Gt=Tt,Ht=ct,Jt=bt,Kt=mt,$t=ft,tn=$t,nn=lt,an=nn,rn=vt,un=dt,en=xt,on=(Vt=E(),Qt=D(1,0,0),Yt=D(0,1,0),function(t,n,a){var r=X(n,a);return r<-.999999?(Z(Vt,Qt,n),H(Vt)<1e-6&&Z(Vt,Yt,n),k(Vt,Vt),Pt(t,Vt,Math.PI),t):r>.999999?(t[0]=0,t[1]=0,t[2]=0,t[3]=1,t):(Z(Vt,n,a),t[0]=Vt[0],t[1]=Vt[1],t[2]=Vt[2],t[3]=1+r,rn(t,t))}),hn=(kt=jt(),Xt=jt(),function(t,n,a,r,u,e){return It(kt,n,u,e),It(Xt,a,r,e),It(t,kt,Xt,2*e*(1-e)),t}),cn=(Zt=m(),function(t,n,a,r){return Zt[0]=a[0],Zt[3]=a[1],Zt[6]=a[2],Zt[1]=r[0],Zt[4]=r[1],Zt[7]=r[2],Zt[2]=-n[0],Zt[5]=-n[1],Zt[8]=-n[2],rn(t,Lt(t,Zt))}),sn=Object.freeze({__proto__:null,create:jt,identity:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t},setAxisAngle:Pt,getAxisAngle:function(t,a){var r=2*Math.acos(a[3]),u=Math.sin(r/2);return u>n?(t[0]=a[0]/u,t[1]=a[1]/u,t[2]=a[2]/u):(t[0]=1,t[1]=0,t[2]=0),r},getAngle:function(t,n){var a=Jt(t,n);return Math.acos(2*a*a-1)},multiply:Tt,rotateX:St,rotateY:Et,rotateZ:Ot,calculateW:function(t,n){var a=n[0],r=n[1],u=n[2];return t[0]=a,t[1]=r,t[2]=u,t[3]=Math.sqrt(Math.abs(1-a*a-r*r-u*u)),t},exp:Dt,ln:Ft,pow:function(t,n,a){return Ft(t,n),Ht(t,t,a),Dt(t,t),t},slerp:It,random:function(t){var n=r(),a=r(),u=r(),e=Math.sqrt(1-n),o=Math.sqrt(n);return t[0]=e*Math.sin(2*Math.PI*a),t[1]=e*Math.cos(2*Math.PI*a),t[2]=o*Math.sin(2*Math.PI*u),t[3]=o*Math.cos(2*Math.PI*u),t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*a+r*r+u*u+e*e,i=o?1/o:0;return t[0]=-a*i,t[1]=-r*i,t[2]=-u*i,t[3]=e*i,t},conjugate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=n[3],t},fromMat3:Lt,fromEuler:function(t,n,a,r){var u=arguments.length>4&&void 0!==arguments[4]?arguments[4]:"zyx",e=.5*Math.PI/180;n*=e,r*=e,a*=e;var o=Math.sin(n),i=Math.cos(n),h=Math.sin(a),c=Math.cos(a),s=Math.sin(r),M=Math.cos(r);switch("string"!=typeof u&&(u="zyx"),u.toLowerCase()){case"xyz":t[0]=o*c*M+i*h*s,t[1]=i*h*M-o*c*s,t[2]=i*c*s+o*h*M,t[3]=i*c*M-o*h*s;break;case"xzy":t[0]=o*c*M-i*h*s,t[1]=i*h*M-o*c*s,t[2]=i*c*s+o*h*M,t[3]=i*c*M+o*h*s;break;case"yxz":t[0]=o*c*M+i*h*s,t[1]=i*h*M-o*c*s,t[2]=i*c*s-o*h*M,t[3]=i*c*M+o*h*s;break;case"yzx":t[0]=o*c*M+i*h*s,t[1]=i*h*M+o*c*s,t[2]=i*c*s-o*h*M,t[3]=i*c*M-o*h*s;break;case"zxy":t[0]=o*c*M-i*h*s,t[1]=i*h*M+o*c*s,t[2]=i*c*s+o*h*M,t[3]=i*c*M-o*h*s;break;case"zyx":default:t[0]=o*c*M-i*h*s,t[1]=i*h*M+o*c*s,t[2]=i*c*s-o*h*M,t[3]=i*c*M+o*h*s}return t},str:function(t){return"quat("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},clone:Bt,fromValues:Nt,copy:Ct,set:Ut,add:Wt,mul:Gt,scale:Ht,dot:Jt,lerp:Kt,length:$t,len:tn,squaredLength:nn,sqrLen:an,normalize:rn,exactEquals:un,equals:en,rotationTo:on,sqlerp:hn,setAxes:cn});function Mn(t,n,a){var r=.5*a[0],u=.5*a[1],e=.5*a[2],o=n[0],i=n[1],h=n[2],c=n[3];return t[0]=o,t[1]=i,t[2]=h,t[3]=c,t[4]=r*c+u*h-e*i,t[5]=u*c+e*o-r*h,t[6]=e*c+r*i-u*o,t[7]=-r*o-u*i-e*h,t}function fn(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t}var ln=Ct;var vn=Ct;function bn(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[4],h=a[5],c=a[6],s=a[7],M=n[4],f=n[5],l=n[6],v=n[7],b=a[0],m=a[1],d=a[2],x=a[3];return t[0]=r*x+o*b+u*d-e*m,t[1]=u*x+o*m+e*b-r*d,t[2]=e*x+o*d+r*m-u*b,t[3]=o*x-r*b-u*m-e*d,t[4]=r*s+o*i+u*c-e*h+M*x+v*b+f*d-l*m,t[5]=u*s+o*h+e*i-r*c+f*x+v*m+l*b-M*d,t[6]=e*s+o*c+r*h-u*i+l*x+v*d+M*m-f*b,t[7]=o*s-r*i-u*h-e*c+v*x-M*b-f*m-l*d,t}var mn=bn;var dn=Jt;var xn=$t,pn=xn,yn=nn,qn=yn;var gn=Object.freeze({__proto__:null,create:function(){var t=new a(8);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[4]=0,t[5]=0,t[6]=0,t[7]=0),t[3]=1,t},clone:function(t){var n=new a(8);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n},fromValues:function(t,n,r,u,e,o,i,h){var c=new a(8);return c[0]=t,c[1]=n,c[2]=r,c[3]=u,c[4]=e,c[5]=o,c[6]=i,c[7]=h,c},fromRotationTranslationValues:function(t,n,r,u,e,o,i){var h=new a(8);h[0]=t,h[1]=n,h[2]=r,h[3]=u;var c=.5*e,s=.5*o,M=.5*i;return h[4]=c*u+s*r-M*n,h[5]=s*u+M*t-c*r,h[6]=M*u+c*n-s*t,h[7]=-c*t-s*n-M*r,h},fromRotationTranslation:Mn,fromTranslation:function(t,n){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=.5*n[0],t[5]=.5*n[1],t[6]=.5*n[2],t[7]=0,t},fromRotation:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=0,t[5]=0,t[6]=0,t[7]=0,t},fromMat4:function(t,n){var r=jt();R(r,n);var u=new a(3);return w(u,n),Mn(t,r,u),t},copy:fn,identity:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t[6]=0,t[7]=0,t},set:function(t,n,a,r,u,e,o,i,h){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=h,t},getReal:ln,getDual:function(t,n){return t[0]=n[4],t[1]=n[5],t[2]=n[6],t[3]=n[7],t},setReal:vn,setDual:function(t,n){return t[4]=n[0],t[5]=n[1],t[6]=n[2],t[7]=n[3],t},getTranslation:function(t,n){var a=n[4],r=n[5],u=n[6],e=n[7],o=-n[0],i=-n[1],h=-n[2],c=n[3];return t[0]=2*(a*c+e*o+r*h-u*i),t[1]=2*(r*c+e*i+u*o-a*h),t[2]=2*(u*c+e*h+a*i-r*o),t},translate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=.5*a[0],h=.5*a[1],c=.5*a[2],s=n[4],M=n[5],f=n[6],l=n[7];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=o*i+u*c-e*h+s,t[5]=o*h+e*i-r*c+M,t[6]=o*c+r*h-u*i+f,t[7]=-r*i-u*h-e*c+l,t},rotateX:function(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=i*o+s*r+h*e-c*u,f=h*o+s*u+c*r-i*e,l=c*o+s*e+i*u-h*r,v=s*o-i*r-h*u-c*e;return St(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t},rotateY:function(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=i*o+s*r+h*e-c*u,f=h*o+s*u+c*r-i*e,l=c*o+s*e+i*u-h*r,v=s*o-i*r-h*u-c*e;return Et(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t},rotateZ:function(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=i*o+s*r+h*e-c*u,f=h*o+s*u+c*r-i*e,l=c*o+s*e+i*u-h*r,v=s*o-i*r-h*u-c*e;return Ot(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t},rotateByQuatAppend:function(t,n,a){var r=a[0],u=a[1],e=a[2],o=a[3],i=n[0],h=n[1],c=n[2],s=n[3];return t[0]=i*o+s*r+h*e-c*u,t[1]=h*o+s*u+c*r-i*e,t[2]=c*o+s*e+i*u-h*r,t[3]=s*o-i*r-h*u-c*e,i=n[4],h=n[5],c=n[6],s=n[7],t[4]=i*o+s*r+h*e-c*u,t[5]=h*o+s*u+c*r-i*e,t[6]=c*o+s*e+i*u-h*r,t[7]=s*o-i*r-h*u-c*e,t},rotateByQuatPrepend:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],h=a[1],c=a[2],s=a[3];return t[0]=r*s+o*i+u*c-e*h,t[1]=u*s+o*h+e*i-r*c,t[2]=e*s+o*c+r*h-u*i,t[3]=o*s-r*i-u*h-e*c,i=a[4],h=a[5],c=a[6],s=a[7],t[4]=r*s+o*i+u*c-e*h,t[5]=u*s+o*h+e*i-r*c,t[6]=e*s+o*c+r*h-u*i,t[7]=o*s-r*i-u*h-e*c,t},rotateAroundAxis:function(t,a,r,u){if(Math.abs(u)0){a=Math.sqrt(a);var r=n[0]/a,u=n[1]/a,e=n[2]/a,o=n[3]/a,i=n[4],h=n[5],c=n[6],s=n[7],M=r*i+u*h+e*c+o*s;t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=(i-r*M)/a,t[5]=(h-u*M)/a,t[6]=(c-e*M)/a,t[7]=(s-o*M)/a}return t},str:function(t){return"quat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],h=t[5],c=t[6],s=t[7],M=a[0],f=a[1],l=a[2],v=a[3],b=a[4],m=a[5],d=a[6],x=a[7];return Math.abs(r-M)<=n*Math.max(1,Math.abs(r),Math.abs(M))&&Math.abs(u-f)<=n*Math.max(1,Math.abs(u),Math.abs(f))&&Math.abs(e-l)<=n*Math.max(1,Math.abs(e),Math.abs(l))&&Math.abs(o-v)<=n*Math.max(1,Math.abs(o),Math.abs(v))&&Math.abs(i-b)<=n*Math.max(1,Math.abs(i),Math.abs(b))&&Math.abs(h-m)<=n*Math.max(1,Math.abs(h),Math.abs(m))&&Math.abs(c-d)<=n*Math.max(1,Math.abs(c),Math.abs(d))&&Math.abs(s-x)<=n*Math.max(1,Math.abs(s),Math.abs(x))}});function _n(){var t=new a(2);return a!=Float32Array&&(t[0]=0,t[1]=0),t}function An(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t}function wn(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t}function zn(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t}function Rn(t,n){var a=n[0]-t[0],r=n[1]-t[1];return Math.hypot(a,r)}function jn(t,n){var a=n[0]-t[0],r=n[1]-t[1];return a*a+r*r}function Pn(t){var n=t[0],a=t[1];return Math.hypot(n,a)}function Tn(t){var n=t[0],a=t[1];return n*n+a*a}var Sn=Pn,En=An,On=wn,Dn=zn,Fn=Rn,In=jn,Ln=Tn,Vn=function(){var t=_n();return function(n,a,r,u,e,o){var i,h;for(a||(a=2),r||(r=0),h=u?Math.min(u*a+r,n.length):n.length,i=r;i0&&(u=1/Math.sqrt(u)),t[0]=n[0]*u,t[1]=n[1]*u,t},dot:function(t,n){return t[0]*n[0]+t[1]*n[1]},cross:function(t,n,a){var r=n[0]*a[1]-n[1]*a[0];return t[0]=t[1]=0,t[2]=r,t},lerp:function(t,n,a,r){var u=n[0],e=n[1];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t},random:function(t,n){n=n||1;var a=2*r()*Math.PI;return t[0]=Math.cos(a)*n,t[1]=Math.sin(a)*n,t},transformMat2:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[2]*u,t[1]=a[1]*r+a[3]*u,t},transformMat2d:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[2]*u+a[4],t[1]=a[1]*r+a[3]*u+a[5],t},transformMat3:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[3]*u+a[6],t[1]=a[1]*r+a[4]*u+a[7],t},transformMat4:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[4]*u+a[12],t[1]=a[1]*r+a[5]*u+a[13],t},rotate:function(t,n,a,r){var u=n[0]-a[0],e=n[1]-a[1],o=Math.sin(r),i=Math.cos(r);return t[0]=u*i-e*o+a[0],t[1]=u*o+e*i+a[1],t},angle:function(t,n){var a=t[0],r=t[1],u=n[0],e=n[1],o=Math.sqrt(a*a+r*r)*Math.sqrt(u*u+e*e),i=o&&(a*u+r*e)/o;return Math.acos(Math.min(Math.max(i,-1),1))},zero:function(t){return t[0]=0,t[1]=0,t},str:function(t){return"vec2("+t[0]+", "+t[1]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]},equals:function(t,a){var r=t[0],u=t[1],e=a[0],o=a[1];return Math.abs(r-e)<=n*Math.max(1,Math.abs(r),Math.abs(e))&&Math.abs(u-o)<=n*Math.max(1,Math.abs(u),Math.abs(o))},len:Sn,sub:En,mul:On,div:Dn,dist:Fn,sqrDist:In,sqrLen:Ln,forEach:Vn});t.glMatrix=e,t.mat2=s,t.mat2d=b,t.mat3=q,t.mat4=S,t.quat=sn,t.quat2=gn,t.vec2=Qn,t.vec3=$,t.vec4=Rt,Object.defineProperty(t,"__esModule",{value:!0})})); 29 | --------------------------------------------------------------------------------