diff --git a/.babelrc b/.babelrc deleted file mode 100644 index f9f2a02..0000000 --- a/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "presets": [ "es2015" ] -} \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..87192f4 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,26 @@ +name: CI + +on: + push: + branches: [master] + pull_request: + +permissions: + contents: read + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: npm + - run: npm ci + - run: npm run typecheck + - run: npm run format:check + - run: npx playwright install --with-deps chromium + - run: npm test + - run: npm run build + - run: node examples/node-render.mjs > /dev/null diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..96c81c7 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,46 @@ +name: Release + +on: + push: + tags: ["v*"] + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: npm + - run: npm ci + - run: npm run typecheck + - run: npm run format:check + - run: npx playwright install --with-deps chromium + - run: npm test + - run: npm run build + - uses: actions/upload-pages-artifact@v3 + with: + path: examples/dist + - run: gh release create "$GITHUB_REF_NAME" packages/c3r/dist/*.js packages/c3r-three/dist/*.js --generate-notes + env: + GH_TOKEN: ${{ github.token }} + + deploy: + needs: build + runs-on: ubuntu-latest + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index adb6415..242b7e4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ - -# Dependency directories node_modules/ -package-lock.json \ No newline at end of file +dist/ +__screenshots__/ +.vitest/ diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..2312dc5 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..ba54d1a --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +**/dist/ +package-lock.json +examples/public/ diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/.prettierrc @@ -0,0 +1 @@ +{} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..c83e263 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["esbenp.prettier-vscode"] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9bf4d12 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true +} diff --git a/README.md b/README.md index 544f6c5..994e7f3 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,27 @@ # CSS 3D Renderer -**C3R.js** is a lightweight library for displaying 3D scenes with CSS. It is designed to be used as a CSS3D backend for existing libraries. It provides classes to construct textured polygons, nest 3D transformed elements and handle camera. +Display textured 3D scenes with plain DOM elements and CSS transforms. -## Usage +| Package | Description | +| --------------------------------- | ---------------------------------------------------- | +| [`c3r`](packages/c3r) | The library | +| [`c3r-three`](packages/c3r-three) | three.js renderer (r160+) with geometry and textures | +| [`c3r-examples`](examples) | Standalone and ported three.js examples | -Just include `C3R.standalone.js` to your project, or include both `C3R.min.js` and `glMatrix` +Try the examples live [here](https://k-adam.github.io/CSS3D-Renderer/). -## Examples +## Install -The example projects be found in the *examples* directory. You can try them out live [here](https://k-adam.github.io/CSS3D-Renderer/examples/) +`npm install c3r`, or `npm install c3r-three three` for three.js. Prebuilt files are on [GitHub Releases](https://github.com/K-Adam/CSS3D-Renderer/releases). -I replaced the original CSS3D renderer of Three.js with a **C3R.js** based implementation, which supports buffergeometry and textures as well. It can be found at *examples/js/renderers/CSS3DRenderer.js* +## Development + +Requires Node 24+. The packages are written in TypeScript. + +```sh +npm install +npm run build # packages/*/dist, with type declarations +npm run dev # serve the examples +npm run typecheck # tsc in strict mode, also the linter +npm run format +``` diff --git a/build/C3R.js b/build/C3R.js deleted file mode 100644 index 365250c..0000000 --- a/build/C3R.js +++ /dev/null @@ -1,1262 +0,0 @@ -/** - * @license - * The MIT License - * - * Copyright © 2018 Adam Kecskes - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : - typeof define === 'function' && define.amd ? define(['exports'], factory) : - (factory((global.C3R = {}))); -}(this, (function (exports) { 'use strict'; - - var classCallCheck = function (instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } - }; - - var createClass = function () { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } - } - - return function (Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; - }(); - - var get = function get(object, property, receiver) { - if (object === null) object = Function.prototype; - var desc = Object.getOwnPropertyDescriptor(object, property); - - if (desc === undefined) { - var parent = Object.getPrototypeOf(object); - - if (parent === null) { - return undefined; - } else { - return get(parent, property, receiver); - } - } else if ("value" in desc) { - return desc.value; - } else { - var getter = desc.get; - - if (getter === undefined) { - return undefined; - } - - return getter.call(receiver); - } - }; - - var inherits = function (subClass, superClass) { - if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); - } - - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - enumerable: false, - writable: true, - configurable: true - } - }); - if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; - }; - - var possibleConstructorReturn = function (self, call) { - if (!self) { - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - } - - return call && (typeof call === "object" || typeof call === "function") ? call : self; - }; - - var toConsumableArray = function (arr) { - if (Array.isArray(arr)) { - for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; - - return arr2; - } else { - return Array.from(arr); - } - }; - - var CSSClass = function () { - function CSSClass() { - classCallCheck(this, CSSClass); - - - this.class_name = "c3r-" + CSSClass.id_counter++; - - this.properties = new Map(); - - this.domElement = document.createElement("style"); - } - - createClass(CSSClass, [{ - key: "init", - value: function init() { - document.head.appendChild(this.domElement); - } - }, { - key: "unload", - value: function unload() { - document.head.removeChild(this.domElement); - } - }, { - key: "attach", - value: function attach(elem) { - elem.classList.add(this.class_name); - } - }, { - key: "detach", - value: function detach(elem) { - elem.classList.remove(this.class_name); - } - }, { - key: "setProperty", - value: function setProperty(prop, val) { - this.properties.set(prop, val); - } - }, { - key: "setProperties", - value: function setProperties(props) { - for (var i in props) { - this.setProperty(i, props[i]); - } - } - }, { - key: "update", - value: function update() { - - this.domElement.innerHTML = '.' + this.class_name + '{' + Array.from(this.properties.entries()).map(function (kv) { - return kv.join(':'); - }).join(';') + '}'; - } - }, { - key: "clone", - value: function clone() { - - var cl = new CSSClass(); - cl.properties = new Map(this.properties); - return cl; - } - }]); - return CSSClass; - }(); - - CSSClass.id_counter = 0; - - var Material = function () { - function Material() { - classCallCheck(this, Material); - - - this.backgroundImageSrc = null; - this.backgroundColor = null; // vec4 0-1 - this.opacity = 1.0; - } - - createClass(Material, [{ - key: "apply", - value: function apply(elem) { - - if (this.backgroundImageSrc) { - elem.style.setProperty("--background-image", "url('" + this.backgroundImageSrc + "')"); - } else { - elem.style.removeProperty("--background-image"); - } - - if (this.backgroundColor) { - elem.style.setProperty("--background-color", "rgba(" + [Math.round(this.backgroundColor[0] * 255), Math.round(this.backgroundColor[1] * 255), Math.round(this.backgroundColor[2] * 255), this.backgroundColor[3]].join() + ")"); - } else { - elem.style.removeProperty("--background-color"); - } - - if (this.opacity == 1.0) { - elem.style.removeProperty("--opacity"); - } else { - elem.style.setProperty("--opacity", this.opacity); - } - } - }]); - return Material; - }(); - - var Object3D = function () { - function Object3D() { - classCallCheck(this, Object3D); - - - this.matrix = mat4.create(); - - this.domElement = document.createElement('div'); - - this.material = null; - } - - // set transform property - - - createClass(Object3D, [{ - key: 'updateMatrix', - value: function updateMatrix() { - this.domElement.style.transform = 'matrix3d(' + this.matrix.join() + ')'; - } - }, { - key: 'clearMatrix', - value: function clearMatrix() { - this.matrix = mat4.create(); - this.domElement.style.transform = ""; - } - }, { - key: 'updateMaterial', - value: function updateMaterial() { - if (this.material) { - this.material.apply(this.domElement); - } - } - - // Used in Group and Polygon - - }], [{ - key: 'getCommonAttributes', - value: function getCommonAttributes() { - return { - "position": "absolute", - "display": "block", - - "transform": "matrix3d(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1)", - "transform-origin": "0 0", - - /* disable selection */ - "-webkit-user-select": "none", - "-moz-user-select": "none", - "-ms-user-select": "none", - "user-select": "none", - - /* Prefix still needed for Safari? */ - "-webkit-backface-visibility": "inherit", - "backface-visibility": "inherit" - }; - } - }]); - return Object3D; - }(); - - // 3D triangle, represented by 3 points - var Triangle = function () { - function Triangle(p1, p2, p3, norm) { - classCallCheck(this, Triangle); - - this.p1 = p1; - this.p2 = p2; - this.p3 = p3; - - this.edges = null; - - this.norm = norm ? norm : this.calculateNormal(); - } - - createClass(Triangle, [{ - key: "updateEdges", - value: function updateEdges() { - - if (this.edges) return; - - this.edges = [vec3.sub(vec3.create(), this.p1, this.p2), vec3.sub(vec3.create(), this.p2, this.p3), vec3.sub(vec3.create(), this.p3, this.p1)]; - } - }, { - key: "calculateNormal", - value: function calculateNormal() { - - this.updateEdges(); - - return vec3.normalize(vec3.create(), vec3.cross(vec3.create(), this.edges[0], this.edges[1])); - } - }, { - key: "calculateEdgeLengths", - value: function calculateEdgeLengths() { - return vec3.fromValues(vec3.len(this.edges[0]), vec3.len(this.edges[1]), vec3.len(this.edges[2])); - } - }, { - key: "getTransformationTo", - value: function getTransformationTo(that) { - - var A = mat4.fromValues(this.p1[0], this.p1[1], this.p1[2], 1, this.p2[0], this.p2[1], this.p2[2], 1, this.p3[0], this.p3[1], this.p3[2], 1, this.norm[0], this.norm[1], this.norm[2], 0); - - var B = mat4.fromValues(that.p1[0], that.p1[1], that.p1[2], 1, that.p2[0], that.p2[1], that.p2[2], 1, that.p3[0], that.p3[1], that.p3[2], 1, that.norm[0], that.norm[1], that.norm[2], 0); - - return mat4.mul(mat4.create(), B, mat4.invert(mat4.create(), A)); - } - }]); - return Triangle; - }(); - - var isWebKit = 'WebkitAppearance' in document.documentElement.style; - - var css_mask = CSS.supports("mask-image: var(--background-image, none)"); - var css_webkit_mask = CSS.supports("-webkit-mask-image: var(--background-image, none)"); - - var css_clip_path = CSS.supports("clip-path: polygon(50% 0%, 0% 100%, 100% 100%)"); - var css_webkit_clip_path = CSS.supports("-webkit-clip-path: polygon(50% 0%, 0% 100%, 100% 100%)"); - - var default_dom_size = function default_dom_size(num) { - return Math.max(250, Math.min(num, 1200)); - }; - - var cross2 = function cross2(a, b, o) { - return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]); - }; - - var Polygon = function (_Object3D) { - inherits(Polygon, _Object3D); - - function Polygon(vertices) { - var contentElement = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; - classCallCheck(this, Polygon); - - var _this = possibleConstructorReturn(this, (Polygon.__proto__ || Object.getPrototypeOf(Polygon)).call(this)); - - _this.vertices = vertices; // vertices in CCW - _this.clipPath = []; // path of the polygon on a rectangular element - - _this.simplify(); - - Polygon.getClass().attach(_this.domElement); - - // Base size of the dom element ( in case of a triangle, it will be the length of the longest side) - _this.getDomSize = default_dom_size; - - // Actual size of the dom element - _this.block_width = 0; - _this.block_height = 0; - - // texture / element / etc - _this.contentElement = contentElement ? contentElement : document.createElement('div'); - Polygon.getContentClass().attach(_this.contentElement); - _this.domElement.appendChild(_this.contentElement); - - _this.uv_scale = vec2.fromValues(1, 1); - _this.uv_offset = vec2.fromValues(0, 0); - - // triangle only data - _this.maxi = 0; // Index of the longest side - - return _this; - } - - // remove redundant vertices ( which are on the same line ) - - - createClass(Polygon, [{ - key: 'simplify', - value: function simplify() { - var vertices = [this.vertices[0]]; - - for (var i = 1; i < this.vertices.length; i++) { - - var prev_i = i - 1; - var next_i = (i + 1) % this.vertices.length; - - var p1 = this.vertices[prev_i].position; - var p2 = this.vertices[i].position; - var p3 = this.vertices[next_i].position; - - var e1 = vec3.sub(vec3.create(), p1, p2); - var e2 = vec3.sub(vec3.create(), p2, p3); - - vec3.normalize(e1, e1); - vec3.normalize(e2, e2); - - // Not collinear - if (Math.abs(vec3.dot(e1, e2)) < 0.9999) { - vertices.push(this.vertices[i]); - } - } - - this.vertices = vertices; - } - }, { - key: 'updateMatrix', - value: function updateMatrix() { - - // The first three polygon points should be transformed to this positions - var tri = new Triangle(this.vertices[0].position, this.vertices[1].position, this.vertices[2].position); - - // Faster method for triangles - if (this.vertices.length == 3) { - - // The longest side will be the base - var ln = tri.calculateEdgeLengths(); - - this.maxi = ln.indexOf(Math.max.apply(Math, toConsumableArray(ln))); - - var ai = this.maxi; - var bi = (this.maxi + 1) % 3; - var ci = (this.maxi + 2) % 3; - - var a = ln[ai]; - var b = ln[bi]; - var c = ln[ci]; - - var Ax = -(b * b - c * c - a * a) / (2 * a); - var Ay = Math.sqrt(c * c - Ax * Ax); - - // Where the longest side is split into two by the height-line - var base_split = Ax / a; - - // scale the element, to avoid blurry texture - - var scale_ratio = this.getDomSize(a) / a; - - this.block_width = a * scale_ratio; - this.block_height = Ay * scale_ratio; - // - - this.clipPath = [vec2.fromValues(0, 0), vec2.fromValues(1, 0), vec2.fromValues(base_split, 1)]; - - var tri_v = [vec3.fromValues(0, 0, 0), vec3.fromValues(this.block_width, 0, 0), vec3.fromValues(Ax * scale_ratio, this.block_height, 0)]; - - this.matrix = new Triangle(tri_v[ai], tri_v[bi], tri_v[ci], [0, 0, 1]).getTransformationTo(tri); - } else if (this.vertices.length > 3) { - - ////////////////////////////////////////////// - // Project polygon points to the 2D plane - ////////////////////////////////////////////// - - // get new bases - var b1 = tri.norm; - var b2 = Math.abs(vec3.dot(b1, [0, 0, 1])) < 0.9 ? vec3.cross(vec3.create(), b1, [0, 0, 1]) : vec3.cross(vec3.create(), b1, [0, 1, 0]); - var b3 = vec3.cross(vec3.create(), b2, b1); - - // Base change matrices - var BT = mat3.fromValues(b2[0], b2[1], b2[2], b3[0], b3[1], b3[2], b1[0], b1[1], b1[2]); - - var BTI = mat3.invert(mat3.create(), BT); - - if (BTI === null) { - throw new Error("Degenerate triangle?"); - } - - // Transform points with the matrices - var points2d = this.vertices.map(function (v) { - var pp = vec3.transformMat3(vec3.create(), v.position, BTI); - return pp.slice(0, 2); - }); - - ////////////////////////////////////////////// - // Find convex hull - ////////////////////////////////////////////// - - // https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain - - var points = points2d.slice().sort(function (a, b) { - return a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]; - }); - - var lower = []; - for (var _i = 0; _i < points.length; _i++) { - while (lower.length >= 2 && cross2(lower[lower.length - 2], lower[lower.length - 1], points[_i]) <= 0) { - lower.pop(); - } - lower.push(points[_i]); - } - - var upper = []; - for (var _i2 = points.length - 1; _i2 >= 0; _i2--) { - while (upper.length >= 2 && cross2(upper[upper.length - 2], upper[upper.length - 1], points[_i2]) <= 0) { - upper.pop(); - } - upper.push(points[_i2]); - } - - upper.pop(); - lower.pop(); - - var hull = lower.concat(upper); - - ////////////////////////////////////////////// - // Find bounding box - ////////////////////////////////////////////// - - // For each edge (of the hull), transform the points to make it axis aligned - // Find the AABB with the smallest area - - var min_area = Number.POSITIVE_INFINITY; - //let corners = []; - var min_bounds = []; - var min_T = mat2.create(); - var min_TI = mat2.create(); - - var _loop = function _loop() { - - var side = vec2.sub(vec2.create(), hull[i], hull[(i + 1) % hull.length]); - vec2.normalize(side, side); - - var AT = mat2.fromValues(side[0], side[1], side[1], -side[0]); - var ATI = mat2.invert(mat2.create(), AT); - - var tpoints = hull.map(function (p) { - return vec2.transformMat2(vec2.create(), p, ATI); - }); - - // [xmin, xmax, ymin, ymax] - var bounds = tpoints.map(function (p) { - return [p[0], p[0], p[1], p[1]]; - }).reduce(function (a, b) { - return [Math.min(a[0], b[0]), Math.max(a[1], b[1]), Math.min(a[2], b[2]), Math.max(a[3], b[3])]; - }); - - var area = (bounds[1] - bounds[0]) * (bounds[3] - bounds[2]); - if (area < min_area) { - min_area = area; - - min_bounds = bounds; - min_TI = ATI; - } - }; - - for (var i = 0; i < hull.length; i++) { - _loop(); - } - - // - - var box_width = min_bounds[1] - min_bounds[0]; - var box_height = min_bounds[3] - min_bounds[2]; - - var _scale_ratio = 1; - - // scale the element, to avoid blurry texture - if (box_width > box_height) { - _scale_ratio = this.getDomSize(box_width) / box_width; - } else { - _scale_ratio = this.getDomSize(box_height) / box_height; - } - - this.block_width = box_width * _scale_ratio; - this.block_height = box_height * _scale_ratio; - - var clipPoints = points2d.map(function (p) { - return vec2.sub(vec2.create(), vec2.transformMat2(vec2.create(), p, min_TI), [min_bounds[0], min_bounds[2]]); - }); - - this.clipPath = clipPoints.map(function (p2) { - return vec2.fromValues(p2[0] / box_width, p2[1] / box_height); - }); - - this.matrix = new Triangle(vec3.fromValues(clipPoints[0][0] * _scale_ratio, clipPoints[0][1] * _scale_ratio, 0), vec3.fromValues(clipPoints[1][0] * _scale_ratio, clipPoints[1][1] * _scale_ratio, 0), vec3.fromValues(clipPoints[2][0] * _scale_ratio, clipPoints[2][1] * _scale_ratio, 0)).getTransformationTo(tri); - } else { - - throw new Error("The polygon has not enough sides"); - } - - var clipData = 'polygon(' + this.clipPath.map(function (p) { - return p[0] * 100 + '% ' + p[1] * 100 + '%'; - }).join() + ')'; - if (css_clip_path) { - this.domElement.style.clipPath = clipData; - } else if (css_webkit_clip_path) { - this.domElement.style['-webkit-clip-path'] = clipData; - } - - //this.domElement.style.width = this.block_width+"px"; - //this.domElement.style.height = this.block_height+"px"; - - // We need the width/height information in the childNode to properly position and scale the texture - // If we use width/height CSS values, then we can rescale this element, without calling updateContent - - this.domElement.style.setProperty("--width", this.block_width + "px"); - this.domElement.style.setProperty("--height", this.block_height + "px"); - - get(Polygon.prototype.__proto__ || Object.getPrototypeOf(Polygon.prototype), 'updateMatrix', this).call(this); - } - }, { - key: 'updateContent', - value: function updateContent() { - var _this2 = this; - - // uv_scale - var uvs = this.vertices.map(function (v) { - var ret = vec2.mul(vec2.create(), v.uv, _this2.uv_scale); - vec2.add(ret, ret, _this2.uv_offset); - return ret; - }); - - // handle texture repeat - var tex_bounds = uvs.map( - // [xmin, xmax, ymin, ymax] - function (uv) { - return [uv[0], uv[0], uv[1], uv[1]]; - }).reduce(function (a, b) { - return [Math.min(a[0], b[0]), Math.max(a[1], b[1]), Math.min(a[2], b[2]), Math.max(a[3], b[3])]; - }); - - var txmin = tex_bounds[0]; - var txmax = tex_bounds[1]; - var tymin = tex_bounds[2]; - var tymax = tex_bounds[3]; - - var xsize = txmax - txmin; - var ysize = tymax - tymin; - - var scx = 1 / xsize, - scy = 1 / ysize; - - this.contentElement.style.backgroundPosition = 'calc(var(--width) * ' + -txmin * scx + ') calc(var(--height) * ' + (1 + tymin * scy) + ')'; - this.contentElement.style.backgroundSize = 100 * scx + '% ' + 100 * scy + '%'; - - var TA = mat3.fromValues((uvs[0][0] - txmin) / xsize, 1 - (uvs[0][1] - tymin) / ysize, 1, (uvs[1][0] - txmin) / xsize, 1 - (uvs[1][1] - tymin) / ysize, 1, (uvs[2][0] - txmin) / xsize, 1 - (uvs[2][1] - tymin) / ysize, 1); - - var ai = void 0, - bi = void 0, - ci = void 0; - // use the longest side as base if it is a triangle - if (this.vertices.length == 3) { - ai = this.maxi; - bi = (this.maxi + 1) % 3; - ci = (this.maxi + 2) % 3; - } else { - ai = 0; - bi = 1; - ci = 2; - } - - var TB = mat3.fromValues(this.clipPath[ai][0], this.clipPath[ai][1], 1, this.clipPath[bi][0], this.clipPath[bi][1], 1, this.clipPath[ci][0], this.clipPath[ci][1], 1); - - var TX = mat3.mul(mat3.create(), TB, mat3.invert(mat3.create(), TA)); - - var bh = this.block_height / this.block_width; - this.contentElement.style.transform = "translate(" + [TX[6] * 100 + "%", TX[7] * 100 + "%"].join() + ")" + "matrix(" + [TX[0], TX[1] * bh, TX[3] / bh, TX[4], 0, 0].join() + ")"; - } - }], [{ - key: 'getClass', - value: function getClass() { - - if (!css_class) { - css_class = new CSSClass(); - css_class.setProperties({ - "width": "var(--width, 0px)", - "height": "var(--height, 0px)", - - "opacity": "var(--opacity, 1)", - - "transform-style": "flat", - "overflow": "hidden" - }); - css_class.setProperties(Object3D.getCommonAttributes()); - css_class.update(); - css_class.init(); - } - - return css_class; - } - }, { - key: 'getContentClass', - value: function getContentClass() { - - if (!css_content_class) { - - css_content_class = new CSSClass(); - css_content_class.setProperties({ - "width": "100%", - "height": "100%", - - "background-color": "var(--background-color, white)", - "background-image": "var(--background-image, none)", - "background-size": "100% 100%", - - "background-blend-mode": "multiply", - - "transform": "matrix(1, 0, 0, 1, 0, 0)", - "transform-origin": "0 0" - }); - - /* - if(css_mask) { - css_content_class.setProperties({ - 'mask-image': 'var(--background-image, none)', - 'mask-size': '100% 100%' - }); - } else if(css_webkit_mask) { - css_content_class.setProperties({ - '-webkit-mask-image': 'var(--background-image, none)', - '-webkit-mask-size': '100% 100%' - }); - }*/ - - css_content_class.update(); - css_content_class.init(); - } - - return css_content_class; - } - }]); - return Polygon; - }(Object3D); - - var css_class = null; - var css_content_class = null; - - var Group = function (_Object3D) { - inherits(Group, _Object3D); - - function Group() { - classCallCheck(this, Group); - - var _this = possibleConstructorReturn(this, (Group.__proto__ || Object.getPrototypeOf(Group)).call(this)); - - Group.getClass().attach(_this.domElement); - - _this.children = []; - - // - _this.vert_cache = null; - _this.norm_cache = null; - _this.vec2tex = null; - - return _this; - } - - createClass(Group, [{ - key: 'addChild', - value: function addChild(obj) { - - this.children.push(obj); - this.domElement.appendChild(obj.domElement); - } - }, { - key: 'removeChild', - value: function removeChild(obj) { - - var index = this.children.indexOf(obj); - - if (index > -1) { - this.removeChildIndex(index); - } - } - }, { - key: 'removeChildIndex', - value: function removeChildIndex(index) { - - var obj = this.children[index]; - - this.children.splice(index, 1); - this.domElement.removeChild(obj.domElement); - } - }, { - key: 'clear', - value: function clear() { - - var i = this.children.length; - while (i-- > 0) { - this.removeChildIndex(i); - } - } - - // - - }, { - key: 'addPolygon', - value: function addPolygon(vertices) { - var element = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; - - - var poly = new Polygon(vertices, element); - - poly.updateMatrix(); - poly.updateContent(); - - this.addChild(poly); - - return poly; - } - - // Adding triangles with this method makes it possible to reconstruct polygons (like quads) - // The polygon (defined by vertices) will be added at last when flushPolygons() is called - - }, { - key: 'pushPolygon', - value: function pushPolygon(vertices) { - var _this2 = this; - - // TODO: if vertices.length > 3, then we should compare more than 1 edge - - // Calculate the normal from vertices - var norm = new Triangle(vertices[0].position, vertices[1].position, vertices[2].position).norm; - - // If there is already a polygon in the cache, compare the current vertices with it - if (this.vert_cache) { - - var same_plane = vec3.equals(this.norm_cache, norm); - - // Check if they are on the same plane - if (same_plane) { - - // Check if the two polygon shares an edge - var shares_edge = false; - for (var i = 0; i < this.vert_cache.length; i++) { - - var c_vert = this.vert_cache[i]; - - for (var j = 0; j < vertices.length; j++) { - - var vert = vertices[j]; - - // First we compare single points - if (vec2.equals(c_vert.uv, vert.uv) && vec3.equals(c_vert.position, vert.position)) { - - var c_vert_next = this.vert_cache[(i + 1) % this.vert_cache.length]; - var vert_prev = vertices[(j + vertices.length - 1) % vertices.length]; - - // If we find the same point in both of them, then compare the other vertex on the edge - if (vec2.equals(c_vert_next.uv, vert_prev.uv) && vec3.equals(c_vert_next.position, vert_prev.position)) { - - // Merge polygons - var start = this.vert_cache.slice(0, i + 1); - var end = this.vert_cache.slice(i + 1); - - var ins = []; - for (var k = 1; k < vertices.length - 1; k++) { - ins.push(vertices[(j + k) % vertices.length]); - } - - // Compare texture coords - if (!ins.every(function (v) { - - var uv = vec3.transformMat4(vec3.create(), v.position, _this2.vec2tex).slice(0, 2); - - return vec2.equals(uv, v.uv); - })) { - continue; - } - - this.vert_cache = start.concat(ins, end); - - shares_edge = true; - break; - } - } - } - - if (shares_edge) { - break; - } - } - - if (!shares_edge) { - this.flushPolygons(); - } - } else { - this.flushPolygons(); - } - } - - // If it was empty or flushed, store verts in cache - if (!this.vert_cache) { - this.vert_cache = vertices; - this.norm_cache = norm; - - this.vec2tex = new Triangle(vertices[0].position, vertices[1].position, vertices[2].position, norm).getTransformationTo(new Triangle(vec3.fromValues(this.vert_cache[0].uv[0], this.vert_cache[0].uv[1], 0), vec3.fromValues(this.vert_cache[1].uv[0], this.vert_cache[1].uv[1], 0), vec3.fromValues(this.vert_cache[2].uv[0], this.vert_cache[2].uv[1], 0))); - } - } - }, { - key: 'flushPolygons', - value: function flushPolygons() { - - if (this.vert_cache) { - this.addPolygon(this.vert_cache); - - this.vert_cache = null; - this.norm_cache = null; - this.vec2tex = null; - } - } - }], [{ - key: 'getClass', - value: function getClass() { - - if (!css_class$1) { - css_class$1 = new CSSClass(); - css_class$1.setProperties({ - /* Center element */ - "width": "0px", - "height": "0px", - - "transform-style": "preserve-3d", - "overflow": "visible" - }); - css_class$1.setProperties(Object3D.getCommonAttributes()); - css_class$1.update(); - css_class$1.init(); - } - - return css_class$1; - } - }]); - return Group; - }(Object3D); - - var css_class$1 = null; - - var PerspectiveCamera = function () { - function PerspectiveCamera() { - var fov = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 70; - classCallCheck(this, PerspectiveCamera); - - - this.fov = fov; - - // Inverse world - this.matrix = mat4.create(); - } - - createClass(PerspectiveCamera, [{ - key: "perspective_coefficient", - get: function get$$1() { - return 1.0 / Math.tan(this.fov * Math.PI / 360); - } - }]); - return PerspectiveCamera; - }(); - - var OrthographicCamera = function OrthographicCamera(left, right, top, bottom) { - classCallCheck(this, OrthographicCamera); - - - this.left = left; - this.right = right; - this.top = top; - this.bottom = bottom; - - // Inverse world - this.matrix = mat4.create(); - }; - - // Edge - var transform_value_support = CSS.supports("transform: translateZ(calc(100px * var(--mult-value,1)))"); - - var RootObject = function (_Group) { - inherits(RootObject, _Group); - - function RootObject() { - classCallCheck(this, RootObject); - - var _this = possibleConstructorReturn(this, (RootObject.__proto__ || Object.getPrototypeOf(RootObject)).call(this)); - - RootObject.getClass().attach(_this.domElement); - return _this; - } - - createClass(RootObject, [{ - key: 'updateMatrix', - value: function updateMatrix(camera) { - - if (camera instanceof PerspectiveCamera) { - var p_coeff = camera.perspective_coefficient; - var pshift = void 0; - - if (transform_value_support) { - pshift = 'calc( ' + p_coeff + ' * var(--viewport-height) / 2 )'; - } else { - pshift = p_coeff * this.domElement.parentNode.offsetHeight / 2 + "px"; - } - - this.domElement.style.transform = 'translateZ(' + pshift + ')scaleY(-1)matrix3d(' + camera.matrix.join() + ')matrix3d(' + this.matrix.join() + ')'; - } else if (camera instanceof OrthographicCamera) { - - var xsize = camera.right - camera.left; - var ysize = camera.top - camera.bottom; - - var xcenter = (camera.right + camera.left) / 2; - var ycenter = (camera.top + camera.bottom) / 2; - - var pwidth = this.domElement.parentNode.offsetWidth; - var pheight = this.domElement.parentNode.offsetHeight; - - this.domElement.style.transform = 'scale(' + [pwidth / xsize, pheight / ysize].join() + ')translate(' + -xcenter + ',' + -ycenter + ')scaleY(-1)matrix3d(' + camera.matrix.join() + ')matrix3d(' + this.matrix.join() + ')'; - } - } - }], [{ - key: 'getClass', - value: function getClass() { - - if (!css_class$2) { - css_class$2 = new CSSClass(); - css_class$2.setProperties({ - "width": "100% !important", - "height": "100% !important", - - "top": "50%", - "left": "50%", - - /* Click trough */ - "pointer-events": "none", - - /* Prefix still needed for Safari? */ - "-webkit-backface-visibility": "hidden !important", - "backface-visibility": "hidden !important" - }); - css_class$2.update(); - css_class$2.init(); - } - - return css_class$2; - } - }]); - return RootObject; - }(Group); - - var css_class$2 = null; - - // Firefox mobile (Android) - var perspective_calc_support = CSS.supports('perspective: calc( 512px * 2 )'); - - var Container = function () { - function Container() { - classCallCheck(this, Container); - - - this.camera = new PerspectiveCamera(); - this.root = null; - - this.domElement = document.createElement('div'); - Container.getClass().attach(this.domElement); - - this.width = 0; - this.height = 0; - - this.addRoot(new RootObject()); - } - - // Needs to be called on camera change and if the root was replaced - - - createClass(Container, [{ - key: 'updateCamera', - value: function updateCamera() { - - if (this.camera instanceof PerspectiveCamera) { - - if (perspective_calc_support) { - this.domElement.style.setProperty("perspective", "calc( " + this.camera.perspective_coefficient + " * var(--viewport-height) / 2 )"); - } else { - this.domElement.style.setProperty("perspective", this.camera.perspective_coefficient * this.domElement.offsetHeight / 2 + "px"); - } - } else if (this.camera instanceof OrthographicCamera) { - - this.domElement.style.removeProperty("perspective"); - } - - this.root.updateMatrix(this.camera); - } - }, { - key: 'addRoot', - value: function addRoot(root) { - - if (this.root) { - this.domElement.removeChild(root.domElement); - } - - this.root = root; - this.domElement.appendChild(root.domElement); - - this.updateCamera(); - } - }, { - key: 'setSize', - value: function setSize(width, height) { - - if (this.width == width && this.height == height) { - return; - } - - this.width = width; - this.height = height; - - this.domElement.style.setProperty("--viewport-width", width + "px"); - this.domElement.style.setProperty("--viewport-height", height + "px"); - } - }, { - key: 'resetSize', - value: function resetSize() { - this.domElement.style.removeProperty("--viewport-width", width + "px"); - this.domElement.style.removeProperty("--viewport-height", height + "px"); - } - }], [{ - key: 'getClass', - value: function getClass() { - - if (!css_class$3) { - - css_class$3 = new CSSClass(); - css_class$3.setProperties({ - "overflow": "hidden", - - "position": "relative", - - "--viewport-width": "100vw", - "--viewport-height": "100vh", - - "width": "var(--viewport-width)", - "height": "var(--viewport-height)" - - }); - css_class$3.update(); - css_class$3.init(); - } - - return css_class$3; - } - }]); - return Container; - }(); - - var css_class$3 = null; - - var CustomElement = function (_Object3D) { - inherits(CustomElement, _Object3D); - - function CustomElement(element) { - classCallCheck(this, CustomElement); - - var _this = possibleConstructorReturn(this, (CustomElement.__proto__ || Object.getPrototypeOf(CustomElement)).call(this)); - - _this.element = element; - _this.domElement.appendChild(element); - - _this.elementScale = vec2.fromValues(1, 1); - _this.elementCenter = vec2.fromValues(.5, .5); - _this.elementRotation = 0; - - Group.getClass().attach(_this.domElement); - CustomElement.getContentClass().attach(_this.element); - - _this.updateElementTransform(); - - return _this; - } - - createClass(CustomElement, [{ - key: 'setSize', - value: function setSize(width, height) { - this.element.style.width = width + "px"; - this.element.style.height = height + "px"; - } - }, { - key: 'setScale', - value: function setScale(scale_x, scale_y) { - this.elementScale = vec2.fromValues(scale_x, scale_y); - this.updateElementTransform(); - } - }, { - key: 'setCenter', - value: function setCenter(center_x, center_y) { - this.elementCenter = vec2.fromValues(center_x, center_y); - this.updateElementTransform(); - } - }, { - key: 'updateElementTransform', - value: function updateElementTransform() { - - var pre_translate = "translate(-50%,-50%)"; - var scale = "scale(" + this.elementScale[0] + "," + -this.elementScale[1] + ")"; - var translate = "translate(" + (0.5 - this.elementCenter[0]) * 100 + "%," + (this.elementCenter[1] - 0.5) * 100 + "%)"; - - var rotate = this.elementRotation == 0 ? "" : "rotate(" + this.elementRotation + "rad)"; - - this.element.style.transform = pre_translate + scale + translate + rotate; - } - }, { - key: 'enablePointer', - value: function enablePointer() { - this.element.style.pointerEvents = "auto"; - } - }, { - key: 'disablePointer', - value: function disablePointer() { - this.element.style.pointerEvents = ""; - } - }], [{ - key: 'getContentClass', - value: function getContentClass() { - - if (!css_content_class$1) { - - css_content_class$1 = new CSSClass(); - css_content_class$1.setProperties({ - - "background-color": "var(--background-color, transparent)", - "background-image": "var(--background-image, white)", - "background-size": "100% 100%", - - "opacity": "var(--opacity, 1)" - - }); - css_content_class$1.update(); - css_content_class$1.init(); - } - - return css_content_class$1; - } - }]); - return CustomElement; - }(Object3D); - - var css_content_class$1 = null; - - var Vertex = function Vertex(position, uv) { - classCallCheck(this, Vertex); - - this.position = position ? position : vec3.create(); - this.uv = uv ? uv : vec2.create(); - }; - - exports.CSSClass = CSSClass; - exports.Material = Material; - exports.Object3D = Object3D; - exports.Group = Group; - exports.RootObject = RootObject; - exports.Container = Container; - exports.Polygon = Polygon; - exports.CustomElement = CustomElement; - exports.Triangle = Triangle; - exports.Vertex = Vertex; - exports.PerspectiveCamera = PerspectiveCamera; - exports.OrthographicCamera = OrthographicCamera; - - Object.defineProperty(exports, '__esModule', { value: true }); - -}))); diff --git a/build/C3R.min.js b/build/C3R.min.js deleted file mode 100644 index 7ffcfac..0000000 --- a/build/C3R.min.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @license - * The MIT License - * - * Copyright © 2018 Adam Kecskes - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(e.C3R={})}(this,function(e){"use strict";var o=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},n=function(){function n(e,t){for(var i=0;i 1 && arguments[1] !== undefined ? arguments[1] : null; - classCallCheck(this, Polygon); - - var _this = possibleConstructorReturn(this, (Polygon.__proto__ || Object.getPrototypeOf(Polygon)).call(this)); - - _this.vertices = vertices; // vertices in CCW - _this.clipPath = []; // path of the polygon on a rectangular element - - _this.simplify(); - - Polygon.getClass().attach(_this.domElement); - - // Base size of the dom element ( in case of a triangle, it will be the length of the longest side) - _this.getDomSize = default_dom_size; - - // Actual size of the dom element - _this.block_width = 0; - _this.block_height = 0; - - // texture / element / etc - _this.contentElement = contentElement ? contentElement : document.createElement('div'); - Polygon.getContentClass().attach(_this.contentElement); - _this.domElement.appendChild(_this.contentElement); - - _this.uv_scale = vec2.fromValues(1, 1); - _this.uv_offset = vec2.fromValues(0, 0); - - // triangle only data - _this.maxi = 0; // Index of the longest side - - return _this; - } - - // remove redundant vertices ( which are on the same line ) - - - createClass(Polygon, [{ - key: 'simplify', - value: function simplify() { - var vertices = [this.vertices[0]]; - - for (var i = 1; i < this.vertices.length; i++) { - - var prev_i = i - 1; - var next_i = (i + 1) % this.vertices.length; - - var p1 = this.vertices[prev_i].position; - var p2 = this.vertices[i].position; - var p3 = this.vertices[next_i].position; - - var e1 = vec3.sub(vec3.create(), p1, p2); - var e2 = vec3.sub(vec3.create(), p2, p3); - - vec3.normalize(e1, e1); - vec3.normalize(e2, e2); - - // Not collinear - if (Math.abs(vec3.dot(e1, e2)) < 0.9999) { - vertices.push(this.vertices[i]); - } - } - - this.vertices = vertices; - } - }, { - key: 'updateMatrix', - value: function updateMatrix() { - - // The first three polygon points should be transformed to this positions - var tri = new Triangle(this.vertices[0].position, this.vertices[1].position, this.vertices[2].position); - - // Faster method for triangles - if (this.vertices.length == 3) { - - // The longest side will be the base - var ln = tri.calculateEdgeLengths(); - - this.maxi = ln.indexOf(Math.max.apply(Math, toConsumableArray(ln))); - - var ai = this.maxi; - var bi = (this.maxi + 1) % 3; - var ci = (this.maxi + 2) % 3; - - var a = ln[ai]; - var b = ln[bi]; - var c = ln[ci]; - - var Ax = -(b * b - c * c - a * a) / (2 * a); - var Ay = Math.sqrt(c * c - Ax * Ax); - - // Where the longest side is split into two by the height-line - var base_split = Ax / a; - - // scale the element, to avoid blurry texture - - var scale_ratio = this.getDomSize(a) / a; - - this.block_width = a * scale_ratio; - this.block_height = Ay * scale_ratio; - // - - this.clipPath = [vec2.fromValues(0, 0), vec2.fromValues(1, 0), vec2.fromValues(base_split, 1)]; - - var tri_v = [vec3.fromValues(0, 0, 0), vec3.fromValues(this.block_width, 0, 0), vec3.fromValues(Ax * scale_ratio, this.block_height, 0)]; - - this.matrix = new Triangle(tri_v[ai], tri_v[bi], tri_v[ci], [0, 0, 1]).getTransformationTo(tri); - } else if (this.vertices.length > 3) { - - ////////////////////////////////////////////// - // Project polygon points to the 2D plane - ////////////////////////////////////////////// - - // get new bases - var b1 = tri.norm; - var b2 = Math.abs(vec3.dot(b1, [0, 0, 1])) < 0.9 ? vec3.cross(vec3.create(), b1, [0, 0, 1]) : vec3.cross(vec3.create(), b1, [0, 1, 0]); - var b3 = vec3.cross(vec3.create(), b2, b1); - - // Base change matrices - var BT = mat3.fromValues(b2[0], b2[1], b2[2], b3[0], b3[1], b3[2], b1[0], b1[1], b1[2]); - - var BTI = mat3.invert(mat3.create(), BT); - - if (BTI === null) { - throw new Error("Degenerate triangle?"); - } - - // Transform points with the matrices - var points2d = this.vertices.map(function (v) { - var pp = vec3.transformMat3(vec3.create(), v.position, BTI); - return pp.slice(0, 2); - }); - - ////////////////////////////////////////////// - // Find convex hull - ////////////////////////////////////////////// - - // https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain - - var points = points2d.slice().sort(function (a, b) { - return a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]; - }); - - var lower = []; - for (var _i = 0; _i < points.length; _i++) { - while (lower.length >= 2 && cross2(lower[lower.length - 2], lower[lower.length - 1], points[_i]) <= 0) { - lower.pop(); - } - lower.push(points[_i]); - } - - var upper = []; - for (var _i2 = points.length - 1; _i2 >= 0; _i2--) { - while (upper.length >= 2 && cross2(upper[upper.length - 2], upper[upper.length - 1], points[_i2]) <= 0) { - upper.pop(); - } - upper.push(points[_i2]); - } - - upper.pop(); - lower.pop(); - - var hull = lower.concat(upper); - - ////////////////////////////////////////////// - // Find bounding box - ////////////////////////////////////////////// - - // For each edge (of the hull), transform the points to make it axis aligned - // Find the AABB with the smallest area - - var min_area = Number.POSITIVE_INFINITY; - //let corners = []; - var min_bounds = []; - var min_T = mat2.create(); - var min_TI = mat2.create(); - - var _loop = function _loop() { - - var side = vec2.sub(vec2.create(), hull[i], hull[(i + 1) % hull.length]); - vec2.normalize(side, side); - - var AT = mat2.fromValues(side[0], side[1], side[1], -side[0]); - var ATI = mat2.invert(mat2.create(), AT); - - var tpoints = hull.map(function (p) { - return vec2.transformMat2(vec2.create(), p, ATI); - }); - - // [xmin, xmax, ymin, ymax] - var bounds = tpoints.map(function (p) { - return [p[0], p[0], p[1], p[1]]; - }).reduce(function (a, b) { - return [Math.min(a[0], b[0]), Math.max(a[1], b[1]), Math.min(a[2], b[2]), Math.max(a[3], b[3])]; - }); - - var area = (bounds[1] - bounds[0]) * (bounds[3] - bounds[2]); - if (area < min_area) { - min_area = area; - - min_bounds = bounds; - min_TI = ATI; - } - }; - - for (var i = 0; i < hull.length; i++) { - _loop(); - } - - // - - var box_width = min_bounds[1] - min_bounds[0]; - var box_height = min_bounds[3] - min_bounds[2]; - - var _scale_ratio = 1; - - // scale the element, to avoid blurry texture - if (box_width > box_height) { - _scale_ratio = this.getDomSize(box_width) / box_width; - } else { - _scale_ratio = this.getDomSize(box_height) / box_height; - } - - this.block_width = box_width * _scale_ratio; - this.block_height = box_height * _scale_ratio; - - var clipPoints = points2d.map(function (p) { - return vec2.sub(vec2.create(), vec2.transformMat2(vec2.create(), p, min_TI), [min_bounds[0], min_bounds[2]]); - }); - - this.clipPath = clipPoints.map(function (p2) { - return vec2.fromValues(p2[0] / box_width, p2[1] / box_height); - }); - - this.matrix = new Triangle(vec3.fromValues(clipPoints[0][0] * _scale_ratio, clipPoints[0][1] * _scale_ratio, 0), vec3.fromValues(clipPoints[1][0] * _scale_ratio, clipPoints[1][1] * _scale_ratio, 0), vec3.fromValues(clipPoints[2][0] * _scale_ratio, clipPoints[2][1] * _scale_ratio, 0)).getTransformationTo(tri); - } else { - - throw new Error("The polygon has not enough sides"); - } - - var clipData = 'polygon(' + this.clipPath.map(function (p) { - return p[0] * 100 + '% ' + p[1] * 100 + '%'; - }).join() + ')'; - if (css_clip_path) { - this.domElement.style.clipPath = clipData; - } else if (css_webkit_clip_path) { - this.domElement.style['-webkit-clip-path'] = clipData; - } - - //this.domElement.style.width = this.block_width+"px"; - //this.domElement.style.height = this.block_height+"px"; - - // We need the width/height information in the childNode to properly position and scale the texture - // If we use width/height CSS values, then we can rescale this element, without calling updateContent - - this.domElement.style.setProperty("--width", this.block_width + "px"); - this.domElement.style.setProperty("--height", this.block_height + "px"); - - get(Polygon.prototype.__proto__ || Object.getPrototypeOf(Polygon.prototype), 'updateMatrix', this).call(this); - } - }, { - key: 'updateContent', - value: function updateContent() { - var _this2 = this; - - // uv_scale - var uvs = this.vertices.map(function (v) { - var ret = vec2.mul(vec2.create(), v.uv, _this2.uv_scale); - vec2.add(ret, ret, _this2.uv_offset); - return ret; - }); - - // handle texture repeat - var tex_bounds = uvs.map( - // [xmin, xmax, ymin, ymax] - function (uv) { - return [uv[0], uv[0], uv[1], uv[1]]; - }).reduce(function (a, b) { - return [Math.min(a[0], b[0]), Math.max(a[1], b[1]), Math.min(a[2], b[2]), Math.max(a[3], b[3])]; - }); - - var txmin = tex_bounds[0]; - var txmax = tex_bounds[1]; - var tymin = tex_bounds[2]; - var tymax = tex_bounds[3]; - - var xsize = txmax - txmin; - var ysize = tymax - tymin; - - var scx = 1 / xsize, - scy = 1 / ysize; - - this.contentElement.style.backgroundPosition = 'calc(var(--width) * ' + -txmin * scx + ') calc(var(--height) * ' + (1 + tymin * scy) + ')'; - this.contentElement.style.backgroundSize = 100 * scx + '% ' + 100 * scy + '%'; - - var TA = mat3.fromValues((uvs[0][0] - txmin) / xsize, 1 - (uvs[0][1] - tymin) / ysize, 1, (uvs[1][0] - txmin) / xsize, 1 - (uvs[1][1] - tymin) / ysize, 1, (uvs[2][0] - txmin) / xsize, 1 - (uvs[2][1] - tymin) / ysize, 1); - - var ai = void 0, - bi = void 0, - ci = void 0; - // use the longest side as base if it is a triangle - if (this.vertices.length == 3) { - ai = this.maxi; - bi = (this.maxi + 1) % 3; - ci = (this.maxi + 2) % 3; - } else { - ai = 0; - bi = 1; - ci = 2; - } - - var TB = mat3.fromValues(this.clipPath[ai][0], this.clipPath[ai][1], 1, this.clipPath[bi][0], this.clipPath[bi][1], 1, this.clipPath[ci][0], this.clipPath[ci][1], 1); - - var TX = mat3.mul(mat3.create(), TB, mat3.invert(mat3.create(), TA)); - - var bh = this.block_height / this.block_width; - this.contentElement.style.transform = "translate(" + [TX[6] * 100 + "%", TX[7] * 100 + "%"].join() + ")" + "matrix(" + [TX[0], TX[1] * bh, TX[3] / bh, TX[4], 0, 0].join() + ")"; - } - }], [{ - key: 'getClass', - value: function getClass() { - - if (!css_class) { - css_class = new CSSClass(); - css_class.setProperties({ - "width": "var(--width, 0px)", - "height": "var(--height, 0px)", - - "opacity": "var(--opacity, 1)", - - "transform-style": "flat", - "overflow": "hidden" - }); - css_class.setProperties(Object3D.getCommonAttributes()); - css_class.update(); - css_class.init(); - } - - return css_class; - } - }, { - key: 'getContentClass', - value: function getContentClass() { - - if (!css_content_class) { - - css_content_class = new CSSClass(); - css_content_class.setProperties({ - "width": "100%", - "height": "100%", - - "background-color": "var(--background-color, white)", - "background-image": "var(--background-image, none)", - "background-size": "100% 100%", - - "background-blend-mode": "multiply", - - "transform": "matrix(1, 0, 0, 1, 0, 0)", - "transform-origin": "0 0" - }); - - /* - if(css_mask) { - css_content_class.setProperties({ - 'mask-image': 'var(--background-image, none)', - 'mask-size': '100% 100%' - }); - } else if(css_webkit_mask) { - css_content_class.setProperties({ - '-webkit-mask-image': 'var(--background-image, none)', - '-webkit-mask-size': '100% 100%' - }); - }*/ - - css_content_class.update(); - css_content_class.init(); - } - - return css_content_class; - } - }]); - return Polygon; -}(Object3D); - -var css_class = null; -var css_content_class = null; - -var Group = function (_Object3D) { - inherits(Group, _Object3D); - - function Group() { - classCallCheck(this, Group); - - var _this = possibleConstructorReturn(this, (Group.__proto__ || Object.getPrototypeOf(Group)).call(this)); - - Group.getClass().attach(_this.domElement); - - _this.children = []; - - // - _this.vert_cache = null; - _this.norm_cache = null; - _this.vec2tex = null; - - return _this; - } - - createClass(Group, [{ - key: 'addChild', - value: function addChild(obj) { - - this.children.push(obj); - this.domElement.appendChild(obj.domElement); - } - }, { - key: 'removeChild', - value: function removeChild(obj) { - - var index = this.children.indexOf(obj); - - if (index > -1) { - this.removeChildIndex(index); - } - } - }, { - key: 'removeChildIndex', - value: function removeChildIndex(index) { - - var obj = this.children[index]; - - this.children.splice(index, 1); - this.domElement.removeChild(obj.domElement); - } - }, { - key: 'clear', - value: function clear() { - - var i = this.children.length; - while (i-- > 0) { - this.removeChildIndex(i); - } - } - - // - - }, { - key: 'addPolygon', - value: function addPolygon(vertices) { - var element = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; - - - var poly = new Polygon(vertices, element); - - poly.updateMatrix(); - poly.updateContent(); - - this.addChild(poly); - - return poly; - } - - // Adding triangles with this method makes it possible to reconstruct polygons (like quads) - // The polygon (defined by vertices) will be added at last when flushPolygons() is called - - }, { - key: 'pushPolygon', - value: function pushPolygon(vertices) { - var _this2 = this; - - // TODO: if vertices.length > 3, then we should compare more than 1 edge - - // Calculate the normal from vertices - var norm = new Triangle(vertices[0].position, vertices[1].position, vertices[2].position).norm; - - // If there is already a polygon in the cache, compare the current vertices with it - if (this.vert_cache) { - - var same_plane = vec3.equals(this.norm_cache, norm); - - // Check if they are on the same plane - if (same_plane) { - - // Check if the two polygon shares an edge - var shares_edge = false; - for (var i = 0; i < this.vert_cache.length; i++) { - - var c_vert = this.vert_cache[i]; - - for (var j = 0; j < vertices.length; j++) { - - var vert = vertices[j]; - - // First we compare single points - if (vec2.equals(c_vert.uv, vert.uv) && vec3.equals(c_vert.position, vert.position)) { - - var c_vert_next = this.vert_cache[(i + 1) % this.vert_cache.length]; - var vert_prev = vertices[(j + vertices.length - 1) % vertices.length]; - - // If we find the same point in both of them, then compare the other vertex on the edge - if (vec2.equals(c_vert_next.uv, vert_prev.uv) && vec3.equals(c_vert_next.position, vert_prev.position)) { - - // Merge polygons - var start = this.vert_cache.slice(0, i + 1); - var end = this.vert_cache.slice(i + 1); - - var ins = []; - for (var k = 1; k < vertices.length - 1; k++) { - ins.push(vertices[(j + k) % vertices.length]); - } - - // Compare texture coords - if (!ins.every(function (v) { - - var uv = vec3.transformMat4(vec3.create(), v.position, _this2.vec2tex).slice(0, 2); - - return vec2.equals(uv, v.uv); - })) { - continue; - } - - this.vert_cache = start.concat(ins, end); - - shares_edge = true; - break; - } - } - } - - if (shares_edge) { - break; - } - } - - if (!shares_edge) { - this.flushPolygons(); - } - } else { - this.flushPolygons(); - } - } - - // If it was empty or flushed, store verts in cache - if (!this.vert_cache) { - this.vert_cache = vertices; - this.norm_cache = norm; - - this.vec2tex = new Triangle(vertices[0].position, vertices[1].position, vertices[2].position, norm).getTransformationTo(new Triangle(vec3.fromValues(this.vert_cache[0].uv[0], this.vert_cache[0].uv[1], 0), vec3.fromValues(this.vert_cache[1].uv[0], this.vert_cache[1].uv[1], 0), vec3.fromValues(this.vert_cache[2].uv[0], this.vert_cache[2].uv[1], 0))); - } - } - }, { - key: 'flushPolygons', - value: function flushPolygons() { - - if (this.vert_cache) { - this.addPolygon(this.vert_cache); - - this.vert_cache = null; - this.norm_cache = null; - this.vec2tex = null; - } - } - }], [{ - key: 'getClass', - value: function getClass() { - - if (!css_class$1) { - css_class$1 = new CSSClass(); - css_class$1.setProperties({ - /* Center element */ - "width": "0px", - "height": "0px", - - "transform-style": "preserve-3d", - "overflow": "visible" - }); - css_class$1.setProperties(Object3D.getCommonAttributes()); - css_class$1.update(); - css_class$1.init(); - } - - return css_class$1; - } - }]); - return Group; -}(Object3D); - -var css_class$1 = null; - -var PerspectiveCamera = function () { - function PerspectiveCamera() { - var fov = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 70; - classCallCheck(this, PerspectiveCamera); - - - this.fov = fov; - - // Inverse world - this.matrix = mat4.create(); - } - - createClass(PerspectiveCamera, [{ - key: "perspective_coefficient", - get: function get$$1() { - return 1.0 / Math.tan(this.fov * Math.PI / 360); - } - }]); - return PerspectiveCamera; -}(); - -var OrthographicCamera = function OrthographicCamera(left, right, top, bottom) { - classCallCheck(this, OrthographicCamera); - - - this.left = left; - this.right = right; - this.top = top; - this.bottom = bottom; - - // Inverse world - this.matrix = mat4.create(); -}; - -// Edge -var transform_value_support = CSS.supports("transform: translateZ(calc(100px * var(--mult-value,1)))"); - -var RootObject = function (_Group) { - inherits(RootObject, _Group); - - function RootObject() { - classCallCheck(this, RootObject); - - var _this = possibleConstructorReturn(this, (RootObject.__proto__ || Object.getPrototypeOf(RootObject)).call(this)); - - RootObject.getClass().attach(_this.domElement); - return _this; - } - - createClass(RootObject, [{ - key: 'updateMatrix', - value: function updateMatrix(camera) { - - if (camera instanceof PerspectiveCamera) { - var p_coeff = camera.perspective_coefficient; - var pshift = void 0; - - if (transform_value_support) { - pshift = 'calc( ' + p_coeff + ' * var(--viewport-height) / 2 )'; - } else { - pshift = p_coeff * this.domElement.parentNode.offsetHeight / 2 + "px"; - } - - this.domElement.style.transform = 'translateZ(' + pshift + ')scaleY(-1)matrix3d(' + camera.matrix.join() + ')matrix3d(' + this.matrix.join() + ')'; - } else if (camera instanceof OrthographicCamera) { - - var xsize = camera.right - camera.left; - var ysize = camera.top - camera.bottom; - - var xcenter = (camera.right + camera.left) / 2; - var ycenter = (camera.top + camera.bottom) / 2; - - var pwidth = this.domElement.parentNode.offsetWidth; - var pheight = this.domElement.parentNode.offsetHeight; - - this.domElement.style.transform = 'scale(' + [pwidth / xsize, pheight / ysize].join() + ')translate(' + -xcenter + ',' + -ycenter + ')scaleY(-1)matrix3d(' + camera.matrix.join() + ')matrix3d(' + this.matrix.join() + ')'; - } - } - }], [{ - key: 'getClass', - value: function getClass() { - - if (!css_class$2) { - css_class$2 = new CSSClass(); - css_class$2.setProperties({ - "width": "100% !important", - "height": "100% !important", - - "top": "50%", - "left": "50%", - - /* Click trough */ - "pointer-events": "none", - - /* Prefix still needed for Safari? */ - "-webkit-backface-visibility": "hidden !important", - "backface-visibility": "hidden !important" - }); - css_class$2.update(); - css_class$2.init(); - } - - return css_class$2; - } - }]); - return RootObject; -}(Group); - -var css_class$2 = null; - -// Firefox mobile (Android) -var perspective_calc_support = CSS.supports('perspective: calc( 512px * 2 )'); - -var Container = function () { - function Container() { - classCallCheck(this, Container); - - - this.camera = new PerspectiveCamera(); - this.root = null; - - this.domElement = document.createElement('div'); - Container.getClass().attach(this.domElement); - - this.width = 0; - this.height = 0; - - this.addRoot(new RootObject()); - } - - // Needs to be called on camera change and if the root was replaced - - - createClass(Container, [{ - key: 'updateCamera', - value: function updateCamera() { - - if (this.camera instanceof PerspectiveCamera) { - - if (perspective_calc_support) { - this.domElement.style.setProperty("perspective", "calc( " + this.camera.perspective_coefficient + " * var(--viewport-height) / 2 )"); - } else { - this.domElement.style.setProperty("perspective", this.camera.perspective_coefficient * this.domElement.offsetHeight / 2 + "px"); - } - } else if (this.camera instanceof OrthographicCamera) { - - this.domElement.style.removeProperty("perspective"); - } - - this.root.updateMatrix(this.camera); - } - }, { - key: 'addRoot', - value: function addRoot(root) { - - if (this.root) { - this.domElement.removeChild(root.domElement); - } - - this.root = root; - this.domElement.appendChild(root.domElement); - - this.updateCamera(); - } - }, { - key: 'setSize', - value: function setSize(width, height) { - - if (this.width == width && this.height == height) { - return; - } - - this.width = width; - this.height = height; - - this.domElement.style.setProperty("--viewport-width", width + "px"); - this.domElement.style.setProperty("--viewport-height", height + "px"); - } - }, { - key: 'resetSize', - value: function resetSize() { - this.domElement.style.removeProperty("--viewport-width", width + "px"); - this.domElement.style.removeProperty("--viewport-height", height + "px"); - } - }], [{ - key: 'getClass', - value: function getClass() { - - if (!css_class$3) { - - css_class$3 = new CSSClass(); - css_class$3.setProperties({ - "overflow": "hidden", - - "position": "relative", - - "--viewport-width": "100vw", - "--viewport-height": "100vh", - - "width": "var(--viewport-width)", - "height": "var(--viewport-height)" - - }); - css_class$3.update(); - css_class$3.init(); - } - - return css_class$3; - } - }]); - return Container; -}(); - -var css_class$3 = null; - -var CustomElement = function (_Object3D) { - inherits(CustomElement, _Object3D); - - function CustomElement(element) { - classCallCheck(this, CustomElement); - - var _this = possibleConstructorReturn(this, (CustomElement.__proto__ || Object.getPrototypeOf(CustomElement)).call(this)); - - _this.element = element; - _this.domElement.appendChild(element); - - _this.elementScale = vec2.fromValues(1, 1); - _this.elementCenter = vec2.fromValues(.5, .5); - _this.elementRotation = 0; - - Group.getClass().attach(_this.domElement); - CustomElement.getContentClass().attach(_this.element); - - _this.updateElementTransform(); - - return _this; - } - - createClass(CustomElement, [{ - key: 'setSize', - value: function setSize(width, height) { - this.element.style.width = width + "px"; - this.element.style.height = height + "px"; - } - }, { - key: 'setScale', - value: function setScale(scale_x, scale_y) { - this.elementScale = vec2.fromValues(scale_x, scale_y); - this.updateElementTransform(); - } - }, { - key: 'setCenter', - value: function setCenter(center_x, center_y) { - this.elementCenter = vec2.fromValues(center_x, center_y); - this.updateElementTransform(); - } - }, { - key: 'updateElementTransform', - value: function updateElementTransform() { - - var pre_translate = "translate(-50%,-50%)"; - var scale = "scale(" + this.elementScale[0] + "," + -this.elementScale[1] + ")"; - var translate = "translate(" + (0.5 - this.elementCenter[0]) * 100 + "%," + (this.elementCenter[1] - 0.5) * 100 + "%)"; - - var rotate = this.elementRotation == 0 ? "" : "rotate(" + this.elementRotation + "rad)"; - - this.element.style.transform = pre_translate + scale + translate + rotate; - } - }, { - key: 'enablePointer', - value: function enablePointer() { - this.element.style.pointerEvents = "auto"; - } - }, { - key: 'disablePointer', - value: function disablePointer() { - this.element.style.pointerEvents = ""; - } - }], [{ - key: 'getContentClass', - value: function getContentClass() { - - if (!css_content_class$1) { - - css_content_class$1 = new CSSClass(); - css_content_class$1.setProperties({ - - "background-color": "var(--background-color, transparent)", - "background-image": "var(--background-image, white)", - "background-size": "100% 100%", - - "opacity": "var(--opacity, 1)" - - }); - css_content_class$1.update(); - css_content_class$1.init(); - } - - return css_content_class$1; - } - }]); - return CustomElement; -}(Object3D); - -var css_content_class$1 = null; - -var Vertex = function Vertex(position, uv) { - classCallCheck(this, Vertex); - - this.position = position ? position : vec3.create(); - this.uv = uv ? uv : vec2.create(); -}; - -export { CSSClass, Material, Object3D, Group, RootObject, Container, Polygon, CustomElement, Triangle, Vertex, PerspectiveCamera, OrthographicCamera }; diff --git a/build/C3R.standalone.js b/build/C3R.standalone.js deleted file mode 100644 index 1dd04ad..0000000 --- a/build/C3R.standalone.js +++ /dev/null @@ -1,45 +0,0 @@ -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. */ -!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var n=e();for(var r in n)("object"==typeof exports?exports:t)[r]=n[r]}}(this,function(){return function(n){function r(t){if(a[t])return a[t].exports;var e=a[t]={i:t,l:!1,exports:{}};return n[t].call(e.exports,e,e.exports,r),e.l=!0,e.exports}var a={};return r.m=n,r.c=a,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:n})},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=4)}([function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.setMatrixArrayType=function(t){e.ARRAY_TYPE=t},e.toRadian=function(t){return t*a},e.equals=function(t,e){return Math.abs(t-e)<=r*Math.max(1,Math.abs(t),Math.abs(e))};var r=e.EPSILON=1e-6,a=(e.ARRAY_TYPE="undefined"!=typeof Float32Array?Float32Array:Array,e.RANDOM=Math.random,Math.PI/180)},function(t,e,n){"use strict";function r(t,e,n){var r=e[0],a=e[1],o=e[2],i=e[3],u=e[4],s=e[5],c=e[6],h=e[7],l=e[8],f=n[0],v=n[1],m=n[2],d=n[3],M=n[4],p=n[5],b=n[6],y=n[7],g=n[8];return t[0]=f*r+v*i+m*c,t[1]=f*a+v*u+m*h,t[2]=f*o+v*s+m*l,t[3]=d*r+M*i+p*c,t[4]=d*a+M*u+p*h,t[5]=d*o+M*s+p*l,t[6]=b*r+y*i+g*c,t[7]=b*a+y*u+g*h,t[8]=b*o+y*s+g*l,t}function a(t,e,n){return t[0]=e[0]-n[0],t[1]=e[1]-n[1],t[2]=e[2]-n[2],t[3]=e[3]-n[3],t[4]=e[4]-n[4],t[5]=e[5]-n[5],t[6]=e[6]-n[6],t[7]=e[7]-n[7],t[8]=e[8]-n[8],t}Object.defineProperty(e,"__esModule",{value:!0}),e.sub=e.mul=void 0,e.create=function(){var t=new g.ARRAY_TYPE(9);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},e.fromMat4=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[4],t[4]=e[5],t[5]=e[6],t[6]=e[8],t[7]=e[9],t[8]=e[10],t},e.clone=function(t){var e=new g.ARRAY_TYPE(9);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e[6]=t[6],e[7]=t[7],e[8]=t[8],e},e.copy=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t},e.fromValues=function(t,e,n,r,a,o,i,u,s){var c=new g.ARRAY_TYPE(9);return c[0]=t,c[1]=e,c[2]=n,c[3]=r,c[4]=a,c[5]=o,c[6]=i,c[7]=u,c[8]=s,c},e.set=function(t,e,n,r,a,o,i,u,s,c){return t[0]=e,t[1]=n,t[2]=r,t[3]=a,t[4]=o,t[5]=i,t[6]=u,t[7]=s,t[8]=c,t},e.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},e.transpose=function(t,e){if(t===e){var n=e[1],r=e[2],a=e[5];t[1]=e[3],t[2]=e[6],t[3]=n,t[5]=e[7],t[6]=r,t[7]=a}else t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[1],t[4]=e[4],t[5]=e[7],t[6]=e[2],t[7]=e[5],t[8]=e[8];return t},e.invert=function(t,e){var n=e[0],r=e[1],a=e[2],o=e[3],i=e[4],u=e[5],s=e[6],c=e[7],h=e[8],l=h*i-u*c,f=-h*o+u*s,v=c*o-i*s,m=n*l+r*f+a*v;return m?(m=1/m,t[0]=l*m,t[1]=(-h*r+a*c)*m,t[2]=(u*r-a*i)*m,t[3]=f*m,t[4]=(h*n-a*s)*m,t[5]=(-u*n+a*o)*m,t[6]=v*m,t[7]=(-c*n+r*s)*m,t[8]=(i*n-r*o)*m,t):null},e.adjoint=function(t,e){var n=e[0],r=e[1],a=e[2],o=e[3],i=e[4],u=e[5],s=e[6],c=e[7],h=e[8];return t[0]=i*h-u*c,t[1]=a*c-r*h,t[2]=r*u-a*i,t[3]=u*s-o*h,t[4]=n*h-a*s,t[5]=a*o-n*u,t[6]=o*c-i*s,t[7]=r*s-n*c,t[8]=n*i-r*o,t},e.determinant=function(t){var e=t[0],n=t[1],r=t[2],a=t[3],o=t[4],i=t[5],u=t[6],s=t[7],c=t[8];return e*(c*o-i*s)+n*(-c*a+i*u)+r*(s*a-o*u)},e.multiply=r,e.translate=function(t,e,n){var r=e[0],a=e[1],o=e[2],i=e[3],u=e[4],s=e[5],c=e[6],h=e[7],l=e[8],f=n[0],v=n[1];return t[0]=r,t[1]=a,t[2]=o,t[3]=i,t[4]=u,t[5]=s,t[6]=f*r+v*i+c,t[7]=f*a+v*u+h,t[8]=f*o+v*s+l,t},e.rotate=function(t,e,n){var r=e[0],a=e[1],o=e[2],i=e[3],u=e[4],s=e[5],c=e[6],h=e[7],l=e[8],f=Math.sin(n),v=Math.cos(n);return t[0]=v*r+f*i,t[1]=v*a+f*u,t[2]=v*o+f*s,t[3]=v*i-f*r,t[4]=v*u-f*a,t[5]=v*s-f*o,t[6]=c,t[7]=h,t[8]=l,t},e.scale=function(t,e,n){var r=n[0],a=n[1];return t[0]=r*e[0],t[1]=r*e[1],t[2]=r*e[2],t[3]=a*e[3],t[4]=a*e[4],t[5]=a*e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t},e.fromTranslation=function(t,e){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=e[0],t[7]=e[1],t[8]=1,t},e.fromRotation=function(t,e){var n=Math.sin(e),r=Math.cos(e);return t[0]=r,t[1]=n,t[2]=0,t[3]=-n,t[4]=r,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},e.fromScaling=function(t,e){return t[0]=e[0],t[1]=0,t[2]=0,t[3]=0,t[4]=e[1],t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},e.fromMat2d=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=0,t[3]=e[2],t[4]=e[3],t[5]=0,t[6]=e[4],t[7]=e[5],t[8]=1,t},e.fromQuat=function(t,e){var n=e[0],r=e[1],a=e[2],o=e[3],i=n+n,u=r+r,s=a+a,c=n*i,h=r*i,l=r*u,f=a*i,v=a*u,m=a*s,d=o*i,M=o*u,p=o*s;return t[0]=1-l-m,t[3]=h-p,t[6]=f+M,t[1]=h+p,t[4]=1-c-m,t[7]=v-d,t[2]=f-M,t[5]=v+d,t[8]=1-c-l,t},e.normalFromMat4=function(t,e){var n=e[0],r=e[1],a=e[2],o=e[3],i=e[4],u=e[5],s=e[6],c=e[7],h=e[8],l=e[9],f=e[10],v=e[11],m=e[12],d=e[13],M=e[14],p=e[15],b=n*u-r*i,y=n*s-a*i,g=n*c-o*i,P=r*s-a*u,E=r*c-o*u,x=a*c-o*s,w=h*d-l*m,_=h*M-f*m,O=h*p-v*m,k=l*M-f*d,S=l*p-v*d,A=f*p-v*M,q=b*A-y*S+g*k+P*O-E*_+x*w;return q?(q=1/q,t[0]=(u*A-s*S+c*k)*q,t[1]=(s*O-i*A-c*_)*q,t[2]=(i*S-u*O+c*w)*q,t[3]=(a*S-r*A-o*k)*q,t[4]=(n*A-a*O+o*_)*q,t[5]=(r*O-n*S-o*w)*q,t[6]=(d*x-M*E+p*P)*q,t[7]=(M*g-m*x-p*y)*q,t[8]=(m*E-d*g+p*b)*q,t):null},e.projection=function(t,e,n){return t[0]=2/e,t[1]=0,t[2]=0,t[3]=0,t[4]=-2/n,t[5]=0,t[6]=-1,t[7]=1,t[8]=1,t},e.str=function(t){return"mat3("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+")"},e.frob=function(t){return Math.sqrt(Math.pow(t[0],2)+Math.pow(t[1],2)+Math.pow(t[2],2)+Math.pow(t[3],2)+Math.pow(t[4],2)+Math.pow(t[5],2)+Math.pow(t[6],2)+Math.pow(t[7],2)+Math.pow(t[8],2))},e.add=function(t,e,n){return t[0]=e[0]+n[0],t[1]=e[1]+n[1],t[2]=e[2]+n[2],t[3]=e[3]+n[3],t[4]=e[4]+n[4],t[5]=e[5]+n[5],t[6]=e[6]+n[6],t[7]=e[7]+n[7],t[8]=e[8]+n[8],t},e.subtract=a,e.multiplyScalar=function(t,e,n){return t[0]=e[0]*n,t[1]=e[1]*n,t[2]=e[2]*n,t[3]=e[3]*n,t[4]=e[4]*n,t[5]=e[5]*n,t[6]=e[6]*n,t[7]=e[7]*n,t[8]=e[8]*n,t},e.multiplyScalarAndAdd=function(t,e,n,r){return t[0]=e[0]+n[0]*r,t[1]=e[1]+n[1]*r,t[2]=e[2]+n[2]*r,t[3]=e[3]+n[3]*r,t[4]=e[4]+n[4]*r,t[5]=e[5]+n[5]*r,t[6]=e[6]+n[6]*r,t[7]=e[7]+n[7]*r,t[8]=e[8]+n[8]*r,t},e.exactEquals=function(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]&&t[4]===e[4]&&t[5]===e[5]&&t[6]===e[6]&&t[7]===e[7]&&t[8]===e[8]},e.equals=function(t,e){var n=t[0],r=t[1],a=t[2],o=t[3],i=t[4],u=t[5],s=t[6],c=t[7],h=t[8],l=e[0],f=e[1],v=e[2],m=e[3],d=e[4],M=e[5],p=e[6],b=e[7],y=e[8];return Math.abs(n-l)<=g.EPSILON*Math.max(1,Math.abs(n),Math.abs(l))&&Math.abs(r-f)<=g.EPSILON*Math.max(1,Math.abs(r),Math.abs(f))&&Math.abs(a-v)<=g.EPSILON*Math.max(1,Math.abs(a),Math.abs(v))&&Math.abs(o-m)<=g.EPSILON*Math.max(1,Math.abs(o),Math.abs(m))&&Math.abs(i-d)<=g.EPSILON*Math.max(1,Math.abs(i),Math.abs(d))&&Math.abs(u-M)<=g.EPSILON*Math.max(1,Math.abs(u),Math.abs(M))&&Math.abs(s-p)<=g.EPSILON*Math.max(1,Math.abs(s),Math.abs(p))&&Math.abs(c-b)<=g.EPSILON*Math.max(1,Math.abs(c),Math.abs(b))&&Math.abs(h-y)<=g.EPSILON*Math.max(1,Math.abs(h),Math.abs(y))};var g=function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e.default=t,e}(n(0));e.mul=r,e.sub=a},function(t,e,n){"use strict";function r(){var t=new d.ARRAY_TYPE(3);return t[0]=0,t[1]=0,t[2]=0,t}function a(t){var e=t[0],n=t[1],r=t[2];return Math.sqrt(e*e+n*n+r*r)}function o(t,e,n){var r=new d.ARRAY_TYPE(3);return r[0]=t,r[1]=e,r[2]=n,r}function i(t,e,n){return t[0]=e[0]-n[0],t[1]=e[1]-n[1],t[2]=e[2]-n[2],t}function u(t,e,n){return t[0]=e[0]*n[0],t[1]=e[1]*n[1],t[2]=e[2]*n[2],t}function s(t,e,n){return t[0]=e[0]/n[0],t[1]=e[1]/n[1],t[2]=e[2]/n[2],t}function c(t,e){var n=e[0]-t[0],r=e[1]-t[1],a=e[2]-t[2];return Math.sqrt(n*n+r*r+a*a)}function h(t,e){var n=e[0]-t[0],r=e[1]-t[1],a=e[2]-t[2];return n*n+r*r+a*a}function l(t){var e=t[0],n=t[1],r=t[2];return e*e+n*n+r*r}function f(t,e){var n=e[0],r=e[1],a=e[2],o=n*n+r*r+a*a;return 0e[5]&e[0]>e[10]?(r=2*Math.sqrt(1+e[0]-e[5]-e[10]),t[3]=(e[6]-e[9])/r,t[0]=.25*r,t[1]=(e[1]+e[4])/r,t[2]=(e[8]+e[2])/r):e[5]>e[10]?(r=2*Math.sqrt(1+e[5]-e[0]-e[10]),t[3]=(e[8]-e[2])/r,t[0]=(e[1]+e[4])/r,t[1]=.25*r,t[2]=(e[6]+e[9])/r):(r=2*Math.sqrt(1+e[10]-e[0]-e[5]),t[3]=(e[1]-e[4])/r,t[0]=(e[8]+e[2])/r,t[1]=(e[6]+e[9])/r,t[2]=.25*r),t},e.fromRotationTranslationScale=function(t,e,n,r){var a=e[0],o=e[1],i=e[2],u=e[3],s=a+a,c=o+o,h=i+i,l=a*s,f=a*c,v=a*h,m=o*c,d=o*h,M=i*h,p=u*s,b=u*c,y=u*h,g=r[0],P=r[1],E=r[2];return t[0]=(1-(m+M))*g,t[1]=(f+y)*g,t[2]=(v-b)*g,t[3]=0,t[4]=(f-y)*P,t[5]=(1-(l+M))*P,t[6]=(d+p)*P,t[7]=0,t[8]=(v+b)*E,t[9]=(d-p)*E,t[10]=(1-(l+m))*E,t[11]=0,t[12]=n[0],t[13]=n[1],t[14]=n[2],t[15]=1,t},e.fromRotationTranslationScaleOrigin=function(t,e,n,r,a){var o=e[0],i=e[1],u=e[2],s=e[3],c=o+o,h=i+i,l=u+u,f=o*c,v=o*h,m=o*l,d=i*h,M=i*l,p=u*l,b=s*c,y=s*h,g=s*l,P=r[0],E=r[1],x=r[2],w=a[0],_=a[1],O=a[2];return t[0]=(1-(d+p))*P,t[1]=(v+g)*P,t[2]=(m-y)*P,t[3]=0,t[4]=(v-g)*E,t[5]=(1-(f+p))*E,t[6]=(M+b)*E,t[7]=0,t[8]=(m+y)*x,t[9]=(M-b)*x,t[10]=(1-(f+d))*x,t[11]=0,t[12]=n[0]+w-(t[0]*w+t[4]*_+t[8]*O),t[13]=n[1]+_-(t[1]*w+t[5]*_+t[9]*O),t[14]=n[2]+O-(t[2]*w+t[6]*_+t[10]*O),t[15]=1,t},e.fromQuat=function(t,e){var n=e[0],r=e[1],a=e[2],o=e[3],i=n+n,u=r+r,s=a+a,c=n*i,h=r*i,l=r*u,f=a*i,v=a*u,m=a*s,d=o*i,M=o*u,p=o*s;return t[0]=1-l-m,t[1]=h+p,t[2]=f-M,t[3]=0,t[4]=h-p,t[5]=1-c-m,t[6]=v+d,t[7]=0,t[8]=f+M,t[9]=v-d,t[10]=1-c-l,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},e.frustum=function(t,e,n,r,a,o,i){var u=1/(n-e),s=1/(a-r),c=1/(o-i);return t[0]=2*o*u,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=2*o*s,t[6]=0,t[7]=0,t[8]=(n+e)*u,t[9]=(a+r)*s,t[10]=(i+o)*c,t[11]=-1,t[12]=0,t[13]=0,t[14]=i*o*2*c,t[15]=0,t},e.perspective=function(t,e,n,r,a){var o=1/Math.tan(e/2),i=1/(r-a);return t[0]=o/n,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[10]=(a+r)*i,t[11]=-1,t[12]=0,t[13]=0,t[14]=2*a*r*i,t[15]=0,t},e.perspectiveFromFieldOfView=function(t,e,n,r){var a=Math.tan(e.upDegrees*Math.PI/180),o=Math.tan(e.downDegrees*Math.PI/180),i=Math.tan(e.leftDegrees*Math.PI/180),u=Math.tan(e.rightDegrees*Math.PI/180),s=2/(i+u),c=2/(a+o);return t[0]=s,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=c,t[6]=0,t[7]=0,t[8]=-(i-u)*s*.5,t[9]=(a-o)*c*.5,t[10]=r/(n-r),t[11]=-1,t[12]=0,t[13]=0,t[14]=r*n/(n-r),t[15]=0,t},e.ortho=function(t,e,n,r,a,o,i){var u=1/(e-n),s=1/(r-a),c=1/(o-i);return t[0]=-2*u,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=-2*s,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=2*c,t[11]=0,t[12]=(e+n)*u,t[13]=(a+r)*s,t[14]=(i+o)*c,t[15]=1,t},e.lookAt=function(t,e,n,r){var a=void 0,o=void 0,i=void 0,u=void 0,s=void 0,c=void 0,h=void 0,l=void 0,f=void 0,v=void 0,m=e[0],d=e[1],M=e[2],p=r[0],b=r[1],y=r[2],g=n[0],P=n[1],E=n[2];return Math.abs(m-g)e[0]&&(a=1),e[8]>e[3*a+a]&&(a=2);var o=(a+1)%3,i=(a+2)%3;r=Math.sqrt(e[3*a+a]-e[3*o+o]-e[3*i+i]+1),t[a]=.5*r,r=.5/r,t[3]=(e[3*o+i]-e[3*i+o])*r,t[o]=(e[3*o+a]+e[3*a+o])*r,t[i]=(e[3*i+a]+e[3*a+i])*r}return t}Object.defineProperty(e,"__esModule",{value:!0}),e.setAxes=e.sqlerp=e.rotationTo=e.equals=e.exactEquals=e.normalize=e.sqrLen=e.squaredLength=e.len=e.length=e.lerp=e.dot=e.scale=e.mul=e.add=e.set=e.copy=e.fromValues=e.clone=void 0,e.create=a,e.identity=function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t},e.setAxisAngle=o,e.getAxisAngle=function(t,e){var n=2*Math.acos(e[3]),r=Math.sin(n/2);return 0!=r?(t[0]=e[0]/r,t[1]=e[1]/r,t[2]=e[2]/r):(t[0]=1,t[1]=0,t[2]=0),n},e.multiply=i,e.rotateX=function(t,e,n){n*=.5;var r=e[0],a=e[1],o=e[2],i=e[3],u=Math.sin(n),s=Math.cos(n);return t[0]=r*s+i*u,t[1]=a*s+o*u,t[2]=o*s-a*u,t[3]=i*s-r*u,t},e.rotateY=function(t,e,n){n*=.5;var r=e[0],a=e[1],o=e[2],i=e[3],u=Math.sin(n),s=Math.cos(n);return t[0]=r*s-o*u,t[1]=a*s+i*u,t[2]=o*s+r*u,t[3]=i*s-a*u,t},e.rotateZ=function(t,e,n){n*=.5;var r=e[0],a=e[1],o=e[2],i=e[3],u=Math.sin(n),s=Math.cos(n);return t[0]=r*s+a*u,t[1]=a*s-r*u,t[2]=o*s+i*u,t[3]=i*s-o*u,t},e.calculateW=function(t,e){var n=e[0],r=e[1],a=e[2];return t[0]=n,t[1]=r,t[2]=a,t[3]=Math.sqrt(Math.abs(1-n*n-r*r-a*a)),t},e.slerp=u,e.invert=function(t,e){var n=e[0],r=e[1],a=e[2],o=e[3],i=n*n+r*r+a*a+o*o,u=i?1/i:0;return t[0]=-n*u,t[1]=-r*u,t[2]=-a*u,t[3]=o*u,t},e.conjugate=function(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t[3]=e[3],t},e.fromMat3=s,e.fromEuler=function(t,e,n,r){var a=.5*Math.PI/180;e*=a,n*=a,r*=a;var o=Math.sin(e),i=Math.cos(e),u=Math.sin(n),s=Math.cos(n),c=Math.sin(r),h=Math.cos(r);return t[0]=o*s*h-i*u*c,t[1]=i*u*h+o*s*c,t[2]=i*s*c-o*u*h,t[3]=i*s*h+o*u*c,t},e.str=function(t){return"quat("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"};var c,h,l,f,v,m,d=r(n(0)),M=r(n(1)),p=r(n(2)),b=r(n(3)),y=(e.clone=b.clone,e.fromValues=b.fromValues,e.copy=b.copy,e.set=b.set,e.add=b.add,e.mul=i,e.scale=b.scale,e.dot=b.dot,e.lerp=b.lerp,e.length=b.length),g=(e.len=y,e.squaredLength=b.squaredLength),P=(e.sqrLen=g,e.normalize=b.normalize);e.exactEquals=b.exactEquals,e.equals=b.equals,e.rotationTo=(f=p.create(),v=p.fromValues(1,0,0),m=p.fromValues(0,1,0),function(t,e,n){var r=p.dot(e,n);return r<-.999999?(p.cross(f,v,e),p.len(f)<1e-6&&p.cross(f,m,e),p.normalize(f,f),o(t,f,Math.PI),t):.999999 - - - CSS3DRenderer - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + c3r - Spinning box + + + + + + diff --git a/examples/index.html b/examples/index.html index 5846047..65f8866 100644 --- a/examples/index.html +++ b/examples/index.html @@ -1,86 +1,137 @@ - - - CSS3D examples - Adam Kecskes - - - - + - - - - - -

CSS3D examples

- -

Standalone projects

- - - -

Ported Three.js projects

- - - -
- -
- - - \ No newline at end of file + +

c3r examples

+ +

Standalone

+ + + +

Ported three.js examples

+ + + +
+ +
+ + diff --git a/examples/js/ImprovedNoise.js b/examples/js/ImprovedNoise.js deleted file mode 100644 index a3f58fd..0000000 --- a/examples/js/ImprovedNoise.js +++ /dev/null @@ -1,71 +0,0 @@ -// http://mrl.nyu.edu/~perlin/noise/ - -var ImprovedNoise = function () { - - var p = [ 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10, - 23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87, - 174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211, - 133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208, - 89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,5, - 202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,170,213,119, - 248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,224,232, - 178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249, - 14,239,107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,205, - 93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 ]; - - for (var i = 0; i < 256 ; i ++) { - - p[256 + i] = p[i]; - - } - - function fade(t) { - - return t * t * t * (t * (t * 6 - 15) + 10); - - } - - function lerp(t, a, b) { - - return a + t * (b - a); - - } - - function grad(hash, x, y, z) { - - var h = hash & 15; - var u = h < 8 ? x : y, v = h < 4 ? y : h == 12 || h == 14 ? x : z; - return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v); - - } - - return { - - noise: function (x, y, z) { - - var floorX = Math.floor(x), floorY = Math.floor(y), floorZ = Math.floor(z); - - var X = floorX & 255, Y = floorY & 255, Z = floorZ & 255; - - x -= floorX; - y -= floorY; - z -= floorZ; - - var xMinus1 = x - 1, yMinus1 = y - 1, zMinus1 = z - 1; - - var u = fade(x), v = fade(y), w = fade(z); - - var A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z, B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z; - - return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), - grad(p[BA], xMinus1, y, z)), - lerp(u, grad(p[AB], x, yMinus1, z), - grad(p[BB], xMinus1, yMinus1, z))), - lerp(v, lerp(u, grad(p[AA + 1], x, y, zMinus1), - grad(p[BA + 1], xMinus1, y, z - 1)), - lerp(u, grad(p[AB + 1], x, yMinus1, zMinus1), - grad(p[BB + 1], xMinus1, yMinus1, zMinus1)))); - - } - } -}; \ No newline at end of file diff --git a/examples/js/controls/OrbitControls.js b/examples/js/controls/OrbitControls.js deleted file mode 100644 index 7234013..0000000 --- a/examples/js/controls/OrbitControls.js +++ /dev/null @@ -1,1067 +0,0 @@ -/** - * @author qiao / https://github.com/qiao - * @author mrdoob / http://mrdoob.com - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - * @author erich666 / http://erichaines.com - */ - -// This set of controls performs orbiting, dollying (zooming), and panning. -// Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). -// -// Orbit - left mouse / touch: one finger move -// Zoom - middle mouse, or mousewheel / touch: two finger spread or squish -// Pan - right mouse, or arrow keys / touch: three finger swipe - -THREE.OrbitControls = function ( object, domElement ) { - - this.object = object; - - this.domElement = ( domElement !== undefined ) ? domElement : document; - - // Set to false to disable this control - this.enabled = true; - - // "target" sets the location of focus, where the object orbits around - this.target = new THREE.Vector3(); - - // How far you can dolly in and out ( PerspectiveCamera only ) - this.minDistance = 0; - this.maxDistance = Infinity; - - // How far you can zoom in and out ( OrthographicCamera only ) - this.minZoom = 0; - this.maxZoom = Infinity; - - // How far you can orbit vertically, upper and lower limits. - // Range is 0 to Math.PI radians. - this.minPolarAngle = 0; // radians - this.maxPolarAngle = Math.PI; // radians - - // How far you can orbit horizontally, upper and lower limits. - // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ]. - this.minAzimuthAngle = - Infinity; // radians - this.maxAzimuthAngle = Infinity; // radians - - // Set to true to enable damping (inertia) - // If damping is enabled, you must call controls.update() in your animation loop - this.enableDamping = false; - this.dampingFactor = 0.25; - - // This option actually enables dollying in and out; left as "zoom" for backwards compatibility. - // Set to false to disable zooming - this.enableZoom = true; - this.zoomSpeed = 1.0; - - // Set to false to disable rotating - this.enableRotate = true; - this.rotateSpeed = 1.0; - - // Set to false to disable panning - this.enablePan = true; - this.panSpeed = 1.0; - this.panningMode = THREE.ScreenSpacePanning; // alternate THREE.HorizontalPanning - this.keyPanSpeed = 7.0; // pixels moved per arrow key push - - // Set to true to automatically rotate around the target - // If auto-rotate is enabled, you must call controls.update() in your animation loop - this.autoRotate = false; - this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 - - // Set to false to disable use of the keys - this.enableKeys = true; - - // The four arrow keys - this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; - - // Mouse buttons - this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT }; - - // for reset - this.target0 = this.target.clone(); - this.position0 = this.object.position.clone(); - this.zoom0 = this.object.zoom; - - // - // public methods - // - - this.getPolarAngle = function () { - - return spherical.phi; - - }; - - this.getAzimuthalAngle = function () { - - return spherical.theta; - - }; - - this.saveState = function () { - - scope.target0.copy( scope.target ); - scope.position0.copy( scope.object.position ); - scope.zoom0 = scope.object.zoom; - - }; - - this.reset = function () { - - scope.target.copy( scope.target0 ); - scope.object.position.copy( scope.position0 ); - scope.object.zoom = scope.zoom0; - - scope.object.updateProjectionMatrix(); - scope.dispatchEvent( changeEvent ); - - scope.update(); - - state = STATE.NONE; - - }; - - // this method is exposed, but perhaps it would be better if we can make it private... - this.update = function () { - - var offset = new THREE.Vector3(); - - // so camera.up is the orbit axis - var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) ); - var quatInverse = quat.clone().inverse(); - - var lastPosition = new THREE.Vector3(); - var lastQuaternion = new THREE.Quaternion(); - - return function update() { - - var position = scope.object.position; - - offset.copy( position ).sub( scope.target ); - - // rotate offset to "y-axis-is-up" space - offset.applyQuaternion( quat ); - - // angle from z-axis around y-axis - spherical.setFromVector3( offset ); - - if ( scope.autoRotate && state === STATE.NONE ) { - - rotateLeft( getAutoRotationAngle() ); - - } - - spherical.theta += sphericalDelta.theta; - spherical.phi += sphericalDelta.phi; - - // restrict theta to be between desired limits - spherical.theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, spherical.theta ) ); - - // restrict phi to be between desired limits - spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) ); - - spherical.makeSafe(); - - - spherical.radius *= scale; - - // restrict radius to be between desired limits - spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) ); - - // move target to panned location - scope.target.add( panOffset ); - - offset.setFromSpherical( spherical ); - - // rotate offset back to "camera-up-vector-is-up" space - offset.applyQuaternion( quatInverse ); - - position.copy( scope.target ).add( offset ); - - scope.object.lookAt( scope.target ); - - if ( scope.enableDamping === true ) { - - sphericalDelta.theta *= ( 1 - scope.dampingFactor ); - sphericalDelta.phi *= ( 1 - scope.dampingFactor ); - - panOffset.multiplyScalar( 1 - scope.dampingFactor ); - - } else { - - sphericalDelta.set( 0, 0, 0 ); - - panOffset.set( 0, 0, 0 ); - - } - - scale = 1; - - // update condition is: - // min(camera displacement, camera rotation in radians)^2 > EPS - // using small-angle approximation cos(x/2) = 1 - x^2 / 8 - - if ( zoomChanged || - lastPosition.distanceToSquared( scope.object.position ) > EPS || - 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) { - - scope.dispatchEvent( changeEvent ); - - lastPosition.copy( scope.object.position ); - lastQuaternion.copy( scope.object.quaternion ); - zoomChanged = false; - - return true; - - } - - return false; - - }; - - }(); - - this.dispose = function () { - - scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false ); - scope.domElement.removeEventListener( 'mousedown', onMouseDown, false ); - scope.domElement.removeEventListener( 'wheel', onMouseWheel, false ); - - scope.domElement.removeEventListener( 'touchstart', onTouchStart, false ); - scope.domElement.removeEventListener( 'touchend', onTouchEnd, false ); - scope.domElement.removeEventListener( 'touchmove', onTouchMove, false ); - - document.removeEventListener( 'mousemove', onMouseMove, false ); - document.removeEventListener( 'mouseup', onMouseUp, false ); - - window.removeEventListener( 'keydown', onKeyDown, false ); - - //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here? - - }; - - // - // internals - // - - var scope = this; - - var changeEvent = { type: 'change' }; - var startEvent = { type: 'start' }; - var endEvent = { type: 'end' }; - - var STATE = { NONE: - 1, ROTATE: 0, DOLLY: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_DOLLY: 4, TOUCH_PAN: 5 }; - - var state = STATE.NONE; - - var EPS = 0.000001; - - // current position in spherical coordinates - var spherical = new THREE.Spherical(); - var sphericalDelta = new THREE.Spherical(); - - var scale = 1; - var panOffset = new THREE.Vector3(); - var zoomChanged = false; - - var rotateStart = new THREE.Vector2(); - var rotateEnd = new THREE.Vector2(); - var rotateDelta = new THREE.Vector2(); - - var panStart = new THREE.Vector2(); - var panEnd = new THREE.Vector2(); - var panDelta = new THREE.Vector2(); - - var dollyStart = new THREE.Vector2(); - var dollyEnd = new THREE.Vector2(); - var dollyDelta = new THREE.Vector2(); - - function getAutoRotationAngle() { - - return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; - - } - - function getZoomScale() { - - return Math.pow( 0.95, scope.zoomSpeed ); - - } - - function rotateLeft( angle ) { - - sphericalDelta.theta -= angle; - - } - - function rotateUp( angle ) { - - sphericalDelta.phi -= angle; - - } - - var panLeft = function () { - - var v = new THREE.Vector3(); - - return function panLeft( distance, objectMatrix ) { - - v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix - v.multiplyScalar( - distance ); - - panOffset.add( v ); - - }; - - }(); - - var panUp = function () { - - var v = new THREE.Vector3(); - - return function panUp( distance, objectMatrix ) { - - switch ( scope.panningMode ) { - - case THREE.ScreenSpacePanning: - - v.setFromMatrixColumn( objectMatrix, 1 ); - break; - - case THREE.HorizontalPanning: - - v.setFromMatrixColumn( objectMatrix, 0 ); - v.crossVectors( scope.object.up, v ); - break; - - } - - v.multiplyScalar( distance ); - - panOffset.add( v ); - - }; - - }(); - - // deltaX and deltaY are in pixels; right and down are positive - var pan = function () { - - var offset = new THREE.Vector3(); - - return function pan( deltaX, deltaY ) { - - var element = scope.domElement === document ? scope.domElement.body : scope.domElement; - - if ( scope.object.isPerspectiveCamera ) { - - // perspective - var position = scope.object.position; - offset.copy( position ).sub( scope.target ); - var targetDistance = offset.length(); - - // half of the fov is center to top of screen - targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 ); - - // we actually don't use screenWidth, since perspective camera is fixed to screen height - panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix ); - panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix ); - - } else if ( scope.object.isOrthographicCamera ) { - - // orthographic - panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix ); - panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix ); - - } else { - - // camera neither orthographic nor perspective - console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); - scope.enablePan = false; - - } - - }; - - }(); - - function dollyIn( dollyScale ) { - - if ( scope.object.isPerspectiveCamera ) { - - scale /= dollyScale; - - } else if ( scope.object.isOrthographicCamera ) { - - scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) ); - scope.object.updateProjectionMatrix(); - zoomChanged = true; - - } else { - - console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); - scope.enableZoom = false; - - } - - } - - function dollyOut( dollyScale ) { - - if ( scope.object.isPerspectiveCamera ) { - - scale *= dollyScale; - - } else if ( scope.object.isOrthographicCamera ) { - - scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) ); - scope.object.updateProjectionMatrix(); - zoomChanged = true; - - } else { - - console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); - scope.enableZoom = false; - - } - - } - - // - // event callbacks - update the object state - // - - function handleMouseDownRotate( event ) { - - //console.log( 'handleMouseDownRotate' ); - - rotateStart.set( event.clientX, event.clientY ); - - } - - function handleMouseDownDolly( event ) { - - //console.log( 'handleMouseDownDolly' ); - - dollyStart.set( event.clientX, event.clientY ); - - } - - function handleMouseDownPan( event ) { - - //console.log( 'handleMouseDownPan' ); - - panStart.set( event.clientX, event.clientY ); - - } - - function handleMouseMoveRotate( event ) { - - //console.log( 'handleMouseMoveRotate' ); - - rotateEnd.set( event.clientX, event.clientY ); - - rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );; - - var element = scope.domElement === document ? scope.domElement.body : scope.domElement; - - // rotating across whole screen goes 360 degrees around - rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth ); - - // rotating up and down along whole screen attempts to go 360, but limited to 180 - rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight ); - - rotateStart.copy( rotateEnd ); - - scope.update(); - - } - - function handleMouseMoveDolly( event ) { - - //console.log( 'handleMouseMoveDolly' ); - - dollyEnd.set( event.clientX, event.clientY ); - - dollyDelta.subVectors( dollyEnd, dollyStart ); - - if ( dollyDelta.y > 0 ) { - - dollyIn( getZoomScale() ); - - } else if ( dollyDelta.y < 0 ) { - - dollyOut( getZoomScale() ); - - } - - dollyStart.copy( dollyEnd ); - - scope.update(); - - } - - function handleMouseMovePan( event ) { - - //console.log( 'handleMouseMovePan' ); - - panEnd.set( event.clientX, event.clientY ); - - panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed ); - - pan( panDelta.x, panDelta.y ); - - panStart.copy( panEnd ); - - scope.update(); - - } - - function handleMouseUp( event ) { - - // console.log( 'handleMouseUp' ); - - } - - function handleMouseWheel( event ) { - - // console.log( 'handleMouseWheel' ); - - if ( event.deltaY < 0 ) { - - dollyOut( getZoomScale() ); - - } else if ( event.deltaY > 0 ) { - - dollyIn( getZoomScale() ); - - } - - scope.update(); - - } - - function handleKeyDown( event ) { - - //console.log( 'handleKeyDown' ); - - switch ( event.keyCode ) { - - case scope.keys.UP: - pan( 0, scope.keyPanSpeed ); - scope.update(); - break; - - case scope.keys.BOTTOM: - pan( 0, - scope.keyPanSpeed ); - scope.update(); - break; - - case scope.keys.LEFT: - pan( scope.keyPanSpeed, 0 ); - scope.update(); - break; - - case scope.keys.RIGHT: - pan( - scope.keyPanSpeed, 0 ); - scope.update(); - break; - - } - - } - - function handleTouchStartRotate( event ) { - - //console.log( 'handleTouchStartRotate' ); - - rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - - } - - function handleTouchStartDolly( event ) { - - //console.log( 'handleTouchStartDolly' ); - - var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; - var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; - - var distance = Math.sqrt( dx * dx + dy * dy ); - - dollyStart.set( 0, distance ); - - } - - function handleTouchStartPan( event ) { - - //console.log( 'handleTouchStartPan' ); - - panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - - } - - function handleTouchMoveRotate( event ) { - - //console.log( 'handleTouchMoveRotate' ); - - rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - - rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed ); - - var element = scope.domElement === document ? scope.domElement.body : scope.domElement; - - // rotating across whole screen goes 360 degrees around - rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth ); - - // rotating up and down along whole screen attempts to go 360, but limited to 180 - rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight ); - - rotateStart.copy( rotateEnd ); - - scope.update(); - - } - - function handleTouchMoveDolly( event ) { - - //console.log( 'handleTouchMoveDolly' ); - - var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; - var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; - - var distance = Math.sqrt( dx * dx + dy * dy ); - - dollyEnd.set( 0, distance ); - - dollyDelta.subVectors( dollyEnd, dollyStart ); - - if ( dollyDelta.y > 0 ) { - - dollyOut( getZoomScale() ); - - } else if ( dollyDelta.y < 0 ) { - - dollyIn( getZoomScale() ); - - } - - dollyStart.copy( dollyEnd ); - - scope.update(); - - } - - function handleTouchMovePan( event ) { - - //console.log( 'handleTouchMovePan' ); - - panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - - panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed ); - - pan( panDelta.x, panDelta.y ); - - panStart.copy( panEnd ); - - scope.update(); - - } - - function handleTouchEnd( event ) { - - //console.log( 'handleTouchEnd' ); - - } - - // - // event handlers - FSM: listen for events and reset state - // - - function onMouseDown( event ) { - - if ( scope.enabled === false ) return; - - event.preventDefault(); - - switch ( event.button ) { - - case scope.mouseButtons.ORBIT: - - if ( scope.enableRotate === false ) return; - - handleMouseDownRotate( event ); - - state = STATE.ROTATE; - - break; - - case scope.mouseButtons.ZOOM: - - if ( scope.enableZoom === false ) return; - - handleMouseDownDolly( event ); - - state = STATE.DOLLY; - - break; - - case scope.mouseButtons.PAN: - - if ( scope.enablePan === false ) return; - - handleMouseDownPan( event ); - - state = STATE.PAN; - - break; - - } - - if ( state !== STATE.NONE ) { - - document.addEventListener( 'mousemove', onMouseMove, false ); - document.addEventListener( 'mouseup', onMouseUp, false ); - - scope.dispatchEvent( startEvent ); - - } - - } - - function onMouseMove( event ) { - - if ( scope.enabled === false ) return; - - event.preventDefault(); - - switch ( state ) { - - case STATE.ROTATE: - - if ( scope.enableRotate === false ) return; - - handleMouseMoveRotate( event ); - - break; - - case STATE.DOLLY: - - if ( scope.enableZoom === false ) return; - - handleMouseMoveDolly( event ); - - break; - - case STATE.PAN: - - if ( scope.enablePan === false ) return; - - handleMouseMovePan( event ); - - break; - - } - - } - - function onMouseUp( event ) { - - if ( scope.enabled === false ) return; - - handleMouseUp( event ); - - document.removeEventListener( 'mousemove', onMouseMove, false ); - document.removeEventListener( 'mouseup', onMouseUp, false ); - - scope.dispatchEvent( endEvent ); - - state = STATE.NONE; - - } - - function onMouseWheel( event ) { - - if ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return; - - event.preventDefault(); - event.stopPropagation(); - - scope.dispatchEvent( startEvent ); - - handleMouseWheel( event ); - - scope.dispatchEvent( endEvent ); - - } - - function onKeyDown( event ) { - - if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return; - - handleKeyDown( event ); - - } - - function onTouchStart( event ) { - - if ( scope.enabled === false ) return; - - switch ( event.touches.length ) { - - case 1: // one-fingered touch: rotate - - if ( scope.enableRotate === false ) return; - - handleTouchStartRotate( event ); - - state = STATE.TOUCH_ROTATE; - - break; - - case 2: // two-fingered touch: dolly - - if ( scope.enableZoom === false ) return; - - handleTouchStartDolly( event ); - - state = STATE.TOUCH_DOLLY; - - break; - - case 3: // three-fingered touch: pan - - if ( scope.enablePan === false ) return; - - handleTouchStartPan( event ); - - state = STATE.TOUCH_PAN; - - break; - - default: - - state = STATE.NONE; - - } - - if ( state !== STATE.NONE ) { - - scope.dispatchEvent( startEvent ); - - } - - } - - function onTouchMove( event ) { - - if ( scope.enabled === false ) return; - - event.preventDefault(); - event.stopPropagation(); - - switch ( event.touches.length ) { - - case 1: // one-fingered touch: rotate - - if ( scope.enableRotate === false ) return; - if ( state !== STATE.TOUCH_ROTATE ) return; // is this needed?... - - handleTouchMoveRotate( event ); - - break; - - case 2: // two-fingered touch: dolly - - if ( scope.enableZoom === false ) return; - if ( state !== STATE.TOUCH_DOLLY ) return; // is this needed?... - - handleTouchMoveDolly( event ); - - break; - - case 3: // three-fingered touch: pan - - if ( scope.enablePan === false ) return; - if ( state !== STATE.TOUCH_PAN ) return; // is this needed?... - - handleTouchMovePan( event ); - - break; - - default: - - state = STATE.NONE; - - } - - } - - function onTouchEnd( event ) { - - if ( scope.enabled === false ) return; - - handleTouchEnd( event ); - - scope.dispatchEvent( endEvent ); - - state = STATE.NONE; - - } - - function onContextMenu( event ) { - - if ( scope.enabled === false ) return; - - event.preventDefault(); - - } - - // - - scope.domElement.addEventListener( 'contextmenu', onContextMenu, false ); - - scope.domElement.addEventListener( 'mousedown', onMouseDown, false ); - scope.domElement.addEventListener( 'wheel', onMouseWheel, false ); - - scope.domElement.addEventListener( 'touchstart', onTouchStart, false ); - scope.domElement.addEventListener( 'touchend', onTouchEnd, false ); - scope.domElement.addEventListener( 'touchmove', onTouchMove, false ); - - window.addEventListener( 'keydown', onKeyDown, false ); - - // force an update at start - - this.update(); - -}; - -THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype ); -THREE.OrbitControls.prototype.constructor = THREE.OrbitControls; - -Object.defineProperties( THREE.OrbitControls.prototype, { - - center: { - - get: function () { - - console.warn( 'THREE.OrbitControls: .center has been renamed to .target' ); - return this.target; - - } - - }, - - // backward compatibility - - noZoom: { - - get: function () { - - console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); - return ! this.enableZoom; - - }, - - set: function ( value ) { - - console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); - this.enableZoom = ! value; - - } - - }, - - noRotate: { - - get: function () { - - console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); - return ! this.enableRotate; - - }, - - set: function ( value ) { - - console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); - this.enableRotate = ! value; - - } - - }, - - noPan: { - - get: function () { - - console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); - return ! this.enablePan; - - }, - - set: function ( value ) { - - console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); - this.enablePan = ! value; - - } - - }, - - noKeys: { - - get: function () { - - console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); - return ! this.enableKeys; - - }, - - set: function ( value ) { - - console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); - this.enableKeys = ! value; - - } - - }, - - staticMoving: { - - get: function () { - - console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); - return ! this.enableDamping; - - }, - - set: function ( value ) { - - console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); - this.enableDamping = ! value; - - } - - }, - - dynamicDampingFactor: { - - get: function () { - - console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); - return this.dampingFactor; - - }, - - set: function ( value ) { - - console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); - this.dampingFactor = value; - - } - - } - -} ); - -THREE.ScreenSpacePanning = 0; -THREE.HorizontalPanning = 1; diff --git a/examples/js/controls/TrackballControls.js b/examples/js/controls/TrackballControls.js deleted file mode 100644 index 79168f8..0000000 --- a/examples/js/controls/TrackballControls.js +++ /dev/null @@ -1,627 +0,0 @@ -/** - * @author Eberhard Graether / http://egraether.com/ - * @author Mark Lundin / http://mark-lundin.com - * @author Simone Manini / http://daron1337.github.io - * @author Luca Antiga / http://lantiga.github.io - */ - -THREE.TrackballControls = function ( object, domElement ) { - - var _this = this; - var STATE = { NONE: - 1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 }; - - this.object = object; - this.domElement = ( domElement !== undefined ) ? domElement : document; - - // API - - this.enabled = true; - - this.screen = { left: 0, top: 0, width: 0, height: 0 }; - - this.rotateSpeed = 1.0; - this.zoomSpeed = 1.2; - this.panSpeed = 0.3; - - this.noRotate = false; - this.noZoom = false; - this.noPan = false; - - this.staticMoving = false; - this.dynamicDampingFactor = 0.2; - - this.minDistance = 0; - this.maxDistance = Infinity; - - this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ]; - - // internals - - this.target = new THREE.Vector3(); - - var EPS = 0.000001; - - var lastPosition = new THREE.Vector3(); - - var _state = STATE.NONE, - _prevState = STATE.NONE, - - _eye = new THREE.Vector3(), - - _movePrev = new THREE.Vector2(), - _moveCurr = new THREE.Vector2(), - - _lastAxis = new THREE.Vector3(), - _lastAngle = 0, - - _zoomStart = new THREE.Vector2(), - _zoomEnd = new THREE.Vector2(), - - _touchZoomDistanceStart = 0, - _touchZoomDistanceEnd = 0, - - _panStart = new THREE.Vector2(), - _panEnd = new THREE.Vector2(); - - // for reset - - this.target0 = this.target.clone(); - this.position0 = this.object.position.clone(); - this.up0 = this.object.up.clone(); - - // events - - var changeEvent = { type: 'change' }; - var startEvent = { type: 'start' }; - var endEvent = { type: 'end' }; - - - // methods - - this.handleResize = function () { - - if ( this.domElement === document ) { - - this.screen.left = 0; - this.screen.top = 0; - this.screen.width = window.innerWidth; - this.screen.height = window.innerHeight; - - } else { - - var box = this.domElement.getBoundingClientRect(); - // adjustments come from similar code in the jquery offset() function - var d = this.domElement.ownerDocument.documentElement; - this.screen.left = box.left + window.pageXOffset - d.clientLeft; - this.screen.top = box.top + window.pageYOffset - d.clientTop; - this.screen.width = box.width; - this.screen.height = box.height; - - } - - }; - - this.handleEvent = function ( event ) { - - if ( typeof this[ event.type ] == 'function' ) { - - this[ event.type ]( event ); - - } - - }; - - var getMouseOnScreen = ( function () { - - var vector = new THREE.Vector2(); - - return function getMouseOnScreen( pageX, pageY ) { - - vector.set( - ( pageX - _this.screen.left ) / _this.screen.width, - ( pageY - _this.screen.top ) / _this.screen.height - ); - - return vector; - - }; - - }() ); - - var getMouseOnCircle = ( function () { - - var vector = new THREE.Vector2(); - - return function getMouseOnCircle( pageX, pageY ) { - - vector.set( - ( ( pageX - _this.screen.width * 0.5 - _this.screen.left ) / ( _this.screen.width * 0.5 ) ), - ( ( _this.screen.height + 2 * ( _this.screen.top - pageY ) ) / _this.screen.width ) // screen.width intentional - ); - - return vector; - - }; - - }() ); - - this.rotateCamera = ( function() { - - var axis = new THREE.Vector3(), - quaternion = new THREE.Quaternion(), - eyeDirection = new THREE.Vector3(), - objectUpDirection = new THREE.Vector3(), - objectSidewaysDirection = new THREE.Vector3(), - moveDirection = new THREE.Vector3(), - angle; - - return function rotateCamera() { - - moveDirection.set( _moveCurr.x - _movePrev.x, _moveCurr.y - _movePrev.y, 0 ); - angle = moveDirection.length(); - - if ( angle ) { - - _eye.copy( _this.object.position ).sub( _this.target ); - - eyeDirection.copy( _eye ).normalize(); - objectUpDirection.copy( _this.object.up ).normalize(); - objectSidewaysDirection.crossVectors( objectUpDirection, eyeDirection ).normalize(); - - objectUpDirection.setLength( _moveCurr.y - _movePrev.y ); - objectSidewaysDirection.setLength( _moveCurr.x - _movePrev.x ); - - moveDirection.copy( objectUpDirection.add( objectSidewaysDirection ) ); - - axis.crossVectors( moveDirection, _eye ).normalize(); - - angle *= _this.rotateSpeed; - quaternion.setFromAxisAngle( axis, angle ); - - _eye.applyQuaternion( quaternion ); - _this.object.up.applyQuaternion( quaternion ); - - _lastAxis.copy( axis ); - _lastAngle = angle; - - } else if ( ! _this.staticMoving && _lastAngle ) { - - _lastAngle *= Math.sqrt( 1.0 - _this.dynamicDampingFactor ); - _eye.copy( _this.object.position ).sub( _this.target ); - quaternion.setFromAxisAngle( _lastAxis, _lastAngle ); - _eye.applyQuaternion( quaternion ); - _this.object.up.applyQuaternion( quaternion ); - - } - - _movePrev.copy( _moveCurr ); - - }; - - }() ); - - - this.zoomCamera = function () { - - var factor; - - if ( _state === STATE.TOUCH_ZOOM_PAN ) { - - factor = _touchZoomDistanceStart / _touchZoomDistanceEnd; - _touchZoomDistanceStart = _touchZoomDistanceEnd; - _eye.multiplyScalar( factor ); - - } else { - - factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed; - - if ( factor !== 1.0 && factor > 0.0 ) { - - _eye.multiplyScalar( factor ); - - } - - if ( _this.staticMoving ) { - - _zoomStart.copy( _zoomEnd ); - - } else { - - _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor; - - } - - } - - }; - - this.panCamera = ( function() { - - var mouseChange = new THREE.Vector2(), - objectUp = new THREE.Vector3(), - pan = new THREE.Vector3(); - - return function panCamera() { - - mouseChange.copy( _panEnd ).sub( _panStart ); - - if ( mouseChange.lengthSq() ) { - - mouseChange.multiplyScalar( _eye.length() * _this.panSpeed ); - - pan.copy( _eye ).cross( _this.object.up ).setLength( mouseChange.x ); - pan.add( objectUp.copy( _this.object.up ).setLength( mouseChange.y ) ); - - _this.object.position.add( pan ); - _this.target.add( pan ); - - if ( _this.staticMoving ) { - - _panStart.copy( _panEnd ); - - } else { - - _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) ); - - } - - } - - }; - - }() ); - - this.checkDistances = function () { - - if ( ! _this.noZoom || ! _this.noPan ) { - - if ( _eye.lengthSq() > _this.maxDistance * _this.maxDistance ) { - - _this.object.position.addVectors( _this.target, _eye.setLength( _this.maxDistance ) ); - _zoomStart.copy( _zoomEnd ); - - } - - if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) { - - _this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) ); - _zoomStart.copy( _zoomEnd ); - - } - - } - - }; - - this.update = function () { - - _eye.subVectors( _this.object.position, _this.target ); - - if ( ! _this.noRotate ) { - - _this.rotateCamera(); - - } - - if ( ! _this.noZoom ) { - - _this.zoomCamera(); - - } - - if ( ! _this.noPan ) { - - _this.panCamera(); - - } - - _this.object.position.addVectors( _this.target, _eye ); - - _this.checkDistances(); - - _this.object.lookAt( _this.target ); - - if ( lastPosition.distanceToSquared( _this.object.position ) > EPS ) { - - _this.dispatchEvent( changeEvent ); - - lastPosition.copy( _this.object.position ); - - } - - }; - - this.reset = function () { - - _state = STATE.NONE; - _prevState = STATE.NONE; - - _this.target.copy( _this.target0 ); - _this.object.position.copy( _this.position0 ); - _this.object.up.copy( _this.up0 ); - - _eye.subVectors( _this.object.position, _this.target ); - - _this.object.lookAt( _this.target ); - - _this.dispatchEvent( changeEvent ); - - lastPosition.copy( _this.object.position ); - - }; - - // listeners - - function keydown( event ) { - - if ( _this.enabled === false ) return; - - window.removeEventListener( 'keydown', keydown ); - - _prevState = _state; - - if ( _state !== STATE.NONE ) { - - return; - - } else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && ! _this.noRotate ) { - - _state = STATE.ROTATE; - - } else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && ! _this.noZoom ) { - - _state = STATE.ZOOM; - - } else if ( event.keyCode === _this.keys[ STATE.PAN ] && ! _this.noPan ) { - - _state = STATE.PAN; - - } - - } - - function keyup( event ) { - - if ( _this.enabled === false ) return; - - _state = _prevState; - - window.addEventListener( 'keydown', keydown, false ); - - } - - function mousedown( event ) { - - if ( _this.enabled === false ) return; - - event.preventDefault(); - event.stopPropagation(); - - if ( _state === STATE.NONE ) { - - _state = event.button; - - } - - if ( _state === STATE.ROTATE && ! _this.noRotate ) { - - _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) ); - _movePrev.copy( _moveCurr ); - - } else if ( _state === STATE.ZOOM && ! _this.noZoom ) { - - _zoomStart.copy( getMouseOnScreen( event.pageX, event.pageY ) ); - _zoomEnd.copy( _zoomStart ); - - } else if ( _state === STATE.PAN && ! _this.noPan ) { - - _panStart.copy( getMouseOnScreen( event.pageX, event.pageY ) ); - _panEnd.copy( _panStart ); - - } - - document.addEventListener( 'mousemove', mousemove, false ); - document.addEventListener( 'mouseup', mouseup, false ); - - _this.dispatchEvent( startEvent ); - - } - - function mousemove( event ) { - - if ( _this.enabled === false ) return; - - event.preventDefault(); - event.stopPropagation(); - - if ( _state === STATE.ROTATE && ! _this.noRotate ) { - - _movePrev.copy( _moveCurr ); - _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) ); - - } else if ( _state === STATE.ZOOM && ! _this.noZoom ) { - - _zoomEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) ); - - } else if ( _state === STATE.PAN && ! _this.noPan ) { - - _panEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) ); - - } - - } - - function mouseup( event ) { - - if ( _this.enabled === false ) return; - - event.preventDefault(); - event.stopPropagation(); - - _state = STATE.NONE; - - document.removeEventListener( 'mousemove', mousemove ); - document.removeEventListener( 'mouseup', mouseup ); - _this.dispatchEvent( endEvent ); - - } - - function mousewheel( event ) { - - if ( _this.enabled === false ) return; - - if ( _this.noZoom === true ) return; - - event.preventDefault(); - event.stopPropagation(); - - switch ( event.deltaMode ) { - - case 2: - // Zoom in pages - _zoomStart.y -= event.deltaY * 0.025; - break; - - case 1: - // Zoom in lines - _zoomStart.y -= event.deltaY * 0.01; - break; - - default: - // undefined, 0, assume pixels - _zoomStart.y -= event.deltaY * 0.00025; - break; - - } - - _this.dispatchEvent( startEvent ); - _this.dispatchEvent( endEvent ); - - } - - function touchstart( event ) { - - if ( _this.enabled === false ) return; - - switch ( event.touches.length ) { - - case 1: - _state = STATE.TOUCH_ROTATE; - _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); - _movePrev.copy( _moveCurr ); - break; - - default: // 2 or more - _state = STATE.TOUCH_ZOOM_PAN; - var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; - var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; - _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy ); - - var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2; - var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2; - _panStart.copy( getMouseOnScreen( x, y ) ); - _panEnd.copy( _panStart ); - break; - - } - - _this.dispatchEvent( startEvent ); - - } - - function touchmove( event ) { - - if ( _this.enabled === false ) return; - - event.preventDefault(); - event.stopPropagation(); - - switch ( event.touches.length ) { - - case 1: - _movePrev.copy( _moveCurr ); - _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); - break; - - default: // 2 or more - var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; - var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; - _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy ); - - var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2; - var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2; - _panEnd.copy( getMouseOnScreen( x, y ) ); - break; - - } - - } - - function touchend( event ) { - - if ( _this.enabled === false ) return; - - switch ( event.touches.length ) { - - case 0: - _state = STATE.NONE; - break; - - case 1: - _state = STATE.TOUCH_ROTATE; - _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); - _movePrev.copy( _moveCurr ); - break; - - } - - _this.dispatchEvent( endEvent ); - - } - - function contextmenu( event ) { - - if ( _this.enabled === false ) return; - - event.preventDefault(); - - } - - this.dispose = function() { - - this.domElement.removeEventListener( 'contextmenu', contextmenu, false ); - this.domElement.removeEventListener( 'mousedown', mousedown, false ); - this.domElement.removeEventListener( 'wheel', mousewheel, false ); - - this.domElement.removeEventListener( 'touchstart', touchstart, false ); - this.domElement.removeEventListener( 'touchend', touchend, false ); - this.domElement.removeEventListener( 'touchmove', touchmove, false ); - - document.removeEventListener( 'mousemove', mousemove, false ); - document.removeEventListener( 'mouseup', mouseup, false ); - - window.removeEventListener( 'keydown', keydown, false ); - window.removeEventListener( 'keyup', keyup, false ); - - }; - - this.domElement.addEventListener( 'contextmenu', contextmenu, false ); - this.domElement.addEventListener( 'mousedown', mousedown, false ); - this.domElement.addEventListener( 'wheel', mousewheel, false ); - - this.domElement.addEventListener( 'touchstart', touchstart, false ); - this.domElement.addEventListener( 'touchend', touchend, false ); - this.domElement.addEventListener( 'touchmove', touchmove, false ); - - window.addEventListener( 'keydown', keydown, false ); - window.addEventListener( 'keyup', keyup, false ); - - this.handleResize(); - - // force an update at start - this.update(); - -}; - -THREE.TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype ); -THREE.TrackballControls.prototype.constructor = THREE.TrackballControls; diff --git a/examples/js/libs/stats.min.js b/examples/js/libs/stats.min.js deleted file mode 100644 index 19dcb2d..0000000 --- a/examples/js/libs/stats.min.js +++ /dev/null @@ -1,5 +0,0 @@ -// stats.js - http://github.com/mrdoob/stats.js -var Stats=function(){function h(a){c.appendChild(a.dom);return a}function k(a){for(var d=0;de+1E3&&(r.update(1E3*a/(c-e),100),e=c,a=0,t)){var d=performance.memory;t.update(d.usedJSHeapSize/1048576,d.jsHeapSizeLimit/1048576)}return c},update:function(){g=this.end()},domElement:c,setMode:k}}; -Stats.Panel=function(h,k,l){var c=Infinity,g=0,e=Math.round,a=e(window.devicePixelRatio||1),r=80*a,f=48*a,t=3*a,u=2*a,d=3*a,m=15*a,n=74*a,p=30*a,q=document.createElement("canvas");q.width=r;q.height=f;q.style.cssText="width:80px;height:48px";var b=q.getContext("2d");b.font="bold "+9*a+"px Helvetica,Arial,sans-serif";b.textBaseline="top";b.fillStyle=l;b.fillRect(0,0,r,f);b.fillStyle=k;b.fillText(h,t,u);b.fillRect(d,m,n,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d,m,n,p);return{dom:q,update:function(f, -v){c=Math.min(c,f);g=Math.max(g,f);b.fillStyle=l;b.globalAlpha=1;b.fillRect(0,0,r,m);b.fillStyle=k;b.fillText(e(f)+" "+h+" ("+e(c)+"-"+e(g)+")",t,u);b.drawImage(q,d+a,m,n-a,p,d,m,n-a,p);b.fillRect(d+n-a,m,a,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d+n-a,m,a,e((1-f/v)*p))}}};"object"===typeof module&&(module.exports=Stats); \ No newline at end of file diff --git a/examples/js/libs/three.min.js b/examples/js/libs/three.min.js deleted file mode 100644 index cf51a81..0000000 --- a/examples/js/libs/three.min.js +++ /dev/null @@ -1,914 +0,0 @@ -// threejs.org/license -(function(l,xa){"object"===typeof exports&&"undefined"!==typeof module?xa(exports):"function"===typeof define&&define.amd?define(["exports"],xa):xa(l.THREE={})})(this,function(l){function xa(){}function C(a,b){this.x=a||0;this.y=b||0}function P(){this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1];0=d||0 0 ) {\n\t\tfloat fogFactor = 0.0;\n\t\tif ( fogType == 1 ) {\n\t\t\tfogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t\t} else {\n\t\t\tconst float LOG2 = 1.442695;\n\t\t\tfogFactor = exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 );\n\t\t\tfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n\t\t}\n\t\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n\t}\n}"].join("\n")); -b.compileShader(T);b.compileShader(y);b.attachShader(ma,T);b.attachShader(ma,y);b.linkProgram(ma);ia=ma;N=b.getAttribLocation(ia,"position");Z=b.getAttribLocation(ia,"uv");f=b.getUniformLocation(ia,"uvOffset");g=b.getUniformLocation(ia,"uvScale");h=b.getUniformLocation(ia,"rotation");k=b.getUniformLocation(ia,"center");m=b.getUniformLocation(ia,"scale");v=b.getUniformLocation(ia,"color");n=b.getUniformLocation(ia,"map");u=b.getUniformLocation(ia,"opacity");q=b.getUniformLocation(ia,"modelViewMatrix"); -r=b.getUniformLocation(ia,"projectionMatrix");l=b.getUniformLocation(ia,"fogType");x=b.getUniformLocation(ia,"fogDensity");B=b.getUniformLocation(ia,"fogNear");w=b.getUniformLocation(ia,"fogFar");A=b.getUniformLocation(ia,"fogColor");b.getUniformLocation(ia,"fogDepth");G=b.getUniformLocation(ia,"alphaTest");ma=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");ma.width=8;ma.height=8;T=ma.getContext("2d");T.fillStyle="white";T.fillRect(0,0,8,8);Ne=new qc(ma)}c.useProgram(ia);c.initAttributes(); -c.enableAttribute(N);c.enableAttribute(Z);c.disableUnusedAttributes();c.disable(b.CULL_FACE);c.enable(b.BLEND);b.bindBuffer(b.ARRAY_BUFFER,ya);b.vertexAttribPointer(N,2,b.FLOAT,!1,16,0);b.vertexAttribPointer(Z,2,b.FLOAT,!1,16,8);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,Rd);b.uniformMatrix4fv(r,!1,kd.projectionMatrix.elements);c.activeTexture(b.TEXTURE0);b.uniform1i(n,0);T=ma=0;(y=p.fog)?(b.uniform3f(A,y.color.r,y.color.g,y.color.b),y.isFog?(b.uniform1f(B,y.near),b.uniform1f(w,y.far),b.uniform1i(l,1),T= -ma=1):y.isFogExp2&&(b.uniform1f(x,y.density),b.uniform1i(l,2),T=ma=2)):(b.uniform1i(l,0),T=ma=0);y=0;for(var z=t.length;yb&&(b=a[c]);return b}function z(){Object.defineProperty(this,"id",{value:bg+=2});this.uuid=S.generateUUID();this.name="";this.type="BufferGeometry";this.index=null;this.attributes={};this.morphAttributes={};this.groups=[];this.boundingSphere=this.boundingBox=null;this.drawRange={start:0,count:Infinity}}function Jb(a,b,c,d,e,f){L.call(this);this.type="BoxGeometry";this.parameters={width:a,height:b,depth:c, -widthSegments:d,heightSegments:e,depthSegments:f};this.fromBufferGeometry(new nb(a,b,c,d,e,f));this.mergeVertices()}function nb(a,b,c,d,e,f){function g(a,b,c,d,e,f,g,l,Z,F,y){var r=f/Z,t=g/F,N=f/2,x=g/2,w=l/2;g=Z+1;var B=F+1,A=f=0,G,C,ya=new p;for(C=0;Cm;m++){if(n= -d[m])if(h=n[0],k=n[1]){v&&e.addAttribute("morphTarget"+m,v[h]);f&&e.addAttribute("morphNormal"+m,f[h]);c[m]=k;continue}c[m]=0}g.getUniforms().setValue(a,"morphTargetInfluences",c)}}}function jg(a,b,c){var d,e,f;this.setMode=function(a){d=a};this.setIndex=function(a){e=a.type;f=a.bytesPerElement};this.render=function(b,h){a.drawElements(d,h,e,b*f);c.calls++;c.vertices+=h;d===a.TRIANGLES?c.faces+=h/3:d===a.POINTS&&(c.points+=h)};this.renderInstances=function(g,h,k){var m=b.get("ANGLE_instanced_arrays"); -null===m?console.error("THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays."):(m.drawElementsInstancedANGLE(d,k,e,h*f,g.maxInstancedCount),c.calls++,c.vertices+=k*g.maxInstancedCount,d===a.TRIANGLES?c.faces+=g.maxInstancedCount*k/3:d===a.POINTS&&(c.points+=g.maxInstancedCount*k))}}function kg(a,b,c){var d;this.setMode=function(a){d=a};this.render=function(b,f){a.drawArrays(d,b,f);c.calls++;c.vertices+=f;d===a.TRIANGLES? -c.faces+=f/3:d===a.POINTS&&(c.points+=f)};this.renderInstances=function(e,f,g){var h=b.get("ANGLE_instanced_arrays");if(null===h)console.error("THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.");else{var k=e.attributes.position;k.isInterleavedBufferAttribute?(g=k.data.count,h.drawArraysInstancedANGLE(d,0,g,e.maxInstancedCount)):h.drawArraysInstancedANGLE(d,f,g,e.maxInstancedCount);c.calls++;c.vertices+=g*e.maxInstancedCount; -d===a.TRIANGLES?c.faces+=e.maxInstancedCount*g/3:d===a.POINTS&&(c.points+=e.maxInstancedCount*g)}}}function lg(a,b,c){function d(a){a=a.target;var g=e[a.id];null!==g.index&&b.remove(g.index);for(var k in g.attributes)b.remove(g.attributes[k]);a.removeEventListener("dispose",d);delete e[a.id];if(k=f[a.id])b.remove(k),delete f[a.id];if(k=f[g.id])b.remove(k),delete f[g.id];c.geometries--}var e={},f={};return{get:function(a,b){var f=e[b.id];if(f)return f;b.addEventListener("dispose",d);b.isBufferGeometry? -f=b:b.isGeometry&&(void 0===b._bufferGeometry&&(b._bufferGeometry=(new z).setFromObject(a)),f=b._bufferGeometry);e[b.id]=f;c.geometries++;return f},update:function(c){var d=c.index,e=c.attributes;null!==d&&b.update(d,a.ELEMENT_ARRAY_BUFFER);for(var f in e)b.update(e[f],a.ARRAY_BUFFER);c=c.morphAttributes;for(f in c){d=c[f];e=0;for(var g=d.length;e/gm,function(a,c){a=R[c];if(void 0===a)throw Error("Can not resolve #include <"+c+">");return Vd(a)})}function Ue(a){return a.replace(/#pragma unroll_loop[\s]+?for \( int i = (\d+); i < (\d+); i \+\+ \) \{([\s\S]+?)(?=\})\}/g, -function(a,c,d,e){a="";for(c=parseInt(c);cb||a.height>b){b/=Math.max(a.width,a.height);var c=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");c.width=Math.floor(a.width*b);c.height=Math.floor(a.height*b);c.getContext("2d").drawImage(a, -0,0,a.width,a.height,0,0,c.width,c.height);console.warn("THREE.WebGLRenderer: image is too big ("+a.width+"x"+a.height+"). Resized to "+c.width+"x"+c.height,a);return c}return a}function m(a){return S.isPowerOfTwo(a.width)&&S.isPowerOfTwo(a.height)}function v(a,b){return a.generateMipmaps&&b&&1003!==a.minFilter&&1006!==a.minFilter}function n(b){return 1003===b||1004===b||1005===b?a.NEAREST:a.LINEAR}function u(b){b=b.target;b.removeEventListener("dispose",u);a:{var c=d.get(b);if(b.image&&c.__image__webglTextureCube)a.deleteTexture(c.__image__webglTextureCube); -else{if(void 0===c.__webglInit)break a;a.deleteTexture(c.__webglTexture)}d.remove(b)}b.isVideoTexture&&delete A[b.id];g.textures--}function q(b){b=b.target;b.removeEventListener("dispose",q);var c=d.get(b),e=d.get(b.texture);if(b){void 0!==e.__webglTexture&&a.deleteTexture(e.__webglTexture);b.depthTexture&&b.depthTexture.dispose();if(b.isWebGLRenderTargetCube)for(e=0;6>e;e++)a.deleteFramebuffer(c.__webglFramebuffer[e]),c.__webglDepthbuffer&&a.deleteRenderbuffer(c.__webglDepthbuffer[e]);else a.deleteFramebuffer(c.__webglFramebuffer), -c.__webglDepthbuffer&&a.deleteRenderbuffer(c.__webglDepthbuffer);d.remove(b.texture);d.remove(b)}g.textures--}function r(b,n){var r=d.get(b);if(b.isVideoTexture){var q=b.id,t=h.frame;A[q]!==t&&(A[q]=t,b.update())}if(0t;t++)q[t]=h||r?r?b.image[t].image: -b.image[t]:k(b.image[t],e.maxCubemapSize);var p=m(q[0]),x=f.convert(b.format),w=f.convert(b.type);l(a.TEXTURE_CUBE_MAP,b,p);for(t=0;6>t;t++)if(h)for(var N,B=q[t].mipmaps,A=0,G=B.length;An;n++)e.__webglFramebuffer[n]=a.createFramebuffer()}else e.__webglFramebuffer=a.createFramebuffer();if(h){c.bindTexture(a.TEXTURE_CUBE_MAP,f.__webglTexture);l(a.TEXTURE_CUBE_MAP,b.texture,k);for(n=0;6>n;n++)p(e.__webglFramebuffer[n],b,a.COLOR_ATTACHMENT0,a.TEXTURE_CUBE_MAP_POSITIVE_X+ -n);v(b.texture,k)&&a.generateMipmap(a.TEXTURE_CUBE_MAP);c.bindTexture(a.TEXTURE_CUBE_MAP,null)}else c.bindTexture(a.TEXTURE_2D,f.__webglTexture),l(a.TEXTURE_2D,b.texture,k),p(e.__webglFramebuffer,b,a.COLOR_ATTACHMENT0,a.TEXTURE_2D),v(b.texture,k)&&a.generateMipmap(a.TEXTURE_2D),c.bindTexture(a.TEXTURE_2D,null);if(b.depthBuffer){e=d.get(b);f=!0===b.isWebGLRenderTargetCube;if(b.depthTexture){if(f)throw Error("target.depthTexture not supported in Cube render targets");if(b&&b.isWebGLRenderTargetCube)throw Error("Depth Texture with cube render targets is not supported"); -a.bindFramebuffer(a.FRAMEBUFFER,e.__webglFramebuffer);if(!b.depthTexture||!b.depthTexture.isDepthTexture)throw Error("renderTarget.depthTexture must be an instance of THREE.DepthTexture");d.get(b.depthTexture).__webglTexture&&b.depthTexture.image.width===b.width&&b.depthTexture.image.height===b.height||(b.depthTexture.image.width=b.width,b.depthTexture.image.height=b.height,b.depthTexture.needsUpdate=!0);r(b.depthTexture,0);e=d.get(b.depthTexture).__webglTexture;if(1026===b.depthTexture.format)a.framebufferTexture2D(a.FRAMEBUFFER, -a.DEPTH_ATTACHMENT,a.TEXTURE_2D,e,0);else if(1027===b.depthTexture.format)a.framebufferTexture2D(a.FRAMEBUFFER,a.DEPTH_STENCIL_ATTACHMENT,a.TEXTURE_2D,e,0);else throw Error("Unknown depthTexture format");}else if(f)for(e.__webglDepthbuffer=[],f=0;6>f;f++)a.bindFramebuffer(a.FRAMEBUFFER,e.__webglFramebuffer[f]),e.__webglDepthbuffer[f]=a.createRenderbuffer(),B(e.__webglDepthbuffer[f],b);else a.bindFramebuffer(a.FRAMEBUFFER,e.__webglFramebuffer),e.__webglDepthbuffer=a.createRenderbuffer(),B(e.__webglDepthbuffer, -b);a.bindFramebuffer(a.FRAMEBUFFER,null)}};this.updateRenderTargetMipmap=function(b){var e=b.texture,f=m(b);v(e,f)&&(b=b.isWebGLRenderTargetCube?a.TEXTURE_CUBE_MAP:a.TEXTURE_2D,e=d.get(e).__webglTexture,c.bindTexture(b,e),a.generateMipmap(b),c.bindTexture(b,null))}}function wg(){var a={};return{get:function(b){b=b.uuid;var c=a[b];void 0===c&&(c={},a[b]=c);return c},remove:function(b){delete a[b.uuid]},update:function(b,c,d){a[b.uuid][c]=d},dispose:function(){a={}}}}function xg(a,b,c){function d(b, -c,d){var e=new Uint8Array(4),f=a.createTexture();a.bindTexture(b,f);a.texParameteri(b,a.TEXTURE_MIN_FILTER,a.NEAREST);a.texParameteri(b,a.TEXTURE_MAG_FILTER,a.NEAREST);for(b=0;ba.matrixWorld.determinant();ba.setMaterial(e,h);h=q(c, -b.fog,e,a);ma="";g(a,h,e)}else z.renderBufferDirect(c,b.fog,d,e,a,f);a.onAfterRender(z,b,c,d,e,f);D=ra.get(b,O||c)}function u(a,b,c){var d=W.get(a),g=D.state.lights;c=qa.getParameters(a,g.state,D.state.shadowsArray,b,Ga.numPlanes,Ga.numIntersection,c);var h=qa.getProgramCode(a,c),k=d.program,m=!0;if(void 0===k)a.addEventListener("dispose",e);else if(k.code!==h)f(a);else{if(d.lightsHash!==g.state.hash)W.update(a,"lightsHash",g.state.hash);else if(void 0!==c.shaderID)return;m=!1}m&&(c.shaderID?(k=qb[c.shaderID], -d.shader={name:a.type,uniforms:Ea.clone(k.uniforms),vertexShader:k.vertexShader,fragmentShader:k.fragmentShader}):d.shader={name:a.type,uniforms:a.uniforms,vertexShader:a.vertexShader,fragmentShader:a.fragmentShader},a.onBeforeCompile(d.shader),k=qa.acquireProgram(a,d.shader,c,h),d.program=k,a.program=k);c=k.getAttributes();if(a.morphTargets)for(h=a.numSupportedMorphTargets=0;he.matrixWorld.determinant();ba.setMaterial(d,g);var h=q(a,b,d,e);a=c.id+"_"+h.id+"_"+(!0===d.wireframe);var k=!1;a!==ma&&(ma=a,k=!0);e.morphTargetInfluences&&(xa.update(e,c,d,h),k=!0);g=c.index;var m=c.attributes.position;b=1;!0===d.wireframe&&(g=ta.getWireframeAttribute(c),b=2);a=za;if(null!==g){var n=sa.get(g); -a=Aa;a.setIndex(n)}if(k){k=void 0;if(c&&c.isInstancedBufferGeometry&&null===ja.get("ANGLE_instanced_arrays"))console.error("THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.");else{void 0===k&&(k=0);ba.initAttributes();var v=c.attributes;h=h.getAttributes();var u=d.defaultAttributeValues;for(N in h){var l=h[N];if(0<=l){var r=v[N];if(void 0!==r){var t=r.normalized,p=r.itemSize,x=sa.get(r);if(void 0!==x){var w= -x.buffer,A=x.type;x=x.bytesPerElement;if(r.isInterleavedBufferAttribute){var B=r.data,G=B.stride;r=r.offset;B&&B.isInstancedInterleavedBuffer?(ba.enableAttributeAndDivisor(l,B.meshPerAttribute),void 0===c.maxInstancedCount&&(c.maxInstancedCount=B.meshPerAttribute*B.count)):ba.enableAttribute(l);E.bindBuffer(E.ARRAY_BUFFER,w);E.vertexAttribPointer(l,p,A,t,G*x,(k*G+r)*x)}else r.isInstancedBufferAttribute?(ba.enableAttributeAndDivisor(l,r.meshPerAttribute),void 0===c.maxInstancedCount&&(c.maxInstancedCount= -r.meshPerAttribute*r.count)):ba.enableAttribute(l),E.bindBuffer(E.ARRAY_BUFFER,w),E.vertexAttribPointer(l,p,A,t,0,k*p*x)}}else if(void 0!==u&&(t=u[N],void 0!==t))switch(t.length){case 2:E.vertexAttrib2fv(l,t);break;case 3:E.vertexAttrib3fv(l,t);break;case 4:E.vertexAttrib4fv(l,t);break;default:E.vertexAttrib1fv(l,t)}}}ba.disableUnusedAttributes()}null!==g&&E.bindBuffer(E.ELEMENT_ARRAY_BUFFER,n.buffer)}n=Infinity;null!==g?n=g.count:void 0!==m&&(n=m.count);g=c.drawRange.start*b;m=null!==f?f.start*b: -0;var N=Math.max(g,m);f=Math.max(0,Math.min(n,g+c.drawRange.count*b,m+(null!==f?f.count*b:Infinity))-1-N+1);if(0!==f){if(e.isMesh)if(!0===d.wireframe)ba.setLineWidth(d.wireframeLinewidth*(null===K?Q:1)),a.setMode(E.LINES);else switch(e.drawMode){case 0:a.setMode(E.TRIANGLES);break;case 1:a.setMode(E.TRIANGLE_STRIP);break;case 2:a.setMode(E.TRIANGLE_FAN)}else e.isLine?(d=d.linewidth,void 0===d&&(d=1),ba.setLineWidth(d*(null===K?Q:1)),e.isLineSegments?a.setMode(E.LINES):e.isLineLoop?a.setMode(E.LINE_LOOP): -a.setMode(E.LINE_STRIP)):e.isPoints&&a.setMode(E.POINTS);c&&c.isInstancedBufferGeometry?0=da.maxTextures&&console.warn("THREE.WebGLRenderer: Trying to use "+a+" texture units while this GPU supports only "+da.maxTextures);aa+=1;return a};this.setTexture2D=function(){var a=!1;return function(b,c){b&&b.isWebGLRenderTarget&&(a||(console.warn("THREE.WebGLRenderer.setTexture2D: don't use render targets as textures. Use their .texture property instead."), -a=!0),b=b.texture);fa.setTexture2D(b,c)}}();this.setTexture=function(){var a=!1;return function(b,c){a||(console.warn("THREE.WebGLRenderer: .setTexture is deprecated, use setTexture2D instead."),a=!0);fa.setTexture2D(b,c)}}();this.setTextureCube=function(){var a=!1;return function(b,c){b&&b.isWebGLRenderTargetCube&&(a||(console.warn("THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead."),a=!0),b=b.texture);b&&b.isCubeTexture||Array.isArray(b.image)&& -6===b.image.length?fa.setTextureCube(b,c):fa.setTextureCubeDynamic(b,c)}}();this.getRenderTarget=function(){return K};this.setRenderTarget=function(a){(K=a)&&void 0===W.get(a).__webglFramebuffer&&fa.setupRenderTarget(a);var b=null,c=!1;a?(b=W.get(a).__webglFramebuffer,a.isWebGLRenderTargetCube&&(b=b[a.activeCubeFace],c=!0),R.copy(a.viewport),Y.copy(a.scissor),U=a.scissorTest):(R.copy(ea).multiplyScalar(Q),Y.copy(ca).multiplyScalar(Q),U=na);L!==b&&(E.bindFramebuffer(E.FRAMEBUFFER,b),L=b);ba.viewport(R); -ba.scissor(Y);ba.setScissorTest(U);c&&(c=W.get(a.texture),E.framebufferTexture2D(E.FRAMEBUFFER,E.COLOR_ATTACHMENT0,E.TEXTURE_CUBE_MAP_POSITIVE_X+a.activeCubeFace,c.__webglTexture,a.activeMipMapLevel))};this.readRenderTargetPixels=function(a,b,c,d,e,f){if(a&&a.isWebGLRenderTarget){var g=W.get(a).__webglFramebuffer;if(g){var h=!1;g!==L&&(E.bindFramebuffer(E.FRAMEBUFFER,g),h=!0);try{var k=a.texture,m=k.format,n=k.type;1023!==m&&oa.convert(m)!==E.getParameter(E.IMPLEMENTATION_COLOR_READ_FORMAT)?console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format."): -1009===n||oa.convert(n)===E.getParameter(E.IMPLEMENTATION_COLOR_READ_TYPE)||1015===n&&(ja.get("OES_texture_float")||ja.get("WEBGL_color_buffer_float"))||1016===n&&ja.get("EXT_color_buffer_half_float")?E.checkFramebufferStatus(E.FRAMEBUFFER)===E.FRAMEBUFFER_COMPLETE?0<=b&&b<=a.width-d&&0<=c&&c<=a.height-e&&E.readPixels(b,c,d,e,oa.convert(m),oa.convert(n),f):console.error("THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete."):console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.")}finally{h&& -E.bindFramebuffer(E.FRAMEBUFFER,L)}}}else console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.")};this.copyFramebufferToTexture=function(a,b,c){var d=b.image.width,e=b.image.height,f=oa.convert(b.format);this.setTexture2D(b,0);E.copyTexImage2D(E.TEXTURE_2D,c||0,f,a.x,a.y,d,e,0)}}function Mb(a,b){this.name="";this.color=new H(a);this.density=void 0!==b?b:2.5E-4}function Nb(a,b,c){this.name="";this.color=new H(a);this.near=void 0!==b?b:1;this.far=void 0!== -c?c:1E3}function pd(){y.call(this);this.type="Scene";this.overrideMaterial=this.fog=this.background=null;this.autoUpdate=!0}function gb(a){O.call(this);this.type="SpriteMaterial";this.color=new H(16777215);this.map=null;this.rotation=0;this.lights=this.fog=!1;this.setValues(a)}function zc(a){y.call(this);this.type="Sprite";this.material=void 0!==a?a:new gb;this.center=new C(.5,.5)}function Ac(){y.call(this);this.type="LOD";Object.defineProperties(this,{levels:{enumerable:!0,value:[]}})}function Bc(a, -b){a=a||[];this.bones=a.slice(0);this.boneMatrices=new Float32Array(16*this.bones.length);if(void 0===b)this.calculateInverses();else if(this.bones.length===b.length)this.boneInverses=b.slice(0);else for(console.warn("THREE.Skeleton boneInverses is the wrong length."),this.boneInverses=[],a=0,b=this.bones.length;ac;c++){var n=v[h[c]];var u=v[h[(c+1)%3]];f[0]=Math.min(n,u);f[1]=Math.max(n,u);n=f[0]+","+f[1];void 0===g[n]&&(g[n]={index1:f[0],index2:f[1]})}}for(n in g)m=g[n], -h=a.vertices[m.index1],b.push(h.x,h.y,h.z),h=a.vertices[m.index2],b.push(h.x,h.y,h.z)}else if(a&&a.isBufferGeometry)if(h=new p,null!==a.index){k=a.attributes.position;v=a.index;var l=a.groups;0===l.length&&(l=[{start:0,count:v.count,materialIndex:0}]);a=0;for(e=l.length;ac;c++)n=v.getX(m+c),u=v.getX(m+(c+1)%3),f[0]=Math.min(n,u),f[1]=Math.max(n,u),n=f[0]+","+f[1],void 0===g[n]&&(g[n]={index1:f[0],index2:f[1]});for(n in g)m=g[n],h.fromBufferAttribute(k, -m.index1),b.push(h.x,h.y,h.z),h.fromBufferAttribute(k,m.index2),b.push(h.x,h.y,h.z)}else for(k=a.attributes.position,m=0,d=k.count/3;mc;c++)g=3*m+c,h.fromBufferAttribute(k,g),b.push(h.x,h.y,h.z),g=3*m+(c+1)%3,h.fromBufferAttribute(k,g),b.push(h.x,h.y,h.z);this.addAttribute("position",new D(b,3))}function Dc(a,b,c){L.call(this);this.type="ParametricGeometry";this.parameters={func:a,slices:b,stacks:c};this.fromBufferGeometry(new Rb(a,b,c));this.mergeVertices()}function Rb(a,b,c){z.call(this); -this.type="ParametricBufferGeometry";this.parameters={func:a,slices:b,stacks:c};var d=[],e=[],f=[],g=[],h=new p,k=new p,m=new p,v=new p,n=new p,u,l,r=b+1;for(u=0;u<=c;u++){var t=u/c;for(l=0;l<=b;l++){var x=l/b;k=a(x,t,k);e.push(k.x,k.y,k.z);0<=x-1E-5?(m=a(x-1E-5,t,m),v.subVectors(k,m)):(m=a(x+1E-5,t,m),v.subVectors(m,k));0<=t-1E-5?(m=a(x,t-1E-5,m),n.subVectors(k,m)):(m=a(x,t+1E-5,m),n.subVectors(m,k));h.crossVectors(v,n).normalize();f.push(h.x,h.y,h.z);g.push(x,t)}}for(u=0;ud&&1===a.x&&(k[b]=a.x-1);0===c.x&&0===c.z&&(k[b]=d/2/Math.PI+.5)}z.call(this);this.type="PolyhedronBufferGeometry";this.parameters={vertices:a,indices:b,radius:c,detail:d};c=c||1;d=d||0;var h=[],k=[];(function(a){for(var c=new p,d=new p,g=new p,h=0;he&&(.2>b&&(k[a+0]+=1),.2>c&&(k[a+2]+=1),.2>d&&(k[a+4]+=1))})();this.addAttribute("position", -new D(h,3));this.addAttribute("normal",new D(h.slice(),3));this.addAttribute("uv",new D(k,2));0===d?this.computeVertexNormals():this.normalizeNormals()}function Fc(a,b){L.call(this);this.type="TetrahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new Sb(a,b));this.mergeVertices()}function Sb(a,b){va.call(this,[1,1,1,-1,-1,1,-1,1,-1,1,-1,-1],[2,1,0,0,3,2,1,3,0,2,3,1],a,b);this.type="TetrahedronBufferGeometry";this.parameters={radius:a,detail:b}}function Gc(a,b){L.call(this); -this.type="OctahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new rb(a,b));this.mergeVertices()}function rb(a,b){va.call(this,[1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1],[0,2,4,0,4,3,0,3,5,0,5,2,1,2,5,1,5,3,1,3,4,1,4,2],a,b);this.type="OctahedronBufferGeometry";this.parameters={radius:a,detail:b}}function Hc(a,b){L.call(this);this.type="IcosahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new Tb(a,b));this.mergeVertices()}function Tb(a,b){var c= -(1+Math.sqrt(5))/2;va.call(this,[-1,c,0,1,c,0,-1,-c,0,1,-c,0,0,-1,c,0,1,c,0,-1,-c,0,1,-c,c,0,-1,c,0,1,-c,0,-1,-c,0,1],[0,11,5,0,5,1,0,1,7,0,7,10,0,10,11,1,5,9,5,11,4,11,10,2,10,7,6,7,1,8,3,9,4,3,4,2,3,2,6,3,6,8,3,8,9,4,9,5,2,4,11,6,2,10,8,6,7,9,8,1],a,b);this.type="IcosahedronBufferGeometry";this.parameters={radius:a,detail:b}}function Ic(a,b){L.call(this);this.type="DodecahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new Ub(a,b));this.mergeVertices()}function Ub(a,b){var c= -(1+Math.sqrt(5))/2,d=1/c;va.call(this,[-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-d,-c,0,-d,c,0,d,-c,0,d,c,-d,-c,0,-d,c,0,d,-c,0,d,c,0,-c,0,-d,c,0,-d,-c,0,d,c,0,d],[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],a,b);this.type="DodecahedronBufferGeometry";this.parameters= -{radius:a,detail:b}}function Jc(a,b,c,d,e,f){L.call(this);this.type="TubeGeometry";this.parameters={path:a,tubularSegments:b,radius:c,radialSegments:d,closed:e};void 0!==f&&console.warn("THREE.TubeGeometry: taper has been removed.");a=new Vb(a,b,c,d,e);this.tangents=a.tangents;this.normals=a.normals;this.binormals=a.binormals;this.fromBufferGeometry(a);this.mergeVertices()}function Vb(a,b,c,d,e){function f(e){v=a.getPointAt(e/b,v);var f=g.normals[e];e=g.binormals[e];for(l=0;l<=d;l++){var m=l/d*Math.PI* -2,n=Math.sin(m);m=-Math.cos(m);k.x=m*f.x+n*e.x;k.y=m*f.y+n*e.y;k.z=m*f.z+n*e.z;k.normalize();r.push(k.x,k.y,k.z);h.x=v.x+c*k.x;h.y=v.y+c*k.y;h.z=v.z+c*k.z;q.push(h.x,h.y,h.z)}}z.call(this);this.type="TubeBufferGeometry";this.parameters={path:a,tubularSegments:b,radius:c,radialSegments:d,closed:e};b=b||64;c=c||1;d=d||8;e=e||!1;var g=a.computeFrenetFrames(b,e);this.tangents=g.tangents;this.normals=g.normals;this.binormals=g.binormals;var h=new p,k=new p,m=new C,v=new p,n,l,q=[],r=[],t=[],x=[];for(n= -0;n=b;e-=d)f=Ye(e,a[e],a[e+1],f);f&&sb(f,f.next)&&(Mc(f),f=f.next);return f}function Nc(a,b){if(!a)return a; -b||(b=a);do{var c=!1;if(a.steiner||!sb(a,a.next)&&0!==sa(a.prev,a,a.next))a=a.next;else{Mc(a);a=b=a.prev;if(a===a.next)break;c=!0}}while(c||a!==b);return b}function Oc(a,b,c,d,e,f,g){if(a){if(!g&&f){var h=a,k=h;do null===k.z&&(k.z=Zd(k.x,k.y,d,e,f)),k.prevZ=k.prev,k=k.nextZ=k.next;while(k!==h);k.prevZ.nextZ=null;k.prevZ=null;h=k;var m,v,n,l,q=1;do{k=h;var r=h=null;for(v=0;k;){v++;var p=k;for(m=n=0;mn.x?v.x>q.x?v.x:q.x:n.x>q.x?n.x:q.x,A=v.y>n.y?v.y>q.y?v.y:q.y:n.y>q.y?n.y:q.y;m=Zd(v.x=m;){if(x!==r.prev&&x!==r.next&&ud(v.x,v.y,n.x,n.y,q.x,q.y,x.x,x.y)&&0<=sa(x.prev,x,x.next)){r=!1;break a}x=x.prevZ}r=!0}}else a:if(r=a,v=r.prev,n=r,q=r.next,0<=sa(v,n,q))r=!1;else{for(m=r.next.next;m!==r.prev;){if(ud(v.x,v.y,n.x,n.y,q.x,q.y,m.x,m.y)&&0<=sa(m.prev,m,m.next)){r=!1;break a}m=m.next}r=!0}if(r)b.push(k.i/c),b.push(a.i/c),b.push(p.i/c),Mc(a),h=a=p.next;else if(a=p,a===h){if(!g)Oc(Nc(a),b,c,d,e,f,1);else if(1===g){g=b;h=c;k=a;do p=k.prev, -r=k.next.next,!sb(p,r)&&Ze(p,k,k.next,r)&&Pc(p,r)&&Pc(r,p)&&(g.push(p.i/h),g.push(k.i/h),g.push(r.i/h),Mc(k),Mc(k.next),k=a=r),k=k.next;while(k!==a);a=k;Oc(a,b,c,d,e,f,2)}else if(2===g)a:{g=a;do{for(h=g.next.next;h!==g.prev;){if(k=g.i!==h.i){k=g;p=h;if(r=k.next.i!==p.i&&k.prev.i!==p.i){b:{r=k;do{if(r.i!==k.i&&r.next.i!==k.i&&r.i!==p.i&&r.next.i!==p.i&&Ze(r,r.next,k,p)){r=!0;break b}r=r.next}while(r!==k);r=!1}r=!r}if(r=r&&Pc(k,p)&&Pc(p,k)){r=k;v=!1;n=(k.x+p.x)/2;p=(k.y+p.y)/2;do r.y>p!==r.next.y>p&& -r.next.y!==r.y&&n<(r.next.x-r.x)*(p-r.y)/(r.next.y-r.y)+r.x&&(v=!v),r=r.next;while(r!==k);r=v}k=r}if(k){a=$e(g,h);g=Nc(g,g.next);a=Nc(a,a.next);Oc(g,b,c,d,e,f);Oc(a,b,c,d,e,f);break a}h=h.next}g=g.next}while(g!==a)}break}}}}function Hg(a,b){return a.x-b.x}function Ig(a,b){var c=b,d=a.x,e=a.y,f=-Infinity;do{if(e<=c.y&&e>=c.next.y&&c.next.y!==c.y){var g=c.x+(e-c.y)*(c.next.x-c.x)/(c.next.y-c.y);if(g<=d&&g>f){f=g;if(g===d){if(e===c.y)return c;if(e===c.next.y)return c.next}var h=c.x=c.x&&c.x>=g&&d!==c.x&&ud(eh.x)&&Pc(c,a)&&(h=c,m=v)}c=c.next}return h}function Zd(a,b,c,d,e){a=32767*(a-c)*e;b=32767*(b-d)*e;a=(a|a<<8)&16711935;a=(a|a<<4)&252645135;a=(a|a<<2)&858993459;b=(b|b<<8)&16711935;b=(b|b<<4)&252645135;b=(b|b<<2)&858993459;return(a|a<<1)&1431655765|((b|b<<1)&1431655765)<<1}function Jg(a){var b= -a,c=a;do b.xsa(a.prev,a,a.next)?0<=sa(a,b,a.next)&&0<=sa(a,a.prev,b):0>sa(a,b,a.prev)|| -0>sa(a,a.next,b)}function $e(a,b){var c=new $d(a.i,a.x,a.y),d=new $d(b.i,b.x,b.y),e=a.next,f=b.prev;a.next=b;b.prev=a;c.next=e;e.prev=c;d.next=c;c.prev=d;f.next=d;d.prev=f;return d}function Ye(a,b,c,d){a=new $d(a,b,c);d?(a.next=d.next,a.prev=d,d.next.prev=a,d.next=a):(a.prev=a,a.next=a);return a}function Mc(a){a.next.prev=a.prev;a.prev.next=a.next;a.prevZ&&(a.prevZ.nextZ=a.nextZ);a.nextZ&&(a.nextZ.prevZ=a.prevZ)}function $d(a,b,c){this.i=a;this.x=b;this.y=c;this.nextZ=this.prevZ=this.z=this.next= -this.prev=null;this.steiner=!1}function af(a){var b=a.length;2l;l++){var n=m[f[l]];var u=m[f[(l+1)%3]];d[0]=Math.min(n,u);d[1]=Math.max(n,u);n=d[0]+","+d[1];void 0===e[n]?e[n]={index1:d[0],index2:d[1], -face1:h,face2:void 0}:e[n].face2=h}for(n in e)if(d=e[n],void 0===d.face2||g[d.face1].normal.dot(g[d.face2].normal)<=b)f=a[d.index1],c.push(f.x,f.y,f.z),f=a[d.index2],c.push(f.x,f.y,f.z);this.addAttribute("position",new D(c,3))}function wb(a,b,c,d,e,f,g,h){L.call(this);this.type="CylinderGeometry";this.parameters={radiusTop:a,radiusBottom:b,height:c,radialSegments:d,heightSegments:e,openEnded:f,thetaStart:g,thetaLength:h};this.fromBufferGeometry(new Za(a,b,c,d,e,f,g,h));this.mergeVertices()}function Za(a, -b,c,d,e,f,g,h){function k(c){var e,f=new C,k=new p,v=0,t=!0===c?a:b,w=!0===c?1:-1;var y=r;for(e=1;e<=d;e++)n.push(0,x*w,0),u.push(0,w,0),q.push(.5,.5),r++;var D=r;for(e=0;e<=d;e++){var z=e/d*h+g,H=Math.cos(z);z=Math.sin(z);k.x=t*z;k.y=x*w;k.z=t*H;n.push(k.x,k.y,k.z);u.push(0,w,0);f.x=.5*H+.5;f.y=.5*z*w+.5;q.push(f.x,f.y);r++}for(e=0;ethis.duration&&this.resetDuration();this.optimize()}function Kd(a){this.manager= -void 0!==a?a:ra;this.textures={}}function ee(a){this.manager=void 0!==a?a:ra}function hc(){this.onLoadStart=function(){};this.onLoadProgress=function(){};this.onLoadComplete=function(){}}function fe(a){"boolean"===typeof a&&(console.warn("THREE.JSONLoader: showStatus parameter has been removed from constructor."),a=void 0);this.manager=void 0!==a?a:ra;this.withCredentials=!1}function ff(a){this.manager=void 0!==a?a:ra;this.texturePath=""}function ge(a){"undefined"===typeof createImageBitmap&&console.warn("THREE.ImageBitmapLoader: createImageBitmap() not supported."); -"undefined"===typeof fetch&&console.warn("THREE.ImageBitmapLoader: fetch() not supported.");this.manager=void 0!==a?a:ra;this.options=void 0}function he(){this.type="ShapePath";this.subPaths=[];this.currentPath=null}function ie(a){this.type="Font";this.data=a}function gf(a){this.manager=void 0!==a?a:ra}function je(a){this.manager=void 0!==a?a:ra}function hf(){this.type="StereoCamera";this.aspect=1;this.eyeSep=.064;this.cameraL=new na;this.cameraL.layers.enable(1);this.cameraL.matrixAutoUpdate=!1; -this.cameraR=new na;this.cameraR.layers.enable(2);this.cameraR.matrixAutoUpdate=!1}function bd(a,b,c){y.call(this);this.type="CubeCamera";var d=new na(90,1,a,b);d.up.set(0,-1,0);d.lookAt(new p(1,0,0));this.add(d);var e=new na(90,1,a,b);e.up.set(0,-1,0);e.lookAt(new p(-1,0,0));this.add(e);var f=new na(90,1,a,b);f.up.set(0,0,1);f.lookAt(new p(0,1,0));this.add(f);var g=new na(90,1,a,b);g.up.set(0,0,-1);g.lookAt(new p(0,-1,0));this.add(g);var h=new na(90,1,a,b);h.up.set(0,-1,0);h.lookAt(new p(0,0,1)); -this.add(h);var k=new na(90,1,a,b);k.up.set(0,-1,0);k.lookAt(new p(0,0,-1));this.add(k);this.renderTarget=new Gb(c,c,{format:1022,magFilter:1006,minFilter:1006});this.renderTarget.texture.name="CubeCamera";this.update=function(a,b){null===this.parent&&this.updateMatrixWorld();var c=this.renderTarget,m=c.texture.generateMipmaps;c.texture.generateMipmaps=!1;c.activeCubeFace=0;a.render(b,d,c);c.activeCubeFace=1;a.render(b,e,c);c.activeCubeFace=2;a.render(b,f,c);c.activeCubeFace=3;a.render(b,g,c);c.activeCubeFace= -4;a.render(b,h,c);c.texture.generateMipmaps=m;c.activeCubeFace=5;a.render(b,k,c);a.setRenderTarget(null)};this.clear=function(a,b,c,d){for(var e=this.renderTarget,f=0;6>f;f++)e.activeCubeFace=f,a.setRenderTarget(e),a.clear(b,c,d);a.setRenderTarget(null)}}function ke(){y.call(this);this.type="AudioListener";this.context=le.getContext();this.gain=this.context.createGain();this.gain.connect(this.context.destination);this.filter=null}function ic(a){y.call(this);this.type="Audio";this.context=a.context; -this.gain=this.context.createGain();this.gain.connect(a.getInput());this.autoplay=!1;this.buffer=null;this.loop=!1;this.offset=this.startTime=0;this.playbackRate=1;this.isPlaying=!1;this.hasPlaybackControl=!0;this.sourceType="empty";this.filters=[]}function me(a){ic.call(this,a);this.panner=this.context.createPanner();this.panner.connect(this.gain)}function ne(a,b){this.analyser=a.context.createAnalyser();this.analyser.fftSize=void 0!==b?b:2048;this.data=new Uint8Array(this.analyser.frequencyBinCount); -a.getOutput().connect(this.analyser)}function oe(a,b,c){this.binding=a;this.valueSize=c;a=Float64Array;switch(b){case "quaternion":b=this._slerp;break;case "string":case "bool":a=Array;b=this._select;break;default:b=this._lerp}this.buffer=new a(4*c);this._mixBufferRegion=b;this.referenceCount=this.useCount=this.cumulativeWeight=0}function jf(a,b,c){c=c||fa.parseTrackName(b);this._targetGroup=a;this._bindings=a.subscribe_(b,c)}function fa(a,b,c){this.path=b;this.parsedPath=c||fa.parseTrackName(b); -this.node=fa.findNode(a,this.parsedPath.nodeName)||a;this.rootNode=a}function kf(){this.uuid=S.generateUUID();this._objects=Array.prototype.slice.call(arguments);this.nCachedObjects_=0;var a={};this._indicesByUUID=a;for(var b=0,c=arguments.length;b!==c;++b)a[arguments[b].uuid]=b;this._paths=[];this._parsedPaths=[];this._bindings=[];this._bindingsIndicesByPath={};var d=this;this.stats={objects:{get total(){return d._objects.length},get inUse(){return this.total-d.nCachedObjects_}},get bindingsPerObject(){return d._bindings.length}}} -function lf(a,b,c){this._mixer=a;this._clip=b;this._localRoot=c||null;a=b.tracks;b=a.length;c=Array(b);for(var d={endingStart:2400,endingEnd:2400},e=0;e!==b;++e){var f=a[e].createInterpolant(null);c[e]=f;f.settings=d}this._interpolantSettings=d;this._interpolants=c;this._propertyBindings=Array(b);this._weightInterpolant=this._timeScaleInterpolant=this._byClipCacheIndex=this._cacheIndex=null;this.loop=2201;this._loopCount=-1;this._startTime=null;this.time=0;this._effectiveWeight=this.weight=this._effectiveTimeScale= -this.timeScale=1;this.repetitions=Infinity;this.paused=!1;this.enabled=!0;this.clampWhenFinished=!1;this.zeroSlopeAtEnd=this.zeroSlopeAtStart=!0}function pe(a){this._root=a;this._initMemoryManager();this.time=this._accuIndex=0;this.timeScale=1}function Ld(a,b){"string"===typeof a&&(console.warn("THREE.Uniform: Type parameter is no longer needed."),a=b);this.value=a}function qe(){z.call(this);this.type="InstancedBufferGeometry";this.maxInstancedCount=void 0}function re(a,b,c,d){this.uuid=S.generateUUID(); -this.data=a;this.itemSize=b;this.offset=c;this.normalized=!0===d}function jc(a,b){this.uuid=S.generateUUID();this.array=a;this.stride=b;this.count=void 0!==a?a.length/b:0;this.dynamic=!1;this.updateRange={offset:0,count:-1};this.onUploadCallback=function(){};this.version=0}function se(a,b,c){jc.call(this,a,b);this.meshPerAttribute=c||1}function te(a,b,c){M.call(this,a,b);this.meshPerAttribute=c||1}function mf(a,b,c,d){this.ray=new pb(a,b);this.near=c||0;this.far=d||Infinity;this.params={Mesh:{},Line:{}, -LOD:{},Points:{threshold:1},Sprite:{}};Object.defineProperties(this.params,{PointCloud:{get:function(){console.warn("THREE.Raycaster: params.PointCloud has been renamed to params.Points.");return this.Points}}})}function nf(a,b){return a.distance-b.distance}function ue(a,b,c,d){if(!1!==a.visible&&(a.raycast(b,c),!0===d)){a=a.children;d=0;for(var e=a.length;dc;c++,d++){var e=c/32*Math.PI*2,f=d/32*Math.PI*2;b.push(Math.cos(e), -Math.sin(e),1,Math.cos(f),Math.sin(f),1)}a.addAttribute("position",new D(b,3));b=new Y({fog:!1});this.cone=new U(a,b);this.add(this.cone);this.update()}function rf(a){var b=[];a&&a.isBone&&b.push(a);for(var c=0;ca?-1:0b;b++)a[b]=(16>b?"0":"")+b.toString(16).toUpperCase(); -return function(){var b=4294967295*Math.random()|0,d=4294967295*Math.random()|0,e=4294967295*Math.random()|0,f=4294967295*Math.random()|0;return a[b&255]+a[b>>8&255]+a[b>>16&255]+a[b>>24&255]+"-"+a[d&255]+a[d>>8&255]+"-"+a[d>>16&15|64]+a[d>>24&255]+"-"+a[e&63|128]+a[e>>8&255]+"-"+a[e>>16&255]+a[e>>24&255]+a[f&255]+a[f>>8&255]+a[f>>16&255]+a[f>>24&255]}}(),clamp:function(a,b,c){return Math.max(b,Math.min(c,a))},euclideanModulo:function(a,b){return(a%b+b)%b},mapLinear:function(a,b,c,d,e){return d+(a- -b)*(e-d)/(c-b)},lerp:function(a,b,c){return(1-c)*a+c*b},smoothstep:function(a,b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*(3-2*a)},smootherstep:function(a,b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*a*(a*(6*a-15)+10)},randInt:function(a,b){return a+Math.floor(Math.random()*(b-a+1))},randFloat:function(a,b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(.5-Math.random())},degToRad:function(a){return a*S.DEG2RAD},radToDeg:function(a){return a* -S.RAD2DEG},isPowerOfTwo:function(a){return 0===(a&a-1)&&0!==a},ceilPowerOfTwo:function(a){return Math.pow(2,Math.ceil(Math.log(a)/Math.LN2))},floorPowerOfTwo:function(a){return Math.pow(2,Math.floor(Math.log(a)/Math.LN2))}};Object.defineProperties(C.prototype,{width:{get:function(){return this.x},set:function(a){this.x=a}},height:{get:function(){return this.y},set:function(a){this.y=a}}});Object.assign(C.prototype,{isVector2:!0,set:function(a,b){this.x=a;this.y=b;return this},setScalar:function(a){this.y= -this.x=a;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;default:throw Error("index is out of range: "+a);}return this},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;default:throw Error("index is out of range: "+a);}},clone:function(){return new this.constructor(this.x,this.y)},copy:function(a){this.x=a.x;this.y=a.y;return this},add:function(a, -b){if(void 0!==b)return console.warn("THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;return this},addScalar:function(a){this.x+=a;this.y+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."), -this.subVectors(a,b);this.x-=a.x;this.y-=a.y;return this},subScalar:function(a){this.x-=a;this.y-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},multiply:function(a){this.x*=a.x;this.y*=a.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},divide:function(a){this.x/=a.x;this.y/=a.y;return this},divideScalar:function(a){return this.multiplyScalar(1/a)},applyMatrix3:function(a){var b=this.x,c=this.y;a=a.elements;this.x=a[0]*b+a[3]*c+a[6];this.y= -a[1]*b+a[4]*c+a[7];return this},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));return this},clampScalar:function(){var a=new C,b=new C;return function(c,d){a.set(c,c);b.set(d,d);return this.clamp(a,b)}}(),clampLength:function(a,b){var c=this.length();return this.divideScalar(c|| -1).multiplyScalar(Math.max(a,Math.min(b,c)))},floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);return this},round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);return this},negate:function(){this.x=-this.x;this.y=-this.y;return this},dot:function(a){return this.x* -a.x+this.y*a.y},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)},normalize:function(){return this.divideScalar(this.length()||1)},angle:function(){var a=Math.atan2(this.y,this.x);0>a&&(a+=2*Math.PI);return a},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x;a=this.y-a.y;return b*b+a*a},manhattanDistanceTo:function(a){return Math.abs(this.x- -a.x)+Math.abs(this.y-a.y)},setLength:function(a){return this.normalize().multiplyScalar(a)},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;return this},lerpVectors:function(a,b,c){return this.subVectors(b,a).multiplyScalar(c).add(a)},equals:function(a){return a.x===this.x&&a.y===this.y},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;return a},fromBufferAttribute:function(a, -b,c){void 0!==c&&console.warn("THREE.Vector2: offset has been removed from .fromBufferAttribute().");this.x=a.getX(b);this.y=a.getY(b);return this},rotateAround:function(a,b){var c=Math.cos(b);b=Math.sin(b);var d=this.x-a.x,e=this.y-a.y;this.x=d*c-e*b+a.x;this.y=d*b+e*c+a.y;return this}});Object.assign(P.prototype,{isMatrix4:!0,set:function(a,b,c,d,e,f,g,h,k,m,l,n,p,q,r,t){var v=this.elements;v[0]=a;v[4]=b;v[8]=c;v[12]=d;v[1]=e;v[5]=f;v[9]=g;v[13]=h;v[2]=k;v[6]=m;v[10]=l;v[14]=n;v[3]=p;v[7]=q;v[11]= -r;v[15]=t;return this},identity:function(){this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return this},clone:function(){return(new P).fromArray(this.elements)},copy:function(a){var b=this.elements;a=a.elements;b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11];b[12]=a[12];b[13]=a[13];b[14]=a[14];b[15]=a[15];return this},copyPosition:function(a){var b=this.elements;a=a.elements;b[12]=a[12];b[13]=a[13];b[14]=a[14];return this},extractBasis:function(a, -b,c){a.setFromMatrixColumn(this,0);b.setFromMatrixColumn(this,1);c.setFromMatrixColumn(this,2);return this},makeBasis:function(a,b,c){this.set(a.x,b.x,c.x,0,a.y,b.y,c.y,0,a.z,b.z,c.z,0,0,0,0,1);return this},extractRotation:function(){var a=new p;return function(b){var c=this.elements,d=b.elements,e=1/a.setFromMatrixColumn(b,0).length(),f=1/a.setFromMatrixColumn(b,1).length();b=1/a.setFromMatrixColumn(b,2).length();c[0]=d[0]*e;c[1]=d[1]*e;c[2]=d[2]*e;c[4]=d[4]*f;c[5]=d[5]*f;c[6]=d[6]*f;c[8]=d[8]*b; -c[9]=d[9]*b;c[10]=d[10]*b;return this}}(),makeRotationFromEuler:function(a){a&&a.isEuler||console.error("THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.");var b=this.elements,c=a.x,d=a.y,e=a.z,f=Math.cos(c);c=Math.sin(c);var g=Math.cos(d);d=Math.sin(d);var h=Math.cos(e);e=Math.sin(e);if("XYZ"===a.order){a=f*h;var k=f*e,m=c*h,l=c*e;b[0]=g*h;b[4]=-g*e;b[8]=d;b[1]=k+m*d;b[5]=a-l*d;b[9]=-c*g;b[2]=l-a*d;b[6]=m+k*d;b[10]=f*g}else"YXZ"===a.order?(a=g* -h,k=g*e,m=d*h,l=d*e,b[0]=a+l*c,b[4]=m*c-k,b[8]=f*d,b[1]=f*e,b[5]=f*h,b[9]=-c,b[2]=k*c-m,b[6]=l+a*c,b[10]=f*g):"ZXY"===a.order?(a=g*h,k=g*e,m=d*h,l=d*e,b[0]=a-l*c,b[4]=-f*e,b[8]=m+k*c,b[1]=k+m*c,b[5]=f*h,b[9]=l-a*c,b[2]=-f*d,b[6]=c,b[10]=f*g):"ZYX"===a.order?(a=f*h,k=f*e,m=c*h,l=c*e,b[0]=g*h,b[4]=m*d-k,b[8]=a*d+l,b[1]=g*e,b[5]=l*d+a,b[9]=k*d-m,b[2]=-d,b[6]=c*g,b[10]=f*g):"YZX"===a.order?(a=f*g,k=f*d,m=c*g,l=c*d,b[0]=g*h,b[4]=l-a*e,b[8]=m*e+k,b[1]=e,b[5]=f*h,b[9]=-c*h,b[2]=-d*h,b[6]=k*e+m,b[10]=a-l* -e):"XZY"===a.order&&(a=f*g,k=f*d,m=c*g,l=c*d,b[0]=g*h,b[4]=-e,b[8]=d*h,b[1]=a*e+l,b[5]=f*h,b[9]=k*e-m,b[2]=m*e-k,b[6]=c*h,b[10]=l*e+a);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},makeRotationFromQuaternion:function(a){var b=this.elements,c=a._x,d=a._y,e=a._z,f=a._w,g=c+c,h=d+d,k=e+e;a=c*g;var m=c*h;c*=k;var l=d*h;d*=k;e*=k;g*=f;h*=f;f*=k;b[0]=1-(l+e);b[4]=m-f;b[8]=c+h;b[1]=m+f;b[5]=1-(a+e);b[9]=d-g;b[2]=c-h;b[6]=d+g;b[10]=1-(a+l);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]= -0;b[15]=1;return this},lookAt:function(){var a=new p,b=new p,c=new p;return function(d,e,f){var g=this.elements;c.subVectors(d,e);0===c.lengthSq()&&(c.z=1);c.normalize();a.crossVectors(f,c);0===a.lengthSq()&&(1===Math.abs(f.z)?c.x+=1E-4:c.z+=1E-4,c.normalize(),a.crossVectors(f,c));a.normalize();b.crossVectors(c,a);g[0]=a.x;g[4]=b.x;g[8]=c.x;g[1]=a.y;g[5]=b.y;g[9]=c.y;g[2]=a.z;g[6]=b.z;g[10]=c.z;return this}}(),multiply:function(a,b){return void 0!==b?(console.warn("THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."), -this.multiplyMatrices(a,b)):this.multiplyMatrices(this,a)},premultiply:function(a){return this.multiplyMatrices(a,this)},multiplyMatrices:function(a,b){var c=a.elements,d=b.elements;b=this.elements;a=c[0];var e=c[4],f=c[8],g=c[12],h=c[1],k=c[5],m=c[9],l=c[13],n=c[2],p=c[6],q=c[10],r=c[14],t=c[3],x=c[7],B=c[11];c=c[15];var w=d[0],A=d[4],G=d[8],N=d[12],y=d[1],F=d[5],D=d[9],C=d[13],z=d[2],H=d[6],I=d[10],K=d[14],L=d[3],T=d[7],M=d[11];d=d[15];b[0]=a*w+e*y+f*z+g*L;b[4]=a*A+e*F+f*H+g*T;b[8]=a*G+e*D+f*I+ -g*M;b[12]=a*N+e*C+f*K+g*d;b[1]=h*w+k*y+m*z+l*L;b[5]=h*A+k*F+m*H+l*T;b[9]=h*G+k*D+m*I+l*M;b[13]=h*N+k*C+m*K+l*d;b[2]=n*w+p*y+q*z+r*L;b[6]=n*A+p*F+q*H+r*T;b[10]=n*G+p*D+q*I+r*M;b[14]=n*N+p*C+q*K+r*d;b[3]=t*w+x*y+B*z+c*L;b[7]=t*A+x*F+B*H+c*T;b[11]=t*G+x*D+B*I+c*M;b[15]=t*N+x*C+B*K+c*d;return this},multiplyScalar:function(a){var b=this.elements;b[0]*=a;b[4]*=a;b[8]*=a;b[12]*=a;b[1]*=a;b[5]*=a;b[9]*=a;b[13]*=a;b[2]*=a;b[6]*=a;b[10]*=a;b[14]*=a;b[3]*=a;b[7]*=a;b[11]*=a;b[15]*=a;return this},applyToBufferAttribute:function(){var a= -new p;return function(b){for(var c=0,d=b.count;cthis.determinant()&&(g=-g);c.x=f[12];c.y=f[13];c.z=f[14];b.copy(this);c=1/g;f=1/h;var m=1/k;b.elements[0]*=c;b.elements[1]*=c;b.elements[2]*=c;b.elements[4]*=f;b.elements[5]*= -f;b.elements[6]*=f;b.elements[8]*=m;b.elements[9]*=m;b.elements[10]*=m;d.setFromRotationMatrix(b);e.x=g;e.y=h;e.z=k;return this}}(),makePerspective:function(a,b,c,d,e,f){void 0===f&&console.warn("THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.");var g=this.elements;g[0]=2*e/(b-a);g[4]=0;g[8]=(b+a)/(b-a);g[12]=0;g[1]=0;g[5]=2*e/(c-d);g[9]=(c+d)/(c-d);g[13]=0;g[2]=0;g[6]=0;g[10]=-(f+e)/(f-e);g[14]=-2*f*e/(f-e);g[3]=0;g[7]=0;g[11]=-1;g[15]=0;return this}, -makeOrthographic:function(a,b,c,d,e,f){var g=this.elements,h=1/(b-a),k=1/(c-d),m=1/(f-e);g[0]=2*h;g[4]=0;g[8]=0;g[12]=-((b+a)*h);g[1]=0;g[5]=2*k;g[9]=0;g[13]=-((c+d)*k);g[2]=0;g[6]=0;g[10]=-2*m;g[14]=-((f+e)*m);g[3]=0;g[7]=0;g[11]=0;g[15]=1;return this},equals:function(a){var b=this.elements;a=a.elements;for(var c=0;16>c;c++)if(b[c]!==a[c])return!1;return!0},fromArray:function(a,b){void 0===b&&(b=0);for(var c=0;16>c;c++)this.elements[c]=a[c+b];return this},toArray:function(a,b){void 0===a&&(a=[]); -void 0===b&&(b=0);var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];a[b+9]=c[9];a[b+10]=c[10];a[b+11]=c[11];a[b+12]=c[12];a[b+13]=c[13];a[b+14]=c[14];a[b+15]=c[15];return a}});Object.assign(ca,{slerp:function(a,b,c,d){return c.copy(a).slerp(b,d)},slerpFlat:function(a,b,c,d,e,f,g){var h=c[d+0],k=c[d+1],m=c[d+2];c=c[d+3];d=e[f+0];var l=e[f+1],n=e[f+2];e=e[f+3];if(c!==e||h!==d||k!==l||m!==n){f=1-g;var p=h*d+k*l+m*n+c*e,q=0<= -p?1:-1,r=1-p*p;r>Number.EPSILON&&(r=Math.sqrt(r),p=Math.atan2(r,p*q),f=Math.sin(f*p)/r,g=Math.sin(g*p)/r);q*=g;h=h*f+d*q;k=k*f+l*q;m=m*f+n*q;c=c*f+e*q;f===1-g&&(g=1/Math.sqrt(h*h+k*k+m*m+c*c),h*=g,k*=g,m*=g,c*=g)}a[b]=h;a[b+1]=k;a[b+2]=m;a[b+3]=c}});Object.defineProperties(ca.prototype,{x:{get:function(){return this._x},set:function(a){this._x=a;this.onChangeCallback()}},y:{get:function(){return this._y},set:function(a){this._y=a;this.onChangeCallback()}},z:{get:function(){return this._z},set:function(a){this._z= -a;this.onChangeCallback()}},w:{get:function(){return this._w},set:function(a){this._w=a;this.onChangeCallback()}}});Object.assign(ca.prototype,{set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._w=d;this.onChangeCallback();return this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._w)},copy:function(a){this._x=a.x;this._y=a.y;this._z=a.z;this._w=a.w;this.onChangeCallback();return this},setFromEuler:function(a,b){if(!a||!a.isEuler)throw Error("THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order."); -var c=a._x,d=a._y,e=a._z;a=a.order;var f=Math.cos,g=Math.sin,h=f(c/2),k=f(d/2);f=f(e/2);c=g(c/2);d=g(d/2);e=g(e/2);"XYZ"===a?(this._x=c*k*f+h*d*e,this._y=h*d*f-c*k*e,this._z=h*k*e+c*d*f,this._w=h*k*f-c*d*e):"YXZ"===a?(this._x=c*k*f+h*d*e,this._y=h*d*f-c*k*e,this._z=h*k*e-c*d*f,this._w=h*k*f+c*d*e):"ZXY"===a?(this._x=c*k*f-h*d*e,this._y=h*d*f+c*k*e,this._z=h*k*e+c*d*f,this._w=h*k*f-c*d*e):"ZYX"===a?(this._x=c*k*f-h*d*e,this._y=h*d*f+c*k*e,this._z=h*k*e-c*d*f,this._w=h*k*f+c*d*e):"YZX"===a?(this._x= -c*k*f+h*d*e,this._y=h*d*f+c*k*e,this._z=h*k*e-c*d*f,this._w=h*k*f-c*d*e):"XZY"===a&&(this._x=c*k*f-h*d*e,this._y=h*d*f-c*k*e,this._z=h*k*e+c*d*f,this._w=h*k*f+c*d*e);if(!1!==b)this.onChangeCallback();return this},setFromAxisAngle:function(a,b){b/=2;var c=Math.sin(b);this._x=a.x*c;this._y=a.y*c;this._z=a.z*c;this._w=Math.cos(b);this.onChangeCallback();return this},setFromRotationMatrix:function(a){var b=a.elements,c=b[0];a=b[4];var d=b[8],e=b[1],f=b[5],g=b[9],h=b[2],k=b[6];b=b[10];var m=c+f+b;0f&&c>b?(c=2*Math.sqrt(1+c-f-b),this._w=(k-g)/c,this._x=.25*c,this._y=(a+e)/c,this._z=(d+h)/c):f>b?(c=2*Math.sqrt(1+f-c-b),this._w=(d-h)/c,this._x=(a+e)/c,this._y=.25*c,this._z=(g+k)/c):(c=2*Math.sqrt(1+b-c-f),this._w=(e-a)/c,this._x=(d+h)/c,this._y=(g+k)/c,this._z=.25*c);this.onChangeCallback();return this},setFromUnitVectors:function(){var a=new p,b;return function(c,d){void 0===a&&(a=new p);b=c.dot(d)+1;1E-6>b? -(b=0,Math.abs(c.x)>Math.abs(c.z)?a.set(-c.y,c.x,0):a.set(0,-c.z,c.y)):a.crossVectors(c,d);this._x=a.x;this._y=a.y;this._z=a.z;this._w=b;return this.normalize()}}(),inverse:function(){return this.conjugate()},conjugate:function(){this._x*=-1;this._y*=-1;this._z*=-1;this.onChangeCallback();return this},dot:function(a){return this._x*a._x+this._y*a._y+this._z*a._z+this._w*a._w},lengthSq:function(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w},length:function(){return Math.sqrt(this._x* -this._x+this._y*this._y+this._z*this._z+this._w*this._w)},normalize:function(){var a=this.length();0===a?(this._z=this._y=this._x=0,this._w=1):(a=1/a,this._x*=a,this._y*=a,this._z*=a,this._w*=a);this.onChangeCallback();return this},multiply:function(a,b){return void 0!==b?(console.warn("THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."),this.multiplyQuaternions(a,b)):this.multiplyQuaternions(this,a)},premultiply:function(a){return this.multiplyQuaternions(a, -this)},multiplyQuaternions:function(a,b){var c=a._x,d=a._y,e=a._z;a=a._w;var f=b._x,g=b._y,h=b._z;b=b._w;this._x=c*b+a*f+d*h-e*g;this._y=d*b+a*g+e*f-c*h;this._z=e*b+a*h+c*g-d*f;this._w=a*b-c*f-d*g-e*h;this.onChangeCallback();return this},slerp:function(a,b){if(0===b)return this;if(1===b)return this.copy(a);var c=this._x,d=this._y,e=this._z,f=this._w,g=f*a._w+c*a._x+d*a._y+e*a._z;0>g?(this._w=-a._w,this._x=-a._x,this._y=-a._y,this._z=-a._z,g=-g):this.copy(a);if(1<=g)return this._w=f,this._x=c,this._y= -d,this._z=e,this;a=Math.sqrt(1-g*g);if(.001>Math.abs(a))return this._w=.5*(f+this._w),this._x=.5*(c+this._x),this._y=.5*(d+this._y),this._z=.5*(e+this._z),this;var h=Math.atan2(a,g);g=Math.sin((1-b)*h)/a;b=Math.sin(b*h)/a;this._w=f*g+this._w*b;this._x=c*g+this._x*b;this._y=d*g+this._y*b;this._z=e*g+this._z*b;this.onChangeCallback();return this},equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._w===this._w},fromArray:function(a,b){void 0===b&&(b=0);this._x=a[b];this._y=a[b+ -1];this._z=a[b+2];this._w=a[b+3];this.onChangeCallback();return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this._x;a[b+1]=this._y;a[b+2]=this._z;a[b+3]=this._w;return a},onChange:function(a){this.onChangeCallback=a;return this},onChangeCallback:function(){}});Object.assign(p.prototype,{isVector3:!0,set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this},setScalar:function(a){this.z=this.y=this.x=a;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y= -a;return this},setZ:function(a){this.z=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;default:throw Error("index is out of range: "+a);}return this},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw Error("index is out of range: "+a);}},clone:function(){return new this.constructor(this.x,this.y,this.z)},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this}, -add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;return this},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;this.z+=a.z*b;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."), -this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;return this},subScalar:function(a){this.x-=a;this.y-=a;this.z-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},multiply:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."),this.multiplyVectors(a,b);this.x*=a.x;this.y*=a.y;this.z*=a.z;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*= -a;return this},multiplyVectors:function(a,b){this.x=a.x*b.x;this.y=a.y*b.y;this.z=a.z*b.z;return this},applyEuler:function(){var a=new ca;return function(b){b&&b.isEuler||console.error("THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.");return this.applyQuaternion(a.setFromEuler(b))}}(),applyAxisAngle:function(){var a=new ca;return function(b,c){return this.applyQuaternion(a.setFromAxisAngle(b,c))}}(),applyMatrix3:function(a){var b=this.x,c=this.y,d=this.z; -a=a.elements;this.x=a[0]*b+a[3]*c+a[6]*d;this.y=a[1]*b+a[4]*c+a[7]*d;this.z=a[2]*b+a[5]*c+a[8]*d;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;var e=1/(a[3]*b+a[7]*c+a[11]*d+a[15]);this.x=(a[0]*b+a[4]*c+a[8]*d+a[12])*e;this.y=(a[1]*b+a[5]*c+a[9]*d+a[13])*e;this.z=(a[2]*b+a[6]*c+a[10]*d+a[14])*e;return this},applyQuaternion:function(a){var b=this.x,c=this.y,d=this.z,e=a.x,f=a.y,g=a.z;a=a.w;var h=a*b+f*d-g*c,k=a*c+g*b-e*d,m=a*d+e*c-f*b;b=-e*b-f*c-g*d;this.x=h*a+b* --e+k*-g-m*-f;this.y=k*a+b*-f+m*-e-h*-g;this.z=m*a+b*-g+h*-f-k*-e;return this},project:function(){var a=new P;return function(b){a.multiplyMatrices(b.projectionMatrix,a.getInverse(b.matrixWorld));return this.applyMatrix4(a)}}(),unproject:function(){var a=new P;return function(b){a.multiplyMatrices(b.matrixWorld,a.getInverse(b.projectionMatrix));return this.applyMatrix4(a)}}(),transformDirection:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d;this.y=a[1]*b+a[5]*c+ -a[9]*d;this.z=a[2]*b+a[6]*c+a[10]*d;return this.normalize()},divide:function(a){this.x/=a.x;this.y/=a.y;this.z/=a.z;return this},divideScalar:function(a){return this.multiplyScalar(1/a)},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);this.z=Math.min(this.z,a.z);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);this.z=Math.max(this.z,a.z);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y, -this.y));this.z=Math.max(a.z,Math.min(b.z,this.z));return this},clampScalar:function(){var a=new p,b=new p;return function(c,d){a.set(c,c,c);b.set(d,d,d);return this.clamp(a,b)}}(),clampLength:function(a,b){var c=this.length();return this.divideScalar(c||1).multiplyScalar(Math.max(a,Math.min(b,c)))},floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);this.z=Math.floor(this.z);return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);this.z=Math.ceil(this.z);return this}, -round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);this.z=Math.round(this.z);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z);return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;return this},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z}, -length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length()||1)},setLength:function(a){return this.normalize().multiplyScalar(a)},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;return this},lerpVectors:function(a,b,c){return this.subVectors(b,a).multiplyScalar(c).add(a)},cross:function(a,b){return void 0!== -b?(console.warn("THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(a,b)):this.crossVectors(this,a)},crossVectors:function(a,b){var c=a.x,d=a.y;a=a.z;var e=b.x,f=b.y;b=b.z;this.x=d*b-a*f;this.y=a*e-c*b;this.z=c*f-d*e;return this},projectOnVector:function(a){var b=a.dot(this)/a.lengthSq();return this.copy(a).multiplyScalar(b)},projectOnPlane:function(){var a=new p;return function(b){a.copy(this).projectOnVector(b);return this.sub(a)}}(),reflect:function(){var a= -new p;return function(b){return this.sub(a.copy(b).multiplyScalar(2*this.dot(b)))}}(),angleTo:function(a){a=this.dot(a)/Math.sqrt(this.lengthSq()*a.lengthSq());return Math.acos(S.clamp(a,-1,1))},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,c=this.y-a.y;a=this.z-a.z;return b*b+c*c+a*a},manhattanDistanceTo:function(a){return Math.abs(this.x-a.x)+Math.abs(this.y-a.y)+Math.abs(this.z-a.z)},setFromSpherical:function(a){var b=Math.sin(a.phi)* -a.radius;this.x=b*Math.sin(a.theta);this.y=Math.cos(a.phi)*a.radius;this.z=b*Math.cos(a.theta);return this},setFromCylindrical:function(a){this.x=a.radius*Math.sin(a.theta);this.y=a.y;this.z=a.radius*Math.cos(a.theta);return this},setFromMatrixPosition:function(a){a=a.elements;this.x=a[12];this.y=a[13];this.z=a[14];return this},setFromMatrixScale:function(a){var b=this.setFromMatrixColumn(a,0).length(),c=this.setFromMatrixColumn(a,1).length();a=this.setFromMatrixColumn(a,2).length();this.x=b;this.y= -c;this.z=a;return this},setFromMatrixColumn:function(a,b){return this.fromArray(a.elements,4*b)},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;return a},fromBufferAttribute:function(a,b,c){void 0!==c&&console.warn("THREE.Vector3: offset has been removed from .fromBufferAttribute()."); -this.x=a.getX(b);this.y=a.getY(b);this.z=a.getZ(b);return this}});Object.assign(ta.prototype,{isMatrix3:!0,set:function(a,b,c,d,e,f,g,h,k){var m=this.elements;m[0]=a;m[1]=d;m[2]=g;m[3]=b;m[4]=e;m[5]=h;m[6]=c;m[7]=f;m[8]=k;return this},identity:function(){this.set(1,0,0,0,1,0,0,0,1);return this},clone:function(){return(new this.constructor).fromArray(this.elements)},copy:function(a){var b=this.elements;a=a.elements;b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]= -a[8];return this},setFromMatrix4:function(a){a=a.elements;this.set(a[0],a[4],a[8],a[1],a[5],a[9],a[2],a[6],a[10]);return this},applyToBufferAttribute:function(){var a=new p;return function(b){for(var c=0,d=b.count;cc;c++)if(b[c]!==a[c])return!1;return!0},fromArray:function(a,b){void 0===b&&(b=0);for(var c=0;9>c;c++)this.elements[c]=a[c+b];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8]; -return a}});var xf=0;aa.DEFAULT_IMAGE=void 0;aa.DEFAULT_MAPPING=300;aa.prototype=Object.assign(Object.create(xa.prototype),{constructor:aa,isTexture:!0,clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.name=a.name;this.image=a.image;this.mipmaps=a.mipmaps.slice(0);this.mapping=a.mapping;this.wrapS=a.wrapS;this.wrapT=a.wrapT;this.magFilter=a.magFilter;this.minFilter=a.minFilter;this.anisotropy=a.anisotropy;this.format=a.format;this.type=a.type;this.offset.copy(a.offset); -this.repeat.copy(a.repeat);this.center.copy(a.center);this.rotation=a.rotation;this.matrixAutoUpdate=a.matrixAutoUpdate;this.matrix.copy(a.matrix);this.generateMipmaps=a.generateMipmaps;this.premultiplyAlpha=a.premultiplyAlpha;this.flipY=a.flipY;this.unpackAlignment=a.unpackAlignment;this.encoding=a.encoding;return this},toJSON:function(a){var b=void 0===a||"string"===typeof a;if(!b&&void 0!==a.textures[this.uuid])return a.textures[this.uuid];var c={metadata:{version:4.5,type:"Texture",generator:"Texture.toJSON"}, -uuid:this.uuid,name:this.name,mapping:this.mapping,repeat:[this.repeat.x,this.repeat.y],offset:[this.offset.x,this.offset.y],center:[this.center.x,this.center.y],rotation:this.rotation,wrap:[this.wrapS,this.wrapT],minFilter:this.minFilter,magFilter:this.magFilter,anisotropy:this.anisotropy,flipY:this.flipY};if(void 0!==this.image){var d=this.image;void 0===d.uuid&&(d.uuid=S.generateUUID());if(!b&&void 0===a.images[d.uuid]){var e=a.images,f=d.uuid,g=d.uuid;if(d instanceof HTMLCanvasElement)var h=d; -else{h=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");h.width=d.width;h.height=d.height;var k=h.getContext("2d");d instanceof ImageData?k.putImageData(d,0,0):k.drawImage(d,0,0,d.width,d.height)}h=2048a.x||1a.x?0:1;break;case 1002:a.x=1===Math.abs(Math.floor(a.x)%2)?Math.ceil(a.x)-a.x:a.x-Math.floor(a.x)}if(0>a.y||1a.y?0:1;break;case 1002:a.y=1===Math.abs(Math.floor(a.y)%2)?Math.ceil(a.y)-a.y:a.y-Math.floor(a.y)}this.flipY&&(a.y=1-a.y)}}});Object.defineProperty(aa.prototype,"needsUpdate",{set:function(a){!0===a&&this.version++}});Object.assign(X.prototype, -{isVector4:!0,set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},setScalar:function(a){this.w=this.z=this.y=this.x=a;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setW:function(a){this.w=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;case 3:this.w=b;break;default:throw Error("index is out of range: "+a);}return this},getComponent:function(a){switch(a){case 0:return this.x; -case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw Error("index is out of range: "+a);}},clone:function(){return new this.constructor(this.x,this.y,this.z,this.w)},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=void 0!==a.w?a.w:1;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;this.w+=a.w;return this}, -addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;this.w+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;this.w=a.w+b.w;return this},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;this.z+=a.z*b;this.w+=a.w*b;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;this.w-=a.w;return this},subScalar:function(a){this.x-= -a;this.y-=a;this.z-=a;this.w-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;this.w=a.w-b.w;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;this.w*=a;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,e=this.w;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12]*e;this.y=a[1]*b+a[5]*c+a[9]*d+a[13]*e;this.z=a[2]*b+a[6]*c+a[10]*d+a[14]*e;this.w=a[3]*b+a[7]*c+a[11]*d+a[15]*e;return this},divideScalar:function(a){return this.multiplyScalar(1/ -a)},setAxisAngleFromQuaternion:function(a){this.w=2*Math.acos(a.w);var b=Math.sqrt(1-a.w*a.w);1E-4>b?(this.x=1,this.z=this.y=0):(this.x=a.x/b,this.y=a.y/b,this.z=a.z/b);return this},setAxisAngleFromRotationMatrix:function(a){a=a.elements;var b=a[0];var c=a[4];var d=a[8],e=a[1],f=a[5],g=a[9];var h=a[2];var k=a[6];var m=a[10];if(.01>Math.abs(c-e)&&.01>Math.abs(d-h)&&.01>Math.abs(g-k)){if(.1>Math.abs(c+e)&&.1>Math.abs(d+h)&&.1>Math.abs(g+k)&&.1>Math.abs(b+f+m-3))return this.set(1,0,0,0),this;a=Math.PI; -b=(b+1)/2;f=(f+1)/2;m=(m+1)/2;c=(c+e)/4;d=(d+h)/4;g=(g+k)/4;b>f&&b>m?.01>b?(k=0,c=h=.707106781):(k=Math.sqrt(b),h=c/k,c=d/k):f>m?.01>f?(k=.707106781,h=0,c=.707106781):(h=Math.sqrt(f),k=c/h,c=g/h):.01>m?(h=k=.707106781,c=0):(c=Math.sqrt(m),k=d/c,h=g/c);this.set(k,h,c,a);return this}a=Math.sqrt((k-g)*(k-g)+(d-h)*(d-h)+(e-c)*(e-c));.001>Math.abs(a)&&(a=1);this.x=(k-g)/a;this.y=(d-h)/a;this.z=(e-c)/a;this.w=Math.acos((b+f+m-1)/2);return this},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y, -a.y);this.z=Math.min(this.z,a.z);this.w=Math.min(this.w,a.w);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);this.z=Math.max(this.z,a.z);this.w=Math.max(this.w,a.w);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));this.z=Math.max(a.z,Math.min(b.z,this.z));this.w=Math.max(a.w,Math.min(b.w,this.w));return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new X,b=new X);a.set(c, -c,c,c);b.set(d,d,d,d);return this.clamp(a,b)}}(),clampLength:function(a,b){var c=this.length();return this.divideScalar(c||1).multiplyScalar(Math.max(a,Math.min(b,c)))},floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);this.z=Math.floor(this.z);this.w=Math.floor(this.w);return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);this.z=Math.ceil(this.z);this.w=Math.ceil(this.w);return this},round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y); -this.z=Math.round(this.z);this.w=Math.round(this.w);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z);this.w=0>this.w?Math.ceil(this.w):Math.floor(this.w);return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;this.w=-this.w;return this},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z+this.w*a.w},lengthSq:function(){return this.x* -this.x+this.y*this.y+this.z*this.z+this.w*this.w},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)},normalize:function(){return this.divideScalar(this.length()||1)},setLength:function(a){return this.normalize().multiplyScalar(a)},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;this.w+=(a.w-this.w)*b;return this},lerpVectors:function(a, -b,c){return this.subVectors(b,a).multiplyScalar(c).add(a)},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z&&a.w===this.w},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];this.w=a[b+3];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;a[b+3]=this.w;return a},fromBufferAttribute:function(a,b,c){void 0!==c&&console.warn("THREE.Vector4: offset has been removed from .fromBufferAttribute()."); -this.x=a.getX(b);this.y=a.getY(b);this.z=a.getZ(b);this.w=a.getW(b);return this}});jb.prototype=Object.assign(Object.create(xa.prototype),{constructor:jb,isWebGLRenderTarget:!0,setSize:function(a,b){if(this.width!==a||this.height!==b)this.width=a,this.height=b,this.dispose();this.viewport.set(0,0,a,b);this.scissor.set(0,0,a,b)},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.width=a.width;this.height=a.height;this.viewport.copy(a.viewport);this.texture=a.texture.clone(); -this.depthBuffer=a.depthBuffer;this.stencilBuffer=a.stencilBuffer;this.depthTexture=a.depthTexture;return this},dispose:function(){this.dispatchEvent({type:"dispose"})}});Gb.prototype=Object.create(jb.prototype);Gb.prototype.constructor=Gb;Gb.prototype.isWebGLRenderTargetCube=!0;kb.prototype=Object.create(aa.prototype);kb.prototype.constructor=kb;kb.prototype.isDataTexture=!0;bb.prototype=Object.create(aa.prototype);bb.prototype.constructor=bb;bb.prototype.isCubeTexture=!0;Object.defineProperty(bb.prototype, -"images",{get:function(){return this.image},set:function(a){this.image=a}});var He=new aa,Ie=new bb,Ce=[],Ee=[],Ge=new Float32Array(16),Fe=new Float32Array(9);Me.prototype.setValue=function(a,b){for(var c=this.seq,d=0,e=c.length;d!==e;++d){var f=c[d];f.setValue(a,b[f.id])}};var Qd=/([\w\d_]+)(\])?(\[|\.)?/g;cb.prototype.setValue=function(a,b,c){b=this.map[b];void 0!==b&&b.setValue(a,c,this.renderer)};cb.prototype.setOptional=function(a,b,c){b=b[c];void 0!==b&&this.setValue(a,c,b)};cb.upload=function(a, -b,c,d){for(var e=0,f=b.length;e!==f;++e){var g=b[e],h=c[g.id];!1!==h.needsUpdate&&g.setValue(a,h.value,d)}};cb.seqWithValue=function(a,b){for(var c=[],d=0,e=a.length;d!==e;++d){var f=a[d];f.id in b&&c.push(f)}return c};var Kg={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272, -cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265, -dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323, -lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912, -mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864, -seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};Object.assign(H.prototype,{isColor:!0,r:1,g:1,b:1,set:function(a){a&&a.isColor?this.copy(a):"number"===typeof a?this.setHex(a):"string"=== -typeof a&&this.setStyle(a);return this},setScalar:function(a){this.b=this.g=this.r=a;return this},setHex:function(a){a=Math.floor(a);this.r=(a>>16&255)/255;this.g=(a>>8&255)/255;this.b=(a&255)/255;return this},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;return this},setHSL:function(){function a(a,c,d){0>d&&(d+=1);1d?c:d<2/3?a+6*(c-a)*(2/3-d):a}return function(b,c,d){b=S.euclideanModulo(b,1);c=S.clamp(c,0,1);d=S.clamp(d,0,1);0===c?this.r=this.g=this.b=d:(c= -.5>=d?d*(1+c):d+c-d*c,d=2*d-c,this.r=a(d,c,b+1/3),this.g=a(d,c,b),this.b=a(d,c,b-1/3));return this}}(),setStyle:function(a){function b(b){void 0!==b&&1>parseFloat(b)&&console.warn("THREE.Color: Alpha component of "+a+" will be ignored.")}var c;if(c=/^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec(a)){var d=c[2];switch(c[1]){case "rgb":case "rgba":if(c=/^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d))return this.r=Math.min(255,parseInt(c[1],10))/255,this.g=Math.min(255,parseInt(c[2],10))/ -255,this.b=Math.min(255,parseInt(c[3],10))/255,b(c[5]),this;if(c=/^(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d))return this.r=Math.min(100,parseInt(c[1],10))/100,this.g=Math.min(100,parseInt(c[2],10))/100,this.b=Math.min(100,parseInt(c[3],10))/100,b(c[5]),this;break;case "hsl":case "hsla":if(c=/^([0-9]*\.?[0-9]+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d)){d=parseFloat(c[1])/360;var e=parseInt(c[2],10)/100,f=parseInt(c[3],10)/100;b(c[5]);return this.setHSL(d, -e,f)}}}else if(c=/^#([A-Fa-f0-9]+)$/.exec(a)){c=c[1];d=c.length;if(3===d)return this.r=parseInt(c.charAt(0)+c.charAt(0),16)/255,this.g=parseInt(c.charAt(1)+c.charAt(1),16)/255,this.b=parseInt(c.charAt(2)+c.charAt(2),16)/255,this;if(6===d)return this.r=parseInt(c.charAt(0)+c.charAt(1),16)/255,this.g=parseInt(c.charAt(2)+c.charAt(3),16)/255,this.b=parseInt(c.charAt(4)+c.charAt(5),16)/255,this}a&&0=h?k/(e+f):k/(2-e-f);switch(e){case b:g=(c-d)/k+(c 0.0 ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\treturn distanceFalloff * maxDistanceCutoffFactor;\n#else\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n#endif\n\t}\n\treturn 1.0;\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n\treturn specularColor * AB.x + AB.y;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n", -bumpmap_pars_fragment:"#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif\n", -clipping_planes_fragment:"#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\tif ( clipped ) discard;\n\t#endif\n#endif\n", -clipping_planes_pars_fragment:"#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( PHYSICAL ) && ! defined( PHONG )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif\n",clipping_planes_pars_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvarying vec3 vViewPosition;\n#endif\n",clipping_planes_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n", -color_fragment:"#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif",color_pars_fragment:"#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif\n",color_pars_vertex:"#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif",color_vertex:"#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif",common:"#define PI 3.14159265359\n#define PI2 6.28318530718\n#define PI_HALF 1.5707963267949\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract(sin(sn) * c);\n}\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat linearToRelativeLuminance( const in vec3 color ) {\n\tvec3 weights = vec3( 0.2126, 0.7152, 0.0722 );\n\treturn dot( weights, color.rgb );\n}\n", -cube_uv_reflection_fragment:"#ifdef ENVMAP_TYPE_CUBE_UV\n#define cubeUV_textureSize (1024.0)\nint getFaceFromDirection(vec3 direction) {\n\tvec3 absDirection = abs(direction);\n\tint face = -1;\n\tif( absDirection.x > absDirection.z ) {\n\t\tif(absDirection.x > absDirection.y )\n\t\t\tface = direction.x > 0.0 ? 0 : 3;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\telse {\n\t\tif(absDirection.z > absDirection.y )\n\t\t\tface = direction.z > 0.0 ? 2 : 5;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\treturn face;\n}\n#define cubeUV_maxLods1 (log2(cubeUV_textureSize*0.25) - 1.0)\n#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))\nvec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {\n\tfloat scale = exp2(cubeUV_maxLods1 - roughnessLevel);\n\tfloat dxRoughness = dFdx(roughness);\n\tfloat dyRoughness = dFdy(roughness);\n\tvec3 dx = dFdx( vec * scale * dxRoughness );\n\tvec3 dy = dFdy( vec * scale * dyRoughness );\n\tfloat d = max( dot( dx, dx ), dot( dy, dy ) );\n\td = clamp(d, 1.0, cubeUV_rangeClamp);\n\tfloat mipLevel = 0.5 * log2(d);\n\treturn vec2(floor(mipLevel), fract(mipLevel));\n}\n#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)\n#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)\nvec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {\n\tmipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;\n\tfloat a = 16.0 * cubeUV_rcpTextureSize;\n\tvec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );\n\tvec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;\n\tfloat powScale = exp2_packed.x * exp2_packed.y;\n\tfloat scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;\n\tfloat mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;\n\tbool bRes = mipLevel == 0.0;\n\tscale = bRes && (scale < a) ? a : scale;\n\tvec3 r;\n\tvec2 offset;\n\tint face = getFaceFromDirection(direction);\n\tfloat rcpPowScale = 1.0 / powScale;\n\tif( face == 0) {\n\t\tr = vec3(direction.x, -direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 1) {\n\t\tr = vec3(direction.y, direction.x, direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 2) {\n\t\tr = vec3(direction.z, direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 3) {\n\t\tr = vec3(direction.x, direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse if( face == 4) {\n\t\tr = vec3(direction.y, direction.x, -direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse {\n\t\tr = vec3(direction.z, -direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\tr = normalize(r);\n\tfloat texelOffset = 0.5 * cubeUV_rcpTextureSize;\n\tvec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;\n\tvec2 base = offset + vec2( texelOffset );\n\treturn base + s * ( scale - 2.0 * texelOffset );\n}\n#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)\nvec4 textureCubeUV(vec3 reflectedDirection, float roughness ) {\n\tfloat roughnessVal = roughness* cubeUV_maxLods3;\n\tfloat r1 = floor(roughnessVal);\n\tfloat r2 = r1 + 1.0;\n\tfloat t = fract(roughnessVal);\n\tvec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);\n\tfloat s = mipInfo.y;\n\tfloat level0 = mipInfo.x;\n\tfloat level1 = level0 + 1.0;\n\tlevel1 = level1 > 5.0 ? 5.0 : level1;\n\tlevel0 += min( floor( s + 0.5 ), 5.0 );\n\tvec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);\n\tvec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));\n\tvec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);\n\tvec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));\n\tvec4 result = mix(color10, color20, t);\n\treturn vec4(result.rgb, 1.0);\n}\n#endif\n", -defaultnormal_vertex:"vec3 transformedNormal = normalMatrix * objectNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n",displacementmap_pars_vertex:"#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif\n",displacementmap_vertex:"#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n#endif\n", -emissivemap_fragment:"#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif\n",emissivemap_pars_fragment:"#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif\n",encodings_fragment:" gl_FragColor = linearToOutputTexel( gl_FragColor );\n",encodings_pars_fragment:"\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.w );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.xyz * value.w * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = min( floor( D ) / 255.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n\tvec3 Xp_Y_XYZp = value.rgb * cLogLuvM;\n\tXp_Y_XYZp = max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract(Le);\n\tvResult.z = (Le - (floor(vResult.w*255.0))/255.0)/255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;\n\treturn vec4( max(vRGB, 0.0), 1.0 );\n}\n", -envmap_fragment:"#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\treflectVec = normalize( reflectVec );\n\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\treflectVec = normalize( reflectVec );\n\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\tenvColor = envMapTexelToLinear( envColor );\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif\n", -envmap_pars_fragment:"#if defined( USE_ENVMAP ) || defined( PHYSICAL )\n\tuniform float reflectivity;\n\tuniform float envMapIntensity;\n#endif\n#ifdef USE_ENVMAP\n\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\n\t\tvarying vec3 vWorldPosition;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\tuniform float flipEnvMap;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif\n", -envmap_pars_vertex:"#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif\n",envmap_vertex:"#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif\n", -fog_vertex:"\n#ifdef USE_FOG\nfogDepth = -mvPosition.z;\n#endif",fog_pars_vertex:"#ifdef USE_FOG\n varying float fogDepth;\n#endif\n",fog_fragment:"#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif\n",fog_pars_fragment:"#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float fogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif\n", -gradientmap_pars_fragment:"#ifdef TOON\n\tuniform sampler2D gradientMap;\n\tvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\t\tfloat dotNL = dot( normal, lightDirection );\n\t\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t\t#ifdef USE_GRADIENTMAP\n\t\t\treturn texture2D( gradientMap, coord ).rgb;\n\t\t#else\n\t\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t\t#endif\n\t}\n#endif\n",lightmap_fragment:"#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif\n", -lightmap_pars_fragment:"#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif",lights_lambert_vertex:"vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\n#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n#endif\n", -lights_pars:"uniform vec3 ambientLightColor;\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t\tfloat shadowCameraNear;\n\t\tfloat shadowCameraFar;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif\n#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\tvec4 envMapColor = textureCubeUV( queryVec, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar + 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\tvec4 envMapColor = textureCubeUV(queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent));\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\t\tvec2 sampleUV;\n\t\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif\n", -lights_phong_fragment:"BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;\n",lights_phong_pars_fragment:"varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifdef TOON\n\t\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#else\n\t\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\t\tvec3 irradiance = dotNL * directLight.color;\n\t#endif\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)\n", -lights_physical_fragment:"PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nmaterial.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );\n#ifdef STANDARD\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.clearCoat = saturate( clearCoat );\tmaterial.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );\n#endif\n", -lights_physical_pars_fragment:"struct PhysicalMaterial {\n\tvec3\tdiffuseColor;\n\tfloat\tspecularRoughness;\n\tvec3\tspecularColor;\n\t#ifndef STANDARD\n\t\tfloat clearCoat;\n\t\tfloat clearCoatRoughness;\n\t#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearCoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.specularRoughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos - halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos + halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos + halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos - halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifndef STANDARD\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness );\n\treflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\t#ifndef STANDARD\n\t\treflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifndef STANDARD\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\tfloat dotNL = dotNV;\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.indirectSpecular += ( 1.0 - clearCoatDHR ) * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness );\n\t#ifndef STANDARD\n\t\treflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\n#define Material_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.specularRoughness )\n#define Material_ClearCoat_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.clearCoatRoughness )\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}\n", -lights_template:"\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = normalize( vViewPosition );\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#ifdef USE_LIGHTMAP\n\t\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tirradiance += getLightProbeIndirectIrradiance( geometry, 8 );\n\t#endif\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tvec3 radiance = getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), 8 );\n\t#ifndef STANDARD\n\t\tvec3 clearCoatRadiance = getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), 8 );\n\t#else\n\t\tvec3 clearCoatRadiance = vec3( 0.0 );\n\t#endif\n\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\n#endif\n", -logdepthbuf_fragment:"#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif",logdepthbuf_pars_fragment:"#ifdef USE_LOGDEPTHBUF\n\tuniform float logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n#endif\n",logdepthbuf_pars_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n\tuniform float logDepthBufFC;\n#endif",logdepthbuf_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t#else\n\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\tgl_Position.z *= gl_Position.w;\n\t#endif\n#endif\n", -map_fragment:"#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif\n",map_pars_fragment:"#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n",map_particle_fragment:"#ifdef USE_MAP\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n\tvec4 mapTexel = texture2D( map, uv );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n",map_particle_pars_fragment:"#ifdef USE_MAP\n\tuniform mat3 uvTransform;\n\tuniform sampler2D map;\n#endif\n", -metalnessmap_fragment:"float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif\n",metalnessmap_pars_fragment:"#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\n\tobjectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n\tobjectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n\tobjectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n\tobjectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n#endif\n", -morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n\t#ifndef USE_MORPHNORMALS\n\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif",morphtarget_vertex:"#ifdef USE_MORPHTARGETS\n\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n\ttransformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n\ttransformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\ttransformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n\ttransformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n\ttransformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n\ttransformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\t#endif\n#endif\n", -normal_fragment:"#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n#endif\n#ifdef USE_NORMALMAP\n\tnormal = perturbNormal2Arb( -vViewPosition, normal );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n", -normalmap_pars_fragment:"#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\n\t\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n\t\tvec3 N = normalize( surf_norm );\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy = normalScale * mapN.xy;\n\t\tmat3 tsn = mat3( S, T, N );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif\n", -packing:"vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}\n", -premultiplied_alpha_fragment:"#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif\n",project_vertex:"vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\ngl_Position = projectionMatrix * mvPosition;\n",dithering_fragment:"#if defined( DITHERING )\n gl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif\n",dithering_pars_fragment:"#if defined( DITHERING )\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif\n", -roughnessmap_fragment:"float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif\n",roughnessmap_pars_fragment:"#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif",shadowmap_pars_fragment:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tfloat texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {\n\t\tconst vec2 offset = vec2( 0.0, 1.0 );\n\t\tvec2 texelSize = vec2( 1.0 ) / size;\n\t\tvec2 centroidUV = floor( uv * size + 0.5 ) / size;\n\t\tfloat lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );\n\t\tfloat lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );\n\t\tfloat rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );\n\t\tfloat rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );\n\t\tvec2 f = fract( uv * size + 0.5 );\n\t\tfloat a = mix( lb, lt, f.y );\n\t\tfloat b = mix( rb, rt, f.y );\n\t\tfloat c = mix( a, b, f.x );\n\t\treturn c;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tshadow = (\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif\n", -shadowmap_pars_vertex:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n#endif\n", -shadowmap_vertex:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n#endif\n", -shadowmask_pars_fragment:"float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tDirectionalLight directionalLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tshadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tSpotLight spotLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tshadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tPointLight pointLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tshadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#endif\n\t#endif\n\treturn shadow;\n}\n", -skinbase_vertex:"#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform sampler2D boneTexture;\n\t\tuniform int boneTextureSize;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif\n", -skinning_vertex:"#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif\n",skinnormal_vertex:"#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n#endif\n", -specularmap_fragment:"float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif",specularmap_pars_fragment:"#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif",tonemapping_fragment:"#if defined( TONE_MAPPING )\n gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif\n",tonemapping_pars_fragment:"#ifndef saturate\n\t#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nuniform float toneMappingWhitePoint;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\nvec3 Uncharted2ToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\n", -uv_pars_fragment:"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n#endif",uv_pars_vertex:"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n#endif\n", -uv_vertex:"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif",uv2_pars_fragment:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif",uv2_pars_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n#endif", -uv2_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = uv2;\n#endif",worldpos_vertex:"#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\n\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n#endif\n",cube_frag:"uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldPosition;\nvoid main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n\tgl_FragColor.a *= opacity;\n}\n", -cube_vert:"varying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}\n",depth_frag:"#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( gl_FragCoord.z ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\n\t#endif\n}\n", -depth_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n", -distanceRGBA_frag:"#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}\n", -distanceRGBA_vert:"#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}\n", -equirect_frag:"uniform sampler2D tEquirect;\nvarying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldPosition );\n\tvec2 sampleUV;\n\tsampleUV.y = asin( clamp( direction.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n}\n",equirect_vert:"varying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}\n", -linedashed_frag:"uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n", -linedashed_vert:"uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}\n", -meshbasic_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\treflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n", -meshbasic_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifdef USE_ENVMAP\n\t#include \n\t#include \n\t#include \n\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n", -meshlambert_frag:"uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\n\t#include \n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n", -meshlambert_vert:"#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n", -meshphong_frag:"#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n", -meshphong_vert:"#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}\n", -meshphysical_frag:"#define PHYSICAL\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifndef STANDARD\n\tuniform float clearCoat;\n\tuniform float clearCoatRoughness;\n#endif\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n", -meshphysical_vert:"#define PHYSICAL\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}\n", -normal_frag:"#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}\n", -normal_vert:"#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}\n", -points_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n", -points_vert:"uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#ifdef USE_SIZEATTENUATION\n\t\tgl_PointSize = size * ( scale / - mvPosition.z );\n\t#else\n\t\tgl_PointSize = size;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n", -shadow_frag:"uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n}\n",shadow_vert:"#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"}, -qb={basic:{uniforms:Ea.merge([I.common,I.specularmap,I.envmap,I.aomap,I.lightmap,I.fog]),vertexShader:R.meshbasic_vert,fragmentShader:R.meshbasic_frag},lambert:{uniforms:Ea.merge([I.common,I.specularmap,I.envmap,I.aomap,I.lightmap,I.emissivemap,I.fog,I.lights,{emissive:{value:new H(0)}}]),vertexShader:R.meshlambert_vert,fragmentShader:R.meshlambert_frag},phong:{uniforms:Ea.merge([I.common,I.specularmap,I.envmap,I.aomap,I.lightmap,I.emissivemap,I.bumpmap,I.normalmap,I.displacementmap,I.gradientmap, -I.fog,I.lights,{emissive:{value:new H(0)},specular:{value:new H(1118481)},shininess:{value:30}}]),vertexShader:R.meshphong_vert,fragmentShader:R.meshphong_frag},standard:{uniforms:Ea.merge([I.common,I.envmap,I.aomap,I.lightmap,I.emissivemap,I.bumpmap,I.normalmap,I.displacementmap,I.roughnessmap,I.metalnessmap,I.fog,I.lights,{emissive:{value:new H(0)},roughness:{value:.5},metalness:{value:.5},envMapIntensity:{value:1}}]),vertexShader:R.meshphysical_vert,fragmentShader:R.meshphysical_frag},points:{uniforms:Ea.merge([I.points, -I.fog]),vertexShader:R.points_vert,fragmentShader:R.points_frag},dashed:{uniforms:Ea.merge([I.common,I.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:R.linedashed_vert,fragmentShader:R.linedashed_frag},depth:{uniforms:Ea.merge([I.common,I.displacementmap]),vertexShader:R.depth_vert,fragmentShader:R.depth_frag},normal:{uniforms:Ea.merge([I.common,I.bumpmap,I.normalmap,I.displacementmap,{opacity:{value:1}}]),vertexShader:R.normal_vert,fragmentShader:R.normal_frag},cube:{uniforms:{tCube:{value:null}, -tFlip:{value:-1},opacity:{value:1}},vertexShader:R.cube_vert,fragmentShader:R.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:R.equirect_vert,fragmentShader:R.equirect_frag},distanceRGBA:{uniforms:Ea.merge([I.common,I.displacementmap,{referencePosition:{value:new p},nearDistance:{value:1},farDistance:{value:1E3}}]),vertexShader:R.distanceRGBA_vert,fragmentShader:R.distanceRGBA_frag},shadow:{uniforms:Ea.merge([I.lights,I.fog,{color:{value:new H(0)},opacity:{value:1}}]),vertexShader:R.shadow_vert, -fragmentShader:R.shadow_frag}};qb.physical={uniforms:Ea.merge([qb.standard.uniforms,{clearCoat:{value:0},clearCoatRoughness:{value:0}}]),vertexShader:R.meshphysical_vert,fragmentShader:R.meshphysical_frag};qc.prototype=Object.create(aa.prototype);qc.prototype.constructor=qc;var Yf=0;O.prototype=Object.assign(Object.create(xa.prototype),{constructor:O,isMaterial:!0,onBeforeCompile:function(){},setValues:function(a){if(void 0!==a)for(var b in a){var c=a[b];if(void 0===c)console.warn("THREE.Material: '"+ -b+"' parameter is undefined.");else if("shading"===b)console.warn("THREE."+this.type+": .shading has been removed. Use the boolean .flatShading instead."),this.flatShading=1===c?!0:!1;else{var d=this[b];void 0===d?console.warn("THREE."+this.type+": '"+b+"' is not a property of this material."):d&&d.isColor?d.set(c):d&&d.isVector3&&c&&c.isVector3?d.copy(c):this[b]="overdraw"===b?Number(c):c}}},toJSON:function(a){function b(a){var b=[],c;for(c in a){var d=a[c];delete d.metadata;b.push(d)}return b}var c= -void 0===a||"string"===typeof a;c&&(a={textures:{},images:{}});var d={metadata:{version:4.5,type:"Material",generator:"Material.toJSON"}};d.uuid=this.uuid;d.type=this.type;""!==this.name&&(d.name=this.name);this.color&&this.color.isColor&&(d.color=this.color.getHex());void 0!==this.roughness&&(d.roughness=this.roughness);void 0!==this.metalness&&(d.metalness=this.metalness);this.emissive&&this.emissive.isColor&&(d.emissive=this.emissive.getHex());1!==this.emissiveIntensity&&(d.emissiveIntensity=this.emissiveIntensity); -this.specular&&this.specular.isColor&&(d.specular=this.specular.getHex());void 0!==this.shininess&&(d.shininess=this.shininess);void 0!==this.clearCoat&&(d.clearCoat=this.clearCoat);void 0!==this.clearCoatRoughness&&(d.clearCoatRoughness=this.clearCoatRoughness);this.map&&this.map.isTexture&&(d.map=this.map.toJSON(a).uuid);this.alphaMap&&this.alphaMap.isTexture&&(d.alphaMap=this.alphaMap.toJSON(a).uuid);this.lightMap&&this.lightMap.isTexture&&(d.lightMap=this.lightMap.toJSON(a).uuid);this.bumpMap&& -this.bumpMap.isTexture&&(d.bumpMap=this.bumpMap.toJSON(a).uuid,d.bumpScale=this.bumpScale);this.normalMap&&this.normalMap.isTexture&&(d.normalMap=this.normalMap.toJSON(a).uuid,d.normalScale=this.normalScale.toArray());this.displacementMap&&this.displacementMap.isTexture&&(d.displacementMap=this.displacementMap.toJSON(a).uuid,d.displacementScale=this.displacementScale,d.displacementBias=this.displacementBias);this.roughnessMap&&this.roughnessMap.isTexture&&(d.roughnessMap=this.roughnessMap.toJSON(a).uuid); -this.metalnessMap&&this.metalnessMap.isTexture&&(d.metalnessMap=this.metalnessMap.toJSON(a).uuid);this.emissiveMap&&this.emissiveMap.isTexture&&(d.emissiveMap=this.emissiveMap.toJSON(a).uuid);this.specularMap&&this.specularMap.isTexture&&(d.specularMap=this.specularMap.toJSON(a).uuid);this.envMap&&this.envMap.isTexture&&(d.envMap=this.envMap.toJSON(a).uuid,d.reflectivity=this.reflectivity);this.gradientMap&&this.gradientMap.isTexture&&(d.gradientMap=this.gradientMap.toJSON(a).uuid);void 0!==this.size&& -(d.size=this.size);void 0!==this.sizeAttenuation&&(d.sizeAttenuation=this.sizeAttenuation);1!==this.blending&&(d.blending=this.blending);!0===this.flatShading&&(d.flatShading=this.flatShading);0!==this.side&&(d.side=this.side);0!==this.vertexColors&&(d.vertexColors=this.vertexColors);1>this.opacity&&(d.opacity=this.opacity);!0===this.transparent&&(d.transparent=this.transparent);d.depthFunc=this.depthFunc;d.depthTest=this.depthTest;d.depthWrite=this.depthWrite;0!==this.rotation&&(d.rotation=this.rotation); -1!==this.linewidth&&(d.linewidth=this.linewidth);void 0!==this.dashSize&&(d.dashSize=this.dashSize);void 0!==this.gapSize&&(d.gapSize=this.gapSize);void 0!==this.scale&&(d.scale=this.scale);!0===this.dithering&&(d.dithering=!0);0e&&(e=m);l>f&&(f=l);n>g&&(g=n)}this.min.set(b,c,d);this.max.set(e,f,g); -return this},setFromBufferAttribute:function(a){for(var b=Infinity,c=Infinity,d=Infinity,e=-Infinity,f=-Infinity,g=-Infinity,h=0,k=a.count;he&&(e=m);l>f&&(f=l);n>g&&(g=n)}this.min.set(b,c,d);this.max.set(e,f,g);return this},setFromPoints:function(a){this.makeEmpty();for(var b=0,c=a.length;bthis.max.x||a.ythis.max.y||a.zthis.max.z?!1:!0},containsBox:function(a){return this.min.x<= -a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y&&this.min.z<=a.min.z&&a.max.z<=this.max.z},getParameter:function(a,b){return(b||new p).set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y),(a.z-this.min.z)/(this.max.z-this.min.z))},intersectsBox:function(a){return a.max.xthis.max.x||a.max.ythis.max.y||a.max.zthis.max.z?!1:!0},intersectsSphere:function(){var a=new p;return function(b){this.clampPoint(b.center, -a);return a.distanceToSquared(b.center)<=b.radius*b.radius}}(),intersectsPlane:function(a){if(0=a.constant},intersectsTriangle:function(){function a(a){var e; -var f=0;for(e=a.length-3;f<=e;f+=3){h.fromArray(a,f);var g=m.x*Math.abs(h.x)+m.y*Math.abs(h.y)+m.z*Math.abs(h.z),k=b.dot(h),n=c.dot(h),l=d.dot(h);if(Math.max(-Math.max(k,n,l),Math.min(k,n,l))>g)return!1}return!0}var b=new p,c=new p,d=new p,e=new p,f=new p,g=new p,h=new p,k=new p,m=new p,l=new p;return function(h){if(this.isEmpty())return!1;this.getCenter(k);m.subVectors(this.max,k);b.subVectors(h.a,k);c.subVectors(h.b,k);d.subVectors(h.c,k);e.subVectors(c,b);f.subVectors(d,c);g.subVectors(b,d);h= -[0,-e.z,e.y,0,-f.z,f.y,0,-g.z,g.y,e.z,0,-e.x,f.z,0,-f.x,g.z,0,-g.x,-e.y,e.x,0,-f.y,f.x,0,-g.y,g.x,0];if(!a(h))return!1;h=[1,0,0,0,1,0,0,0,1];if(!a(h))return!1;l.crossVectors(e,f);h=[l.x,l.y,l.z];return a(h)}}(),clampPoint:function(a,b){return(b||new p).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new p;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),getBoundingSphere:function(){var a=new p;return function(b){b=b||new Ca;this.getCenter(b.center); -b.radius=.5*this.getSize(a).length();return b}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);this.isEmpty()&&this.makeEmpty();return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},applyMatrix4:function(){var a=[new p,new p,new p,new p,new p,new p,new p,new p];return function(b){if(this.isEmpty())return this;a[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(b);a[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(b);a[2].set(this.min.x,this.max.y, -this.min.z).applyMatrix4(b);a[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(b);a[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(b);a[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(b);a[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(b);a[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(b);this.setFromPoints(a);return this}}(),translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)}}); -Object.assign(Ca.prototype,{set:function(a,b){this.center.copy(a);this.radius=b;return this},setFromPoints:function(){var a=new Va;return function(b,c){var d=this.center;void 0!==c?d.copy(c):a.setFromPoints(b).getCenter(d);for(var e=c=0,f=b.length;e=this.radius}, -containsPoint:function(a){return a.distanceToSquared(this.center)<=this.radius*this.radius},distanceToPoint:function(a){return a.distanceTo(this.center)-this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.center.distanceToSquared(this.center)<=b*b},intersectsBox:function(a){return a.intersectsSphere(this)},intersectsPlane:function(a){return Math.abs(a.distanceToPoint(this.center))<=this.radius},clampPoint:function(a,b){var c=this.center.distanceToSquared(a);b=b||new p;b.copy(a); -c>this.radius*this.radius&&(b.sub(this.center).normalize(),b.multiplyScalar(this.radius).add(this.center));return b},getBoundingBox:function(a){a=a||new Va;a.set(this.center,this.center);a.expandByScalar(this.radius);return a},applyMatrix4:function(a){this.center.applyMatrix4(a);this.radius*=a.getMaxScaleOnAxis();return this},translate:function(a){this.center.add(a);return this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius}});Object.assign(pa.prototype,{set:function(a, -b){this.normal.copy(a);this.constant=b;return this},setComponents:function(a,b,c,d){this.normal.set(a,b,c);this.constant=d;return this},setFromNormalAndCoplanarPoint:function(a,b){this.normal.copy(a);this.constant=-b.dot(this.normal);return this},setFromCoplanarPoints:function(){var a=new p,b=new p;return function(c,d,e){d=a.subVectors(e,d).cross(b.subVectors(c,d)).normalize();this.setFromNormalAndCoplanarPoint(d,c);return this}}(),clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.normal.copy(a.normal); -this.constant=a.constant;return this},normalize:function(){var a=1/this.normal.length();this.normal.multiplyScalar(a);this.constant*=a;return this},negate:function(){this.constant*=-1;this.normal.negate();return this},distanceToPoint:function(a){return this.normal.dot(a)+this.constant},distanceToSphere:function(a){return this.distanceToPoint(a.center)-a.radius},projectPoint:function(a,b){return(b||new p).copy(this.normal).multiplyScalar(-this.distanceToPoint(a)).add(a)},intersectLine:function(){var a= -new p;return function(b,c){c=c||new p;var d=b.delta(a),e=this.normal.dot(d);if(0===e){if(0===this.distanceToPoint(b.start))return c.copy(b.start)}else if(e=-(b.start.dot(this.normal)+this.constant)/e,!(0>e||1b&&0a&&0c;c++)b[c].copy(a.planes[c]);return this},setFromMatrix:function(a){var b=this.planes,c=a.elements;a=c[0];var d=c[1],e=c[2],f=c[3],g=c[4],h=c[5],k=c[6],m=c[7],l=c[8],n=c[9],p=c[10],q=c[11],r=c[12],t=c[13],x=c[14];c=c[15];b[0].setComponents(f-a,m-g,q-l,c-r).normalize();b[1].setComponents(f+ -a,m+g,q+l,c+r).normalize();b[2].setComponents(f+d,m+h,q+n,c+t).normalize();b[3].setComponents(f-d,m-h,q-n,c-t).normalize();b[4].setComponents(f-e,m-k,q-p,c-x).normalize();b[5].setComponents(f+e,m+k,q+p,c+x).normalize();return this},intersectsObject:function(){var a=new Ca;return function(b){var c=b.geometry;null===c.boundingSphere&&c.computeBoundingSphere();a.copy(c.boundingSphere).applyMatrix4(b.matrixWorld);return this.intersectsSphere(a)}}(),intersectsSprite:function(){var a=new Ca;return function(b){a.center.set(0, -0,0);a.radius=.7071067811865476;a.applyMatrix4(b.matrixWorld);return this.intersectsSphere(a)}}(),intersectsSphere:function(a){var b=this.planes,c=a.center;a=-a.radius;for(var d=0;6>d;d++)if(b[d].distanceToPoint(c)e;e++){var f=d[e];a.x=0g&&0>f)return!1}return!0}}(),containsPoint:function(a){for(var b=this.planes,c=0;6>c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0}});fb.RotationOrders="XYZ YZX ZXY XZY YXZ ZYX".split(" ");fb.DefaultOrder="XYZ";Object.defineProperties(fb.prototype,{x:{get:function(){return this._x},set:function(a){this._x=a;this.onChangeCallback()}},y:{get:function(){return this._y},set:function(a){this._y=a;this.onChangeCallback()}}, -z:{get:function(){return this._z},set:function(a){this._z=a;this.onChangeCallback()}},order:{get:function(){return this._order},set:function(a){this._order=a;this.onChangeCallback()}}});Object.assign(fb.prototype,{isEuler:!0,set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._order=d||this._order;this.onChangeCallback();return this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._order)},copy:function(a){this._x=a._x;this._y=a._y;this._z=a._z;this._order=a._order; -this.onChangeCallback();return this},setFromRotationMatrix:function(a,b,c){var d=S.clamp,e=a.elements;a=e[0];var f=e[4],g=e[8],h=e[1],k=e[5],m=e[9],l=e[2],n=e[6];e=e[10];b=b||this._order;"XYZ"===b?(this._y=Math.asin(d(g,-1,1)),.99999>Math.abs(g)?(this._x=Math.atan2(-m,e),this._z=Math.atan2(-f,a)):(this._x=Math.atan2(n,k),this._z=0)):"YXZ"===b?(this._x=Math.asin(-d(m,-1,1)),.99999>Math.abs(m)?(this._y=Math.atan2(g,e),this._z=Math.atan2(h,k)):(this._y=Math.atan2(-l,a),this._z=0)):"ZXY"===b?(this._x= -Math.asin(d(n,-1,1)),.99999>Math.abs(n)?(this._y=Math.atan2(-l,e),this._z=Math.atan2(-f,k)):(this._y=0,this._z=Math.atan2(h,a))):"ZYX"===b?(this._y=Math.asin(-d(l,-1,1)),.99999>Math.abs(l)?(this._x=Math.atan2(n,e),this._z=Math.atan2(h,a)):(this._x=0,this._z=Math.atan2(-f,k))):"YZX"===b?(this._z=Math.asin(d(h,-1,1)),.99999>Math.abs(h)?(this._x=Math.atan2(-m,k),this._y=Math.atan2(-l,a)):(this._x=0,this._y=Math.atan2(g,e))):"XZY"===b?(this._z=Math.asin(-d(f,-1,1)),.99999>Math.abs(f)?(this._x=Math.atan2(n, -k),this._y=Math.atan2(g,a)):(this._x=Math.atan2(-m,e),this._y=0)):console.warn("THREE.Euler: .setFromRotationMatrix() given unsupported order: "+b);this._order=b;if(!1!==c)this.onChangeCallback();return this},setFromQuaternion:function(){var a=new P;return function(b,c,d){a.makeRotationFromQuaternion(b);return this.setFromRotationMatrix(a,c,d)}}(),setFromVector3:function(a,b){return this.set(a.x,a.y,a.z,b||this._order)},reorder:function(){var a=new ca;return function(b){a.setFromEuler(this);return this.setFromQuaternion(a, -b)}}(),equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._order===this._order},fromArray:function(a){this._x=a[0];this._y=a[1];this._z=a[2];void 0!==a[3]&&(this._order=a[3]);this.onChangeCallback();return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this._x;a[b+1]=this._y;a[b+2]=this._z;a[b+3]=this._order;return a},toVector3:function(a){return a?a.set(this._x,this._y,this._z):new p(this._x,this._y,this._z)},onChange:function(a){this.onChangeCallback= -a;return this},onChangeCallback:function(){}});Object.assign(Sd.prototype,{set:function(a){this.mask=1<g;g++)if(d[g]===d[(g+1)%3]){a.push(f);break}for(f=a.length-1;0<=f;f--)for(d=a[f],this.faces.splice(d,1),c=0,e=this.faceVertexUvs.length;ca?b.copy(this.origin):b.copy(this.direction).multiplyScalar(a).add(this.origin)},distanceToPoint:function(a){return Math.sqrt(this.distanceSqToPoint(a))},distanceSqToPoint:function(){var a=new p;return function(b){var c= -a.subVectors(b,this.origin).dot(this.direction);if(0>c)return this.origin.distanceToSquared(b);a.copy(this.direction).multiplyScalar(c).add(this.origin);return a.distanceToSquared(b)}}(),distanceSqToSegment:function(){var a=new p,b=new p,c=new p;return function(d,e,f,g){a.copy(d).add(e).multiplyScalar(.5);b.copy(e).sub(d).normalize();c.copy(this.origin).sub(a);var h=.5*d.distanceTo(e),k=-this.direction.dot(b),m=c.dot(this.direction),l=-c.dot(b),n=c.lengthSq(),p=Math.abs(1-k*k);if(0=-q?e<=q?(h=1/p,d*=h,e*=h,k=d*(d+k*e+2*m)+e*(k*d+e+2*l)+n):(e=h,d=Math.max(0,-(k*e+m)),k=-d*d+e*(e+2*l)+n):(e=-h,d=Math.max(0,-(k*e+m)),k=-d*d+e*(e+2*l)+n):e<=-q?(d=Math.max(0,-(-k*h+m)),e=0b)return null;b=Math.sqrt(b-e);e=d-b;d+=b;return 0>e&&0>d?null:0>e?this.at(d,c):this.at(e,c)}}(),intersectsSphere:function(a){return this.distanceToPoint(a.center)<=a.radius},distanceToPlane:function(a){var b=a.normal.dot(this.direction);if(0===b)return 0===a.distanceToPoint(this.origin)? -0:null;a=-(this.origin.dot(a.normal)+a.constant)/b;return 0<=a?a:null},intersectPlane:function(a,b){a=this.distanceToPlane(a);return null===a?null:this.at(a,b)},intersectsPlane:function(a){var b=a.distanceToPoint(this.origin);return 0===b||0>a.normal.dot(this.direction)*b?!0:!1},intersectBox:function(a,b){var c=1/this.direction.x;var d=1/this.direction.y;var e=1/this.direction.z,f=this.origin;if(0<=c){var g=(a.min.x-f.x)*c;c*=a.max.x-f.x}else g=(a.max.x-f.x)*c,c*=a.min.x-f.x;if(0<=d){var h=(a.min.y- -f.y)*d;d*=a.max.y-f.y}else h=(a.max.y-f.y)*d,d*=a.min.y-f.y;if(g>d||h>c)return null;if(h>g||g!==g)g=h;if(da||h>c)return null;if(h>g||g!==g)g=h;if(ac?null:this.at(0<=g?g:c,b)},intersectsBox:function(){var a=new p;return function(b){return null!==this.intersectBox(b,a)}}(),intersectTriangle:function(){var a=new p,b=new p,c=new p,d=new p;return function(e,f,g,h,k){b.subVectors(f, -e);c.subVectors(g,e);d.crossVectors(b,c);f=this.direction.dot(d);if(0f)h=-1,f=-f;else return null;a.subVectors(this.origin,e);e=h*this.direction.dot(c.crossVectors(a,c));if(0>e)return null;g=h*this.direction.dot(b.cross(a));if(0>g||e+g>f)return null;e=-h*a.dot(d);return 0>e?null:this.at(e/f,k)}}(),applyMatrix4:function(a){this.origin.applyMatrix4(a);this.direction.transformDirection(a);return this},equals:function(a){return a.origin.equals(this.origin)&&a.direction.equals(this.direction)}}); -Object.assign(Kb.prototype,{set:function(a,b){this.start.copy(a);this.end.copy(b);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.start.copy(a.start);this.end.copy(a.end);return this},getCenter:function(a){return(a||new p).addVectors(this.start,this.end).multiplyScalar(.5)},delta:function(a){return(a||new p).subVectors(this.end,this.start)},distanceSq:function(){return this.start.distanceToSquared(this.end)},distance:function(){return this.start.distanceTo(this.end)}, -at:function(a,b){b=b||new p;return this.delta(b).multiplyScalar(a).add(this.start)},closestPointToPointParameter:function(){var a=new p,b=new p;return function(c,d){a.subVectors(c,this.start);b.subVectors(this.end,this.start);c=b.dot(b);c=b.dot(a)/c;d&&(c=S.clamp(c,0,1));return c}}(),closestPointToPoint:function(a,b,c){a=this.closestPointToPointParameter(a,b);c=c||new p;return this.delta(c).multiplyScalar(a).add(this.start)},applyMatrix4:function(a){this.start.applyMatrix4(a);this.end.applyMatrix4(a); -return this},equals:function(a){return a.start.equals(this.start)&&a.end.equals(this.end)}});Object.assign(Xa,{normal:function(){var a=new p;return function(b,c,d,e){e=e||new p;e.subVectors(d,c);a.subVectors(b,c);e.cross(a);b=e.lengthSq();return 0=b.x+b.y}}()});Object.assign(Xa.prototype,{set:function(a,b,c){this.a.copy(a);this.b.copy(b);this.c.copy(c);return this},setFromPointsAndIndices:function(a,b,c,d){this.a.copy(a[b]);this.b.copy(a[c]);this.c.copy(a[d]);return this},clone:function(){return(new this.constructor).copy(this)}, -copy:function(a){this.a.copy(a.a);this.b.copy(a.b);this.c.copy(a.c);return this},area:function(){var a=new p,b=new p;return function(){a.subVectors(this.c,this.b);b.subVectors(this.a,this.b);return.5*a.cross(b).length()}}(),midpoint:function(a){return(a||new p).addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},normal:function(a){return Xa.normal(this.a,this.b,this.c,a)},plane:function(a){return(a||new pa).setFromCoplanarPoints(this.a,this.b,this.c)},barycoordFromPoint:function(a,b){return Xa.barycoordFromPoint(a, -this.a,this.b,this.c,b)},containsPoint:function(a){return Xa.containsPoint(a,this.a,this.b,this.c)},intersectsBox:function(a){return a.intersectsTriangle(this)},closestPointToPoint:function(){var a=new pa,b=[new Kb,new Kb,new Kb],c=new p,d=new p;return function(e,f){f=f||new p;var g=Infinity;a.setFromCoplanarPoints(this.a,this.b,this.c);a.projectPoint(e,c);if(!0===this.containsPoint(c))f.copy(c);else for(b[0].set(this.a,this.b),b[1].set(this.b,this.c),b[2].set(this.c,this.a),e=0;ec.far?null:{distance:b,point:B.clone(),object:a}}function c(c,d,e,f,m,l,n,p){g.fromBufferAttribute(f,l);h.fromBufferAttribute(f,n);k.fromBufferAttribute(f,p);if(c=b(c,c.material,d,e,g,h,k,x))m&&(u.fromBufferAttribute(m,l),q.fromBufferAttribute(m,n),r.fromBufferAttribute(m,p),c.uv=a(x,g,h,k,u,q,r)),c.face=new Wa(l,n,p,Xa.normal(g,h,k)),c.faceIndex=l;return c}var d=new P,e=new pb,f=new Ca,g=new p,h=new p,k=new p,m=new p,l=new p,n=new p,u=new C,q=new C,r=new C,t=new p,x=new p,B=new p;return function(p, -v){var t=this.geometry,w=this.material,B=this.matrixWorld;if(void 0!==w&&(null===t.boundingSphere&&t.computeBoundingSphere(),f.copy(t.boundingSphere),f.applyMatrix4(B),!1!==p.ray.intersectsSphere(f)&&(d.getInverse(B),e.copy(p.ray).applyMatrix4(d),null===t.boundingBox||!1!==e.intersectsBox(t.boundingBox)))){var A;if(t.isBufferGeometry){w=t.index;var y=t.attributes.position;B=t.attributes.uv;var D;if(null!==w){var C=0;for(D=w.count;Cf|| -(f=d.ray.origin.distanceTo(a),fd.far||e.push({distance:f,point:a.clone(),face:null,object:this}))}}(),clone:function(){return(new this.constructor(this.material)).copy(this)},copy:function(a){y.prototype.copy.call(this,a);void 0!==a.center&&this.center.copy(a.center);return this}});Ac.prototype=Object.assign(Object.create(y.prototype),{constructor:Ac,copy:function(a){y.prototype.copy.call(this,a,!1);a=a.levels;for(var b=0,c=a.length;b=d[e].distance)d[e-1].object.visible=!1,d[e].object.visible=!0;else break;for(;ef||(l.applyMatrix4(this.matrixWorld),t=d.ray.origin.distanceTo(l),td.far||e.push({distance:t,point:h.clone().applyMatrix4(this.matrixWorld),index:g,face:null,faceIndex:null,object:this}))}}else for(g=0,r=q.length/3-1;gf||(l.applyMatrix4(this.matrixWorld),t=d.ray.origin.distanceTo(l),td.far||e.push({distance:t,point:h.clone().applyMatrix4(this.matrixWorld),index:g,face:null,faceIndex:null,object:this}))}else if(g.isGeometry)for(k=g.vertices,m=k.length,g=0;gf||(l.applyMatrix4(this.matrixWorld),t=d.ray.origin.distanceTo(l),td.far||e.push({distance:t,point:h.clone().applyMatrix4(this.matrixWorld),index:g, -face:null,faceIndex:null,object:this}))}}}(),clone:function(){return(new this.constructor(this.geometry,this.material)).copy(this)}});U.prototype=Object.assign(Object.create(qa.prototype),{constructor:U,isLineSegments:!0,computeLineDistances:function(){var a=new p,b=new p;return function(){var c=this.geometry;if(c.isBufferGeometry)if(null===c.index){for(var d=c.attributes.position,e=[],f=0,g=d.count;fd.far|| -e.push({distance:h,distanceToRay:Math.sqrt(f),point:a.clone(),index:c,face:null,object:g})}}var g=this,h=this.geometry,k=this.matrixWorld,m=d.params.Points.threshold;null===h.boundingSphere&&h.computeBoundingSphere();c.copy(h.boundingSphere);c.applyMatrix4(k);c.radius+=m;if(!1!==d.ray.intersectsSphere(c)){a.getInverse(k);b.copy(d.ray).applyMatrix4(a);m/=(this.scale.x+this.scale.y+this.scale.z)/3;var l=m*m;m=new p;if(h.isBufferGeometry){var n=h.index;h=h.attributes.position.array;if(null!==n){var u= -n.array;n=0;for(var q=u.length;n= -a.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}});Pb.prototype=Object.create(aa.prototype);Pb.prototype.constructor=Pb;Pb.prototype.isCompressedTexture=!0;Cc.prototype=Object.create(aa.prototype);Cc.prototype.constructor=Cc;Cc.prototype.isDepthTexture=!0;Qb.prototype=Object.create(z.prototype);Qb.prototype.constructor=Qb;Dc.prototype=Object.create(L.prototype);Dc.prototype.constructor=Dc;Rb.prototype=Object.create(z.prototype);Rb.prototype.constructor=Rb;Ec.prototype=Object.create(L.prototype);Ec.prototype.constructor= -Ec;va.prototype=Object.create(z.prototype);va.prototype.constructor=va;Fc.prototype=Object.create(L.prototype);Fc.prototype.constructor=Fc;Sb.prototype=Object.create(va.prototype);Sb.prototype.constructor=Sb;Gc.prototype=Object.create(L.prototype);Gc.prototype.constructor=Gc;rb.prototype=Object.create(va.prototype);rb.prototype.constructor=rb;Hc.prototype=Object.create(L.prototype);Hc.prototype.constructor=Hc;Tb.prototype=Object.create(va.prototype);Tb.prototype.constructor=Tb;Ic.prototype=Object.create(L.prototype); -Ic.prototype.constructor=Ic;Ub.prototype=Object.create(va.prototype);Ub.prototype.constructor=Ub;Jc.prototype=Object.create(L.prototype);Jc.prototype.constructor=Jc;Vb.prototype=Object.create(z.prototype);Vb.prototype.constructor=Vb;Kc.prototype=Object.create(L.prototype);Kc.prototype.constructor=Kc;Wb.prototype=Object.create(z.prototype);Wb.prototype.constructor=Wb;Lc.prototype=Object.create(L.prototype);Lc.prototype.constructor=Lc;Xb.prototype=Object.create(z.prototype);Xb.prototype.constructor= -Xb;var Lg={triangulate:function(a,b,c){c=c||2;var d=b&&b.length,e=d?b[0]*c:a.length,f=Xe(a,0,e,c,!0),g=[];if(!f)return g;var h;if(d){var k=c;d=[];var m;var l=0;for(m=b.length;l80*c){var q=h=a[0];var r=d=a[1];for(k=c;kh&&(h=l),b>d&&(d= -b);h=Math.max(h-q,d-r);h=0!==h?1/h:0}Oc(f,g,c,q,r,h);return g}},Ya={area:function(a){for(var b=a.length,c=0,d=b-1,e=0;eYa.area(a)},triangulateShape:function(a,b){var c=[],d=[],e=[];af(a);bf(c,a);var f=a.length;b.forEach(af);for(a=0;aNumber.EPSILON){var k=Math.sqrt(h),m=Math.sqrt(f*f+g*g);h=b.x-e/k;b=b.y+d/k;g=((c.x-g/m-h)*g-(c.y+f/m-b)*f)/(d*g-e*f);f=h+d*g-a.x;d=b+e* -g-a.y;e=f*f+d*d;if(2>=e)return new C(f,d);e=Math.sqrt(e/2)}else a=!1,d>Number.EPSILON?f>Number.EPSILON&&(a=!0):d<-Number.EPSILON?f<-Number.EPSILON&&(a=!0):Math.sign(e)===Math.sign(g)&&(a=!0),a?(f=-e,e=Math.sqrt(h)):(f=d,d=e,e=Math.sqrt(h/2));return new C(f/e,d/e)}function e(a,b){for(J=a.length;0<=--J;){var c=J;var d=J-1;0>d&&(d=a.length-1);var e,f=A+2*x;for(e=0;eMath.abs(g-k)?[new C(a,1-c),new C(h,1-d),new C(m,1-e),new C(n,1-b)]:[new C(g,1-c),new C(k,1-d),new C(l,1-e), -new C(p,1-b)]}};Qc.prototype=Object.create(L.prototype);Qc.prototype.constructor=Qc;Yb.prototype=Object.create(Ia.prototype);Yb.prototype.constructor=Yb;Rc.prototype=Object.create(L.prototype);Rc.prototype.constructor=Rc;tb.prototype=Object.create(z.prototype);tb.prototype.constructor=tb;Sc.prototype=Object.create(L.prototype);Sc.prototype.constructor=Sc;Zb.prototype=Object.create(z.prototype);Zb.prototype.constructor=Zb;Tc.prototype=Object.create(L.prototype);Tc.prototype.constructor=Tc;$b.prototype= -Object.create(z.prototype);$b.prototype.constructor=$b;ub.prototype=Object.create(L.prototype);ub.prototype.constructor=ub;ub.prototype.toJSON=function(){var a=L.prototype.toJSON.call(this);return cf(this.parameters.shapes,a)};vb.prototype=Object.create(z.prototype);vb.prototype.constructor=vb;vb.prototype.toJSON=function(){var a=z.prototype.toJSON.call(this);return cf(this.parameters.shapes,a)};ac.prototype=Object.create(z.prototype);ac.prototype.constructor=ac;wb.prototype=Object.create(L.prototype); -wb.prototype.constructor=wb;Za.prototype=Object.create(z.prototype);Za.prototype.constructor=Za;Uc.prototype=Object.create(wb.prototype);Uc.prototype.constructor=Uc;Vc.prototype=Object.create(Za.prototype);Vc.prototype.constructor=Vc;Wc.prototype=Object.create(L.prototype);Wc.prototype.constructor=Wc;bc.prototype=Object.create(z.prototype);bc.prototype.constructor=bc;var oa=Object.freeze({WireframeGeometry:Qb,ParametricGeometry:Dc,ParametricBufferGeometry:Rb,TetrahedronGeometry:Fc,TetrahedronBufferGeometry:Sb, -OctahedronGeometry:Gc,OctahedronBufferGeometry:rb,IcosahedronGeometry:Hc,IcosahedronBufferGeometry:Tb,DodecahedronGeometry:Ic,DodecahedronBufferGeometry:Ub,PolyhedronGeometry:Ec,PolyhedronBufferGeometry:va,TubeGeometry:Jc,TubeBufferGeometry:Vb,TorusKnotGeometry:Kc,TorusKnotBufferGeometry:Wb,TorusGeometry:Lc,TorusBufferGeometry:Xb,TextGeometry:Qc,TextBufferGeometry:Yb,SphereGeometry:Rc,SphereBufferGeometry:tb,RingGeometry:Sc,RingBufferGeometry:Zb,PlaneGeometry:xc,PlaneBufferGeometry:ob,LatheGeometry:Tc, -LatheBufferGeometry:$b,ShapeGeometry:ub,ShapeBufferGeometry:vb,ExtrudeGeometry:hb,ExtrudeBufferGeometry:Ia,EdgesGeometry:ac,ConeGeometry:Uc,ConeBufferGeometry:Vc,CylinderGeometry:wb,CylinderBufferGeometry:Za,CircleGeometry:Wc,CircleBufferGeometry:bc,BoxGeometry:Jb,BoxBufferGeometry:nb});cc.prototype=Object.create(O.prototype);cc.prototype.constructor=cc;cc.prototype.isShadowMaterial=!0;dc.prototype=Object.create(Da.prototype);dc.prototype.constructor=dc;dc.prototype.isRawShaderMaterial=!0;Sa.prototype= -Object.create(O.prototype);Sa.prototype.constructor=Sa;Sa.prototype.isMeshStandardMaterial=!0;Sa.prototype.copy=function(a){O.prototype.copy.call(this,a);this.defines={STANDARD:""};this.color.copy(a.color);this.roughness=a.roughness;this.metalness=a.metalness;this.map=a.map;this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive);this.emissiveMap=a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity; -this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.roughnessMap=a.roughnessMap;this.metalnessMap=a.metalnessMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.envMapIntensity=a.envMapIntensity;this.refractionRatio=a.refractionRatio;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap= -a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};xb.prototype=Object.create(Sa.prototype);xb.prototype.constructor=xb;xb.prototype.isMeshPhysicalMaterial=!0;xb.prototype.copy=function(a){Sa.prototype.copy.call(this,a);this.defines={PHYSICAL:""};this.reflectivity=a.reflectivity;this.clearCoat=a.clearCoat;this.clearCoatRoughness=a.clearCoatRoughness;return this};Ja.prototype=Object.create(O.prototype); -Ja.prototype.constructor=Ja;Ja.prototype.isMeshPhongMaterial=!0;Ja.prototype.copy=function(a){O.prototype.copy.call(this,a);this.color.copy(a.color);this.specular.copy(a.specular);this.shininess=a.shininess;this.map=a.map;this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive);this.emissiveMap=a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity;this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale; -this.normalMap=a.normalMap;this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.specularMap=a.specularMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.combine=a.combine;this.reflectivity=a.reflectivity;this.refractionRatio=a.refractionRatio;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin; -this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};yb.prototype=Object.create(Ja.prototype);yb.prototype.constructor=yb;yb.prototype.isMeshToonMaterial=!0;yb.prototype.copy=function(a){Ja.prototype.copy.call(this,a);this.gradientMap=a.gradientMap;return this};zb.prototype=Object.create(O.prototype);zb.prototype.constructor=zb;zb.prototype.isMeshNormalMaterial=!0;zb.prototype.copy=function(a){O.prototype.copy.call(this,a);this.bumpMap=a.bumpMap; -this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};Ab.prototype=Object.create(O.prototype);Ab.prototype.constructor=Ab;Ab.prototype.isMeshLambertMaterial=!0;Ab.prototype.copy= -function(a){O.prototype.copy.call(this,a);this.color.copy(a.color);this.map=a.map;this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive);this.emissiveMap=a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity;this.specularMap=a.specularMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.combine=a.combine;this.reflectivity=a.reflectivity;this.refractionRatio=a.refractionRatio;this.wireframe=a.wireframe; -this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};Bb.prototype=Object.create(Y.prototype);Bb.prototype.constructor=Bb;Bb.prototype.isLineDashedMaterial=!0;Bb.prototype.copy=function(a){Y.prototype.copy.call(this,a);this.scale=a.scale;this.dashSize=a.dashSize;this.gapSize=a.gapSize;return this};var Mg=Object.freeze({ShadowMaterial:cc, -SpriteMaterial:gb,RawShaderMaterial:dc,ShaderMaterial:Da,PointsMaterial:Ha,MeshPhysicalMaterial:xb,MeshStandardMaterial:Sa,MeshPhongMaterial:Ja,MeshToonMaterial:yb,MeshNormalMaterial:zb,MeshLambertMaterial:Ab,MeshDepthMaterial:db,MeshDistanceMaterial:eb,MeshBasicMaterial:za,LineDashedMaterial:Bb,LineBasicMaterial:Y,Material:O}),Fb={enabled:!1,files:{},add:function(a,b){!1!==this.enabled&&(this.files[a]=b)},get:function(a){if(!1!==this.enabled)return this.files[a]},remove:function(a){delete this.files[a]}, -clear:function(){this.files={}}},ra=new ae,ab={};Object.assign(Ka.prototype,{load:function(a,b,c,d){void 0===a&&(a="");void 0!==this.path&&(a=this.path+a);a=this.manager.resolveURL(a);var e=this,f=Fb.get(a);if(void 0!==f)return e.manager.itemStart(a),setTimeout(function(){b&&b(f);e.manager.itemEnd(a)},0),f;if(void 0!==ab[a])ab[a].push({onLoad:b,onProgress:c,onError:d});else{var g=a.match(/^data:(.*?)(;base64)?,(.*)$/);if(g){c=g[1];var h=!!g[2];g=g[3];g=window.decodeURIComponent(g);h&&(g=window.atob(g)); -try{var k=(this.responseType||"").toLowerCase();switch(k){case "arraybuffer":case "blob":var m=new Uint8Array(g.length);for(h=0;hg)e=a+1;else if(0b&&(b=0);1Number.EPSILON&&(g.normalize(), -c=Math.acos(S.clamp(d[k-1].dot(d[k]),-1,1)),e[k].applyMatrix4(h.makeRotationAxis(g,c))),f[k].crossVectors(d[k],e[k]);if(!0===b)for(c=Math.acos(S.clamp(e[0].dot(e[a]),-1,1)),c/=a,0d;)d+=c;for(;d>c;)d-=c;de&&(e=1);1E-4>d&&(d=e);1E-4>k&&(k=e);ye.initNonuniformCatmullRom(f.x, -g.x,h.x,c.x,d,e,k);ze.initNonuniformCatmullRom(f.y,g.y,h.y,c.y,d,e,k);Ae.initNonuniformCatmullRom(f.z,g.z,h.z,c.z,d,e,k)}else"catmullrom"===this.curveType&&(ye.initCatmullRom(f.x,g.x,h.x,c.x,this.tension),ze.initCatmullRom(f.y,g.y,h.y,c.y,this.tension),Ae.initCatmullRom(f.z,g.z,h.z,c.z,this.tension));b.set(ye.calc(a),ze.calc(a),Ae.calc(a));return b};da.prototype.copy=function(a){K.prototype.copy.call(this,a);this.points=[];for(var b=0,c=a.points.length;bc.length- -2?c.length-1:a+1];c=c[a>c.length-3?c.length-1:a+2];b.set(ef(d,e.x,f.x,g.x,c.x),ef(d,e.y,f.y,g.y,c.y));return b};Oa.prototype.copy=function(a){K.prototype.copy.call(this,a);this.points=[];for(var b=0,c=a.points.length;b=b)return b=c[a]-b,a=this.curves[a],c=a.getLength(),a.getPointAt(0===c?0:1-b/c);a++}return null},getLength:function(){var a=this.getCurveLengths();return a[a.length-1]},updateArcLengths:function(){this.needsUpdate=!0;this.cacheLengths=null;this.getCurveLengths()},getCurveLengths:function(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths; -for(var a=[],b=0,c=0,d=this.curves.length;c=e)break a;else{f=b[1];a=e)break b}d=c;c=0}}for(;c>>1,ab;)--f;++f;if(0!==e||f!==d)e>=f&&(f=Math.max(f,1),e=f-1),a=this.getValueSize(),this.times=W.arraySlice(c,e,f),this.values=W.arraySlice(this.values,e*a,f*a);return this},validate:function(){var a=!0,b=this.getValueSize();0!==b-Math.floor(b)&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),a=!1);var c=this.times;b=this.values; -var d=c.length;0===d&&(console.error("THREE.KeyframeTrack: Track is empty.",this),a=!1);for(var e=null,f=0;f!==d;f++){var g=c[f];if("number"===typeof g&&isNaN(g)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,f,g);a=!1;break}if(null!==e&&e>g){console.error("THREE.KeyframeTrack: Out of order keys.",this,f,g,e);a=!1;break}e=g}if(void 0!==b&&W.isTypedArray(b))for(f=0,c=b.length;f!==c;++f)if(d=b[f],isNaN(d)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this, -f,d);a=!1;break}return a},optimize:function(){for(var a=this.times,b=this.values,c=this.getValueSize(),d=2302===this.getInterpolation(),e=1,f=a.length-1,g=1;gm.opacity&&(m.transparent=!0);d.setTextures(k);return d.parse(m)}}()});var Be={decodeText:function(a){if("undefined"!==typeof TextDecoder)return(new TextDecoder).decode(a);for(var b="",c=0,d=a.length;cf;f++){var y=h[q++]; -var z=A[2*y];y=A[2*y+1];z=new C(z,y);2!==f&&c.faceVertexUvs[e][t].push(z);0!==f&&c.faceVertexUvs[e][t+1].push(z)}}x&&(x=3*h[q++],r.normal.set(m[x++],m[x++],m[x]),w.normal.copy(r.normal));if(B)for(e=0;4>e;e++)x=3*h[q++],B=new p(m[x++],m[x++],m[x]),2!==e&&r.vertexNormals.push(B),0!==e&&w.vertexNormals.push(B);n&&(n=h[q++],n=l[n],r.color.setHex(n),w.color.setHex(n));if(k)for(e=0;4>e;e++)n=h[q++],n=l[n],2!==e&&r.vertexColors.push(new H(n)),0!==e&&w.vertexColors.push(new H(n));c.faces.push(r);c.faces.push(w)}else{r= -new Wa;r.a=h[q++];r.b=h[q++];r.c=h[q++];t&&(t=h[q++],r.materialIndex=t);t=c.faces.length;if(e)for(e=0;ef;f++)y=h[q++],z=A[2*y],y=A[2*y+1],z=new C(z,y),c.faceVertexUvs[e][t].push(z);x&&(x=3*h[q++],r.normal.set(m[x++],m[x++],m[x]));if(B)for(e=0;3>e;e++)x=3*h[q++],B=new p(m[x++],m[x++],m[x]),r.vertexNormals.push(B);n&&(n=h[q++],r.color.setHex(l[n]));if(k)for(e=0;3>e;e++)n=h[q++],r.vertexColors.push(new H(l[n]));c.faces.push(r)}}d=a;q=void 0!==d.influencesPerVertex? -d.influencesPerVertex:2;if(d.skinWeights)for(g=0,h=d.skinWeights.length;gNumber.EPSILON){if(0>l&&(g=b[f],k=-k,h=b[e],l=-l),!(a.yh.y))if(a.y===g.y){if(a.x===g.x)return!0}else{e=l*(a.x-g.x)-k*(a.y-g.y);if(0===e)return!0;0>e||(d=!d)}}else if(a.y===g.y&&(h.x<=a.x&&a.x<=g.x||g.x<=a.x&&a.x<=h.x))return!0}return d}var e=Ya.isClockWise,f=this.subPaths;if(0===f.length)return[];if(!0===b)return c(f);b=[];if(1===f.length){var g=f[0];var h=new ib;h.curves=g.curves;b.push(h); -return b}var k=!e(f[0].getPoints());k=a?!k:k;h=[];var l=[],p=[],n=0;l[n]=void 0;p[n]=[];for(var u=0,q=f.length;ud&&this._mixBufferRegion(c,a,3*b,1-d,b);d=b;for(var f=b+b;d!==f;++d)if(c[d]!==c[d+b]){e.setValue(c,a);break}},saveOriginalState:function(){var a=this.buffer,b=this.valueSize,c=3*b;this.binding.getValue(a,c); -for(var d=b;d!==c;++d)a[d]=a[c+d%b];this.cumulativeWeight=0},restoreOriginalState:function(){this.binding.setValue(this.buffer,3*this.valueSize)},_select:function(a,b,c,d,e){if(.5<=d)for(d=0;d!==e;++d)a[b+d]=a[c+d]},_slerp:function(a,b,c,d){ca.slerpFlat(a,b,a,b,a,c,d)},_lerp:function(a,b,c,d,e){for(var f=1-d,g=0;g!==e;++g){var h=b+g;a[h]=a[h]*f+a[c+g]*d}}});Object.assign(jf.prototype,{getValue:function(a,b){this.bind();var c=this._bindings[this._targetGroup.nCachedObjects_];void 0!==c&&c.getValue(a, -b)},setValue:function(a,b){for(var c=this._bindings,d=this._targetGroup.nCachedObjects_,e=c.length;d!==e;++d)c[d].setValue(a,b)},bind:function(){for(var a=this._bindings,b=this._targetGroup.nCachedObjects_,c=a.length;b!==c;++b)a[b].bind()},unbind:function(){for(var a=this._bindings,b=this._targetGroup.nCachedObjects_,c=a.length;b!==c;++b)a[b].unbind()}});Object.assign(fa,{Composite:jf,create:function(a,b,c){return a&&a.isAnimationObjectGroup?new fa.Composite(a,b,c):new fa(a,b,c)},sanitizeNodeName:function(){var a= -/[\[\]\.:\/]/g;return function(b){return b.replace(/\s/g,"_").replace(a,"")}}(),parseTrackName:function(){var a="[^"+"\\[\\]\\.:\\/".replace("\\.","")+"]",b=/((?:WC+[\/:])*)/.source.replace("WC","[^\\[\\]\\.:\\/]");a=/(WCOD+)?/.source.replace("WCOD",a);var c=/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC","[^\\[\\]\\.:\\/]"),d=/\.(WC+)(?:\[(.+)\])?/.source.replace("WC","[^\\[\\]\\.:\\/]"),e=new RegExp("^"+b+a+c+d+"$"),f=["material","materials","bones"];return function(a){var b=e.exec(a);if(!b)throw Error("PropertyBinding: Cannot parse trackName: "+ -a);b={nodeName:b[2],objectName:b[3],objectIndex:b[4],propertyName:b[5],propertyIndex:b[6]};var c=b.nodeName&&b.nodeName.lastIndexOf(".");if(void 0!==c&&-1!==c){var d=b.nodeName.substring(c+1);-1!==f.indexOf(d)&&(b.nodeName=b.nodeName.substring(0,c),b.objectName=d)}if(null===b.propertyName||0===b.propertyName.length)throw Error("PropertyBinding: can not parse propertyName from trackName: "+a);return b}}(),findNode:function(a,b){if(!b||""===b||"root"===b||"."===b||-1===b||b===a.name||b===a.uuid)return a; -if(a.skeleton){var c=a.skeleton.getBoneByName(b);if(void 0!==c)return c}if(a.children){var d=function(a){for(var c=0;c=b){var p=b++,n=a[p];c[n.uuid]=l;a[l]=n;c[k]=p;a[p]=h;h=0;for(k=e;h!==k;++h){n=d[h];var u=n[l];n[l]=n[p];n[p]=u}}}this.nCachedObjects_=b},uncache:function(){for(var a=this._objects,b=a.length,c=this.nCachedObjects_,d=this._indicesByUUID,e=this._bindings,f=e.length,g=0,h=arguments.length;g!==h;++g){var k= -arguments[g].uuid,l=d[k];if(void 0!==l)if(delete d[k],lb||0===c)return;this._startTime=null;b*=c}b*=this._updateTimeScale(a);c=this._updateTime(b);a=this._updateWeight(a);if(0c.parameterPositions[1]&&(this.stopFading(),0===d&&(this.enabled=!1))}}return this._effectiveWeight=b},_updateTimeScale:function(a){var b=0;if(!this.paused){b=this.timeScale;var c=this._timeScaleInterpolant;if(null!==c){var d=c.evaluate(a)[0];b*=d;a>c.parameterPositions[1]&&(this.stopWarping(),0===b?this.paused=!0:this.timeScale=b)}}return this._effectiveTimeScale=b},_updateTime:function(a){var b=this.time+a;if(0===a)return b;var c=this._clip.duration,d=this.loop,e=this._loopCount;if(2200=== -d)a:{if(-1===e&&(this._loopCount=0,this._setEndings(!0,!0,!1)),b>=c)b=c;else if(0>b)b=0;else break a;this.clampWhenFinished?this.paused=!0:this.enabled=!1;this._mixer.dispatchEvent({type:"finished",action:this,direction:0>a?-1:1})}else{d=2202===d;-1===e&&(0<=a?(e=0,this._setEndings(!0,0===this.repetitions,d)):this._setEndings(0===this.repetitions,!0,d));if(b>=c||0>b){var f=Math.floor(b/c);b-=c*f;e+=Math.abs(f);var g=this.repetitions-e;0>g?(this.clampWhenFinished?this.paused=!0:this.enabled=!1,b=0< -a?c:0,this._mixer.dispatchEvent({type:"finished",action:this,direction:0a,this._setEndings(a,!a,d)):this._setEndings(!1,!1,d),this._loopCount=e,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:f}))}if(d&&1===(e&1))return this.time=b,c-b}return this.time=b},_setEndings:function(a,b,c){var d=this._interpolantSettings;c?(d.endingStart=2401,d.endingEnd=2401):(d.endingStart=a?this.zeroSlopeAtStart?2401:2400:2402,d.endingEnd=b?this.zeroSlopeAtEnd?2401:2400:2402)},_scheduleFading:function(a, -b,c){var d=this._mixer,e=d.time,f=this._weightInterpolant;null===f&&(this._weightInterpolant=f=d._lendControlInterpolant());d=f.parameterPositions;f=f.sampleValues;d[0]=e;f[0]=b;d[1]=e+a;f[1]=c;return this}});pe.prototype=Object.assign(Object.create(xa.prototype),{constructor:pe,_bindAction:function(a,b){var c=a._localRoot||this._root,d=a._clip.tracks,e=d.length,f=a._propertyBindings;a=a._interpolants;var g=c.uuid,h=this._bindingsByRootAndName,k=h[g];void 0===k&&(k={},h[g]=k);for(h=0;h!==e;++h){var l= -d[h],p=l.name,n=k[p];if(void 0===n){n=f[h];if(void 0!==n){null===n._cacheIndex&&(++n.referenceCount,this._addInactiveBinding(n,g,p));continue}n=new oe(fa.create(c,p,b&&b._propertyBindings[h].binding.parsedPath),l.ValueTypeName,l.getValueSize());++n.referenceCount;this._addInactiveBinding(n,g,p)}f[h]=n;a[h].resultBuffer=n.buffer}},_activateAction:function(a){if(!this._isActiveAction(a)){if(null===a._cacheIndex){var b=(a._localRoot||this._root).uuid,c=a._clip.uuid,d=this._actionsByClip[c];this._bindAction(a, -d&&d.knownActions[0]);this._addInactiveAction(a,c,b)}b=a._propertyBindings;c=0;for(d=b.length;c!==d;++c){var e=b[c];0===e.useCount++&&(this._lendBinding(e),e.saveOriginalState())}this._lendAction(a)}},_deactivateAction:function(a){if(this._isActiveAction(a)){for(var b=a._propertyBindings,c=0,d=b.length;c!==d;++c){var e=b[c];0===--e.useCount&&(e.restoreOriginalState(),this._takeBackBinding(e))}this._takeBackAction(a)}},_initMemoryManager:function(){this._actions=[];this._nActiveActions=0;this._actionsByClip= -{};this._bindings=[];this._nActiveBindings=0;this._bindingsByRootAndName={};this._controlInterpolants=[];this._nActiveControlInterpolants=0;var a=this;this.stats={actions:{get total(){return a._actions.length},get inUse(){return a._nActiveActions}},bindings:{get total(){return a._bindings.length},get inUse(){return a._nActiveBindings}},controlInterpolants:{get total(){return a._controlInterpolants.length},get inUse(){return a._nActiveControlInterpolants}}}},_isActiveAction:function(a){a=a._cacheIndex; -return null!==a&&athis.max.x||a.ythis.max.y?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y},getParameter:function(a,b){return(b||new C).set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y))},intersectsBox:function(a){return a.max.x< -this.min.x||a.min.x>this.max.x||a.max.ythis.max.y?!1:!0},clampPoint:function(a,b){return(b||new C).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new C;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&& -a.max.equals(this.max)}});cd.prototype=Object.create(y.prototype);cd.prototype.constructor=cd;cd.prototype.isImmediateRenderObject=!0;dd.prototype=Object.create(U.prototype);dd.prototype.constructor=dd;dd.prototype.update=function(){var a=new p,b=new p,c=new ta;return function(){var d=["a","b","c"];this.object.updateMatrixWorld(!0);c.getNormalMatrix(this.object.matrixWorld);var e=this.object.matrixWorld,f=this.geometry.attributes.position,g=this.object.geometry;if(g&&g.isGeometry)for(var h=g.vertices, -k=g.faces,l=g=0,p=k.length;lMath.abs(b)&&(b=1E-8);this.scale.set(.5*this.size,.5*this.size,b);this.lookAt(this.plane.normal); -y.prototype.updateMatrixWorld.call(this,a)};var Nd,we;Eb.prototype=Object.create(y.prototype);Eb.prototype.constructor=Eb;Eb.prototype.setDirection=function(){var a=new p,b;return function(c){.99999c.y?this.quaternion.set(1,0,0,0):(a.set(c.z,0,-c.x).normalize(),b=Math.acos(c.y),this.quaternion.setFromAxisAngle(a,b))}}();Eb.prototype.setLength=function(a,b,c){void 0===b&&(b=.2*a);void 0===c&&(c=.2*b);this.line.scale.set(1,Math.max(0,a-b),1);this.line.updateMatrix(); -this.cone.scale.set(c,b,c);this.cone.position.y=a;this.cone.updateMatrix()};Eb.prototype.setColor=function(a){this.line.material.color.copy(a);this.cone.material.color.copy(a)};jd.prototype=Object.create(U.prototype);jd.prototype.constructor=jd;K.create=function(a,b){console.log("THREE.Curve.create() has been deprecated");a.prototype=Object.create(K.prototype);a.prototype.constructor=a;a.prototype.getPoint=b;return a};Object.assign($a.prototype,{createPointsGeometry:function(a){console.warn("THREE.CurvePath: .createPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead."); -a=this.getPoints(a);return this.createGeometry(a)},createSpacedPointsGeometry:function(a){console.warn("THREE.CurvePath: .createSpacedPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.");a=this.getSpacedPoints(a);return this.createGeometry(a)},createGeometry:function(a){console.warn("THREE.CurvePath: .createGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.");for(var b=new L,c=0,d=a.length;c(a*=2)?0.5*a*a:-0.5*(--a*(a-2)-1)}},Cubic:{In:function(a){return a*a*a},Out:function(a){return--a*a*a+1},InOut:function(a){return 1>(a*=2)?0.5*a*a*a:0.5*((a-=2)*a*a+2)}},Quartic:{In:function(a){return a*a*a*a},Out:function(a){return 1- --a*a*a*a},InOut:function(a){return 1>(a*=2)?0.5*a*a*a*a:-0.5*((a-=2)*a*a*a-2)}},Quintic:{In:function(a){return a*a*a* -a*a},Out:function(a){return--a*a*a*a*a+1},InOut:function(a){return 1>(a*=2)?0.5*a*a*a*a*a:0.5*((a-=2)*a*a*a*a+2)}},Sinusoidal:{In:function(a){return 1-Math.cos(a*Math.PI/2)},Out:function(a){return Math.sin(a*Math.PI/2)},InOut:function(a){return 0.5*(1-Math.cos(Math.PI*a))}},Exponential:{In:function(a){return 0===a?0:Math.pow(1024,a-1)},Out:function(a){return 1===a?1:1-Math.pow(2,-10*a)},InOut:function(a){return 0===a?0:1===a?1:1>(a*=2)?0.5*Math.pow(1024,a-1):0.5*(-Math.pow(2,-10*(a-1))+2)}},Circular:{In:function(a){return 1- -Math.sqrt(1-a*a)},Out:function(a){return Math.sqrt(1- --a*a)},InOut:function(a){return 1>(a*=2)?-0.5*(Math.sqrt(1-a*a)-1):0.5*(Math.sqrt(1-(a-=2)*a)+1)}},Elastic:{In:function(a){var c,b=0.1;if(0===a)return 0;if(1===a)return 1;!b||1>b?(b=1,c=0.1):c=0.4*Math.asin(1/b)/(2*Math.PI);return-(b*Math.pow(2,10*(a-=1))*Math.sin((a-c)*2*Math.PI/0.4))},Out:function(a){var c,b=0.1;if(0===a)return 0;if(1===a)return 1;!b||1>b?(b=1,c=0.1):c=0.4*Math.asin(1/b)/(2*Math.PI);return b*Math.pow(2,-10*a)*Math.sin((a-c)* -2*Math.PI/0.4)+1},InOut:function(a){var c,b=0.1;if(0===a)return 0;if(1===a)return 1;!b||1>b?(b=1,c=0.1):c=0.4*Math.asin(1/b)/(2*Math.PI);return 1>(a*=2)?-0.5*b*Math.pow(2,10*(a-=1))*Math.sin((a-c)*2*Math.PI/0.4):0.5*b*Math.pow(2,-10*(a-=1))*Math.sin((a-c)*2*Math.PI/0.4)+1}},Back:{In:function(a){return a*a*(2.70158*a-1.70158)},Out:function(a){return--a*a*(2.70158*a+1.70158)+1},InOut:function(a){return 1>(a*=2)?0.5*a*a*(3.5949095*a-2.5949095):0.5*((a-=2)*a*(3.5949095*a+2.5949095)+2)}},Bounce:{In:function(a){return 1- -TWEEN.Easing.Bounce.Out(1-a)},Out:function(a){return a<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375},InOut:function(a){return 0.5>a?0.5*TWEEN.Easing.Bounce.In(2*a):0.5*TWEEN.Easing.Bounce.Out(2*a-1)+0.5}}}; -TWEEN.Interpolation={Linear:function(a,c){var b=a.length-1,d=b*c,e=Math.floor(d),f=TWEEN.Interpolation.Utils.Linear;return 0>c?f(a[0],a[1],d):1b?b:e+1],d-e)},Bezier:function(a,c){var b=0,d=a.length-1,e=Math.pow,f=TWEEN.Interpolation.Utils.Bernstein,h;for(h=0;h<=d;h++)b+=e(1-c,d-h)*e(c,h)*a[h]*f(d,h);return b},CatmullRom:function(a,c){var b=a.length-1,d=b*c,e=Math.floor(d),f=TWEEN.Interpolation.Utils.CatmullRom;return a[0]===a[b]?(0>c&&(e=Math.floor(d=b*(1+c))),f(a[(e- -1+b)%b],a[e],a[(e+1)%b],a[(e+2)%b],d-e)):0>c?a[0]-(f(a[0],a[0],a[1],a[1],-d)-a[0]):1 0 ? libraries[ libraries.length - 1 ] : '' ), - smooth: ( previous !== undefined ? previous.smooth : this.smooth ), - groupStart: ( previous !== undefined ? previous.groupEnd : 0 ), - groupEnd: - 1, - groupCount: - 1, - inherited: false, - - clone: function ( index ) { - - var cloned = { - index: ( typeof index === 'number' ? index : this.index ), - name: this.name, - mtllib: this.mtllib, - smooth: this.smooth, - groupStart: 0, - groupEnd: - 1, - groupCount: - 1, - inherited: false - }; - cloned.clone = this.clone.bind( cloned ); - return cloned; - - } - }; - - this.materials.push( material ); - - return material; - - }, - - currentMaterial: function () { - - if ( this.materials.length > 0 ) { - - return this.materials[ this.materials.length - 1 ]; - - } - - return undefined; - - }, - - _finalize: function ( end ) { - - var lastMultiMaterial = this.currentMaterial(); - if ( lastMultiMaterial && lastMultiMaterial.groupEnd === - 1 ) { - - lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3; - lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart; - lastMultiMaterial.inherited = false; - - } - - // Ignore objects tail materials if no face declarations followed them before a new o/g started. - if ( end && this.materials.length > 1 ) { - - for ( var mi = this.materials.length - 1; mi >= 0; mi -- ) { - - if ( this.materials[ mi ].groupCount <= 0 ) { - - this.materials.splice( mi, 1 ); - - } - - } - - } - - // Guarantee at least one empty material, this makes the creation later more straight forward. - if ( end && this.materials.length === 0 ) { - - this.materials.push( { - name: '', - smooth: this.smooth - } ); - - } - - return lastMultiMaterial; - - } - }; - - // Inherit previous objects material. - // Spec tells us that a declared material must be set to all objects until a new material is declared. - // If a usemtl declaration is encountered while this new object is being parsed, it will - // overwrite the inherited material. Exception being that there was already face declarations - // to the inherited material, then it will be preserved for proper MultiMaterial continuation. - - if ( previousMaterial && previousMaterial.name && typeof previousMaterial.clone === 'function' ) { - - var declared = previousMaterial.clone( 0 ); - declared.inherited = true; - this.object.materials.push( declared ); - - } - - this.objects.push( this.object ); - - }, - - finalize: function () { - - if ( this.object && typeof this.object._finalize === 'function' ) { - - this.object._finalize( true ); - - } - - }, - - parseVertexIndex: function ( value, len ) { - - var index = parseInt( value, 10 ); - return ( index >= 0 ? index - 1 : index + len / 3 ) * 3; - - }, - - parseNormalIndex: function ( value, len ) { - - var index = parseInt( value, 10 ); - return ( index >= 0 ? index - 1 : index + len / 3 ) * 3; - - }, - - parseUVIndex: function ( value, len ) { - - var index = parseInt( value, 10 ); - return ( index >= 0 ? index - 1 : index + len / 2 ) * 2; - - }, - - addVertex: function ( a, b, c ) { - - var src = this.vertices; - var dst = this.object.geometry.vertices; - - dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); - dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] ); - dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] ); - - }, - - addVertexPoint: function ( a ) { - - var src = this.vertices; - var dst = this.object.geometry.vertices; - - dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); - - }, - - addVertexLine: function ( a ) { - - var src = this.vertices; - var dst = this.object.geometry.vertices; - - dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); - - }, - - addNormal: function ( a, b, c ) { - - var src = this.normals; - var dst = this.object.geometry.normals; - - dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); - dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] ); - dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] ); - - }, - - addColor: function ( a, b, c ) { - - var src = this.colors; - var dst = this.object.geometry.colors; - - dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); - dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] ); - dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] ); - - }, - - addUV: function ( a, b, c ) { - - var src = this.uvs; - var dst = this.object.geometry.uvs; - - dst.push( src[ a + 0 ], src[ a + 1 ] ); - dst.push( src[ b + 0 ], src[ b + 1 ] ); - dst.push( src[ c + 0 ], src[ c + 1 ] ); - - }, - - addUVLine: function ( a ) { - - var src = this.uvs; - var dst = this.object.geometry.uvs; - - dst.push( src[ a + 0 ], src[ a + 1 ] ); - - }, - - addFace: function ( a, b, c, ua, ub, uc, na, nb, nc ) { - - var vLen = this.vertices.length; - - var ia = this.parseVertexIndex( a, vLen ); - var ib = this.parseVertexIndex( b, vLen ); - var ic = this.parseVertexIndex( c, vLen ); - - this.addVertex( ia, ib, ic ); - - if ( ua !== undefined && ua !== '' ) { - - var uvLen = this.uvs.length; - ia = this.parseUVIndex( ua, uvLen ); - ib = this.parseUVIndex( ub, uvLen ); - ic = this.parseUVIndex( uc, uvLen ); - this.addUV( ia, ib, ic ); - - } - - if ( na !== undefined && na !== '' ) { - - // Normals are many times the same. If so, skip function call and parseInt. - var nLen = this.normals.length; - ia = this.parseNormalIndex( na, nLen ); - - ib = na === nb ? ia : this.parseNormalIndex( nb, nLen ); - ic = na === nc ? ia : this.parseNormalIndex( nc, nLen ); - - this.addNormal( ia, ib, ic ); - - } - - if ( this.colors.length > 0 ) { - - this.addColor( ia, ib, ic ); - - } - - }, - - addPointGeometry: function ( vertices ) { - - this.object.geometry.type = 'Points'; - - var vLen = this.vertices.length; - - for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) { - - this.addVertexPoint( this.parseVertexIndex( vertices[ vi ], vLen ) ); - - } - - }, - - addLineGeometry: function ( vertices, uvs ) { - - this.object.geometry.type = 'Line'; - - var vLen = this.vertices.length; - var uvLen = this.uvs.length; - - for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) { - - this.addVertexLine( this.parseVertexIndex( vertices[ vi ], vLen ) ); - - } - - for ( var uvi = 0, l = uvs.length; uvi < l; uvi ++ ) { - - this.addUVLine( this.parseUVIndex( uvs[ uvi ], uvLen ) ); - - } - - } - - }; - - state.startObject( '', false ); - - return state; - - } - - // - - function OBJLoader( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - - this.materials = null; - - } - - OBJLoader.prototype = { - - constructor: OBJLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.FileLoader( scope.manager ); - loader.setPath( this.path ); - loader.load( url, function ( text ) { - - onLoad( scope.parse( text ) ); - - }, onProgress, onError ); - - }, - - setPath: function ( value ) { - - this.path = value; - - }, - - setMaterials: function ( materials ) { - - this.materials = materials; - - return this; - - }, - - parse: function ( text ) { - - console.time( 'OBJLoader' ); - - var state = new ParserState(); - - if ( text.indexOf( '\r\n' ) !== - 1 ) { - - // This is faster than String.split with regex that splits on both - text = text.replace( /\r\n/g, '\n' ); - - } - - if ( text.indexOf( '\\\n' ) !== - 1 ) { - - // join lines separated by a line continuation character (\) - text = text.replace( /\\\n/g, '' ); - - } - - var lines = text.split( '\n' ); - var line = '', lineFirstChar = ''; - var lineLength = 0; - var result = []; - - // Faster to just trim left side of the line. Use if available. - var trimLeft = ( typeof ''.trimLeft === 'function' ); - - for ( var i = 0, l = lines.length; i < l; i ++ ) { - - line = lines[ i ]; - - line = trimLeft ? line.trimLeft() : line.trim(); - - lineLength = line.length; - - if ( lineLength === 0 ) continue; - - lineFirstChar = line.charAt( 0 ); - - // @todo invoke passed in handler if any - if ( lineFirstChar === '#' ) continue; - - if ( lineFirstChar === 'v' ) { - - var data = line.split( /\s+/ ); - - switch ( data[ 0 ] ) { - - case 'v': - state.vertices.push( - parseFloat( data[ 1 ] ), - parseFloat( data[ 2 ] ), - parseFloat( data[ 3 ] ) - ); - if ( data.length === 8 ) { - - state.colors.push( - parseFloat( data[ 4 ] ), - parseFloat( data[ 5 ] ), - parseFloat( data[ 6 ] ) - - ); - - } - break; - case 'vn': - state.normals.push( - parseFloat( data[ 1 ] ), - parseFloat( data[ 2 ] ), - parseFloat( data[ 3 ] ) - ); - break; - case 'vt': - state.uvs.push( - parseFloat( data[ 1 ] ), - parseFloat( data[ 2 ] ) - ); - break; - - } - - } else if ( lineFirstChar === 'f' ) { - - var lineData = line.substr( 1 ).trim(); - var vertexData = lineData.split( /\s+/ ); - var faceVertices = []; - - // Parse the face vertex data into an easy to work with format - - for ( var j = 0, jl = vertexData.length; j < jl; j ++ ) { - - var vertex = vertexData[ j ]; - - if ( vertex.length > 0 ) { - - var vertexParts = vertex.split( '/' ); - faceVertices.push( vertexParts ); - - } - - } - - // Draw an edge between the first vertex and all subsequent vertices to form an n-gon - - var v1 = faceVertices[ 0 ]; - - for ( var j = 1, jl = faceVertices.length - 1; j < jl; j ++ ) { - - var v2 = faceVertices[ j ]; - var v3 = faceVertices[ j + 1 ]; - - state.addFace( - v1[ 0 ], v2[ 0 ], v3[ 0 ], - v1[ 1 ], v2[ 1 ], v3[ 1 ], - v1[ 2 ], v2[ 2 ], v3[ 2 ] - ); - - } - - } else if ( lineFirstChar === 'l' ) { - - var lineParts = line.substring( 1 ).trim().split( " " ); - var lineVertices = [], lineUVs = []; - - if ( line.indexOf( "/" ) === - 1 ) { - - lineVertices = lineParts; - - } else { - - for ( var li = 0, llen = lineParts.length; li < llen; li ++ ) { - - var parts = lineParts[ li ].split( "/" ); - - if ( parts[ 0 ] !== "" ) lineVertices.push( parts[ 0 ] ); - if ( parts[ 1 ] !== "" ) lineUVs.push( parts[ 1 ] ); - - } - - } - state.addLineGeometry( lineVertices, lineUVs ); - - } else if ( lineFirstChar === 'p' ) { - - var lineData = line.substr( 1 ).trim(); - var pointData = lineData.split( " " ); - - state.addPointGeometry( pointData ); - - } else if ( ( result = object_pattern.exec( line ) ) !== null ) { - - // o object_name - // or - // g group_name - - // WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869 - // var name = result[ 0 ].substr( 1 ).trim(); - var name = ( " " + result[ 0 ].substr( 1 ).trim() ).substr( 1 ); - - state.startObject( name ); - - } else if ( material_use_pattern.test( line ) ) { - - // material - - state.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries ); - - } else if ( material_library_pattern.test( line ) ) { - - // mtl file - - state.materialLibraries.push( line.substring( 7 ).trim() ); - - } else if ( lineFirstChar === 's' ) { - - result = line.split( ' ' ); - - // smooth shading - - // @todo Handle files that have varying smooth values for a set of faces inside one geometry, - // but does not define a usemtl for each face set. - // This should be detected and a dummy material created (later MultiMaterial and geometry groups). - // This requires some care to not create extra material on each smooth value for "normal" obj files. - // where explicit usemtl defines geometry groups. - // Example asset: examples/models/obj/cerberus/Cerberus.obj - - /* - * http://paulbourke.net/dataformats/obj/ - * or - * http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf - * - * From chapter "Grouping" Syntax explanation "s group_number": - * "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off. - * Polygonal elements use group numbers to put elements in different smoothing groups. For free-form - * surfaces, smoothing groups are either turned on or off; there is no difference between values greater - * than 0." - */ - if ( result.length > 1 ) { - - var value = result[ 1 ].trim().toLowerCase(); - state.object.smooth = ( value !== '0' && value !== 'off' ); - - } else { - - // ZBrush can produce "s" lines #11707 - state.object.smooth = true; - - } - var material = state.object.currentMaterial(); - if ( material ) material.smooth = state.object.smooth; - - } else { - - // Handle null terminated files without exception - if ( line === '\0' ) continue; - - throw new Error( 'THREE.OBJLoader: Unexpected line: "' + line + '"' ); - - } - - } - - state.finalize(); - - var container = new THREE.Group(); - container.materialLibraries = [].concat( state.materialLibraries ); - - for ( var i = 0, l = state.objects.length; i < l; i ++ ) { - - var object = state.objects[ i ]; - var geometry = object.geometry; - var materials = object.materials; - var isLine = ( geometry.type === 'Line' ); - var isPoints = ( geometry.type === 'Points' ); - var hasVertexColors = false; - - // Skip o/g line declarations that did not follow with any faces - if ( geometry.vertices.length === 0 ) continue; - - var buffergeometry = new THREE.BufferGeometry(); - - buffergeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( geometry.vertices, 3 ) ); - - if ( geometry.normals.length > 0 ) { - - buffergeometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( geometry.normals, 3 ) ); - - } else { - - buffergeometry.computeVertexNormals(); - - } - - if ( geometry.colors.length > 0 ) { - - hasVertexColors = true; - buffergeometry.addAttribute( 'color', new THREE.Float32BufferAttribute( geometry.colors, 3 ) ); - - } - - if ( geometry.uvs.length > 0 ) { - - buffergeometry.addAttribute( 'uv', new THREE.Float32BufferAttribute( geometry.uvs, 2 ) ); - - } - - // Create materials - - var createdMaterials = []; - - for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) { - - var sourceMaterial = materials[ mi ]; - var material = undefined; - - if ( this.materials !== null ) { - - material = this.materials.create( sourceMaterial.name ); - - // mtl etc. loaders probably can't create line materials correctly, copy properties to a line material. - if ( isLine && material && ! ( material instanceof THREE.LineBasicMaterial ) ) { - - var materialLine = new THREE.LineBasicMaterial(); - materialLine.copy( material ); - materialLine.lights = false; // TOFIX - material = materialLine; - - } else if ( isPoints && material && ! ( material instanceof THREE.PointsMaterial ) ) { - - var materialPoints = new THREE.PointsMaterial( { size: 10, sizeAttenuation: false } ); - materialLine.copy( material ); - material = materialPoints; - - } - - } - - if ( ! material ) { - - if ( isLine ) { - - material = new THREE.LineBasicMaterial(); - - } else if ( isPoints ) { - - material = new THREE.PointsMaterial( { size: 1, sizeAttenuation: false } ); - - } else { - - material = new THREE.MeshPhongMaterial(); - - } - - material.name = sourceMaterial.name; - - } - - material.flatShading = sourceMaterial.smooth ? false : true; - material.vertexColors = hasVertexColors ? THREE.VertexColors : THREE.NoColors; - - createdMaterials.push( material ); - - } - - // Create mesh - - var mesh; - - if ( createdMaterials.length > 1 ) { - - for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) { - - var sourceMaterial = materials[ mi ]; - buffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi ); - - } - - if ( isLine ) { - - mesh = new THREE.LineSegments( buffergeometry, createdMaterials ); - - } else if ( isPoints ) { - - mesh = new THREE.Points( buffergeometry, createdMaterials ); - - } else { - - mesh = new THREE.Mesh( buffergeometry, createdMaterials ); - - } - - } else { - - if ( isLine ) { - - mesh = new THREE.LineSegments( buffergeometry, createdMaterials[ 0 ] ); - - } else if ( isPoints ) { - - mesh = new THREE.Points( buffergeometry, createdMaterials[ 0 ] ); - - } else { - - mesh = new THREE.Mesh( buffergeometry, createdMaterials[ 0 ] ); - - } - - } - - mesh.name = object.name; - - container.add( mesh ); - - } - - console.timeEnd( 'OBJLoader' ); - - return container; - - } - - }; - - return OBJLoader; - -} )(); \ No newline at end of file diff --git a/examples/js/renderers/CSS3DRenderer.js b/examples/js/renderers/CSS3DRenderer.js deleted file mode 100644 index 45ec1a9..0000000 --- a/examples/js/renderers/CSS3DRenderer.js +++ /dev/null @@ -1,759 +0,0 @@ -/** - * @author Adam Kecskes - */ - -// The CSS3DObject and CSS3DSprite classes are preserved for compatibility -THREE.CSS3DObject = function (element) { - - THREE.Object3D.call(this); - - this.element = element; - this.element.style.position = 'absolute'; - - this.addEventListener('removed', function () { - - if (this.element.parentNode !== null) { - - this.element.parentNode.removeChild(this.element); - - } - - }); - -}; - -THREE.CSS3DObject.prototype = Object.assign(Object.create(THREE.Object3D.prototype), { - - isDomElement: true - -}); -THREE.CSS3DObject.prototype.constructor = THREE.CSS3DObject; - -THREE.CSS3DSprite = function (element) { - - THREE.CSS3DObject.call(this, element); - - this.center = new THREE.Vector2(0.5, 0.5); - -}; - -THREE.CSS3DSprite.prototype = Object.create(THREE.CSS3DObject.prototype); -THREE.CSS3DSprite.prototype.constructor = THREE.CSS3DSprite; - -// CSS Renderer - -THREE.CSS3DRenderer = function (parameters) { - - console.log('THREE.CSS3DRenderer', THREE.REVISION); - - parameters = parameters || {}; - var _this = this; - - var _width, _height; - - // Create containers, so it can render multiple overlapping scenes - var active_container = null; - this.domElement = document.createElement('div'); - - var containers = []; - - var createContainer = function () { - - var container = new C3R.Container(); - container.domElement.style.position = "absolute"; - containers.push(container); - return container; - - }; - - var activateContainer = function (container, remove_current) { - - if (remove_current && active_container) { - hideContainer(active_container); - } - - container.setSize(_width, _height); - - active_container = container; - - if (container.domElement.parentNode !== _this.domElement) { - - _this.domElement.appendChild(container.domElement); - - } - } - - var hideContainer = function (container) { - - if (container.domElement.parentNode === _this.domElement) { - - _this.domElement.removeChild(container.domElement); - - } - - if (active_container === container) { - - active_container = null; - - } - }; - - - - // Warn if some features can not be user - - if (!CSS.supports("clip-path: polygon(0% 0%,100% 0%,100% 100%)")) { - - console.warn("CSS clip-path is not supported in your browser. Polygons can not be rendered correctly"); - - } - - if (!CSS.supports("background-blend-mode: multiply")) { - - console.warn("CSS background-blend-mode (multiply) is not supported in your browser. Sprites can not be rendered correctly"); - - } - - if (!CSS.supports("transform: rotate(calc(90deg * var(--mult-value,1)))")) { - - console.warn("CSS calc and/or var is not supported in transformations in your browser"); - - } - - var css_mask = CSS.supports("mask-image: var(--background-image, none)"); - var css_webkit_mask = CSS.supports("-webkit-mask-image: var(--background-image, none)"); - - //https://stackoverflow.com/a/16436975 - - var arraysEqual = function (a, b) { - - if (a === b) return true; - if (a == null || b == null) return false; - if (a.length != b.length) return false; - - // If you don't care about the order of the elements inside - // the array, you should sort both arrays here. - - for (var i = 0; i < a.length; ++i) { - - if (a[i] !== b[i]) return false; - - } - - return true; - - } - - // List of objects, which needed update - // One element in the scene graph can appear multiple times in the tree, so we need to update later - var threejs_updated = []; - - var updateCamera = function (camera) { - - var changed = false; - - if (camera.isPerspectiveCamera) { - - if (active_container.camera instanceof C3R.PerspectiveCamera) { - - if (camera.fov !== active_container.camera.fov) { - active_container.camera.fov = camera.fov; - changed = true; - } - - } else { - - active_container.camera = new C3R.PerspectiveCamera(active_container.camera.fov); - changed = true; - - } - - } else if (camera.isOrthographicCamera) { - - if (active_container.camera instanceof C3R.OrthographicCamera) { - - if ( - camera.left !== active_container.camera.left || - camera.right !== active_container.camera.right || - camera.top !== active_container.camera.top || - camera.bottom !== active_container.camera.bottom - ) { - - active_container.camera.left = camera.left; - active_container.camera.right = camera.right; - active_container.camera.top = camera.top; - active_container.camera.bottom = camera.bottom; - - changed = true; - - } - - } else { - - active_container.camera = new C3R.OrthographicCamera(camera.left, camera.right, camera.top, camera.bottom); - changed = true; - - } - - } - - // Compare camera world inv matrices - if (!mat4.equals(active_container.camera.matrix, camera.matrixWorldInverse.elements)) { - - mat4.copy(active_container.camera.matrix, camera.matrixWorldInverse.elements); - changed = true; - - } - - if (changed) { - - active_container.updateCamera(); - - } - - }; - - - var tMatrix = new THREE.Matrix4(); - var updateSpriteMatrix = function (three_object, c3d_object) { - - tMatrix.fromArray(active_container.camera.matrix); - tMatrix.transpose(); - tMatrix.copyPosition(three_object.matrixWorld); - tMatrix.multiplyMatrices(tMatrix, (new THREE.Matrix4()).extractRotation(three_object.matrixWorld).transpose()); - tMatrix.scale(three_object.scale); - - tMatrix.elements[3] = 0; - tMatrix.elements[7] = 0; - tMatrix.elements[11] = 0; - tMatrix.elements[15] = 1; - - if (!vec2.equals([three_object.center.x, three_object.center.y], c3d_object.elementCenter)) { - - c3d_object.setCenter(three_object.center.x, three_object.center.y); - - } - - return tMatrix.elements; - - }; - - var updateChildren = function (three_object, c3d_object) { - - var t_child_ids = []; - var t_child_map = {}; - for (var i = 0; i < three_object.children.length; i++) { - - var child = three_object.children[i]; - t_child_ids.push(child.id); - t_child_map[child.id] = child; - - } - - if (!c3d_object.threejs_children) { - - c3d_object.threejs_children = {}; - - } - - var t_child_ids_current = Object.keys(c3d_object.threejs_children).map(Number); - - t_child_ids.sort(); - t_child_ids_current.sort(); - - var child_change = !arraysEqual(t_child_ids, t_child_ids_current); - if (child_change) { - - var threejs_children_next = {}; - - // Insert added elements to the DOM - three_object.children.forEach(function (three_child) { - - var c3d_node; - - if (c3d_object.threejs_children[three_child.id]) { - - c3d_node = c3d_object.threejs_children[three_child.id]; - - } else { - - // CSS3D Object - if (three_child.isDomElement) { - var element = three_child.element; - - c3d_node = new C3R.CustomElement(element); - - c3d_node.domElement.style['backface-visibility'] = 'visible'; - - c3d_object.addChild(c3d_node); - c3d_node.threejs_id = three_child.id; - - } else if (three_child.isSprite) { - - var element = document.createElement('div'); - - element.style['background-blend-mode'] = 'multiply'; - - if (css_mask) { - element.style['mask-image'] = 'var(--background-image, none)'; - } else if (css_webkit_mask) { - element.style['-webkit-mask-image'] = 'var(--background-image, none)'; - } - - c3d_node = new C3R.CustomElement(element); - - c3d_node.setSize(128, 128); - c3d_node.setScale(1 / 128, 1 / 128); - - c3d_object.addChild(c3d_node); - c3d_node.threejs_id = three_child.id; - - } else { - c3d_node = new C3R.Group(); - c3d_object.addChild(c3d_node); - c3d_node.threejs_id = three_child.id; - } - - } - - threejs_children_next[three_child.id] = c3d_node; - - }); - - // Remove elements from DOM, which are not in the children array - for (var threejs_id in c3d_object.threejs_children) { - - if (!t_child_map[threejs_id]) { - - c3d_object.removeChild( - c3d_object.threejs_children[threejs_id] - ); - - } - - } - - c3d_object.threejs_children = threejs_children_next; - - } - - // Update child nodes - for (var threejs_id in c3d_object.threejs_children) { - - var c = c3d_object.threejs_children[threejs_id]; - updateObject(t_child_map[threejs_id], c); - - } - - }; - - var updateMesh = function (three_object, c3d_object) { - - var geometry = three_object.geometry; - - if (!geometry.isBufferGeometry) { - - // TODO: support for not just bufferGeometry - three_object.geometry = geometry = (new THREE.BufferGeometry()).fromGeometry(geometry); - - } - - var indexed = !!geometry.index; - - var groups = geometry.groups; - if (!groups || groups.length === 0) { - - var dr = Object.assign({}, geometry.drawRange); - dr.materialIndex = 0; - - if (dr.count == Infinity) { - - dr.count = indexed ? geometry.index.count : geometry.attributes.position.count; - - } - - groups = [dr]; - - } - - if ( - (indexed && (geometry.index.version === 0 || geometry.index.needsUpdate)) || - - (geometry.attributes.position.version === 0 || geometry.attributes.position.needsUpdate) || - (geometry.attributes.uv.version === 0 || geometry.attributes.uv.needsUpdate) - ) { - - if (indexed) { - - threejs_updated.push(geometry.index); - - } - - threejs_updated.push(geometry.attributes.position, geometry.attributes.uv); - - // Remove old content - (c3d_object.threejs_groups || []).forEach(function (gr) { - - c3d_object.removeChild(gr); - - }); - - var indices = indexed ? geometry.index.array : []; - var positions = geometry.attributes.position.array; - var uvs = geometry.attributes.uv.array; - - var threejs_groups = []; - - for (var g = 0; g < groups.length; g++) { - - var c3d_group = new C3R.Group(); - - c3d_group.threejs_tex_repeat = [1, 1]; - c3d_group.threejs_tex_offset = [0, 0]; - - var start = groups[g].start; - var end = start + groups[g].count; - for (var i = start; i < end; i += 3) { - - var i1, i2, i3; - - if (indexed) { - i1 = indices[i + 0]; - i2 = indices[i + 1]; - i3 = indices[i + 2]; - } else { - i1 = i + 0; - i2 = i + 1; - i3 = i + 2; - } - - var p1 = vec3.fromValues(positions[i1 * 3], positions[i1 * 3 + 1], positions[i1 * 3 + 2]); - var p2 = vec3.fromValues(positions[i2 * 3], positions[i2 * 3 + 1], positions[i2 * 3 + 2]); - var p3 = vec3.fromValues(positions[i3 * 3], positions[i3 * 3 + 1], positions[i3 * 3 + 2]); - - var t1 = vec2.fromValues(uvs[i1 * 2], uvs[i1 * 2 + 1]); - var t2 = vec2.fromValues(uvs[i2 * 2], uvs[i2 * 2 + 1]); - var t3 = vec2.fromValues(uvs[i3 * 2], uvs[i3 * 2 + 1]); - - c3d_group.pushPolygon([ - new C3R.Vertex(p1, t1), - new C3R.Vertex(p2, t2), - new C3R.Vertex(p3, t3) - ]); - - } - - c3d_group.flushPolygons(); - - c3d_object.addChild(c3d_group); - - threejs_groups.push(c3d_group); - - } - - c3d_object.threejs_groups = threejs_groups; - - } - - // Materials - - var multi_material = Array.isArray(three_object.material); - var threejs_materials = multi_material ? three_object.material : [three_object.material]; - - for (var g = 0; g < groups.length; g++) { - - var c3d_group = c3d_object.threejs_groups[g]; - var threejs_material = threejs_materials[groups[g].materialIndex % threejs_materials.length]; - - updateObjectMaterial(threejs_material, c3d_group); - - } - }; - - var updateSpriteMaterial = function (three_object, c3d_object) { - - if (three_object.material) { - - if (three_object.material.rotation != c3d_object.elementRotation) { - - c3d_object.elementRotation = three_object.material.rotation; - c3d_object.updateElementTransform(); - - } - - updateObjectMaterial(three_object.material, c3d_object); - - } - - }; - - var updateObject = function (three_object, c3d_object) { - - // Compare object matrices - var three_matrix = three_object.matrix.elements; - - if ((three_object instanceof THREE.CSS3DSprite) || three_object.isSprite) { - - three_matrix = updateSpriteMatrix(three_object, c3d_object); - - } - - if (!mat4.equals(c3d_object.matrix, three_matrix)) { - - mat4.copy(c3d_object.matrix, three_matrix); - c3d_object.updateMatrix(); - - } - - // Update content - - updateChildren(three_object, c3d_object); - - if (three_object.isSprite) { - - updateSpriteMaterial(three_object, c3d_object); - - } - - if (three_object.isMesh) { - - updateMesh(three_object, c3d_object); - - } - - }; - - var updateObjectMaterial = function (threejs_material, c3d_object) { - - if (!c3d_object.material || c3d_object.material.threejs_id !== threejs_material.id) { - - c3d_object.material = new C3R.Material(); - c3d_object.material.threejs_id = threejs_material.id; - - } - - var material_needs_update = false; - if (threejs_material.map && threejs_material.map.image) { - - var img = threejs_material.map.image; - switch (img.tagName) { - - case 'IMG': - - if (c3d_object.material.backgroundImageSrc !== img.src) { - - c3d_object.material.backgroundImageSrc = img.src; - material_needs_update = true; - - } - - break; - - case 'CANVAS': - - if (c3d_object.material.threejs_version !== threejs_material.map.version) { - - c3d_object.material.backgroundImageSrc = img.toDataURL(); - c3d_object.material.threejs_version = threejs_material.map.version; - material_needs_update = true; - - } - - break; - - } - - } else { - - if (c3d_object.material.backgroundImageSrc) { - - c3d_object.material.backgroundImageSrc = null; - material_needs_update = true; - - } - - } - - if (threejs_material.color) { - - var col = vec4.fromValues( - threejs_material.color.r, - threejs_material.color.g, - threejs_material.color.b, - 1.0 - ); - - if (!c3d_object.material.backgroundColor || !vec4.equals(col, c3d_object.material.backgroundColor)) { - - c3d_object.material.backgroundColor = col; - material_needs_update = true; - - } - - } else { - - if (c3d_object.material.backgroundColor) { - - c3d_object.material.backgroundColor = null; - material_needs_update = true; - - } - - } - - if (threejs_material.opacity != c3d_object.material.opacity) { - - c3d_object.material.opacity = threejs_material.opacity; - material_needs_update = true; - - } - - if (material_needs_update) { - - c3d_object.updateMaterial(); - - } - - // TODO: Check if child supports texture repeat? - if (c3d_object.threejs_tex_repeat && c3d_object.threejs_tex_offset) { - - var tex_repeat = threejs_material.map ? [threejs_material.map.repeat.x, threejs_material.map.repeat.y] : [1, 1]; - var tex_offset = threejs_material.map ? [threejs_material.map.offset.x, threejs_material.map.offset.y] : [0, 0]; - - if (!vec2.equals(c3d_object.threejs_tex_repeat, tex_repeat) || - !vec2.equals(c3d_object.threejs_tex_offset, tex_offset) - ) { - - c3d_object.threejs_tex_repeat = tex_repeat; - c3d_object.threejs_tex_offset = tex_offset; - - c3d_object.children.forEach(function (child) { - - if (!child instanceof C3R.Polygon) { - return; - } - - child.uv_scale = tex_repeat; - child.uv_offset = tex_offset; - - child.updateContent(); - - }); - - } - - } - - }; - - // Public Renderer functions and attributes - // Some of them is only provided for compatibility - - this.autoClear = true; - - this.setClearColor = function (col) { - - _this.domElement.style.backgroundColor = 'rgb(' + [ - Math.round(col.r * 255), - Math.round(col.g * 255), - Math.round(col.b * 255) - ].join() + ')'; - - }; - - this.getSize = function () { - - return { - width: _width, - height: _height - }; - - }; - - this.setSize = function (width, height) { - - _width = width; - _height = height; - - _this.domElement.style.width = width + "px"; - _this.domElement.style.height = height + "px"; - - if (active_container) { - active_container.setSize(width, height); - } - - }; - - this.setPixelRatio = function (val) {}; - - this.clearDepth = function () {}; - - var clearNext = false; - this.clear = function () { - - clearNext = true; - - }; - - this.shadowMap = { - - render: function () {} - - }; - - this.render = function (scene, camera) { - - if (clearNext) { - - // TODO: Hide containers except the currently rendered ones - // collect the rendered containers in an array, and clear the others with a timeout? - - clearNext = false; - - } - - if (!active_container || active_container.threejs_id !== scene.id) { - - var new_container = containers.find(function (container) { - - return container.threejs_id === scene.id; - - }); - - if (!new_container) { - - new_container = createContainer(); - new_container.threejs_id = scene.id; - - } - - activateContainer(new_container); - - } - - scene.updateMatrixWorld(); - - if (camera.parent === null) { - - camera.updateMatrixWorld(); - - } - - updateCamera(camera); - updateObject(scene, active_container.root); - - threejs_updated.forEach(function (o) { - - if (o.needsUpdate) { - o.needsUpdate = false; - } else if (o.isBufferAttribute && o.version === 0) { - o.version = 1; - } - - }); - - threejs_updated = []; - - }; - -}; \ No newline at end of file diff --git a/examples/js/renderers/Projector.js b/examples/js/renderers/Projector.js deleted file mode 100644 index a907928..0000000 --- a/examples/js/renderers/Projector.js +++ /dev/null @@ -1,1028 +0,0 @@ -/** - * @author mrdoob / http://mrdoob.com/ - * @author supereggbert / http://www.paulbrunt.co.uk/ - * @author julianwa / https://github.com/julianwa - */ - -THREE.RenderableObject = function () { - - this.id = 0; - - this.object = null; - this.z = 0; - this.renderOrder = 0; - -}; - -// - -THREE.RenderableFace = function () { - - this.id = 0; - - this.v1 = new THREE.RenderableVertex(); - this.v2 = new THREE.RenderableVertex(); - this.v3 = new THREE.RenderableVertex(); - - this.normalModel = new THREE.Vector3(); - - this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; - this.vertexNormalsLength = 0; - - this.color = new THREE.Color(); - this.material = null; - this.uvs = [ new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ]; - - this.z = 0; - this.renderOrder = 0; - -}; - -// - -THREE.RenderableVertex = function () { - - this.position = new THREE.Vector3(); - this.positionWorld = new THREE.Vector3(); - this.positionScreen = new THREE.Vector4(); - - this.visible = true; - -}; - -THREE.RenderableVertex.prototype.copy = function ( vertex ) { - - this.positionWorld.copy( vertex.positionWorld ); - this.positionScreen.copy( vertex.positionScreen ); - -}; - -// - -THREE.RenderableLine = function () { - - this.id = 0; - - this.v1 = new THREE.RenderableVertex(); - this.v2 = new THREE.RenderableVertex(); - - this.vertexColors = [ new THREE.Color(), new THREE.Color() ]; - this.material = null; - - this.z = 0; - this.renderOrder = 0; - -}; - -// - -THREE.RenderableSprite = function () { - - this.id = 0; - - this.object = null; - - this.x = 0; - this.y = 0; - this.z = 0; - - this.rotation = 0; - this.scale = new THREE.Vector2(); - - this.material = null; - this.renderOrder = 0; - -}; - -// - -THREE.Projector = function () { - - var _object, _objectCount, _objectPool = [], _objectPoolLength = 0, - _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0, - _face, _faceCount, _facePool = [], _facePoolLength = 0, - _line, _lineCount, _linePool = [], _linePoolLength = 0, - _sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0, - - _renderData = { objects: [], lights: [], elements: [] }, - - _vector3 = new THREE.Vector3(), - _vector4 = new THREE.Vector4(), - - _clipBox = new THREE.Box3( new THREE.Vector3( - 1, - 1, - 1 ), new THREE.Vector3( 1, 1, 1 ) ), - _boundingBox = new THREE.Box3(), - _points3 = new Array( 3 ), - - _viewMatrix = new THREE.Matrix4(), - _viewProjectionMatrix = new THREE.Matrix4(), - - _modelMatrix, - _modelViewProjectionMatrix = new THREE.Matrix4(), - - _normalMatrix = new THREE.Matrix3(), - - _frustum = new THREE.Frustum(), - - _clippedVertex1PositionScreen = new THREE.Vector4(), - _clippedVertex2PositionScreen = new THREE.Vector4(); - - // - - this.projectVector = function ( vector, camera ) { - - console.warn( 'THREE.Projector: .projectVector() is now vector.project().' ); - vector.project( camera ); - - }; - - this.unprojectVector = function ( vector, camera ) { - - console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' ); - vector.unproject( camera ); - - }; - - this.pickingRay = function () { - - console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' ); - - }; - - // - - var RenderList = function () { - - var normals = []; - var colors = []; - var uvs = []; - - var object = null; - var material = null; - - var normalMatrix = new THREE.Matrix3(); - - function setObject( value ) { - - object = value; - material = object.material; - - normalMatrix.getNormalMatrix( object.matrixWorld ); - - normals.length = 0; - colors.length = 0; - uvs.length = 0; - - } - - function projectVertex( vertex ) { - - var position = vertex.position; - var positionWorld = vertex.positionWorld; - var positionScreen = vertex.positionScreen; - - positionWorld.copy( position ).applyMatrix4( _modelMatrix ); - positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix ); - - var invW = 1 / positionScreen.w; - - positionScreen.x *= invW; - positionScreen.y *= invW; - positionScreen.z *= invW; - - vertex.visible = positionScreen.x >= - 1 && positionScreen.x <= 1 && - positionScreen.y >= - 1 && positionScreen.y <= 1 && - positionScreen.z >= - 1 && positionScreen.z <= 1; - - } - - function pushVertex( x, y, z ) { - - _vertex = getNextVertexInPool(); - _vertex.position.set( x, y, z ); - - projectVertex( _vertex ); - - } - - function pushNormal( x, y, z ) { - - normals.push( x, y, z ); - - } - - function pushColor( r, g, b ) { - - colors.push( r, g, b ); - - } - - function pushUv( x, y ) { - - uvs.push( x, y ); - - } - - function checkTriangleVisibility( v1, v2, v3 ) { - - if ( v1.visible === true || v2.visible === true || v3.visible === true ) return true; - - _points3[ 0 ] = v1.positionScreen; - _points3[ 1 ] = v2.positionScreen; - _points3[ 2 ] = v3.positionScreen; - - return _clipBox.intersectsBox( _boundingBox.setFromPoints( _points3 ) ); - - } - - function checkBackfaceCulling( v1, v2, v3 ) { - - return ( ( v3.positionScreen.x - v1.positionScreen.x ) * - ( v2.positionScreen.y - v1.positionScreen.y ) - - ( v3.positionScreen.y - v1.positionScreen.y ) * - ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0; - - } - - function pushLine( a, b ) { - - var v1 = _vertexPool[ a ]; - var v2 = _vertexPool[ b ]; - - // Clip - - v1.positionScreen.copy( v1.position ).applyMatrix4( _modelViewProjectionMatrix ); - v2.positionScreen.copy( v2.position ).applyMatrix4( _modelViewProjectionMatrix ); - - if ( clipLine( v1.positionScreen, v2.positionScreen ) === true ) { - - // Perform the perspective divide - v1.positionScreen.multiplyScalar( 1 / v1.positionScreen.w ); - v2.positionScreen.multiplyScalar( 1 / v2.positionScreen.w ); - - _line = getNextLineInPool(); - _line.id = object.id; - _line.v1.copy( v1 ); - _line.v2.copy( v2 ); - _line.z = Math.max( v1.positionScreen.z, v2.positionScreen.z ); - _line.renderOrder = object.renderOrder; - - _line.material = object.material; - - if ( object.material.vertexColors === THREE.VertexColors ) { - - _line.vertexColors[ 0 ].fromArray( colors, a * 3 ); - _line.vertexColors[ 1 ].fromArray( colors, b * 3 ); - - } - - _renderData.elements.push( _line ); - - } - - } - - function pushTriangle( a, b, c ) { - - var v1 = _vertexPool[ a ]; - var v2 = _vertexPool[ b ]; - var v3 = _vertexPool[ c ]; - - if ( checkTriangleVisibility( v1, v2, v3 ) === false ) return; - - if ( material.side === THREE.DoubleSide || checkBackfaceCulling( v1, v2, v3 ) === true ) { - - _face = getNextFaceInPool(); - - _face.id = object.id; - _face.v1.copy( v1 ); - _face.v2.copy( v2 ); - _face.v3.copy( v3 ); - _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; - _face.renderOrder = object.renderOrder; - - // use first vertex normal as face normal - - _face.normalModel.fromArray( normals, a * 3 ); - _face.normalModel.applyMatrix3( normalMatrix ).normalize(); - - for ( var i = 0; i < 3; i ++ ) { - - var normal = _face.vertexNormalsModel[ i ]; - normal.fromArray( normals, arguments[ i ] * 3 ); - normal.applyMatrix3( normalMatrix ).normalize(); - - var uv = _face.uvs[ i ]; - uv.fromArray( uvs, arguments[ i ] * 2 ); - - } - - _face.vertexNormalsLength = 3; - - _face.material = object.material; - - _renderData.elements.push( _face ); - - } - - } - - return { - setObject: setObject, - projectVertex: projectVertex, - checkTriangleVisibility: checkTriangleVisibility, - checkBackfaceCulling: checkBackfaceCulling, - pushVertex: pushVertex, - pushNormal: pushNormal, - pushColor: pushColor, - pushUv: pushUv, - pushLine: pushLine, - pushTriangle: pushTriangle - }; - - }; - - var renderList = new RenderList(); - - function projectObject( object ) { - - if ( object.visible === false ) return; - - if ( object instanceof THREE.Light ) { - - _renderData.lights.push( object ); - - } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Points ) { - - if ( object.material.visible === false ) return; - if ( object.frustumCulled === true && _frustum.intersectsObject( object ) === false ) return; - - addObject( object ); - - } else if ( object instanceof THREE.Sprite ) { - - if ( object.material.visible === false ) return; - if ( object.frustumCulled === true && _frustum.intersectsSprite( object ) === false ) return; - - addObject( object ); - - } - - var children = object.children; - - for ( var i = 0, l = children.length; i < l; i ++ ) { - - projectObject( children[ i ] ); - - } - - } - - function addObject( object ) { - - _object = getNextObjectInPool(); - _object.id = object.id; - _object.object = object; - - _vector3.setFromMatrixPosition( object.matrixWorld ); - _vector3.applyMatrix4( _viewProjectionMatrix ); - _object.z = _vector3.z; - _object.renderOrder = object.renderOrder; - - _renderData.objects.push( _object ); - - } - - this.projectScene = function ( scene, camera, sortObjects, sortElements ) { - - _faceCount = 0; - _lineCount = 0; - _spriteCount = 0; - - _renderData.elements.length = 0; - - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); - if ( camera.parent === null ) camera.updateMatrixWorld(); - - _viewMatrix.copy( camera.matrixWorldInverse ); - _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix ); - - _frustum.setFromMatrix( _viewProjectionMatrix ); - - // - - _objectCount = 0; - - _renderData.objects.length = 0; - _renderData.lights.length = 0; - - projectObject( scene ); - - if ( sortObjects === true ) { - - _renderData.objects.sort( painterSort ); - - } - - // - - var objects = _renderData.objects; - - for ( var o = 0, ol = objects.length; o < ol; o ++ ) { - - var object = objects[ o ].object; - var geometry = object.geometry; - - renderList.setObject( object ); - - _modelMatrix = object.matrixWorld; - - _vertexCount = 0; - - if ( object instanceof THREE.Mesh ) { - - if ( geometry instanceof THREE.BufferGeometry ) { - - var attributes = geometry.attributes; - var groups = geometry.groups; - - if ( attributes.position === undefined ) continue; - - var positions = attributes.position.array; - - for ( var i = 0, l = positions.length; i < l; i += 3 ) { - - renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); - - } - - if ( attributes.normal !== undefined ) { - - var normals = attributes.normal.array; - - for ( var i = 0, l = normals.length; i < l; i += 3 ) { - - renderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ); - - } - - } - - if ( attributes.uv !== undefined ) { - - var uvs = attributes.uv.array; - - for ( var i = 0, l = uvs.length; i < l; i += 2 ) { - - renderList.pushUv( uvs[ i ], uvs[ i + 1 ] ); - - } - - } - - if ( geometry.index !== null ) { - - var indices = geometry.index.array; - - if ( groups.length > 0 ) { - - for ( var g = 0; g < groups.length; g ++ ) { - - var group = groups[ g ]; - - for ( var i = group.start, l = group.start + group.count; i < l; i += 3 ) { - - renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); - - } - - } - - } else { - - for ( var i = 0, l = indices.length; i < l; i += 3 ) { - - renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); - - } - - } - - } else { - - for ( var i = 0, l = positions.length / 3; i < l; i += 3 ) { - - renderList.pushTriangle( i, i + 1, i + 2 ); - - } - - } - - } else if ( geometry instanceof THREE.Geometry ) { - - var vertices = geometry.vertices; - var faces = geometry.faces; - var faceVertexUvs = geometry.faceVertexUvs[ 0 ]; - - _normalMatrix.getNormalMatrix( _modelMatrix ); - - var material = object.material; - - var isMultiMaterial = Array.isArray( material ); - - for ( var v = 0, vl = vertices.length; v < vl; v ++ ) { - - var vertex = vertices[ v ]; - - _vector3.copy( vertex ); - - if ( material.morphTargets === true ) { - - var morphTargets = geometry.morphTargets; - var morphInfluences = object.morphTargetInfluences; - - for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { - - var influence = morphInfluences[ t ]; - - if ( influence === 0 ) continue; - - var target = morphTargets[ t ]; - var targetVertex = target.vertices[ v ]; - - _vector3.x += ( targetVertex.x - vertex.x ) * influence; - _vector3.y += ( targetVertex.y - vertex.y ) * influence; - _vector3.z += ( targetVertex.z - vertex.z ) * influence; - - } - - } - - renderList.pushVertex( _vector3.x, _vector3.y, _vector3.z ); - - } - - for ( var f = 0, fl = faces.length; f < fl; f ++ ) { - - var face = faces[ f ]; - - material = isMultiMaterial === true - ? object.material[ face.materialIndex ] - : object.material; - - if ( material === undefined ) continue; - - var side = material.side; - - var v1 = _vertexPool[ face.a ]; - var v2 = _vertexPool[ face.b ]; - var v3 = _vertexPool[ face.c ]; - - if ( renderList.checkTriangleVisibility( v1, v2, v3 ) === false ) continue; - - var visible = renderList.checkBackfaceCulling( v1, v2, v3 ); - - if ( side !== THREE.DoubleSide ) { - - if ( side === THREE.FrontSide && visible === false ) continue; - if ( side === THREE.BackSide && visible === true ) continue; - - } - - _face = getNextFaceInPool(); - - _face.id = object.id; - _face.v1.copy( v1 ); - _face.v2.copy( v2 ); - _face.v3.copy( v3 ); - - _face.normalModel.copy( face.normal ); - - if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { - - _face.normalModel.negate(); - - } - - _face.normalModel.applyMatrix3( _normalMatrix ).normalize(); - - var faceVertexNormals = face.vertexNormals; - - for ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) { - - var normalModel = _face.vertexNormalsModel[ n ]; - normalModel.copy( faceVertexNormals[ n ] ); - - if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { - - normalModel.negate(); - - } - - normalModel.applyMatrix3( _normalMatrix ).normalize(); - - } - - _face.vertexNormalsLength = faceVertexNormals.length; - - var vertexUvs = faceVertexUvs[ f ]; - - if ( vertexUvs !== undefined ) { - - for ( var u = 0; u < 3; u ++ ) { - - _face.uvs[ u ].copy( vertexUvs[ u ] ); - - } - - } - - _face.color = face.color; - _face.material = material; - - _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; - _face.renderOrder = object.renderOrder; - - _renderData.elements.push( _face ); - - } - - } - - } else if ( object instanceof THREE.Line ) { - - _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix ); - - if ( geometry instanceof THREE.BufferGeometry ) { - - var attributes = geometry.attributes; - - if ( attributes.position !== undefined ) { - - var positions = attributes.position.array; - - for ( var i = 0, l = positions.length; i < l; i += 3 ) { - - renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); - - } - - if ( attributes.color !== undefined ) { - - var colors = attributes.color.array; - - for ( var i = 0, l = colors.length; i < l; i += 3 ) { - - renderList.pushColor( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ); - - } - - } - - if ( geometry.index !== null ) { - - var indices = geometry.index.array; - - for ( var i = 0, l = indices.length; i < l; i += 2 ) { - - renderList.pushLine( indices[ i ], indices[ i + 1 ] ); - - } - - } else { - - var step = object instanceof THREE.LineSegments ? 2 : 1; - - for ( var i = 0, l = ( positions.length / 3 ) - 1; i < l; i += step ) { - - renderList.pushLine( i, i + 1 ); - - } - - } - - } - - } else if ( geometry instanceof THREE.Geometry ) { - - var vertices = object.geometry.vertices; - - if ( vertices.length === 0 ) continue; - - v1 = getNextVertexInPool(); - v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix ); - - var step = object instanceof THREE.LineSegments ? 2 : 1; - - for ( var v = 1, vl = vertices.length; v < vl; v ++ ) { - - v1 = getNextVertexInPool(); - v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix ); - - if ( ( v + 1 ) % step > 0 ) continue; - - v2 = _vertexPool[ _vertexCount - 2 ]; - - _clippedVertex1PositionScreen.copy( v1.positionScreen ); - _clippedVertex2PositionScreen.copy( v2.positionScreen ); - - if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) { - - // Perform the perspective divide - _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w ); - _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w ); - - _line = getNextLineInPool(); - - _line.id = object.id; - _line.v1.positionScreen.copy( _clippedVertex1PositionScreen ); - _line.v2.positionScreen.copy( _clippedVertex2PositionScreen ); - - _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z ); - _line.renderOrder = object.renderOrder; - - _line.material = object.material; - - if ( object.material.vertexColors === THREE.VertexColors ) { - - _line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] ); - _line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] ); - - } - - _renderData.elements.push( _line ); - - } - - } - - } - - } else if ( object instanceof THREE.Points ) { - - _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix ); - - if ( geometry instanceof THREE.Geometry ) { - - var vertices = object.geometry.vertices; - - for ( var v = 0, vl = vertices.length; v < vl; v ++ ) { - - var vertex = vertices[ v ]; - - _vector4.set( vertex.x, vertex.y, vertex.z, 1 ); - _vector4.applyMatrix4( _modelViewProjectionMatrix ); - - pushPoint( _vector4, object, camera ); - - } - - } else if ( geometry instanceof THREE.BufferGeometry ) { - - var attributes = geometry.attributes; - - if ( attributes.position !== undefined ) { - - var positions = attributes.position.array; - - for ( var i = 0, l = positions.length; i < l; i += 3 ) { - - _vector4.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ], 1 ); - _vector4.applyMatrix4( _modelViewProjectionMatrix ); - - pushPoint( _vector4, object, camera ); - - } - - } - - } - - } else if ( object instanceof THREE.Sprite ) { - - _vector4.set( _modelMatrix.elements[ 12 ], _modelMatrix.elements[ 13 ], _modelMatrix.elements[ 14 ], 1 ); - _vector4.applyMatrix4( _viewProjectionMatrix ); - - pushPoint( _vector4, object, camera ); - - } - - } - - if ( sortElements === true ) { - - _renderData.elements.sort( painterSort ); - - } - - return _renderData; - - }; - - function pushPoint( _vector4, object, camera ) { - - var invW = 1 / _vector4.w; - - _vector4.z *= invW; - - if ( _vector4.z >= - 1 && _vector4.z <= 1 ) { - - _sprite = getNextSpriteInPool(); - _sprite.id = object.id; - _sprite.x = _vector4.x * invW; - _sprite.y = _vector4.y * invW; - _sprite.z = _vector4.z; - _sprite.renderOrder = object.renderOrder; - _sprite.object = object; - - _sprite.rotation = object.rotation; - - _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[ 0 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 12 ] ) ); - _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[ 5 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 13 ] ) ); - - _sprite.material = object.material; - - _renderData.elements.push( _sprite ); - - } - - } - - // Pools - - function getNextObjectInPool() { - - if ( _objectCount === _objectPoolLength ) { - - var object = new THREE.RenderableObject(); - _objectPool.push( object ); - _objectPoolLength ++; - _objectCount ++; - return object; - - } - - return _objectPool[ _objectCount ++ ]; - - } - - function getNextVertexInPool() { - - if ( _vertexCount === _vertexPoolLength ) { - - var vertex = new THREE.RenderableVertex(); - _vertexPool.push( vertex ); - _vertexPoolLength ++; - _vertexCount ++; - return vertex; - - } - - return _vertexPool[ _vertexCount ++ ]; - - } - - function getNextFaceInPool() { - - if ( _faceCount === _facePoolLength ) { - - var face = new THREE.RenderableFace(); - _facePool.push( face ); - _facePoolLength ++; - _faceCount ++; - return face; - - } - - return _facePool[ _faceCount ++ ]; - - - } - - function getNextLineInPool() { - - if ( _lineCount === _linePoolLength ) { - - var line = new THREE.RenderableLine(); - _linePool.push( line ); - _linePoolLength ++; - _lineCount ++; - return line; - - } - - return _linePool[ _lineCount ++ ]; - - } - - function getNextSpriteInPool() { - - if ( _spriteCount === _spritePoolLength ) { - - var sprite = new THREE.RenderableSprite(); - _spritePool.push( sprite ); - _spritePoolLength ++; - _spriteCount ++; - return sprite; - - } - - return _spritePool[ _spriteCount ++ ]; - - } - - // - - function painterSort( a, b ) { - - if ( a.renderOrder !== b.renderOrder ) { - - return a.renderOrder - b.renderOrder; - - } else if ( a.z !== b.z ) { - - return b.z - a.z; - - } else if ( a.id !== b.id ) { - - return a.id - b.id; - - } else { - - return 0; - - } - - } - - function clipLine( s1, s2 ) { - - var alpha1 = 0, alpha2 = 1, - - // Calculate the boundary coordinate of each vertex for the near and far clip planes, - // Z = -1 and Z = +1, respectively. - - bc1near = s1.z + s1.w, - bc2near = s2.z + s2.w, - bc1far = - s1.z + s1.w, - bc2far = - s2.z + s2.w; - - if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) { - - // Both vertices lie entirely within all clip planes. - return true; - - } else if ( ( bc1near < 0 && bc2near < 0 ) || ( bc1far < 0 && bc2far < 0 ) ) { - - // Both vertices lie entirely outside one of the clip planes. - return false; - - } else { - - // The line segment spans at least one clip plane. - - if ( bc1near < 0 ) { - - // v1 lies outside the near plane, v2 inside - alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) ); - - } else if ( bc2near < 0 ) { - - // v2 lies outside the near plane, v1 inside - alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) ); - - } - - if ( bc1far < 0 ) { - - // v1 lies outside the far plane, v2 inside - alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) ); - - } else if ( bc2far < 0 ) { - - // v2 lies outside the far plane, v2 inside - alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) ); - - } - - if ( alpha2 < alpha1 ) { - - // The line segment spans two boundaries, but is outside both of them. - // (This can't happen when we're only clipping against just near/far but good - // to leave the check here for future usage if other clip planes are added.) - return false; - - } else { - - // Update the s1 and s2 vertices to match the clipped line segment. - s1.lerp( s2, alpha1 ); - s2.lerp( s1, 1 - alpha2 ); - - return true; - - } - - } - - } - -}; \ No newline at end of file diff --git a/examples/models/platform/platform.json b/examples/models/platform/platform.json deleted file mode 100644 index eee956a..0000000 --- a/examples/models/platform/platform.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "metadata": { - "version": 4, - "type": "geometry" - }, - "vertices": [2.78,0,-8.67,6.12,0,6.74,-8.9,0,1.93,-2.78,0,-8.67,8.9,0,1.93,-6.12,0,6.74,2.78,2.8,-14.65,11.3,2.8,9.73,-14.08,2.8,4.92,-2.78,2.8,-14.65,14.08,2.8,4.92,-11.3,2.8,9.73,0,2.8,-14.65,12.69,2.8,7.32,-12.69,2.8,7.32,0,0,-8.67,7.51,0,4.33,-7.51,0,4.33,4.58,2.8,-16.45,11.95,2.8,12.19,-16.53,2.8,4.26,-4.58,2.8,-16.45,16.53,2.8,4.26,-11.95,2.8,12.19,0,2.8,-18.97,16.43,2.8,9.49,-16.43,2.8,9.49,4.58,2.8,-21.59,16.41,2.8,14.76,-20.99,2.8,6.83,-4.58,2.8,-21.59,20.99,2.8,6.83,-16.41,2.8,14.76,0,2.8,-23.37,20.24,2.8,11.68,-20.24,2.8,11.68,2.79,2.8,-23.37,18.85,2.8,14.1,-21.63,2.8,9.27,-2.79,2.8,-23.37,21.63,2.8,9.27,-18.85,2.8,14.1,16.03,7.6,-16.45,6.23,7.6,22.1,-22.26,7.6,-5.66,-16.03,7.6,-16.45,22.26,7.6,-5.66,-6.23,7.6,22.1,16.03,7.6,-21.59,10.68,7.6,24.68,-26.71,7.6,-3.09,-16.03,7.6,-21.59,26.71,7.6,-3.09,-10.68,7.6,24.68,16.03,7.6,-16.45,6.23,7.6,22.11,-22.26,7.6,-5.66,-16.03,7.6,-16.45,22.26,7.6,-5.66,-6.23,7.6,22.11,16.03,7.6,-21.59,10.68,7.6,24.68,-26.71,7.6,-3.09,-16.03,7.6,-21.59,26.71,7.6,-3.09,-10.68,7.6,24.68,20.64,7.6,-21.59,8.38,7.6,28.67,-29.01,7.6,-7.08,-20.64,7.6,-21.59,29.01,7.6,-7.08,-8.38,7.6,28.67,17.4,7.6,-16.45,5.54,7.6,23.29,-22.94,7.6,-6.85,-17.4,7.6,-16.45,22.94,7.6,-6.85,-5.54,7.6,23.29,16.03,7.6,-18.74,8.22,7.6,23.26,-24.25,7.6,-4.51,-16.03,7.6,-18.74,24.25,7.6,-4.51,-8.22,7.6,23.26,19.99,7.6,-13.49,1.69,7.6,24.06,-21.68,7.6,-10.57,-19.99,7.6,-13.49,21.68,7.6,-10.57,-1.69,7.6,24.06,18.88,7.6,-13.79,2.5,7.6,23.24,-21.38,7.6,-9.46,-18.88,7.6,-13.79,21.38,7.6,-9.46,-2.5,7.6,23.24,20.83,7.6,-12.02,0,7.6,24.05,-20.83,7.6,-12.03,-20.83,7.6,-12.02,20.83,7.6,-12.03,0,7.6,24.05,24.89,7.6,-14.37,0,7.6,28.74,-24.89,7.6,-14.37,-24.89,7.6,-14.37,24.89,7.6,-14.37,0,7.6,28.74,16.32,7.6,-10.91,1.29,7.6,19.59,-17.61,7.6,-8.68,-16.32,7.6,-10.91,17.61,7.6,-8.68,-1.29,7.6,19.59,17,7.6,-9.82,0,7.6,19.63,-17,7.6,-9.82,-17,7.6,-9.82,17,7.6,-9.82,0,7.6,19.63,3.59,0,-2.07,0,0,4.15,-3.59,0,-2.07,-3.59,0,-2.07,3.59,0,-2.07,0,0,4.15,0,0,-4.15,3.6,0,2.08,-3.6,0,2.08,8.9,0,-5.14,0,0,10.28,-8.9,0,-5.14,-8.9,0,-5.14,8.9,0,-5.14,0,0,10.28,2.78,2.8,-14.65,11.3,2.8,9.73,-14.08,2.8,4.92,-2.78,2.8,-14.65,14.08,2.8,4.92,-11.3,2.8,9.73,2.78,0,-8.67,6.12,0,6.74,-8.9,0,1.93,-2.78,0,-8.67,8.9,0,1.93,-6.12,0,6.74,4.58,2.8,-16.45,11.95,2.8,12.19,-16.53,2.8,4.26,-4.58,2.8,-16.45,16.53,2.8,4.26,-11.95,2.8,12.19,0,2.8,-23.37,20.24,2.8,11.68,-20.24,2.8,11.68,2.79,2.8,-23.37,18.85,2.8,14.1,-21.63,2.8,9.27,-2.79,2.8,-23.37,21.63,2.8,9.27,-18.85,2.8,14.1,4.58,2.8,-21.59,16.41,2.8,14.76,-20.99,2.8,6.83,-4.58,2.8,-21.59,20.99,2.8,6.83,-16.41,2.8,14.76,16.03,7.6,-21.59,10.68,7.6,24.68,-26.71,7.6,-3.09,-16.03,7.6,-21.59,26.71,7.6,-3.09,-10.68,7.6,24.68,16.03,7.6,-16.45,6.23,7.6,22.1,-22.26,7.6,-5.66,-16.03,7.6,-16.45,22.26,7.6,-5.66,-6.23,7.6,22.1,20.64,7.6,-21.59,8.38,7.6,28.67,-29.01,7.6,-7.08,-20.64,7.6,-21.59,29.01,7.6,-7.08,-8.38,7.6,28.67,16.03,7.6,-21.59,10.68,7.6,24.68,-26.71,7.6,-3.09,-16.03,7.6,-21.59,26.71,7.6,-3.09,-10.68,7.6,24.68,16.03,7.6,-16.45,6.23,7.6,22.11,-22.26,7.6,-5.66,-16.03,7.6,-16.45,22.26,7.6,-5.66,-6.23,7.6,22.11,17.4,7.6,-16.45,5.54,7.6,23.29,-22.94,7.6,-6.85,-17.4,7.6,-16.45,22.94,7.6,-6.85,-5.54,7.6,23.29,18.88,7.6,-13.79,2.5,7.6,23.24,-21.38,7.6,-9.46,-18.88,7.6,-13.79,21.38,7.6,-9.46,-2.5,7.6,23.24,24.89,7.6,-14.37,0,7.6,28.74,-24.89,7.6,-14.37,-24.89,7.6,-14.37,24.89,7.6,-14.37,0,7.6,28.74,17,7.6,-9.82,0,7.6,19.63,-17,7.6,-9.82,-17,7.6,-9.82,17,7.6,-9.82,0,7.6,19.63,16.32,7.6,-10.91,1.29,7.6,19.59,-17.61,7.6,-8.68,-16.32,7.6,-10.91,17.61,7.6,-8.68,-1.29,7.6,19.59,3.59,0,-2.07,0,0,4.15,-3.59,0,-2.07,-3.59,0,-2.07,3.59,0,-2.07,0,0,4.15,0,0,-4.15,3.6,0,2.08,-3.6,0,2.08,8.9,0,-5.14,0,0,10.28,-8.9,0,-5.14,-8.9,0,-5.14,8.9,0,-5.14,0,0,10.28,2.81,-0.85,-8.67,6.1,-0.85,6.76,-8.91,-0.85,1.9,-2.81,-0.85,-8.67,8.91,-0.85,1.9,-6.1,-0.85,6.76,8.93,-0.85,-5.14,-0.01,-0.85,10.3,-8.92,-0.85,-5.16,-8.93,-0.85,-5.14,8.92,-0.85,-5.16,0.01,-0.85,10.3,3.62,-0.85,-2.07,-0.01,-0.85,4.17,-3.6,-0.85,-2.1,-3.62,-0.85,-2.07,3.6,-0.85,-2.1,0.01,-0.85,4.17,0,-0.85,-8.67,7.5,-0.85,4.33,-7.5,-0.85,4.33,0,-0.85,-4.15,3.6,-0.85,2.08,-3.6,-0.85,2.08,18.9,6.75,-13.79,2.49,6.75,23.26,-21.39,6.75,-9.48,-18.9,6.75,-13.79,21.39,6.75,-9.48,-2.49,6.75,23.26,16.35,6.75,-10.91,1.28,6.75,19.61,-17.62,6.75,-8.7,-16.35,6.75,-10.91,17.62,6.75,-8.7,-1.28,6.75,19.61,17.03,6.75,-9.83,0,6.75,19.66,-17.03,6.75,-9.83,-17.03,6.75,-9.83,17.03,6.75,-9.83,0,6.75,19.66,20.85,6.75,-12.04,0,6.75,24.08,-20.85,6.75,-12.04,-20.85,6.75,-12.04,20.85,6.75,-12.04,0,6.75,24.08,24.91,6.75,-14.38,0,6.75,28.77,-24.91,6.75,-14.38,-24.91,6.75,-14.38,24.91,6.75,-14.38,0,6.75,28.77,20.66,6.75,-21.59,8.36,6.75,28.69,-29.03,6.75,-7.1,-20.66,6.75,-21.59,29.03,6.75,-7.1,-8.36,6.75,28.69,17.43,6.75,-16.44,5.53,6.75,23.31,-22.95,6.75,-6.87,-17.43,6.75,-16.44,22.95,6.75,-6.87,-5.53,6.75,23.31,16.06,6.75,-18.74,8.2,6.75,23.28,-24.26,6.75,-4.54,-16.06,6.75,-18.74,24.26,6.75,-4.54,-8.2,6.75,23.28,16.06,6.75,-16.44,6.21,6.75,22.13,-22.27,6.75,-5.68,-16.06,6.75,-16.44,22.27,6.75,-5.68,-6.21,6.75,22.13,16.06,6.75,-21.59,10.67,6.75,24.7,-26.72,6.75,-3.11,-16.06,6.75,-21.59,26.72,6.75,-3.11,-10.67,6.75,24.7,16.06,6.75,-16.44,6.21,6.75,22.13,-22.27,6.75,-5.68,-16.06,6.75,-16.44,22.27,6.75,-5.68,-6.21,6.75,22.13,4.6,1.95,-16.44,11.94,1.95,12.21,-16.54,1.95,4.24,-4.6,1.95,-16.44,16.54,1.95,4.24,-11.94,1.95,12.21,16.06,6.75,-21.59,10.67,6.75,24.7,-26.72,6.75,-3.11,-16.06,6.75,-21.59,26.72,6.75,-3.11,-10.67,6.75,24.7,4.6,1.95,-21.59,16.39,1.95,14.78,-21,1.95,6.81,-4.6,1.95,-21.59,21,1.95,6.81,-16.39,1.95,14.78,2.81,1.95,-23.37,18.83,1.95,14.12,-21.65,1.95,9.25,-2.81,1.95,-23.37,21.65,1.95,9.25,-18.83,1.95,14.12,0,1.95,-23.37,20.23,1.95,11.68,-20.23,1.95,11.68,0,1.95,-18.97,16.43,1.95,9.49,-16.43,1.95,9.48,0,1.95,-18.97,16.43,1.95,9.48,-16.43,1.95,9.49,2.81,1.95,-14.65,11.28,1.95,9.75,-14.09,1.95,4.89,-2.81,1.95,-14.65,14.09,1.95,4.89,-11.28,1.95,9.75,0,1.95,-14.65,12.69,1.95,7.32,-12.69,1.95,7.32,20.02,6.75,-13.49,1.67,6.75,24.08,-21.69,6.75,-10.59,-20.02,6.75,-13.49,21.69,6.75,-10.59,-1.67,6.75,24.08], - "uvs": [[0.007544,0.336649,0.749592,0.170358,0.006326,0.171122,0.750809,0.335884,0.144602,0.54169,0.560668,0.358683,0.143734,0.359599,0.318466,0.658909,0.81479,0.657819,0.984918,0.357752,0.986279,0.540201,0.003455,0.335026,0.996032,0.00243,0.002592,0.00243,0.996894,0.335026,0.492694,0.573781,0.548034,0.637342,0.335213,0.637987,0.140199,0.559941,0.326277,0.345848,0.855424,0.598001,0.78998,0.641537,0.993052,0.346056,0.989689,0.599244,0.843989,0.781591,0.745574,0.714764,0.843162,0.920011,0.309465,0.919927,0.304178,0.814147,0.153419,0.437245,0.349552,0.667112,0.362164,0.355232,0.709627,0.667198,0.974985,0.354255,0.003064,0.94063,0.122096,0.3414,0.003193,0.341511,0.121967,0.940363,0.003319,0.795986,0.122431,0.451794,0.003616,0.452352,0.122134,0.796857,0.003647,0.685438,0.12223,0.339336,0.003839,0.339481,0.122728,0.685409,0.004466,0.687038,0.123262,0.56705,0.00372,0.566846,0.122929,0.687242,0.005123,0.997825,0.123437,0.338751,0.004869,0.338817,0.123691,0.997759,0.004862,0.794918,0.122534,0.5669,0.004517,0.567196,0.121532,0.794622,0.005099,0.684676,0.122529,0.557363,0.004317,0.557682,0.121964,0.685271,0.004985,0.793209,0.122398,0.340454,0.005276,0.340628,0.122106,0.793034,0.998771,0.927054,0.162297,0.998734,0.162118,0.926526,0.998949,0.999262,0.998246,0.927837,0.133282,0.99941,0.13347,0.927365,0.998058,0.999882,0.003412,0.795023,0.122242,0.570718,0.003775,0.570941,0.12188,0.7948,0.122264,0.339711,0.003797,0.339934,0.004173,0.795395,0.122582,0.566445,0.004111,0.566812,0.122645,0.795028,0.500355,0.928348,0.970999,0.999245,0.971331,0.927953,0.500023,0.998839,0.793582,0.672092,0.135372,0.344864,0.415507,0.67293,0.778833,0.344616,0.99841,0.430304,0.435298,0.44406,0.145318,0.601852,0.348856,0.405663,0.346332,0.644244,0.280435,0.600399,0.81261,0.346076,0.141657,0.346868,0.589797,0.639738,0.803953,0.640203,1.0001,0.561458,0.650819,0.577007,0.568735,0.349316,0.134015,0.536057,0.310106,0.656051,0.134517,0.34932,0.81809,0.656048,0.995464,0.349313,0.995465,0.535684]], - "faces": [24,0,12,15,0,1,2,0,24,6,12,0,3,1,0,0,24,1,13,16,0,1,2,1,24,7,13,1,3,1,0,2,24,2,14,17,0,1,2,3,24,8,14,2,3,1,0,3,24,12,3,15,1,0,2,0,24,9,3,12,3,0,1,0,24,13,4,16,1,0,2,4,24,10,4,13,3,0,1,4,24,14,5,17,1,0,2,5,24,11,5,14,3,0,1,6,24,6,24,12,4,5,6,7,24,18,24,6,7,5,4,8,24,7,25,13,4,5,6,7,24,19,25,7,7,5,4,7,24,8,26,14,4,5,6,8,24,20,26,8,7,5,4,7,24,24,9,12,5,4,6,7,24,21,9,24,7,4,5,8,24,25,10,13,5,4,6,8,24,22,10,25,7,4,5,7,24,26,11,14,5,4,6,7,24,23,11,26,7,4,5,7,24,18,27,24,7,8,5,8,24,19,28,25,7,8,5,8,24,20,29,26,7,8,5,8,24,30,21,24,8,7,5,8,24,31,22,25,8,7,5,8,24,32,23,26,8,7,5,8,24,33,27,36,9,8,10,8,24,24,27,33,5,8,9,8,24,34,28,37,9,8,10,8,24,25,28,34,5,8,9,8,24,35,29,38,9,8,10,8,24,26,29,35,5,8,9,8,24,30,33,39,8,9,10,8,24,24,33,30,5,9,8,8,24,31,34,40,8,9,10,8,24,25,34,31,5,9,8,8,24,32,35,41,8,9,10,8,24,26,35,32,5,9,8,8,24,18,48,27,11,12,13,9,24,42,48,18,14,12,11,9,24,19,49,28,11,12,13,10,24,43,49,19,14,12,11,11,24,20,50,29,11,12,13,12,24,44,50,20,14,12,11,13,24,51,21,30,12,11,13,14,24,45,21,51,14,11,12,14,24,52,22,31,12,11,13,15,24,46,22,52,14,11,12,16,24,53,23,32,12,11,13,17,24,47,23,53,14,11,12,18,24,54,72,78,15,16,17,8,24,55,73,79,15,16,17,8,24,56,74,80,15,16,17,8,24,75,57,81,16,15,17,8,24,76,58,82,16,15,17,8,24,77,59,83,16,15,17,8,24,72,60,78,16,18,17,8,24,66,60,72,19,18,16,8,24,73,61,79,16,18,17,8,24,67,61,73,19,18,16,8,24,74,62,80,16,18,17,8,24,68,62,74,19,18,16,8,24,63,75,81,18,16,17,8,24,69,75,63,19,16,18,8,24,64,76,82,18,16,17,8,24,70,76,64,19,16,18,8,24,65,77,83,18,16,17,8,24,71,77,65,19,16,18,8,24,72,84,66,16,20,19,8,24,90,84,72,21,20,16,8,24,73,85,67,16,20,19,8,24,91,85,73,21,20,16,8,24,74,86,68,16,20,19,8,24,92,86,74,21,20,16,8,24,87,75,69,20,16,19,8,24,93,75,87,21,16,20,8,24,88,76,70,20,16,19,8,24,94,76,88,21,16,20,8,24,89,77,71,20,16,19,8,24,95,77,89,21,16,20,8,24,84,102,66,20,22,19,8,24,96,102,84,23,22,20,7,24,85,103,67,20,22,19,7,24,97,103,85,23,22,20,8,24,86,104,68,20,22,19,8,24,98,104,86,23,22,20,8,24,105,87,69,22,20,19,8,24,99,87,105,23,20,22,8,24,106,88,70,22,20,19,8,24,100,88,106,23,20,22,8,24,107,89,71,22,20,19,8,24,101,89,107,23,20,22,8,24,84,90,96,24,25,26,8,24,85,91,97,24,25,26,7,24,86,92,98,24,25,26,8,24,93,87,99,25,24,26,8,24,94,88,100,25,24,26,8,24,95,89,101,25,24,26,7,24,90,114,96,25,27,26,8,24,108,114,90,28,27,25,8,24,91,115,97,25,27,26,8,24,109,115,91,28,27,25,8,24,92,116,98,25,27,26,8,24,110,116,92,28,27,25,8,24,117,93,99,27,25,26,8,24,111,93,117,28,25,27,8,24,118,94,100,27,25,26,8,24,112,94,118,28,25,27,8,24,119,95,101,27,25,26,8,24,113,95,119,28,25,27,8,24,15,126,0,29,30,31,7,24,16,127,1,29,30,31,8,24,17,128,2,29,30,31,7,24,126,15,3,30,29,31,7,24,127,16,4,30,29,31,7,24,128,17,5,30,29,31,8,24,0,120,129,31,32,33,8,24,126,120,0,30,32,31,8,24,1,121,130,31,32,33,8,24,127,121,1,30,32,31,8,24,2,122,131,31,32,33,8,24,128,122,2,30,32,31,8,24,123,3,132,32,31,33,8,24,126,3,123,30,31,32,8,24,124,4,133,32,31,33,8,24,127,4,124,30,31,32,8,24,125,5,134,32,31,33,8,24,128,5,125,30,31,32,8,24,237,243,141,34,35,36,19,24,249,243,237,37,35,34,20,24,238,244,142,34,35,36,21,24,250,244,238,37,35,34,22,24,239,245,143,34,35,36,23,24,251,245,239,37,35,34,24,24,246,240,144,35,34,36,25,24,252,240,246,37,34,35,26,24,247,241,145,35,34,36,27,24,253,241,247,37,34,35,28,24,248,242,146,35,34,36,29,24,254,242,248,37,34,35,30,24,234,255,228,38,39,40,31,24,264,255,234,41,39,38,32,24,235,256,229,38,39,40,33,24,265,256,235,41,39,38,34,24,236,257,230,38,39,40,35,24,266,257,236,41,39,38,36,24,258,234,231,39,38,40,37,24,264,234,258,41,38,39,38,24,259,235,232,39,38,40,39,24,265,235,259,41,38,39,40,24,260,236,233,39,38,40,41,24,266,236,260,41,38,39,42,24,204,273,222,42,43,44,43,24,267,273,204,45,43,42,44,24,205,274,223,42,43,44,45,24,268,274,205,45,43,42,46,24,206,275,224,42,43,44,47,24,269,275,206,45,43,42,48,24,276,207,225,43,42,44,49,24,270,207,276,45,42,43,50,24,277,208,226,43,42,44,51,24,271,208,277,45,42,43,52,24,278,209,227,43,42,44,53,24,272,209,278,45,42,43,54,24,222,279,216,46,47,48,55,24,273,279,222,49,47,46,56,24,223,280,217,46,47,48,57,24,274,280,223,49,47,46,58,24,224,281,218,46,47,48,59,24,275,281,224,49,47,46,60,24,282,225,219,47,46,48,61,24,276,225,282,49,46,47,62,24,283,226,220,47,46,48,63,24,277,226,283,49,46,47,64,24,284,227,221,47,46,48,65,24,278,227,284,49,46,47,66,24,210,297,180,50,51,52,67,24,291,297,210,53,51,50,68,24,211,298,181,50,51,52,69,24,292,298,211,53,51,50,70,24,212,299,182,50,51,52,71,24,293,299,212,53,51,50,72,24,300,213,183,51,50,52,73,24,294,213,300,53,50,51,74,24,301,214,184,51,50,52,75,24,295,214,301,53,50,51,76,24,302,215,185,51,50,52,77,24,296,215,302,53,50,51,78,24,198,267,204,54,55,56,79,24,303,267,198,57,55,54,80,24,199,268,205,54,55,56,81,24,304,268,199,57,55,54,82,24,200,269,206,54,55,56,83,24,305,269,200,57,55,54,84,24,270,201,207,55,54,56,85,24,306,201,270,57,54,55,86,24,271,202,208,55,54,56,87,24,307,202,271,57,54,55,88,24,272,203,209,55,54,56,89,24,308,203,272,57,54,55,90,24,192,303,198,58,59,60,91,24,315,303,192,61,59,58,92,24,193,304,199,58,59,60,93,24,316,304,193,61,59,58,94,24,194,305,200,58,59,60,95,24,317,305,194,61,59,58,96,24,306,195,201,59,58,60,91,24,318,195,306,61,58,59,97,24,307,196,202,59,58,60,98,24,319,196,307,61,58,59,99,24,308,197,203,59,58,60,100,24,320,197,308,61,58,59,101,24,180,321,186,62,63,64,102,24,297,321,180,65,63,62,102,24,181,322,187,62,63,64,103,24,298,322,181,65,63,62,104,24,182,323,188,62,63,64,105,24,299,323,182,65,63,62,106,24,324,183,189,63,62,64,102,24,300,183,324,65,62,63,102,24,325,184,190,63,62,64,107,24,301,184,325,65,62,63,108,24,326,185,191,63,62,64,109,24,302,185,326,65,62,63,110,24,147,327,174,66,67,68,111,24,333,327,147,69,67,66,112,24,148,328,175,66,67,68,113,24,334,328,148,69,67,66,114,24,149,329,176,66,67,68,115,24,335,329,149,69,67,66,116,24,330,150,177,67,66,68,117,24,336,150,330,69,66,67,118,24,331,151,178,67,66,68,119,24,337,151,331,69,66,67,120,24,332,152,179,67,66,68,121,24,338,152,332,69,66,67,122,24,168,345,162,70,71,72,102,24,339,345,168,73,71,70,123,24,169,346,163,70,71,72,124,24,340,346,169,73,71,70,125,24,170,347,164,70,71,72,126,24,341,347,170,73,71,70,127,24,348,171,165,71,70,72,102,24,342,171,348,73,70,71,102,24,349,172,166,71,70,72,128,24,343,172,349,73,70,71,129,24,350,173,167,71,70,72,130,24,344,173,350,73,70,71,131,24,162,351,156,74,75,76,132,24,345,351,162,77,75,74,133,24,163,352,157,74,75,76,134,24,346,352,163,77,75,74,135,24,164,353,158,74,75,76,136,24,347,353,164,77,75,74,137,24,354,165,159,75,74,76,138,24,348,165,354,77,74,75,139,24,355,166,160,75,74,76,140,24,349,166,355,77,74,75,141,24,356,167,161,75,74,76,142,24,350,167,356,77,74,75,143,24,156,357,153,76,78,79,102,24,351,357,156,75,78,76,102,24,157,358,154,76,78,79,144,24,352,358,157,75,78,76,145,24,158,359,155,76,78,79,146,24,353,359,158,75,78,76,147,24,357,159,153,78,76,79,102,24,354,159,357,75,76,78,102,24,358,160,154,78,76,79,148,24,355,160,358,75,76,78,149,24,359,161,155,78,76,79,150,24,356,161,359,75,76,78,151,24,135,333,147,80,81,82,152,24,366,333,135,83,81,80,153,24,136,334,148,80,81,82,154,24,367,334,136,83,81,80,155,24,137,335,149,80,81,82,156,24,368,335,137,83,81,80,157,24,336,138,150,81,80,82,158,24,369,138,336,83,80,81,159,24,337,139,151,81,80,82,160,24,370,139,337,83,80,81,161,24,338,140,152,81,80,82,162,24,371,140,338,83,80,81,163,24,141,366,135,84,85,86,164,24,243,366,141,87,85,84,165,24,142,367,136,84,85,86,166,24,244,367,142,87,85,84,167,24,143,368,137,84,85,86,168,24,245,368,143,87,85,84,169,24,369,144,138,85,84,86,170,24,246,144,369,87,84,85,171,24,370,145,139,85,84,86,172,24,247,145,370,87,84,85,173,24,371,146,140,85,84,86,174,24,248,146,371,87,84,85,175,24,264,249,255,88,89,90,176,24,243,249,264,91,89,88,177,24,265,250,256,88,89,90,176,24,244,250,265,91,89,88,176,24,266,251,257,88,89,90,176,24,245,251,266,91,89,88,176,24,252,264,258,89,88,90,176,24,246,264,252,91,88,89,177,24,253,265,259,89,88,90,176,24,247,265,253,91,88,89,176,24,254,266,260,89,88,90,176,24,248,266,254,91,88,89,177,24,264,261,243,88,92,91,176,24,265,262,244,88,92,91,176,24,266,263,245,88,92,91,176,24,261,264,246,92,88,91,176,24,262,265,247,92,88,91,176,24,263,266,248,92,88,91,176,24,273,285,279,93,94,95,176,24,267,285,273,96,94,93,176,24,274,286,280,93,94,95,176,24,268,286,274,96,94,93,176,24,275,287,281,93,94,95,176,24,269,287,275,96,94,93,176,24,288,276,282,94,93,95,176,24,270,276,288,96,93,94,176,24,289,277,283,94,93,95,176,24,271,277,289,96,93,94,177,24,290,278,284,94,93,95,176,24,272,278,290,96,93,94,177,24,267,375,285,96,97,94,176,24,268,376,286,96,97,94,176,24,269,377,287,96,97,94,176,24,378,270,288,97,96,94,176,24,379,271,289,97,96,94,176,24,380,272,290,97,96,94,176,24,285,297,291,94,98,99,176,24,375,297,285,97,98,94,176,24,286,298,292,94,98,99,176,24,376,298,286,97,98,94,176,24,287,299,293,94,98,99,176,24,377,299,287,97,98,94,176,24,300,288,294,98,94,99,176,24,378,288,300,97,94,98,176,24,301,289,295,98,94,99,176,24,379,289,301,97,94,98,176,24,302,290,296,98,94,99,176,24,380,290,302,97,94,98,177,24,267,297,375,96,98,97,176,24,303,297,267,100,98,96,176,24,268,298,376,96,98,97,176,24,304,298,268,100,98,96,176,24,269,299,377,96,98,97,176,24,305,299,269,100,98,96,176,24,300,270,378,98,96,97,176,24,306,270,300,100,96,98,176,24,301,271,379,98,96,97,176,24,307,271,301,100,96,98,176,24,302,272,380,98,96,97,176,24,308,272,302,100,96,98,176,24,297,309,321,98,101,102,177,24,303,309,297,100,101,98,176,24,298,310,322,98,101,102,177,24,304,310,298,100,101,98,176,24,299,311,323,98,101,102,176,24,305,311,299,100,101,98,177,24,312,300,324,101,98,102,177,24,306,300,312,100,98,101,177,24,313,301,325,101,98,102,177,24,307,301,313,100,98,101,177,24,314,302,326,101,98,102,177,24,308,302,314,100,98,101,176,24,303,315,309,100,103,101,176,24,304,316,310,100,103,101,177,24,305,317,311,100,103,101,176,24,318,306,312,103,100,101,176,24,319,307,313,103,100,101,176,24,320,308,314,103,100,101,176,24,327,345,339,11,12,13,178,24,333,345,327,14,12,11,178,24,328,346,340,11,12,13,179,24,334,346,328,14,12,11,180,24,329,347,341,11,12,13,181,24,335,347,329,14,12,11,182,24,348,330,342,12,11,13,183,24,336,330,348,14,11,12,183,24,349,331,343,12,11,13,184,24,337,331,349,14,11,12,185,24,350,332,344,12,11,13,186,24,338,332,350,14,11,12,187,24,360,351,345,104,105,106,176,24,357,351,360,107,105,104,176,24,361,352,346,104,105,106,176,24,358,352,361,107,105,104,176,24,362,353,347,104,105,106,176,24,359,353,362,107,105,104,176,24,354,363,348,105,104,106,176,24,357,363,354,107,104,105,176,24,355,364,349,105,104,106,176,24,358,364,355,107,104,105,176,24,356,365,350,105,104,106,176,24,359,365,356,107,104,105,176,24,345,333,360,106,108,104,176,24,346,334,361,106,108,104,177,24,347,335,362,106,108,104,176,24,336,348,363,108,106,104,176,24,337,349,364,108,106,104,176,24,338,350,365,108,106,104,177,24,333,372,360,108,109,104,177,24,366,372,333,110,109,108,176,24,334,373,361,108,109,104,176,24,367,373,334,110,109,108,176,24,335,374,362,108,109,104,176,24,368,374,335,110,109,108,176,24,372,336,363,109,108,104,177,24,369,336,372,110,108,109,176,24,373,337,364,109,108,104,176,24,370,337,373,110,108,109,176,24,374,338,365,109,108,104,176,24,371,338,374,110,108,109,176,24,366,261,372,0,1,2,188,24,243,261,366,3,1,0,188,24,367,262,373,0,1,2,189,24,244,262,367,3,1,0,190,24,368,263,374,0,1,2,191,24,245,263,368,3,1,0,192,24,261,369,372,1,0,2,188,24,246,369,261,3,0,1,188,24,262,370,373,1,0,2,193,24,247,370,262,3,0,1,194,24,263,371,374,1,0,2,195,24,248,371,263,3,0,1,196], - "normals": [] -} \ No newline at end of file diff --git a/examples/node-render.mjs b/examples/node-render.mjs new file mode 100644 index 0000000..0eab8e7 --- /dev/null +++ b/examples/node-render.mjs @@ -0,0 +1,43 @@ +// Prints a static HTML render, after `npm run build`: node examples/node-render.mjs > examples/static.html +import { GlobalRegistrator } from "@happy-dom/global-registrator"; + +GlobalRegistrator.register(); + +const THREE = await import("three"); +const { C3RRenderer } = await import("c3r-three"); +const { cssText } = await import("c3r"); + +const width = 800; +const height = 600; + +const scene = new THREE.Scene(); +const camera = new THREE.PerspectiveCamera(70, width / height, 1, 1000); +camera.position.z = 500; + +// TextureLoader needs a browser +const texture = new THREE.Texture( + Object.assign(document.createElement("img"), { + src: "public/textures/crate.gif", + }), +); +const cube = new THREE.Mesh( + new THREE.BoxGeometry(200, 200, 200), + new THREE.MeshBasicMaterial({ map: texture }), +); +cube.rotation.set(0.4, 0.6, 0); +scene.add(cube); + +const renderer = new C3RRenderer(); +renderer.setSize(width, height); +renderer.render(scene, camera); + +process.stdout.write(` + + + + C3R static render + + + ${renderer.domElement.outerHTML} + +`); diff --git a/examples/package.json b/examples/package.json new file mode 100644 index 0000000..7780dd3 --- /dev/null +++ b/examples/package.json @@ -0,0 +1,14 @@ +{ + "name": "c3r-examples", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --open", + "build": "vite build" + }, + "devDependencies": { + "gl-matrix": "^3.4.4", + "three": "^0.186.1", + "vite": "^8.3.5" + } +} diff --git a/examples/js/libs/ammo.js b/examples/public/js/libs/ammo.js similarity index 100% rename from examples/js/libs/ammo.js rename to examples/public/js/libs/ammo.js diff --git a/examples/models/obj/suzanne/suzanne.obj b/examples/public/models/obj/suzanne/suzanne.obj similarity index 100% rename from examples/models/obj/suzanne/suzanne.obj rename to examples/public/models/obj/suzanne/suzanne.obj diff --git a/examples/models/platform/platform.jpg b/examples/public/models/platform/platform.jpg similarity index 100% rename from examples/models/platform/platform.jpg rename to examples/public/models/platform/platform.jpg diff --git a/examples/public/models/platform/platform.json b/examples/public/models/platform/platform.json new file mode 100644 index 0000000..6cb3278 --- /dev/null +++ b/examples/public/models/platform/platform.json @@ -0,0 +1 @@ +{"metadata":{"version":4.5,"type":"BufferGeometry","generator":"BufferGeometry.toJSON"},"type":"BufferGeometry","data":{"attributes":{"position":{"itemSize":3,"type":"Float32Array","array":[2.78,0,-8.67,0,2.8,-14.65,0,0,-8.67,2.78,2.8,-14.65,0,2.8,-14.65,2.78,0,-8.67,6.12,0,6.74,12.69,2.8,7.32,7.51,0,4.33,11.3,2.8,9.73,12.69,2.8,7.32,6.12,0,6.74,-8.9,0,1.93,-12.69,2.8,7.32,-7.51,0,4.33,-14.08,2.8,4.92,-12.69,2.8,7.32,-8.9,0,1.93,0,2.8,-14.65,-2.78,0,-8.67,0,0,-8.67,-2.78,2.8,-14.65,-2.78,0,-8.67,0,2.8,-14.65,12.69,2.8,7.32,8.9,0,1.93,7.51,0,4.33,14.08,2.8,4.92,8.9,0,1.93,12.69,2.8,7.32,-12.69,2.8,7.32,-6.12,0,6.74,-7.51,0,4.33,-11.3,2.8,9.73,-6.12,0,6.74,-12.69,2.8,7.32,2.78,2.8,-14.65,0,2.8,-18.97,0,2.8,-14.65,4.58,2.8,-16.45,0,2.8,-18.97,2.78,2.8,-14.65,11.3,2.8,9.73,16.43,2.8,9.49,12.69,2.8,7.32,11.95,2.8,12.19,16.43,2.8,9.49,11.3,2.8,9.73,-14.08,2.8,4.92,-16.43,2.8,9.49,-12.69,2.8,7.32,-16.53,2.8,4.26,-16.43,2.8,9.49,-14.08,2.8,4.92,0,2.8,-18.97,-2.78,2.8,-14.65,0,2.8,-14.65,-4.58,2.8,-16.45,-2.78,2.8,-14.65,0,2.8,-18.97,16.43,2.8,9.49,14.08,2.8,4.92,12.69,2.8,7.32,16.53,2.8,4.26,14.08,2.8,4.92,16.43,2.8,9.49,-16.43,2.8,9.49,-11.3,2.8,9.73,-12.69,2.8,7.32,-11.95,2.8,12.19,-11.3,2.8,9.73,-16.43,2.8,9.49,4.58,2.8,-16.45,4.58,2.8,-21.59,0,2.8,-18.97,11.95,2.8,12.19,16.41,2.8,14.76,16.43,2.8,9.49,-16.53,2.8,4.26,-20.99,2.8,6.83,-16.43,2.8,9.49,-4.58,2.8,-21.59,-4.58,2.8,-16.45,0,2.8,-18.97,20.99,2.8,6.83,16.53,2.8,4.26,16.43,2.8,9.49,-16.41,2.8,14.76,-11.95,2.8,12.19,-16.43,2.8,9.49,0,2.8,-23.37,4.58,2.8,-21.59,2.79,2.8,-23.37,0,2.8,-18.97,4.58,2.8,-21.59,0,2.8,-23.37,20.24,2.8,11.68,16.41,2.8,14.76,18.85,2.8,14.1,16.43,2.8,9.49,16.41,2.8,14.76,20.24,2.8,11.68,-20.24,2.8,11.68,-20.99,2.8,6.83,-21.63,2.8,9.27,-16.43,2.8,9.49,-20.99,2.8,6.83,-20.24,2.8,11.68,-4.58,2.8,-21.59,0,2.8,-23.37,-2.79,2.8,-23.37,0,2.8,-18.97,0,2.8,-23.37,-4.58,2.8,-21.59,20.99,2.8,6.83,20.24,2.8,11.68,21.63,2.8,9.27,16.43,2.8,9.49,20.24,2.8,11.68,20.99,2.8,6.83,-16.41,2.8,14.76,-20.24,2.8,11.68,-18.85,2.8,14.1,-16.43,2.8,9.49,-20.24,2.8,11.68,-16.41,2.8,14.76,4.58,2.8,-16.45,16.03,7.6,-21.59,4.58,2.8,-21.59,16.03,7.6,-16.45,16.03,7.6,-21.59,4.58,2.8,-16.45,11.95,2.8,12.19,10.68,7.6,24.68,16.41,2.8,14.76,6.23,7.6,22.1,10.68,7.6,24.68,11.95,2.8,12.19,-16.53,2.8,4.26,-26.71,7.6,-3.09,-20.99,2.8,6.83,-22.26,7.6,-5.66,-26.71,7.6,-3.09,-16.53,2.8,4.26,-16.03,7.6,-21.59,-4.58,2.8,-16.45,-4.58,2.8,-21.59,-16.03,7.6,-16.45,-4.58,2.8,-16.45,-16.03,7.6,-21.59,26.71,7.6,-3.09,16.53,2.8,4.26,20.99,2.8,6.83,22.26,7.6,-5.66,16.53,2.8,4.26,26.71,7.6,-3.09,-10.68,7.6,24.68,-11.95,2.8,12.19,-16.41,2.8,14.76,-6.23,7.6,22.1,-11.95,2.8,12.19,-10.68,7.6,24.68,16.03,7.6,-16.45,17.4,7.6,-16.45,16.03,7.6,-18.74,6.23,7.6,22.11,5.54,7.6,23.29,8.22,7.6,23.26,-22.26,7.6,-5.66,-22.94,7.6,-6.85,-24.25,7.6,-4.51,-17.4,7.6,-16.45,-16.03,7.6,-16.45,-16.03,7.6,-18.74,22.94,7.6,-6.85,22.26,7.6,-5.66,24.25,7.6,-4.51,-5.54,7.6,23.29,-6.23,7.6,22.11,-8.22,7.6,23.26,17.4,7.6,-16.45,16.03,7.6,-21.59,16.03,7.6,-18.74,20.64,7.6,-21.59,16.03,7.6,-21.59,17.4,7.6,-16.45,5.54,7.6,23.29,10.68,7.6,24.68,8.22,7.6,23.26,8.38,7.6,28.67,10.68,7.6,24.68,5.54,7.6,23.29,-22.94,7.6,-6.85,-26.71,7.6,-3.09,-24.25,7.6,-4.51,-29.01,7.6,-7.08,-26.71,7.6,-3.09,-22.94,7.6,-6.85,-16.03,7.6,-21.59,-17.4,7.6,-16.45,-16.03,7.6,-18.74,-20.64,7.6,-21.59,-17.4,7.6,-16.45,-16.03,7.6,-21.59,26.71,7.6,-3.09,22.94,7.6,-6.85,24.25,7.6,-4.51,29.01,7.6,-7.08,22.94,7.6,-6.85,26.71,7.6,-3.09,-10.68,7.6,24.68,-5.54,7.6,23.29,-8.22,7.6,23.26,-8.38,7.6,28.67,-5.54,7.6,23.29,-10.68,7.6,24.68,17.4,7.6,-16.45,19.99,7.6,-13.49,20.64,7.6,-21.59,18.88,7.6,-13.79,19.99,7.6,-13.49,17.4,7.6,-16.45,5.54,7.6,23.29,1.69,7.6,24.06,8.38,7.6,28.67,2.5,7.6,23.24,1.69,7.6,24.06,5.54,7.6,23.29,-22.94,7.6,-6.85,-21.68,7.6,-10.57,-29.01,7.6,-7.08,-21.38,7.6,-9.46,-21.68,7.6,-10.57,-22.94,7.6,-6.85,-19.99,7.6,-13.49,-17.4,7.6,-16.45,-20.64,7.6,-21.59,-18.88,7.6,-13.79,-17.4,7.6,-16.45,-19.99,7.6,-13.49,21.68,7.6,-10.57,22.94,7.6,-6.85,29.01,7.6,-7.08,21.38,7.6,-9.46,22.94,7.6,-6.85,21.68,7.6,-10.57,-1.69,7.6,24.06,-5.54,7.6,23.29,-8.38,7.6,28.67,-2.5,7.6,23.24,-5.54,7.6,23.29,-1.69,7.6,24.06,19.99,7.6,-13.49,24.89,7.6,-14.37,20.64,7.6,-21.59,20.83,7.6,-12.02,24.89,7.6,-14.37,19.99,7.6,-13.49,1.69,7.6,24.06,0,7.6,28.74,8.38,7.6,28.67,0,7.6,24.05,0,7.6,28.74,1.69,7.6,24.06,-21.68,7.6,-10.57,-24.89,7.6,-14.37,-29.01,7.6,-7.08,-20.83,7.6,-12.03,-24.89,7.6,-14.37,-21.68,7.6,-10.57,-24.89,7.6,-14.37,-19.99,7.6,-13.49,-20.64,7.6,-21.59,-20.83,7.6,-12.02,-19.99,7.6,-13.49,-24.89,7.6,-14.37,24.89,7.6,-14.37,21.68,7.6,-10.57,29.01,7.6,-7.08,20.83,7.6,-12.03,21.68,7.6,-10.57,24.89,7.6,-14.37,0,7.6,28.74,-1.69,7.6,24.06,-8.38,7.6,28.67,0,7.6,24.05,-1.69,7.6,24.06,0,7.6,28.74,19.99,7.6,-13.49,18.88,7.6,-13.79,20.83,7.6,-12.02,1.69,7.6,24.06,2.5,7.6,23.24,0,7.6,24.05,-21.68,7.6,-10.57,-21.38,7.6,-9.46,-20.83,7.6,-12.03,-18.88,7.6,-13.79,-19.99,7.6,-13.49,-20.83,7.6,-12.02,21.38,7.6,-9.46,21.68,7.6,-10.57,20.83,7.6,-12.03,-2.5,7.6,23.24,-1.69,7.6,24.06,0,7.6,24.05,18.88,7.6,-13.79,17,7.6,-9.82,20.83,7.6,-12.02,16.32,7.6,-10.91,17,7.6,-9.82,18.88,7.6,-13.79,2.5,7.6,23.24,0,7.6,19.63,0,7.6,24.05,1.29,7.6,19.59,0,7.6,19.63,2.5,7.6,23.24,-21.38,7.6,-9.46,-17,7.6,-9.82,-20.83,7.6,-12.03,-17.61,7.6,-8.68,-17,7.6,-9.82,-21.38,7.6,-9.46,-17,7.6,-9.82,-18.88,7.6,-13.79,-20.83,7.6,-12.02,-16.32,7.6,-10.91,-18.88,7.6,-13.79,-17,7.6,-9.82,17,7.6,-9.82,21.38,7.6,-9.46,20.83,7.6,-12.03,17.61,7.6,-8.68,21.38,7.6,-9.46,17,7.6,-9.82,0,7.6,19.63,-2.5,7.6,23.24,0,7.6,24.05,-1.29,7.6,19.59,-2.5,7.6,23.24,0,7.6,19.63,0,0,-8.67,0,0,-4.15,2.78,0,-8.67,7.51,0,4.33,3.6,0,2.08,6.12,0,6.74,-7.51,0,4.33,-3.6,0,2.08,-8.9,0,1.93,0,0,-4.15,0,0,-8.67,-2.78,0,-8.67,3.6,0,2.08,7.51,0,4.33,8.9,0,1.93,-3.6,0,2.08,-7.51,0,4.33,-6.12,0,6.74,2.78,0,-8.67,3.59,0,-2.07,8.9,0,-5.14,0,0,-4.15,3.59,0,-2.07,2.78,0,-8.67,6.12,0,6.74,0,0,4.15,0,0,10.28,3.6,0,2.08,0,0,4.15,6.12,0,6.74,-8.9,0,1.93,-3.59,0,-2.07,-8.9,0,-5.14,-3.6,0,2.08,-3.59,0,-2.07,-8.9,0,1.93,-3.59,0,-2.07,-2.78,0,-8.67,-8.9,0,-5.14,0,0,-4.15,-2.78,0,-8.67,-3.59,0,-2.07,3.59,0,-2.07,8.9,0,1.93,8.9,0,-5.14,3.6,0,2.08,8.9,0,1.93,3.59,0,-2.07,0,0,4.15,-6.12,0,6.74,0,0,10.28,-3.6,0,2.08,-6.12,0,6.74,0,0,4.15,8.9,0,-5.14,2.81,-0.85,-8.67,2.78,0,-8.67,8.93,-0.85,-5.14,2.81,-0.85,-8.67,8.9,0,-5.14,0,0,10.28,6.1,-0.85,6.76,6.12,0,6.74,-0.01,-0.85,10.3,6.1,-0.85,6.76,0,0,10.28,-8.9,0,-5.14,-8.91,-0.85,1.9,-8.9,0,1.93,-8.92,-0.85,-5.16,-8.91,-0.85,1.9,-8.9,0,-5.14,-2.81,-0.85,-8.67,-8.9,0,-5.14,-2.78,0,-8.67,-8.93,-0.85,-5.14,-8.9,0,-5.14,-2.81,-0.85,-8.67,8.91,-0.85,1.9,8.9,0,-5.14,8.9,0,1.93,8.92,-0.85,-5.16,8.9,0,-5.14,8.91,-0.85,1.9,-6.1,-0.85,6.76,0,0,10.28,-6.12,0,6.74,0.01,-0.85,10.3,0,0,10.28,-6.1,-0.85,6.76,0,0,-4.15,3.62,-0.85,-2.07,3.59,0,-2.07,0,-0.85,-4.15,3.62,-0.85,-2.07,0,0,-4.15,3.6,0,2.08,-0.01,-0.85,4.17,0,0,4.15,3.6,-0.85,2.08,-0.01,-0.85,4.17,3.6,0,2.08,-3.6,0,2.08,-3.6,-0.85,-2.1,-3.59,0,-2.07,-3.6,-0.85,2.08,-3.6,-0.85,-2.1,-3.6,0,2.08,-3.62,-0.85,-2.07,0,0,-4.15,-3.59,0,-2.07,0,-0.85,-4.15,0,0,-4.15,-3.62,-0.85,-2.07,3.6,-0.85,-2.1,3.6,0,2.08,3.59,0,-2.07,3.6,-0.85,2.08,3.6,0,2.08,3.6,-0.85,-2.1,0.01,-0.85,4.17,-3.6,0,2.08,0,0,4.15,-3.6,-0.85,2.08,-3.6,0,2.08,0.01,-0.85,4.17,18.88,7.6,-13.79,16.35,6.75,-10.91,16.32,7.6,-10.91,18.9,6.75,-13.79,16.35,6.75,-10.91,18.88,7.6,-13.79,2.5,7.6,23.24,1.28,6.75,19.61,1.29,7.6,19.59,2.49,6.75,23.26,1.28,6.75,19.61,2.5,7.6,23.24,-21.38,7.6,-9.46,-17.62,6.75,-8.7,-17.61,7.6,-8.68,-21.39,6.75,-9.48,-17.62,6.75,-8.7,-21.38,7.6,-9.46,-16.35,6.75,-10.91,-18.88,7.6,-13.79,-16.32,7.6,-10.91,-18.9,6.75,-13.79,-18.88,7.6,-13.79,-16.35,6.75,-10.91,17.62,6.75,-8.7,21.38,7.6,-9.46,17.61,7.6,-8.68,21.39,6.75,-9.48,21.38,7.6,-9.46,17.62,6.75,-8.7,-1.28,6.75,19.61,-2.5,7.6,23.24,-1.29,7.6,19.59,-2.49,6.75,23.26,-2.5,7.6,23.24,-1.28,6.75,19.61,16.32,7.6,-10.91,17.03,6.75,-9.83,17,7.6,-9.82,16.35,6.75,-10.91,17.03,6.75,-9.83,16.32,7.6,-10.91,1.29,7.6,19.59,0,6.75,19.66,0,7.6,19.63,1.28,6.75,19.61,0,6.75,19.66,1.29,7.6,19.59,-17.61,7.6,-8.68,-17.03,6.75,-9.83,-17,7.6,-9.82,-17.62,6.75,-8.7,-17.03,6.75,-9.83,-17.61,7.6,-8.68,-17.03,6.75,-9.83,-16.32,7.6,-10.91,-17,7.6,-9.82,-16.35,6.75,-10.91,-16.32,7.6,-10.91,-17.03,6.75,-9.83,17.03,6.75,-9.83,17.61,7.6,-8.68,17,7.6,-9.82,17.62,6.75,-8.7,17.61,7.6,-8.68,17.03,6.75,-9.83,0,6.75,19.66,-1.29,7.6,19.59,0,7.6,19.63,-1.28,6.75,19.61,-1.29,7.6,19.59,0,6.75,19.66,24.89,7.6,-14.37,20.66,6.75,-21.59,20.64,7.6,-21.59,24.91,6.75,-14.38,20.66,6.75,-21.59,24.89,7.6,-14.37,0,7.6,28.74,8.36,6.75,28.69,8.38,7.6,28.67,0,6.75,28.77,8.36,6.75,28.69,0,7.6,28.74,-24.89,7.6,-14.37,-29.03,6.75,-7.1,-29.01,7.6,-7.08,-24.91,6.75,-14.38,-29.03,6.75,-7.1,-24.89,7.6,-14.37,-20.66,6.75,-21.59,-24.89,7.6,-14.37,-20.64,7.6,-21.59,-24.91,6.75,-14.38,-24.89,7.6,-14.37,-20.66,6.75,-21.59,29.03,6.75,-7.1,24.89,7.6,-14.37,29.01,7.6,-7.08,24.91,6.75,-14.38,24.89,7.6,-14.37,29.03,6.75,-7.1,-8.36,6.75,28.69,0,7.6,28.74,-8.38,7.6,28.67,0,6.75,28.77,0,7.6,28.74,-8.36,6.75,28.69,17.4,7.6,-16.45,18.9,6.75,-13.79,18.88,7.6,-13.79,17.43,6.75,-16.44,18.9,6.75,-13.79,17.4,7.6,-16.45,5.54,7.6,23.29,2.49,6.75,23.26,2.5,7.6,23.24,5.53,6.75,23.31,2.49,6.75,23.26,5.54,7.6,23.29,-22.94,7.6,-6.85,-21.39,6.75,-9.48,-21.38,7.6,-9.46,-22.95,6.75,-6.87,-21.39,6.75,-9.48,-22.94,7.6,-6.85,-18.9,6.75,-13.79,-17.4,7.6,-16.45,-18.88,7.6,-13.79,-17.43,6.75,-16.44,-17.4,7.6,-16.45,-18.9,6.75,-13.79,21.39,6.75,-9.48,22.94,7.6,-6.85,21.38,7.6,-9.46,22.95,6.75,-6.87,22.94,7.6,-6.85,21.39,6.75,-9.48,-2.49,6.75,23.26,-5.54,7.6,23.29,-2.5,7.6,23.24,-5.53,6.75,23.31,-5.54,7.6,23.29,-2.49,6.75,23.26,16.03,7.6,-16.45,17.43,6.75,-16.44,17.4,7.6,-16.45,16.06,6.75,-16.44,17.43,6.75,-16.44,16.03,7.6,-16.45,6.23,7.6,22.11,5.53,6.75,23.31,5.54,7.6,23.29,6.21,6.75,22.13,5.53,6.75,23.31,6.23,7.6,22.11,-22.26,7.6,-5.66,-22.95,6.75,-6.87,-22.94,7.6,-6.85,-22.27,6.75,-5.68,-22.95,6.75,-6.87,-22.26,7.6,-5.66,-17.43,6.75,-16.44,-16.03,7.6,-16.45,-17.4,7.6,-16.45,-16.06,6.75,-16.44,-16.03,7.6,-16.45,-17.43,6.75,-16.44,22.95,6.75,-6.87,22.26,7.6,-5.66,22.94,7.6,-6.85,22.27,6.75,-5.68,22.26,7.6,-5.66,22.95,6.75,-6.87,-5.53,6.75,23.31,-6.23,7.6,22.11,-5.54,7.6,23.29,-6.21,6.75,22.13,-6.23,7.6,22.11,-5.53,6.75,23.31,20.64,7.6,-21.59,16.06,6.75,-21.59,16.03,7.6,-21.59,20.66,6.75,-21.59,16.06,6.75,-21.59,20.64,7.6,-21.59,8.38,7.6,28.67,10.67,6.75,24.7,10.68,7.6,24.68,8.36,6.75,28.69,10.67,6.75,24.7,8.38,7.6,28.67,-29.01,7.6,-7.08,-26.72,6.75,-3.11,-26.71,7.6,-3.09,-29.03,6.75,-7.1,-26.72,6.75,-3.11,-29.01,7.6,-7.08,-16.06,6.75,-21.59,-20.64,7.6,-21.59,-16.03,7.6,-21.59,-20.66,6.75,-21.59,-20.64,7.6,-21.59,-16.06,6.75,-21.59,26.72,6.75,-3.11,29.01,7.6,-7.08,26.71,7.6,-3.09,29.03,6.75,-7.1,29.01,7.6,-7.08,26.72,6.75,-3.11,-10.67,6.75,24.7,-8.38,7.6,28.67,-10.68,7.6,24.68,-8.36,6.75,28.69,-8.38,7.6,28.67,-10.67,6.75,24.7,4.58,2.8,-16.45,16.06,6.75,-16.44,16.03,7.6,-16.45,4.6,1.95,-16.44,16.06,6.75,-16.44,4.58,2.8,-16.45,11.95,2.8,12.19,6.21,6.75,22.13,6.23,7.6,22.1,11.94,1.95,12.21,6.21,6.75,22.13,11.95,2.8,12.19,-16.53,2.8,4.26,-22.27,6.75,-5.68,-22.26,7.6,-5.66,-16.54,1.95,4.24,-22.27,6.75,-5.68,-16.53,2.8,4.26,-16.06,6.75,-16.44,-4.58,2.8,-16.45,-16.03,7.6,-16.45,-4.6,1.95,-16.44,-4.58,2.8,-16.45,-16.06,6.75,-16.44,22.27,6.75,-5.68,16.53,2.8,4.26,22.26,7.6,-5.66,16.54,1.95,4.24,16.53,2.8,4.26,22.27,6.75,-5.68,-6.21,6.75,22.13,-11.95,2.8,12.19,-6.23,7.6,22.1,-11.94,1.95,12.21,-11.95,2.8,12.19,-6.21,6.75,22.13,16.03,7.6,-21.59,4.6,1.95,-21.59,4.58,2.8,-21.59,16.06,6.75,-21.59,4.6,1.95,-21.59,16.03,7.6,-21.59,10.68,7.6,24.68,16.39,1.95,14.78,16.41,2.8,14.76,10.67,6.75,24.7,16.39,1.95,14.78,10.68,7.6,24.68,-26.71,7.6,-3.09,-21,1.95,6.81,-20.99,2.8,6.83,-26.72,6.75,-3.11,-21,1.95,6.81,-26.71,7.6,-3.09,-4.6,1.95,-21.59,-16.03,7.6,-21.59,-4.58,2.8,-21.59,-16.06,6.75,-21.59,-16.03,7.6,-21.59,-4.6,1.95,-21.59,21,1.95,6.81,26.71,7.6,-3.09,20.99,2.8,6.83,26.72,6.75,-3.11,26.71,7.6,-3.09,21,1.95,6.81,-16.39,1.95,14.78,-10.68,7.6,24.68,-16.41,2.8,14.76,-10.67,6.75,24.7,-10.68,7.6,24.68,-16.39,1.95,14.78,4.58,2.8,-21.59,2.81,1.95,-23.37,2.79,2.8,-23.37,4.6,1.95,-21.59,2.81,1.95,-23.37,4.58,2.8,-21.59,16.41,2.8,14.76,18.83,1.95,14.12,18.85,2.8,14.1,16.39,1.95,14.78,18.83,1.95,14.12,16.41,2.8,14.76,-20.99,2.8,6.83,-21.65,1.95,9.25,-21.63,2.8,9.27,-21,1.95,6.81,-21.65,1.95,9.25,-20.99,2.8,6.83,-2.81,1.95,-23.37,-4.58,2.8,-21.59,-2.79,2.8,-23.37,-4.6,1.95,-21.59,-4.58,2.8,-21.59,-2.81,1.95,-23.37,21.65,1.95,9.25,20.99,2.8,6.83,21.63,2.8,9.27,21,1.95,6.81,20.99,2.8,6.83,21.65,1.95,9.25,-18.83,1.95,14.12,-16.41,2.8,14.76,-18.85,2.8,14.1,-16.39,1.95,14.78,-16.41,2.8,14.76,-18.83,1.95,14.12,2.79,2.8,-23.37,0,1.95,-23.37,0,2.8,-23.37,2.81,1.95,-23.37,0,1.95,-23.37,2.79,2.8,-23.37,18.85,2.8,14.1,20.23,1.95,11.68,20.24,2.8,11.68,18.83,1.95,14.12,20.23,1.95,11.68,18.85,2.8,14.1,-21.63,2.8,9.27,-20.23,1.95,11.68,-20.24,2.8,11.68,-21.65,1.95,9.25,-20.23,1.95,11.68,-21.63,2.8,9.27,0,1.95,-23.37,-2.79,2.8,-23.37,0,2.8,-23.37,-2.81,1.95,-23.37,-2.79,2.8,-23.37,0,1.95,-23.37,20.23,1.95,11.68,21.63,2.8,9.27,20.24,2.8,11.68,21.65,1.95,9.25,21.63,2.8,9.27,20.23,1.95,11.68,-20.23,1.95,11.68,-18.85,2.8,14.1,-20.24,2.8,11.68,-18.83,1.95,14.12,-18.85,2.8,14.1,-20.23,1.95,11.68,2.78,2.8,-14.65,4.6,1.95,-16.44,4.58,2.8,-16.45,2.81,1.95,-14.65,4.6,1.95,-16.44,2.78,2.8,-14.65,11.3,2.8,9.73,11.94,1.95,12.21,11.95,2.8,12.19,11.28,1.95,9.75,11.94,1.95,12.21,11.3,2.8,9.73,-14.08,2.8,4.92,-16.54,1.95,4.24,-16.53,2.8,4.26,-14.09,1.95,4.89,-16.54,1.95,4.24,-14.08,2.8,4.92,-4.6,1.95,-16.44,-2.78,2.8,-14.65,-4.58,2.8,-16.45,-2.81,1.95,-14.65,-2.78,2.8,-14.65,-4.6,1.95,-16.44,16.54,1.95,4.24,14.08,2.8,4.92,16.53,2.8,4.26,14.09,1.95,4.89,14.08,2.8,4.92,16.54,1.95,4.24,-11.94,1.95,12.21,-11.3,2.8,9.73,-11.95,2.8,12.19,-11.28,1.95,9.75,-11.3,2.8,9.73,-11.94,1.95,12.21,2.78,0,-8.67,2.81,1.95,-14.65,2.78,2.8,-14.65,2.81,-0.85,-8.67,2.81,1.95,-14.65,2.78,0,-8.67,6.12,0,6.74,11.28,1.95,9.75,11.3,2.8,9.73,6.1,-0.85,6.76,11.28,1.95,9.75,6.12,0,6.74,-8.9,0,1.93,-14.09,1.95,4.89,-14.08,2.8,4.92,-8.91,-0.85,1.9,-14.09,1.95,4.89,-8.9,0,1.93,-2.81,1.95,-14.65,-2.78,0,-8.67,-2.78,2.8,-14.65,-2.81,-0.85,-8.67,-2.78,0,-8.67,-2.81,1.95,-14.65,14.09,1.95,4.89,8.9,0,1.93,14.08,2.8,4.92,8.91,-0.85,1.9,8.9,0,1.93,14.09,1.95,4.89,-11.28,1.95,9.75,-6.12,0,6.74,-11.3,2.8,9.73,-6.1,-0.85,6.76,-6.12,0,6.74,-11.28,1.95,9.75,0,-0.85,-4.15,8.93,-0.85,-5.14,3.62,-0.85,-2.07,2.81,-0.85,-8.67,8.93,-0.85,-5.14,0,-0.85,-4.15,3.6,-0.85,2.08,-0.01,-0.85,10.3,-0.01,-0.85,4.17,6.1,-0.85,6.76,-0.01,-0.85,10.3,3.6,-0.85,2.08,-3.6,-0.85,2.08,-8.92,-0.85,-5.16,-3.6,-0.85,-2.1,-8.91,-0.85,1.9,-8.92,-0.85,-5.16,-3.6,-0.85,2.08,-8.93,-0.85,-5.14,0,-0.85,-4.15,-3.62,-0.85,-2.07,-2.81,-0.85,-8.67,0,-0.85,-4.15,-8.93,-0.85,-5.14,8.92,-0.85,-5.16,3.6,-0.85,2.08,3.6,-0.85,-2.1,8.91,-0.85,1.9,3.6,-0.85,2.08,8.92,-0.85,-5.16,0.01,-0.85,10.3,-3.6,-0.85,2.08,0.01,-0.85,4.17,-6.1,-0.85,6.76,-3.6,-0.85,2.08,0.01,-0.85,10.3,0,-0.85,-4.15,0,-0.85,-8.67,2.81,-0.85,-8.67,3.6,-0.85,2.08,7.5,-0.85,4.33,6.1,-0.85,6.76,-3.6,-0.85,2.08,-7.5,-0.85,4.33,-8.91,-0.85,1.9,0,-0.85,-8.67,0,-0.85,-4.15,-2.81,-0.85,-8.67,7.5,-0.85,4.33,3.6,-0.85,2.08,8.91,-0.85,1.9,-7.5,-0.85,4.33,-3.6,-0.85,2.08,-6.1,-0.85,6.76,16.35,6.75,-10.91,20.85,6.75,-12.04,17.03,6.75,-9.83,18.9,6.75,-13.79,20.85,6.75,-12.04,16.35,6.75,-10.91,1.28,6.75,19.61,0,6.75,24.08,0,6.75,19.66,2.49,6.75,23.26,0,6.75,24.08,1.28,6.75,19.61,-17.62,6.75,-8.7,-20.85,6.75,-12.04,-17.03,6.75,-9.83,-21.39,6.75,-9.48,-20.85,6.75,-12.04,-17.62,6.75,-8.7,-20.85,6.75,-12.04,-16.35,6.75,-10.91,-17.03,6.75,-9.83,-18.9,6.75,-13.79,-16.35,6.75,-10.91,-20.85,6.75,-12.04,20.85,6.75,-12.04,17.62,6.75,-8.7,17.03,6.75,-9.83,21.39,6.75,-9.48,17.62,6.75,-8.7,20.85,6.75,-12.04,0,6.75,24.08,-1.28,6.75,19.61,0,6.75,19.66,-2.49,6.75,23.26,-1.28,6.75,19.61,0,6.75,24.08,18.9,6.75,-13.79,20.02,6.75,-13.49,20.85,6.75,-12.04,2.49,6.75,23.26,1.67,6.75,24.08,0,6.75,24.08,-21.39,6.75,-9.48,-21.69,6.75,-10.59,-20.85,6.75,-12.04,-20.02,6.75,-13.49,-18.9,6.75,-13.79,-20.85,6.75,-12.04,21.69,6.75,-10.59,21.39,6.75,-9.48,20.85,6.75,-12.04,-1.67,6.75,24.08,-2.49,6.75,23.26,0,6.75,24.08,20.85,6.75,-12.04,20.66,6.75,-21.59,24.91,6.75,-14.38,20.02,6.75,-13.49,20.66,6.75,-21.59,20.85,6.75,-12.04,0,6.75,24.08,8.36,6.75,28.69,0,6.75,28.77,1.67,6.75,24.08,8.36,6.75,28.69,0,6.75,24.08,-20.85,6.75,-12.04,-29.03,6.75,-7.1,-24.91,6.75,-14.38,-21.69,6.75,-10.59,-29.03,6.75,-7.1,-20.85,6.75,-12.04,-20.66,6.75,-21.59,-20.85,6.75,-12.04,-24.91,6.75,-14.38,-20.02,6.75,-13.49,-20.85,6.75,-12.04,-20.66,6.75,-21.59,29.03,6.75,-7.1,20.85,6.75,-12.04,24.91,6.75,-14.38,21.69,6.75,-10.59,20.85,6.75,-12.04,29.03,6.75,-7.1,-8.36,6.75,28.69,0,6.75,24.08,0,6.75,28.77,-1.67,6.75,24.08,0,6.75,24.08,-8.36,6.75,28.69,18.9,6.75,-13.79,20.66,6.75,-21.59,20.02,6.75,-13.49,17.43,6.75,-16.44,20.66,6.75,-21.59,18.9,6.75,-13.79,2.49,6.75,23.26,8.36,6.75,28.69,1.67,6.75,24.08,5.53,6.75,23.31,8.36,6.75,28.69,2.49,6.75,23.26,-21.39,6.75,-9.48,-29.03,6.75,-7.1,-21.69,6.75,-10.59,-22.95,6.75,-6.87,-29.03,6.75,-7.1,-21.39,6.75,-9.48,-20.66,6.75,-21.59,-18.9,6.75,-13.79,-20.02,6.75,-13.49,-17.43,6.75,-16.44,-18.9,6.75,-13.79,-20.66,6.75,-21.59,29.03,6.75,-7.1,21.39,6.75,-9.48,21.69,6.75,-10.59,22.95,6.75,-6.87,21.39,6.75,-9.48,29.03,6.75,-7.1,-8.36,6.75,28.69,-2.49,6.75,23.26,-1.67,6.75,24.08,-5.53,6.75,23.31,-2.49,6.75,23.26,-8.36,6.75,28.69,20.66,6.75,-21.59,16.06,6.75,-18.74,16.06,6.75,-21.59,17.43,6.75,-16.44,16.06,6.75,-18.74,20.66,6.75,-21.59,8.36,6.75,28.69,8.2,6.75,23.28,10.67,6.75,24.7,5.53,6.75,23.31,8.2,6.75,23.28,8.36,6.75,28.69,-29.03,6.75,-7.1,-24.26,6.75,-4.54,-26.72,6.75,-3.11,-22.95,6.75,-6.87,-24.26,6.75,-4.54,-29.03,6.75,-7.1,-16.06,6.75,-18.74,-20.66,6.75,-21.59,-16.06,6.75,-21.59,-17.43,6.75,-16.44,-20.66,6.75,-21.59,-16.06,6.75,-18.74,24.26,6.75,-4.54,29.03,6.75,-7.1,26.72,6.75,-3.11,22.95,6.75,-6.87,29.03,6.75,-7.1,24.26,6.75,-4.54,-8.2,6.75,23.28,-8.36,6.75,28.69,-10.67,6.75,24.7,-5.53,6.75,23.31,-8.36,6.75,28.69,-8.2,6.75,23.28,17.43,6.75,-16.44,16.06,6.75,-16.44,16.06,6.75,-18.74,5.53,6.75,23.31,6.21,6.75,22.13,8.2,6.75,23.28,-22.95,6.75,-6.87,-22.27,6.75,-5.68,-24.26,6.75,-4.54,-16.06,6.75,-16.44,-17.43,6.75,-16.44,-16.06,6.75,-18.74,22.27,6.75,-5.68,22.95,6.75,-6.87,24.26,6.75,-4.54,-6.21,6.75,22.13,-5.53,6.75,23.31,-8.2,6.75,23.28,16.06,6.75,-16.44,4.6,1.95,-21.59,16.06,6.75,-21.59,4.6,1.95,-16.44,4.6,1.95,-21.59,16.06,6.75,-16.44,6.21,6.75,22.13,16.39,1.95,14.78,10.67,6.75,24.7,11.94,1.95,12.21,16.39,1.95,14.78,6.21,6.75,22.13,-22.27,6.75,-5.68,-21,1.95,6.81,-26.72,6.75,-3.11,-16.54,1.95,4.24,-21,1.95,6.81,-22.27,6.75,-5.68,-4.6,1.95,-21.59,-16.06,6.75,-16.44,-16.06,6.75,-21.59,-4.6,1.95,-16.44,-16.06,6.75,-16.44,-4.6,1.95,-21.59,21,1.95,6.81,22.27,6.75,-5.68,26.72,6.75,-3.11,16.54,1.95,4.24,22.27,6.75,-5.68,21,1.95,6.81,-16.39,1.95,14.78,-6.21,6.75,22.13,-10.67,6.75,24.7,-11.94,1.95,12.21,-6.21,6.75,22.13,-16.39,1.95,14.78,0,1.95,-18.97,2.81,1.95,-23.37,4.6,1.95,-21.59,0,1.95,-23.37,2.81,1.95,-23.37,0,1.95,-18.97,16.43,1.95,9.49,18.83,1.95,14.12,16.39,1.95,14.78,20.23,1.95,11.68,18.83,1.95,14.12,16.43,1.95,9.49,-16.43,1.95,9.48,-21.65,1.95,9.25,-21,1.95,6.81,-20.23,1.95,11.68,-21.65,1.95,9.25,-16.43,1.95,9.48,-2.81,1.95,-23.37,0,1.95,-18.97,-4.6,1.95,-21.59,0,1.95,-23.37,0,1.95,-18.97,-2.81,1.95,-23.37,21.65,1.95,9.25,16.43,1.95,9.48,21,1.95,6.81,20.23,1.95,11.68,16.43,1.95,9.48,21.65,1.95,9.25,-18.83,1.95,14.12,-16.43,1.95,9.49,-16.39,1.95,14.78,-20.23,1.95,11.68,-16.43,1.95,9.49,-18.83,1.95,14.12,4.6,1.95,-21.59,4.6,1.95,-16.44,0,1.95,-18.97,16.39,1.95,14.78,11.94,1.95,12.21,16.43,1.95,9.49,-21,1.95,6.81,-16.54,1.95,4.24,-16.43,1.95,9.48,-4.6,1.95,-16.44,-4.6,1.95,-21.59,0,1.95,-18.97,16.54,1.95,4.24,21,1.95,6.81,16.43,1.95,9.48,-11.94,1.95,12.21,-16.39,1.95,14.78,-16.43,1.95,9.49,4.6,1.95,-16.44,0,1.95,-14.65,0,1.95,-18.97,2.81,1.95,-14.65,0,1.95,-14.65,4.6,1.95,-16.44,11.94,1.95,12.21,12.69,1.95,7.32,16.43,1.95,9.49,11.28,1.95,9.75,12.69,1.95,7.32,11.94,1.95,12.21,-16.54,1.95,4.24,-12.69,1.95,7.32,-16.43,1.95,9.48,-14.09,1.95,4.89,-12.69,1.95,7.32,-16.54,1.95,4.24,0,1.95,-14.65,-4.6,1.95,-16.44,0,1.95,-18.97,-2.81,1.95,-14.65,-4.6,1.95,-16.44,0,1.95,-14.65,12.69,1.95,7.32,16.54,1.95,4.24,16.43,1.95,9.48,14.09,1.95,4.89,16.54,1.95,4.24,12.69,1.95,7.32,-12.69,1.95,7.32,-11.94,1.95,12.21,-16.43,1.95,9.49,-11.28,1.95,9.75,-11.94,1.95,12.21,-12.69,1.95,7.32,2.81,1.95,-14.65,0,-0.85,-8.67,0,1.95,-14.65,2.81,-0.85,-8.67,0,-0.85,-8.67,2.81,1.95,-14.65,11.28,1.95,9.75,7.5,-0.85,4.33,12.69,1.95,7.32,6.1,-0.85,6.76,7.5,-0.85,4.33,11.28,1.95,9.75,-14.09,1.95,4.89,-7.5,-0.85,4.33,-12.69,1.95,7.32,-8.91,-0.85,1.9,-7.5,-0.85,4.33,-14.09,1.95,4.89,0,-0.85,-8.67,-2.81,1.95,-14.65,0,1.95,-14.65,-2.81,-0.85,-8.67,-2.81,1.95,-14.65,0,-0.85,-8.67,7.5,-0.85,4.33,14.09,1.95,4.89,12.69,1.95,7.32,8.91,-0.85,1.9,14.09,1.95,4.89,7.5,-0.85,4.33,-7.5,-0.85,4.33,-11.28,1.95,9.75,-12.69,1.95,7.32,-6.1,-0.85,6.76,-11.28,1.95,9.75,-7.5,-0.85,4.33],"normalized":false},"uv":{"itemSize":2,"type":"Float32Array","array":[0.0075,0.3366,0.7496,0.1704,0.0063,0.1711,0.7508,0.3359,0.7496,0.1704,0.0075,0.3366,0.0075,0.3366,0.7496,0.1704,0.0063,0.1711,0.7508,0.3359,0.7496,0.1704,0.0075,0.3366,0.0075,0.3366,0.7496,0.1704,0.0063,0.1711,0.7508,0.3359,0.7496,0.1704,0.0075,0.3366,0.7496,0.1704,0.0075,0.3366,0.0063,0.1711,0.7508,0.3359,0.0075,0.3366,0.7496,0.1704,0.7496,0.1704,0.0075,0.3366,0.0063,0.1711,0.7508,0.3359,0.0075,0.3366,0.7496,0.1704,0.7496,0.1704,0.0075,0.3366,0.0063,0.1711,0.7508,0.3359,0.0075,0.3366,0.7496,0.1704,0.1446,0.5417,0.5607,0.3587,0.1437,0.3596,0.3185,0.6589,0.5607,0.3587,0.1446,0.5417,0.1446,0.5417,0.5607,0.3587,0.1437,0.3596,0.3185,0.6589,0.5607,0.3587,0.1446,0.5417,0.1446,0.5417,0.5607,0.3587,0.1437,0.3596,0.3185,0.6589,0.5607,0.3587,0.1446,0.5417,0.5607,0.3587,0.1446,0.5417,0.1437,0.3596,0.3185,0.6589,0.1446,0.5417,0.5607,0.3587,0.5607,0.3587,0.1446,0.5417,0.1437,0.3596,0.3185,0.6589,0.1446,0.5417,0.5607,0.3587,0.5607,0.3587,0.1446,0.5417,0.1437,0.3596,0.3185,0.6589,0.1446,0.5417,0.5607,0.3587,0.3185,0.6589,0.8148,0.6578,0.5607,0.3587,0.3185,0.6589,0.8148,0.6578,0.5607,0.3587,0.3185,0.6589,0.8148,0.6578,0.5607,0.3587,0.8148,0.6578,0.3185,0.6589,0.5607,0.3587,0.8148,0.6578,0.3185,0.6589,0.5607,0.3587,0.8148,0.6578,0.3185,0.6589,0.5607,0.3587,0.9849,0.3578,0.8148,0.6578,0.9863,0.5402,0.5607,0.3587,0.8148,0.6578,0.9849,0.3578,0.9849,0.3578,0.8148,0.6578,0.9863,0.5402,0.5607,0.3587,0.8148,0.6578,0.9849,0.3578,0.9849,0.3578,0.8148,0.6578,0.9863,0.5402,0.5607,0.3587,0.8148,0.6578,0.9849,0.3578,0.8148,0.6578,0.9849,0.3578,0.9863,0.5402,0.5607,0.3587,0.9849,0.3578,0.8148,0.6578,0.8148,0.6578,0.9849,0.3578,0.9863,0.5402,0.5607,0.3587,0.9849,0.3578,0.8148,0.6578,0.8148,0.6578,0.9849,0.3578,0.9863,0.5402,0.5607,0.3587,0.9849,0.3578,0.8148,0.6578,0.0035,0.335,0.996,0.0024,0.0026,0.0024,0.9969,0.335,0.996,0.0024,0.0035,0.335,0.0035,0.335,0.996,0.0024,0.0026,0.0024,0.9969,0.335,0.996,0.0024,0.0035,0.335,0.0035,0.335,0.996,0.0024,0.0026,0.0024,0.9969,0.335,0.996,0.0024,0.0035,0.335,0.996,0.0024,0.0035,0.335,0.0026,0.0024,0.9969,0.335,0.0035,0.335,0.996,0.0024,0.996,0.0024,0.0035,0.335,0.0026,0.0024,0.9969,0.335,0.0035,0.335,0.996,0.0024,0.996,0.0024,0.0035,0.335,0.0026,0.0024,0.9969,0.335,0.0035,0.335,0.996,0.0024,0.4927,0.5738,0.548,0.6373,0.3352,0.638,0.4927,0.5738,0.548,0.6373,0.3352,0.638,0.4927,0.5738,0.548,0.6373,0.3352,0.638,0.548,0.6373,0.4927,0.5738,0.3352,0.638,0.548,0.6373,0.4927,0.5738,0.3352,0.638,0.548,0.6373,0.4927,0.5738,0.3352,0.638,0.548,0.6373,0.1402,0.5599,0.3352,0.638,0.3263,0.3458,0.1402,0.5599,0.548,0.6373,0.548,0.6373,0.1402,0.5599,0.3352,0.638,0.3263,0.3458,0.1402,0.5599,0.548,0.6373,0.548,0.6373,0.1402,0.5599,0.3352,0.638,0.3263,0.3458,0.1402,0.5599,0.548,0.6373,0.1402,0.5599,0.548,0.6373,0.3352,0.638,0.3263,0.3458,0.548,0.6373,0.1402,0.5599,0.1402,0.5599,0.548,0.6373,0.3352,0.638,0.3263,0.3458,0.548,0.6373,0.1402,0.5599,0.1402,0.5599,0.548,0.6373,0.3352,0.638,0.3263,0.3458,0.548,0.6373,0.1402,0.5599,0.548,0.6373,0.8554,0.598,0.3263,0.3458,0.79,0.6415,0.8554,0.598,0.548,0.6373,0.548,0.6373,0.8554,0.598,0.3263,0.3458,0.79,0.6415,0.8554,0.598,0.548,0.6373,0.548,0.6373,0.8554,0.598,0.3263,0.3458,0.79,0.6415,0.8554,0.598,0.548,0.6373,0.8554,0.598,0.548,0.6373,0.3263,0.3458,0.79,0.6415,0.548,0.6373,0.8554,0.598,0.8554,0.598,0.548,0.6373,0.3263,0.3458,0.79,0.6415,0.548,0.6373,0.8554,0.598,0.8554,0.598,0.548,0.6373,0.3263,0.3458,0.79,0.6415,0.548,0.6373,0.8554,0.598,0.8554,0.598,0.9931,0.3461,0.3263,0.3458,0.9897,0.5992,0.9931,0.3461,0.8554,0.598,0.8554,0.598,0.9931,0.3461,0.3263,0.3458,0.9897,0.5992,0.9931,0.3461,0.8554,0.598,0.8554,0.598,0.9931,0.3461,0.3263,0.3458,0.9897,0.5992,0.9931,0.3461,0.8554,0.598,0.9931,0.3461,0.8554,0.598,0.3263,0.3458,0.9897,0.5992,0.8554,0.598,0.9931,0.3461,0.9931,0.3461,0.8554,0.598,0.3263,0.3458,0.9897,0.5992,0.8554,0.598,0.9931,0.3461,0.9931,0.3461,0.8554,0.598,0.3263,0.3458,0.9897,0.5992,0.8554,0.598,0.9931,0.3461,0.844,0.7816,0.7456,0.7148,0.8432,0.92,0.844,0.7816,0.7456,0.7148,0.8432,0.92,0.844,0.7816,0.7456,0.7148,0.8432,0.92,0.7456,0.7148,0.844,0.7816,0.8432,0.92,0.7456,0.7148,0.844,0.7816,0.8432,0.92,0.7456,0.7148,0.844,0.7816,0.8432,0.92,0.7456,0.7148,0.3095,0.9199,0.8432,0.92,0.3042,0.8141,0.3095,0.9199,0.7456,0.7148,0.7456,0.7148,0.3095,0.9199,0.8432,0.92,0.3042,0.8141,0.3095,0.9199,0.7456,0.7148,0.7456,0.7148,0.3095,0.9199,0.8432,0.92,0.3042,0.8141,0.3095,0.9199,0.7456,0.7148,0.3095,0.9199,0.7456,0.7148,0.8432,0.92,0.3042,0.8141,0.7456,0.7148,0.3095,0.9199,0.3095,0.9199,0.7456,0.7148,0.8432,0.92,0.3042,0.8141,0.7456,0.7148,0.3095,0.9199,0.3095,0.9199,0.7456,0.7148,0.8432,0.92,0.3042,0.8141,0.7456,0.7148,0.3095,0.9199,0.1534,0.4372,0.3496,0.6671,0.3622,0.3552,0.1534,0.4372,0.3496,0.6671,0.3622,0.3552,0.1534,0.4372,0.3496,0.6671,0.3622,0.3552,0.3496,0.6671,0.1534,0.4372,0.3622,0.3552,0.3496,0.6671,0.1534,0.4372,0.3622,0.3552,0.3496,0.6671,0.1534,0.4372,0.3622,0.3552,0.3622,0.3552,0.7096,0.6672,0.975,0.3543,0.3496,0.6671,0.7096,0.6672,0.3622,0.3552,0.3622,0.3552,0.7096,0.6672,0.975,0.3543,0.3496,0.6671,0.7096,0.6672,0.3622,0.3552,0.3622,0.3552,0.7096,0.6672,0.975,0.3543,0.3496,0.6671,0.7096,0.6672,0.3622,0.3552,0.7096,0.6672,0.3622,0.3552,0.975,0.3543,0.3496,0.6671,0.3622,0.3552,0.7096,0.6672,0.7096,0.6672,0.3622,0.3552,0.975,0.3543,0.3496,0.6671,0.3622,0.3552,0.7096,0.6672,0.7096,0.6672,0.3622,0.3552,0.975,0.3543,0.3496,0.6671,0.3622,0.3552,0.7096,0.6672,0.0031,0.9406,0.1221,0.3414,0.0032,0.3415,0.122,0.9404,0.1221,0.3414,0.0031,0.9406,0.0031,0.9406,0.1221,0.3414,0.0032,0.3415,0.122,0.9404,0.1221,0.3414,0.0031,0.9406,0.0031,0.9406,0.1221,0.3414,0.0032,0.3415,0.122,0.9404,0.1221,0.3414,0.0031,0.9406,0.1221,0.3414,0.0031,0.9406,0.0032,0.3415,0.122,0.9404,0.0031,0.9406,0.1221,0.3414,0.1221,0.3414,0.0031,0.9406,0.0032,0.3415,0.122,0.9404,0.0031,0.9406,0.1221,0.3414,0.1221,0.3414,0.0031,0.9406,0.0032,0.3415,0.122,0.9404,0.0031,0.9406,0.1221,0.3414,0.0033,0.796,0.1224,0.4518,0.0036,0.4524,0.1221,0.7969,0.1224,0.4518,0.0033,0.796,0.0033,0.796,0.1224,0.4518,0.0036,0.4524,0.1221,0.7969,0.1224,0.4518,0.0033,0.796,0.0033,0.796,0.1224,0.4518,0.0036,0.4524,0.1221,0.7969,0.1224,0.4518,0.0033,0.796,0.1224,0.4518,0.0033,0.796,0.0036,0.4524,0.1221,0.7969,0.0033,0.796,0.1224,0.4518,0.1224,0.4518,0.0033,0.796,0.0036,0.4524,0.1221,0.7969,0.0033,0.796,0.1224,0.4518,0.1224,0.4518,0.0033,0.796,0.0036,0.4524,0.1221,0.7969,0.0033,0.796,0.1224,0.4518,0.0036,0.6854,0.1222,0.3393,0.0038,0.3395,0.1227,0.6854,0.1222,0.3393,0.0036,0.6854,0.0036,0.6854,0.1222,0.3393,0.0038,0.3395,0.1227,0.6854,0.1222,0.3393,0.0036,0.6854,0.0036,0.6854,0.1222,0.3393,0.0038,0.3395,0.1227,0.6854,0.1222,0.3393,0.0036,0.6854,0.1222,0.3393,0.0036,0.6854,0.0038,0.3395,0.1227,0.6854,0.0036,0.6854,0.1222,0.3393,0.1222,0.3393,0.0036,0.6854,0.0038,0.3395,0.1227,0.6854,0.0036,0.6854,0.1222,0.3393,0.1222,0.3393,0.0036,0.6854,0.0038,0.3395,0.1227,0.6854,0.0036,0.6854,0.1222,0.3393,0.0045,0.687,0.1233,0.567,0.0037,0.5668,0.1229,0.6872,0.1233,0.567,0.0045,0.687,0.0045,0.687,0.1233,0.567,0.0037,0.5668,0.1229,0.6872,0.1233,0.567,0.0045,0.687,0.0045,0.687,0.1233,0.567,0.0037,0.5668,0.1229,0.6872,0.1233,0.567,0.0045,0.687,0.1233,0.567,0.0045,0.687,0.0037,0.5668,0.1229,0.6872,0.0045,0.687,0.1233,0.567,0.1233,0.567,0.0045,0.687,0.0037,0.5668,0.1229,0.6872,0.0045,0.687,0.1233,0.567,0.1233,0.567,0.0045,0.687,0.0037,0.5668,0.1229,0.6872,0.0045,0.687,0.1233,0.567,0.0051,0.9978,0.1234,0.3388,0.0049,0.3388,0.1237,0.9978,0.1234,0.3388,0.0051,0.9978,0.0051,0.9978,0.1234,0.3388,0.0049,0.3388,0.1237,0.9978,0.1234,0.3388,0.0051,0.9978,0.0051,0.9978,0.1234,0.3388,0.0049,0.3388,0.1237,0.9978,0.1234,0.3388,0.0051,0.9978,0.1234,0.3388,0.0051,0.9978,0.0049,0.3388,0.1237,0.9978,0.0051,0.9978,0.1234,0.3388,0.1234,0.3388,0.0051,0.9978,0.0049,0.3388,0.1237,0.9978,0.0051,0.9978,0.1234,0.3388,0.1234,0.3388,0.0051,0.9978,0.0049,0.3388,0.1237,0.9978,0.0051,0.9978,0.1234,0.3388,0.0049,0.7949,0.1225,0.5669,0.0045,0.5672,0.1215,0.7946,0.1225,0.5669,0.0049,0.7949,0.0049,0.7949,0.1225,0.5669,0.0045,0.5672,0.1215,0.7946,0.1225,0.5669,0.0049,0.7949,0.0049,0.7949,0.1225,0.5669,0.0045,0.5672,0.1215,0.7946,0.1225,0.5669,0.0049,0.7949,0.1225,0.5669,0.0049,0.7949,0.0045,0.5672,0.1215,0.7946,0.0049,0.7949,0.1225,0.5669,0.1225,0.5669,0.0049,0.7949,0.0045,0.5672,0.1215,0.7946,0.0049,0.7949,0.1225,0.5669,0.1225,0.5669,0.0049,0.7949,0.0045,0.5672,0.1215,0.7946,0.0049,0.7949,0.1225,0.5669,0.0051,0.6847,0.1225,0.5574,0.0043,0.5577,0.122,0.6853,0.1225,0.5574,0.0051,0.6847,0.0051,0.6847,0.1225,0.5574,0.0043,0.5577,0.122,0.6853,0.1225,0.5574,0.0051,0.6847,0.0051,0.6847,0.1225,0.5574,0.0043,0.5577,0.122,0.6853,0.1225,0.5574,0.0051,0.6847,0.1225,0.5574,0.0051,0.6847,0.0043,0.5577,0.122,0.6853,0.0051,0.6847,0.1225,0.5574,0.1225,0.5574,0.0051,0.6847,0.0043,0.5577,0.122,0.6853,0.0051,0.6847,0.1225,0.5574,0.1225,0.5574,0.0051,0.6847,0.0043,0.5577,0.122,0.6853,0.0051,0.6847,0.1225,0.5574,0.005,0.7932,0.1224,0.3405,0.0053,0.3406,0.1221,0.793,0.1224,0.3405,0.005,0.7932,0.005,0.7932,0.1224,0.3405,0.0053,0.3406,0.1221,0.793,0.1224,0.3405,0.005,0.7932,0.005,0.7932,0.1224,0.3405,0.0053,0.3406,0.1221,0.793,0.1224,0.3405,0.005,0.7932,0.1224,0.3405,0.005,0.7932,0.0053,0.3406,0.1221,0.793,0.005,0.7932,0.1224,0.3405,0.1224,0.3405,0.005,0.7932,0.0053,0.3406,0.1221,0.793,0.005,0.7932,0.1224,0.3405,0.1224,0.3405,0.005,0.7932,0.0053,0.3406,0.1221,0.793,0.005,0.7932,0.1224,0.3405,0.9988,0.9271,0.1623,0.9987,0.1621,0.9265,0.9989,0.9993,0.1623,0.9987,0.9988,0.9271,0.9988,0.9271,0.1623,0.9987,0.1621,0.9265,0.9989,0.9993,0.1623,0.9987,0.9988,0.9271,0.9988,0.9271,0.1623,0.9987,0.1621,0.9265,0.9989,0.9993,0.1623,0.9987,0.9988,0.9271,0.1623,0.9987,0.9988,0.9271,0.1621,0.9265,0.9989,0.9993,0.9988,0.9271,0.1623,0.9987,0.1623,0.9987,0.9988,0.9271,0.1621,0.9265,0.9989,0.9993,0.9988,0.9271,0.1623,0.9987,0.1623,0.9987,0.9988,0.9271,0.1621,0.9265,0.9989,0.9993,0.9988,0.9271,0.1623,0.9987,0.9982,0.9278,0.1333,0.9994,0.1335,0.9274,0.9981,0.9999,0.1333,0.9994,0.9982,0.9278,0.9982,0.9278,0.1333,0.9994,0.1335,0.9274,0.9981,0.9999,0.1333,0.9994,0.9982,0.9278,0.9982,0.9278,0.1333,0.9994,0.1335,0.9274,0.9981,0.9999,0.1333,0.9994,0.9982,0.9278,0.1333,0.9994,0.9982,0.9278,0.1335,0.9274,0.9981,0.9999,0.9982,0.9278,0.1333,0.9994,0.1333,0.9994,0.9982,0.9278,0.1335,0.9274,0.9981,0.9999,0.9982,0.9278,0.1333,0.9994,0.1333,0.9994,0.9982,0.9278,0.1335,0.9274,0.9981,0.9999,0.9982,0.9278,0.1333,0.9994,0.0034,0.795,0.1222,0.5707,0.0038,0.5709,0.1219,0.7948,0.1222,0.5707,0.0034,0.795,0.0034,0.795,0.1222,0.5707,0.0038,0.5709,0.1219,0.7948,0.1222,0.5707,0.0034,0.795,0.0034,0.795,0.1222,0.5707,0.0038,0.5709,0.1219,0.7948,0.1222,0.5707,0.0034,0.795,0.1222,0.5707,0.0034,0.795,0.0038,0.5709,0.1219,0.7948,0.0034,0.795,0.1222,0.5707,0.1222,0.5707,0.0034,0.795,0.0038,0.5709,0.1219,0.7948,0.0034,0.795,0.1222,0.5707,0.1222,0.5707,0.0034,0.795,0.0038,0.5709,0.1219,0.7948,0.0034,0.795,0.1222,0.5707,0.0038,0.5709,0.1223,0.3397,0.0038,0.3399,0.1222,0.5707,0.1223,0.3397,0.0038,0.5709,0.0038,0.5709,0.1223,0.3397,0.0038,0.3399,0.1222,0.5707,0.1223,0.3397,0.0038,0.5709,0.0038,0.5709,0.1223,0.3397,0.0038,0.3399,0.1222,0.5707,0.1223,0.3397,0.0038,0.5709,0.1223,0.3397,0.0038,0.5709,0.0038,0.3399,0.1222,0.5707,0.0038,0.5709,0.1223,0.3397,0.1223,0.3397,0.0038,0.5709,0.0038,0.3399,0.1222,0.5707,0.0038,0.5709,0.1223,0.3397,0.1223,0.3397,0.0038,0.5709,0.0038,0.3399,0.1222,0.5707,0.0038,0.5709,0.1223,0.3397,0.0042,0.7954,0.1226,0.5664,0.0041,0.5668,0.1226,0.795,0.1226,0.5664,0.0042,0.7954,0.0042,0.7954,0.1226,0.5664,0.0041,0.5668,0.1226,0.795,0.1226,0.5664,0.0042,0.7954,0.0042,0.7954,0.1226,0.5664,0.0041,0.5668,0.1226,0.795,0.1226,0.5664,0.0042,0.7954,0.1226,0.5664,0.0042,0.7954,0.0041,0.5668,0.1226,0.795,0.0042,0.7954,0.1226,0.5664,0.1226,0.5664,0.0042,0.7954,0.0041,0.5668,0.1226,0.795,0.0042,0.7954,0.1226,0.5664,0.1226,0.5664,0.0042,0.7954,0.0041,0.5668,0.1226,0.795,0.0042,0.7954,0.1226,0.5664,0.5004,0.9283,0.971,0.9992,0.9713,0.928,0.5,0.9988,0.971,0.9992,0.5004,0.9283,0.5004,0.9283,0.971,0.9992,0.9713,0.928,0.5,0.9988,0.971,0.9992,0.5004,0.9283,0.5004,0.9283,0.971,0.9992,0.9713,0.928,0.5,0.9988,0.971,0.9992,0.5004,0.9283,0.971,0.9992,0.5004,0.9283,0.9713,0.928,0.5,0.9988,0.5004,0.9283,0.971,0.9992,0.971,0.9992,0.5004,0.9283,0.9713,0.928,0.5,0.9988,0.5004,0.9283,0.971,0.9992,0.971,0.9992,0.5004,0.9283,0.9713,0.928,0.5,0.9988,0.5004,0.9283,0.971,0.9992,0.7936,0.6721,0.1354,0.3449,0.4155,0.6729,0.7788,0.3446,0.1354,0.3449,0.7936,0.6721,0.7936,0.6721,0.1354,0.3449,0.4155,0.6729,0.7788,0.3446,0.1354,0.3449,0.7936,0.6721,0.7936,0.6721,0.1354,0.3449,0.4155,0.6729,0.7788,0.3446,0.1354,0.3449,0.7936,0.6721,0.1354,0.3449,0.7936,0.6721,0.4155,0.6729,0.7788,0.3446,0.7936,0.6721,0.1354,0.3449,0.1354,0.3449,0.7936,0.6721,0.4155,0.6729,0.7788,0.3446,0.7936,0.6721,0.1354,0.3449,0.1354,0.3449,0.7936,0.6721,0.4155,0.6729,0.7788,0.3446,0.7936,0.6721,0.1354,0.3449,0.7936,0.6721,0.9984,0.4303,0.7788,0.3446,0.7936,0.6721,0.9984,0.4303,0.7788,0.3446,0.7936,0.6721,0.9984,0.4303,0.7788,0.3446,0.9984,0.4303,0.7936,0.6721,0.7788,0.3446,0.9984,0.4303,0.7936,0.6721,0.7788,0.3446,0.9984,0.4303,0.7936,0.6721,0.7788,0.3446,0.4353,0.4441,0.1453,0.6019,0.3489,0.4057,0.3463,0.6442,0.1453,0.6019,0.4353,0.4441,0.4353,0.4441,0.1453,0.6019,0.3489,0.4057,0.3463,0.6442,0.1453,0.6019,0.4353,0.4441,0.4353,0.4441,0.1453,0.6019,0.3489,0.4057,0.3463,0.6442,0.1453,0.6019,0.4353,0.4441,0.1453,0.6019,0.4353,0.4441,0.3489,0.4057,0.3463,0.6442,0.4353,0.4441,0.1453,0.6019,0.1453,0.6019,0.4353,0.4441,0.3489,0.4057,0.3463,0.6442,0.4353,0.4441,0.1453,0.6019,0.1453,0.6019,0.4353,0.4441,0.3489,0.4057,0.3463,0.6442,0.4353,0.4441,0.1453,0.6019,0.3463,0.6442,0.2804,0.6004,0.1453,0.6019,0.3463,0.6442,0.2804,0.6004,0.1453,0.6019,0.3463,0.6442,0.2804,0.6004,0.1453,0.6019,0.2804,0.6004,0.3463,0.6442,0.1453,0.6019,0.2804,0.6004,0.3463,0.6442,0.1453,0.6019,0.2804,0.6004,0.3463,0.6442,0.1453,0.6019,0.1453,0.6019,0.8126,0.3461,0.1417,0.3469,0.2804,0.6004,0.8126,0.3461,0.1453,0.6019,0.1453,0.6019,0.8126,0.3461,0.1417,0.3469,0.2804,0.6004,0.8126,0.3461,0.1453,0.6019,0.1453,0.6019,0.8126,0.3461,0.1417,0.3469,0.2804,0.6004,0.8126,0.3461,0.1453,0.6019,0.8126,0.3461,0.1453,0.6019,0.1417,0.3469,0.2804,0.6004,0.1453,0.6019,0.8126,0.3461,0.8126,0.3461,0.1453,0.6019,0.1417,0.3469,0.2804,0.6004,0.1453,0.6019,0.8126,0.3461,0.8126,0.3461,0.1453,0.6019,0.1417,0.3469,0.2804,0.6004,0.1453,0.6019,0.8126,0.3461,0.3463,0.6442,0.8126,0.3461,0.2804,0.6004,0.5898,0.6397,0.8126,0.3461,0.3463,0.6442,0.3463,0.6442,0.8126,0.3461,0.2804,0.6004,0.5898,0.6397,0.8126,0.3461,0.3463,0.6442,0.3463,0.6442,0.8126,0.3461,0.2804,0.6004,0.5898,0.6397,0.8126,0.3461,0.3463,0.6442,0.8126,0.3461,0.3463,0.6442,0.2804,0.6004,0.5898,0.6397,0.3463,0.6442,0.8126,0.3461,0.8126,0.3461,0.3463,0.6442,0.2804,0.6004,0.5898,0.6397,0.3463,0.6442,0.8126,0.3461,0.8126,0.3461,0.3463,0.6442,0.2804,0.6004,0.5898,0.6397,0.3463,0.6442,0.8126,0.3461,0.8126,0.3461,0.804,0.6402,1.0001,0.5615,0.5898,0.6397,0.804,0.6402,0.8126,0.3461,0.8126,0.3461,0.804,0.6402,1.0001,0.5615,0.5898,0.6397,0.804,0.6402,0.8126,0.3461,0.8126,0.3461,0.804,0.6402,1.0001,0.5615,0.5898,0.6397,0.804,0.6402,0.8126,0.3461,0.804,0.6402,0.8126,0.3461,1.0001,0.5615,0.5898,0.6397,0.8126,0.3461,0.804,0.6402,0.804,0.6402,0.8126,0.3461,1.0001,0.5615,0.5898,0.6397,0.8126,0.3461,0.804,0.6402,0.804,0.6402,0.8126,0.3461,1.0001,0.5615,0.5898,0.6397,0.8126,0.3461,0.804,0.6402,0.5898,0.6397,0.6508,0.577,0.804,0.6402,0.5898,0.6397,0.6508,0.577,0.804,0.6402,0.5898,0.6397,0.6508,0.577,0.804,0.6402,0.6508,0.577,0.5898,0.6397,0.804,0.6402,0.6508,0.577,0.5898,0.6397,0.804,0.6402,0.6508,0.577,0.5898,0.6397,0.804,0.6402,0.0035,0.335,0.996,0.0024,0.0026,0.0024,0.9969,0.335,0.996,0.0024,0.0035,0.335,0.0035,0.335,0.996,0.0024,0.0026,0.0024,0.9969,0.335,0.996,0.0024,0.0035,0.335,0.0035,0.335,0.996,0.0024,0.0026,0.0024,0.9969,0.335,0.996,0.0024,0.0035,0.335,0.996,0.0024,0.0035,0.335,0.0026,0.0024,0.9969,0.335,0.0035,0.335,0.996,0.0024,0.996,0.0024,0.0035,0.335,0.0026,0.0024,0.9969,0.335,0.0035,0.335,0.996,0.0024,0.996,0.0024,0.0035,0.335,0.0026,0.0024,0.9969,0.335,0.0035,0.335,0.996,0.0024,0.5687,0.3493,0.134,0.5361,0.3101,0.6561,0.1345,0.3493,0.134,0.5361,0.5687,0.3493,0.5687,0.3493,0.134,0.5361,0.3101,0.6561,0.1345,0.3493,0.134,0.5361,0.5687,0.3493,0.5687,0.3493,0.134,0.5361,0.3101,0.6561,0.1345,0.3493,0.134,0.5361,0.5687,0.3493,0.134,0.5361,0.5687,0.3493,0.3101,0.6561,0.1345,0.3493,0.5687,0.3493,0.134,0.5361,0.134,0.5361,0.5687,0.3493,0.3101,0.6561,0.1345,0.3493,0.5687,0.3493,0.134,0.5361,0.134,0.5361,0.5687,0.3493,0.3101,0.6561,0.1345,0.3493,0.5687,0.3493,0.134,0.5361,0.3101,0.6561,0.8181,0.656,0.5687,0.3493,0.3101,0.6561,0.8181,0.656,0.5687,0.3493,0.3101,0.6561,0.8181,0.656,0.5687,0.3493,0.8181,0.656,0.3101,0.6561,0.5687,0.3493,0.8181,0.656,0.3101,0.6561,0.5687,0.3493,0.8181,0.656,0.3101,0.6561,0.5687,0.3493,0.8181,0.656,0.9955,0.3493,0.5687,0.3493,0.9955,0.5357,0.9955,0.3493,0.8181,0.656,0.8181,0.656,0.9955,0.3493,0.5687,0.3493,0.9955,0.5357,0.9955,0.3493,0.8181,0.656,0.8181,0.656,0.9955,0.3493,0.5687,0.3493,0.9955,0.5357,0.9955,0.3493,0.8181,0.656,0.9955,0.3493,0.8181,0.656,0.5687,0.3493,0.9955,0.5357,0.8181,0.656,0.9955,0.3493,0.9955,0.3493,0.8181,0.656,0.5687,0.3493,0.9955,0.5357,0.8181,0.656,0.9955,0.3493,0.9955,0.3493,0.8181,0.656,0.5687,0.3493,0.9955,0.5357,0.8181,0.656,0.9955,0.3493,0.0075,0.3366,0.7496,0.1704,0.0063,0.1711,0.7508,0.3359,0.7496,0.1704,0.0075,0.3366,0.0075,0.3366,0.7496,0.1704,0.0063,0.1711,0.7508,0.3359,0.7496,0.1704,0.0075,0.3366,0.0075,0.3366,0.7496,0.1704,0.0063,0.1711,0.7508,0.3359,0.7496,0.1704,0.0075,0.3366,0.7496,0.1704,0.0075,0.3366,0.0063,0.1711,0.7508,0.3359,0.0075,0.3366,0.7496,0.1704,0.7496,0.1704,0.0075,0.3366,0.0063,0.1711,0.7508,0.3359,0.0075,0.3366,0.7496,0.1704,0.7496,0.1704,0.0075,0.3366,0.0063,0.1711,0.7508,0.3359,0.0075,0.3366,0.7496,0.1704],"normalized":false}},"groups":[{"start":0,"materialIndex":0,"count":1296}]}} \ No newline at end of file diff --git a/examples/textures/UV_Grid_Sm.jpg b/examples/public/textures/UV_Grid_Sm.jpg similarity index 100% rename from examples/textures/UV_Grid_Sm.jpg rename to examples/public/textures/UV_Grid_Sm.jpg diff --git a/examples/textures/crate.gif b/examples/public/textures/crate.gif similarity index 100% rename from examples/textures/crate.gif rename to examples/public/textures/crate.gif diff --git a/examples/textures/crate.jpg b/examples/public/textures/crate.jpg similarity index 100% rename from examples/textures/crate.jpg rename to examples/public/textures/crate.jpg diff --git a/examples/textures/cube/skybox/nx.jpg b/examples/public/textures/cube/skybox/nx.jpg similarity index 100% rename from examples/textures/cube/skybox/nx.jpg rename to examples/public/textures/cube/skybox/nx.jpg diff --git a/examples/textures/cube/skybox/ny.jpg b/examples/public/textures/cube/skybox/ny.jpg similarity index 100% rename from examples/textures/cube/skybox/ny.jpg rename to examples/public/textures/cube/skybox/ny.jpg diff --git a/examples/textures/cube/skybox/nz.jpg b/examples/public/textures/cube/skybox/nz.jpg similarity index 100% rename from examples/textures/cube/skybox/nz.jpg rename to examples/public/textures/cube/skybox/nz.jpg diff --git a/examples/textures/cube/skybox/px.jpg b/examples/public/textures/cube/skybox/px.jpg similarity index 100% rename from examples/textures/cube/skybox/px.jpg rename to examples/public/textures/cube/skybox/px.jpg diff --git a/examples/textures/cube/skybox/py.jpg b/examples/public/textures/cube/skybox/py.jpg similarity index 100% rename from examples/textures/cube/skybox/py.jpg rename to examples/public/textures/cube/skybox/py.jpg diff --git a/examples/textures/cube/skybox/pz.jpg b/examples/public/textures/cube/skybox/pz.jpg similarity index 100% rename from examples/textures/cube/skybox/pz.jpg rename to examples/public/textures/cube/skybox/pz.jpg diff --git a/examples/textures/grid.png b/examples/public/textures/grid.png similarity index 100% rename from examples/textures/grid.png rename to examples/public/textures/grid.png diff --git a/examples/textures/land_ocean_ice_cloud_2048.jpg b/examples/public/textures/land_ocean_ice_cloud_2048.jpg similarity index 100% rename from examples/textures/land_ocean_ice_cloud_2048.jpg rename to examples/public/textures/land_ocean_ice_cloud_2048.jpg diff --git a/examples/textures/lensflare/lensflare0.png b/examples/public/textures/lensflare/lensflare0.png similarity index 100% rename from examples/textures/lensflare/lensflare0.png rename to examples/public/textures/lensflare/lensflare0.png diff --git a/examples/textures/lensflare/lensflare0_alpha.png b/examples/public/textures/lensflare/lensflare0_alpha.png similarity index 100% rename from examples/textures/lensflare/lensflare0_alpha.png rename to examples/public/textures/lensflare/lensflare0_alpha.png diff --git a/examples/textures/sprite.png b/examples/public/textures/sprite.png similarity index 100% rename from examples/textures/sprite.png rename to examples/public/textures/sprite.png diff --git a/examples/textures/sprite0.jpg b/examples/public/textures/sprite0.jpg similarity index 100% rename from examples/textures/sprite0.jpg rename to examples/public/textures/sprite0.jpg diff --git a/examples/textures/sprite0.png b/examples/public/textures/sprite0.png similarity index 100% rename from examples/textures/sprite0.png rename to examples/public/textures/sprite0.png diff --git a/examples/textures/sprite1.jpg b/examples/public/textures/sprite1.jpg similarity index 100% rename from examples/textures/sprite1.jpg rename to examples/public/textures/sprite1.jpg diff --git a/examples/textures/sprite1.png b/examples/public/textures/sprite1.png similarity index 100% rename from examples/textures/sprite1.png rename to examples/public/textures/sprite1.png diff --git a/examples/textures/sprite2.png b/examples/public/textures/sprite2.png similarity index 100% rename from examples/textures/sprite2.png rename to examples/public/textures/sprite2.png diff --git a/examples/three_fps.html b/examples/three_fps.html index b5ba28b..6678a8d 100644 --- a/examples/three_fps.html +++ b/examples/three_fps.html @@ -1,339 +1,379 @@ - + - - three.js - css3d - platformer demo - - - - - - -
-
three.js - platformer demo. cubemap by Jochum Skoglund.
Use arrow keys to look around, WASD to move and SPACE to jump.
- - - - - - - - - + const start = function (gameLoop, gameViewportSize) { + const resize = function () { + const viewport = gameViewportSize(); + renderer.setSize(viewport.width, viewport.height); + camera.aspect = viewport.width / viewport.height; + camera.updateProjectionMatrix(); + }; + + window.addEventListener("resize", resize); + resize(); + + let lastTimeStamp; + const render = function (timeStamp) { + const timeElapsed = lastTimeStamp ? timeStamp - lastTimeStamp : 0; + lastTimeStamp = timeStamp; + + // call our game loop with the time elapsed since last rendering, in ms + gameLoop(timeElapsed); + + renderer.render(scene, camera); + requestAnimationFrame(render); + }; + + requestAnimationFrame(render); + + if (navigator.userAgent.toLowerCase().indexOf("firefox") > -1) { + // The scene is not rendered in Firefox, without an initial move + setTimeout(function () { + motion.velocity.y = 0.5; + }, 1500); + } + }; + + const gameLoop = function (dt) { + resetPlayer(); + keyboardControls(); + jumpPads(); + applyPhysics(dt); + updateCamera(); + }; + + const gameViewportSize = function () { + return { + width: window.innerWidth, + height: window.innerHeight, + }; + }; + + document.getElementById("container").appendChild(renderer.domElement); + + start(gameLoop, gameViewportSize); + + diff --git a/examples/three_geometry_cube.html b/examples/three_geometry_cube.html index 6c51b5a..406caa1 100644 --- a/examples/three_geometry_cube.html +++ b/examples/three_geometry_cube.html @@ -1,211 +1,176 @@ - + - - three.js CSS3D - geometry - cube - - - - - + + + + c3r - Cube geometry + + + + + let container, stats; - - - - + let camera, scene, renderer; - + let cube, plane; - - - - \ No newline at end of file + stats.begin(); + render(); + stats.end(); + } + + function render() { + plane.rotation.y = cube.rotation.y += + (targetRotation - cube.rotation.y) * 0.05; + renderer.render(scene, camera); + } + + + diff --git a/examples/three_geometry_earth.html b/examples/three_geometry_earth.html index 194532b..0e4ff63 100644 --- a/examples/three_geometry_earth.html +++ b/examples/three_geometry_earth.html @@ -1,178 +1,164 @@ - + - - three.js CSS3D - geometry - earth - - - + + +
+
+ three.js - + earth demo +
+ + - - - - - - - - - - - - \ No newline at end of file + render(); + stats.update(); + } + + function render() { + camera.position.x += (mouseX - camera.position.x) * 0.05; + camera.position.y += (-mouseY - camera.position.y) * 0.05; + camera.lookAt(scene.position); + + group.rotation.y -= 0.005; + + renderer.render(scene, camera); + } + + + diff --git a/examples/three_interactive_cubes_tween.html b/examples/three_interactive_cubes_tween.html index 32a10fb..4e6325e 100644 --- a/examples/three_interactive_cubes_tween.html +++ b/examples/three_interactive_cubes_tween.html @@ -1,148 +1,152 @@ - + - - three.js css3d - interactive - cubes tween - - - - - - - - - - - - - - - - - + camera.position.x = radius * Math.sin(THREE.MathUtils.degToRad(theta)); + camera.position.y = radius * Math.sin(THREE.MathUtils.degToRad(theta)); + camera.position.z = radius * Math.cos(THREE.MathUtils.degToRad(theta)); + camera.lookAt(scene.position); - - \ No newline at end of file + renderer.render(scene, camera); + } + + + diff --git a/examples/three_loader_obj.html b/examples/three_loader_obj.html index 3fb598a..6884396 100644 --- a/examples/three_loader_obj.html +++ b/examples/three_loader_obj.html @@ -1,179 +1,161 @@ - - + - - three.js css3d - loaders - OBJ loader - - - - - - -
- three.js - OBJLoader test -
- - - - - - - - - - + camera.lookAt(scene.position); - + renderer.render(scene, camera); + } + + diff --git a/examples/three_materials_texture_canvas.html b/examples/three_materials_texture_canvas.html index bae6829..79fac3f 100644 --- a/examples/three_materials_texture_canvas.html +++ b/examples/three_materials_texture_canvas.html @@ -1,159 +1,150 @@ - + - - three.js css3d - materials - canvas texture - - - - - - -
- three.js - webgl - canvas as a texture -
click and draw in the white box
-
- - - - - - - - - - - - \ No newline at end of file + + + + c3r - Canvas material + + + +
+ three.js - + webgl - canvas as a texture +
click and draw in the white box
+
+ + + + + diff --git a/examples/three_periodictable.html b/examples/three_periodictable.html index 3345a9a..71a1fee 100644 --- a/examples/three_periodictable.html +++ b/examples/three_periodictable.html @@ -1,471 +1,934 @@ - - - - three.js css3d - periodic table - - - - - - - - - - - - - -
three.js css3d - periodic table. info.
-
- - - - + function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + + render(); + } + + function animate() { + requestAnimationFrame(animate); + + TWEEN.update(); + + controls.update(); + } + + function render() { + renderer.render(scene, camera); + } + + diff --git a/examples/three_physics_rope.html b/examples/three_physics_rope.html index e6afd3f..8089b75 100644 --- a/examples/three_physics_rope.html +++ b/examples/three_physics_rope.html @@ -1,482 +1,533 @@ + - - Amjs softbody rope demo - - - + + +
+ Ammo.js physics soft body rope demo
Press Q or A to move the arm. +
+





Loading...
+ + + + - - - - - - - - - - - - + } + pos.y += brickHeight; + } + + // The rope + const ropeNumSegments = 10; + const ropeLength = 4; + const ropeMass = 3; + const ropePos = ball.position.clone(); + ropePos.y += ballRadius; + + // C3R renders only meshes: one box per segment, moved each frame + const ropeGeometry = new THREE.BoxGeometry(0.06, 0.06, 1).translate( + 0, + 0, + 0.5, + ); + const ropeMaterial = new THREE.MeshPhongMaterial({ color: 0x000000 }); + for (let i = 0; i < ropeNumSegments; i++) { + const segment = new THREE.Mesh(ropeGeometry, ropeMaterial); + scene.add(segment); + ropeSegments.push(segment); + } + + // Rope physic object + const softBodyHelpers = new Ammo.btSoftBodyHelpers(); + const ropeStart = new Ammo.btVector3(ropePos.x, ropePos.y, ropePos.z); + const ropeEnd = new Ammo.btVector3( + ropePos.x, + ropePos.y + ropeLength, + ropePos.z, + ); + ropeSoftBody = softBodyHelpers.CreateRope( + physicsWorld.getWorldInfo(), + ropeStart, + ropeEnd, + ropeNumSegments - 1, + 0, + ); + const sbConfig = ropeSoftBody.get_m_cfg(); + sbConfig.set_viterations(10); + sbConfig.set_piterations(10); + ropeSoftBody.setTotalMass(ropeMass, false); + Ammo.castObject(ropeSoftBody, Ammo.btCollisionObject) + .getCollisionShape() + .setMargin(margin * 3); + physicsWorld.addSoftBody(ropeSoftBody, 1, -1); + // Disable deactivation + ropeSoftBody.setActivationState(4); + + // The base + const armMass = 2; + const armLength = 3; + const pylonHeight = ropePos.y + ropeLength; + const baseMaterial = new THREE.MeshPhongMaterial({ color: 0x606060 }); + pos.set(ropePos.x, 0.1, ropePos.z - armLength); + quat.set(0, 0, 0, 1); + const base = createParalellepiped( + 1, + 0.2, + 1, + 0, + pos, + quat, + baseMaterial, + ); + base.castShadow = true; + base.receiveShadow = true; + pos.set(ropePos.x, 0.5 * pylonHeight, ropePos.z - armLength); + const pylon = createParalellepiped( + 0.4, + pylonHeight, + 0.4, + 0, + pos, + quat, + baseMaterial, + ); + pylon.castShadow = true; + pylon.receiveShadow = true; + pos.set(ropePos.x, pylonHeight + 0.2, ropePos.z - 0.5 * armLength); + const arm = createParalellepiped( + 0.4, + 0.4, + armLength + 0.4, + armMass, + pos, + quat, + baseMaterial, + ); + arm.castShadow = true; + arm.receiveShadow = true; + + // Glue the rope extremes to the ball and the arm + const influence = 1; + ropeSoftBody.appendAnchor( + 0, + ball.userData.physicsBody, + true, + influence, + ); + ropeSoftBody.appendAnchor( + ropeNumSegments, + arm.userData.physicsBody, + true, + influence, + ); + + // Hinge constraint to move the arm + const pivotA = new Ammo.btVector3(0, pylonHeight * 0.5, 0); + const pivotB = new Ammo.btVector3(0, -0.2, -armLength * 0.5); + const axis = new Ammo.btVector3(0, 1, 0); + hinge = new Ammo.btHingeConstraint( + pylon.userData.physicsBody, + arm.userData.physicsBody, + pivotA, + pivotB, + axis, + axis, + true, + ); + physicsWorld.addConstraint(hinge, true); + } + + function createParalellepiped( + sx, + sy, + sz, + mass, + pos, + quat, + material, + scale, + ) { + scale = scale || 1; + + const threeObject = new THREE.Mesh( + new THREE.BoxGeometry(sx * scale, sy * scale, sz * scale, 1, 1, 1), + material, + ); + const shape = new Ammo.btBoxShape( + new Ammo.btVector3(sx * 0.5, sy * 0.5, sz * 0.5), + ); + shape.setMargin(margin); + + createRigidBody(threeObject, shape, mass, pos, quat); + + threeObject.scale.set(1 / scale, 1 / scale, 1 / scale); + + return threeObject; + } + + function createRigidBody(threeObject, physicsShape, mass, pos, quat) { + threeObject.position.copy(pos); + threeObject.quaternion.copy(quat); + + const transform = new Ammo.btTransform(); + transform.setIdentity(); + transform.setOrigin(new Ammo.btVector3(pos.x, pos.y, pos.z)); + transform.setRotation( + new Ammo.btQuaternion(quat.x, quat.y, quat.z, quat.w), + ); + const motionState = new Ammo.btDefaultMotionState(transform); + + const localInertia = new Ammo.btVector3(0, 0, 0); + physicsShape.calculateLocalInertia(mass, localInertia); + + const rbInfo = new Ammo.btRigidBodyConstructionInfo( + mass, + motionState, + physicsShape, + localInertia, + ); + const body = new Ammo.btRigidBody(rbInfo); + + threeObject.userData.physicsBody = body; + + scene.add(threeObject); + + if (mass > 0) { + rigidBodies.push(threeObject); + + // Disable deactivation + body.setActivationState(4); + } + + physicsWorld.addRigidBody(body); + } + + function createRandomColor() { + return Math.floor(Math.random() * (1 << 24)); + } + + function createMaterial() { + return new THREE.MeshPhongMaterial({ color: createRandomColor() }); + } + + function initInput() { + window.addEventListener("keydown", function (event) { + switch (event.keyCode) { + // Q + case 81: + armMovement = 1; + break; + + // A + case 65: + armMovement = -1; + break; + } + }); + + window.addEventListener("keyup", function () { + armMovement = 0; + }); + } + + function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + } + + function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); + } + + function render() { + const deltaTime = timer.update().getDelta(); + + updatePhysics(deltaTime); + + renderer.render(scene, camera); + + time += deltaTime; + } + + function updatePhysics(deltaTime) { + // Hinge control + hinge.enableAngularMotor(true, 1.5 * armMovement, 50); + + // Step world + physicsWorld.stepSimulation(deltaTime, 10); + + // Update rope + const nodes = ropeSoftBody.get_m_nodes(); + for (let i = 0; i < ropeSegments.length; i++) { + const a = nodes.at(i).get_m_x(); + const b = nodes.at(i + 1).get_m_x(); + ropeAux1.set(b.x(), b.y(), b.z()); + + const segment = ropeSegments[i]; + segment.position.set(a.x(), a.y(), a.z()); + segment.scale.z = segment.position.distanceTo(ropeAux1); + segment.lookAt(ropeAux1); + } + + // Update rigid bodies + for (let i = 0, il = rigidBodies.length; i < il; i++) { + const objThree = rigidBodies[i]; + const objPhys = objThree.userData.physicsBody; + const ms = objPhys.getMotionState(); + if (ms) { + ms.getWorldTransform(transformAux1); + const p = transformAux1.getOrigin(); + const q = transformAux1.getRotation(); + objThree.position.set(p.x(), p.y(), p.z()); + objThree.quaternion.set(q.x(), q.y(), q.z(), q.w()); + } + } + } + + diff --git a/examples/three_sprites.html b/examples/three_sprites.html index b01af0d..4d3fa0e 100644 --- a/examples/three_sprites.html +++ b/examples/three_sprites.html @@ -1,232 +1,210 @@ - - - - three.js css3d - sprites - - - - - - - - - - - - - - - -
three.js css3d - sprites.
-
- - - + + + + + + c3r - Sprites + + + +
+ three.js css3d + - sprites. +
+
+ + + diff --git a/examples/three_sprites2.html b/examples/three_sprites2.html index 8b805e2..b70f18d 100644 --- a/examples/three_sprites2.html +++ b/examples/three_sprites2.html @@ -1,240 +1,223 @@ - + - - three.js webgl - sprites - - - - + + + + c3r - Sprites 2 + + - - - + + + let spriteTL, spriteTR, spriteBL, spriteBR, spriteC; - + let mapC; - - + if (material.map !== mapC) { + material.opacity = + Math.sin(time + sprite.position.x * 0.01) * 0.4 + 0.6; + } + } + + group.rotation.x = time * 0.5; + group.rotation.y = time * 0.75; + group.rotation.z = time * 1.0; + + renderer.render(scene, camera); + renderer.render(sceneOrtho, cameraOrtho); + } + + diff --git a/examples/vite.config.mjs b/examples/vite.config.mjs new file mode 100644 index 0000000..bbb72d2 --- /dev/null +++ b/examples/vite.config.mjs @@ -0,0 +1,22 @@ +import { readdirSync } from "node:fs"; +import { resolve } from "node:path"; +import { defineConfig } from "vite"; + +const here = (path) => resolve(import.meta.dirname, path); + +export default defineConfig({ + base: "./", + resolve: { + alias: { + c3r: here("../packages/c3r/src/C3R.ts"), + "c3r-three": here("../packages/c3r-three/src/C3RRenderer.ts"), + }, + }, + build: { + rolldownOptions: { + input: readdirSync(import.meta.dirname) + .filter((file) => file.endsWith(".html")) + .map(here), + }, + }, +}); diff --git a/index.md b/index.md deleted file mode 100644 index d3c8069..0000000 --- a/index.md +++ /dev/null @@ -1,3 +0,0 @@ -# Example projects - -[Open examples](./examples) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..b0d9c85 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2061 @@ +{ + "name": "c3r-workspace", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "c3r-workspace", + "workspaces": [ + "packages/*", + "examples" + ], + "devDependencies": { + "@happy-dom/global-registrator": "^21.0.4", + "@vitest/browser-playwright": "^5.0.5", + "happy-dom": "^21.0.4", + "husky": "^9.1.7", + "lint-staged": "^17.6.0", + "pixelmatch": "^8.0.0", + "playwright": "^1.64.1", + "prettier": "^3.9.10", + "typescript": "^7.0.2", + "vitest": "^5.0.5" + }, + "engines": { + "node": ">=24" + } + }, + "examples": { + "name": "c3r-examples", + "devDependencies": { + "gl-matrix": "^3.4.4", + "three": "^0.186.1", + "vite": "^8.3.5" + } + }, + "node_modules/@blazediff/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@blazediff/core/-/core-1.10.0.tgz", + "integrity": "sha512-AOQff0zgR7cGsZL+4E7hVkmujoPUpm0J9xzWGWZj5wCjd3gmxESXAPfKyuzs93VdpQNFhHlBhfOjrcZ+XTERtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@dimforge/rapier3d-compat": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", + "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@happy-dom/global-registrator": { + "version": "21.0.4", + "resolved": "https://registry.npmjs.org/@happy-dom/global-registrator/-/global-registrator-21.0.4.tgz", + "integrity": "sha512-Bbr0hW9hhDhBf3Jp0EyDlkCbFgbr0z2jd3BMKYOYW+fOkPM4Nx195GMXyCtRCGEgoNn6i09FabXrSkNFm2ONzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": ">=20.0.0", + "happy-dom": "^21.0.4" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.155.0.tgz", + "integrity": "sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/oxc-project" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.15.tgz", + "integrity": "sha512-aLcgK9gIJ3YRvrrtfSBbRa27F5WrpiTaPulnFpsHPxpUHgFlSgnU4854MHwoRGEBhfRJDWCS2WQ7lIjskE9Olw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.15.tgz", + "integrity": "sha512-xD7DdZCrbThKuxNg7ooQmvp07ys4J/pnSEMTG3/OdOWl6daC67m/Q4fL78sRHMxTH/N4fGUbYhcPM0MF5WFHkg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.15.tgz", + "integrity": "sha512-m2WuQ6r0B4OTYxyPpNLtXaMRbRDUbG8YQV2Q3KTdSSK8Th6KHCnC8jVCJt8bvYeSB5WivkkNbc85mKadaSdOxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.15.tgz", + "integrity": "sha512-5RtnsHM36nodM9WbMy+zip0LGS/G+y5wro5RHrpOlr4ac24+1zSi9kiV2MP1myZeZ/ifEHfulQcWjnAXzc2C2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.15.tgz", + "integrity": "sha512-g3l09pyFqhu+135JKkbkwiKGQmwU5hUMUPJ4VdBADvuqR8d33L6H578rh8m7rtxbdp+VmX/+nzI7nvhSZlzpUQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.15.tgz", + "integrity": "sha512-nIe3VugI97nGQtspPxDqA4sXMUpeiocKIP/CqpY/u/vgbT+alX+cVxu1C/oVBPKg4feNTmYovE91v4DgXvXNwQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.15.tgz", + "integrity": "sha512-iTBjXx+B5QSvgI89lJfmqh4wTh8NabR1YZIIN3hNx4zSG0EVfVqkOvLulNpG4251pbd6/IAmZ/LefVk1Y4rPhw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.15.tgz", + "integrity": "sha512-uN26XOnVR7rqQupG3V9oAG2EGGatWjcJHOeDOHUFCh4TBWmP2tHTFoVN13aYbwfm0aHqJAEmcwhAu6sooIjfqQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.15.tgz", + "integrity": "sha512-9nWkcdd+H+XhaA3fQIwpHnKIrfx/PQ6rO0pivr78Og07tXlUlctBBJoEYLPfhTmCR/QxEVdn6uPjHV5SymPhdw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.15.tgz", + "integrity": "sha512-Ggh0ciFjLwIusLSLz7LZYEaGdxOAUJXI+Qu5JCbhPJJHEt8vP+IjRATTJheiJsdzzTYgUiHUiw3X1Ea3ZpMBdA==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.15.tgz", + "integrity": "sha512-FHg60rS6DBePAYZ9X9F67x+JObFdmgn6tupA1C/a3B+CufFmTD4mX+e8M75tCiAO3foR/6xwVBI0KQiI7sn/rw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.15.tgz", + "integrity": "sha512-/cvV/7v5VGz/moiz0XKRj2dE8DzsKyhIu1KpOvJGPjRywg3yscON889UGvAe8zfiJLHup7VLjBduoGWi3HusWQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.15.tgz", + "integrity": "sha512-MyzC5Hrv/sm+Z7TSGKP/j8001RO2xQm1zOpCNVL4j0cY/VhBZviludA2YFQ7i4lH6ZAXxQm0lcMdBzM+99mE7w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.15.tgz", + "integrity": "sha512-+PgYiS+AH5omy6L45ZLxybasauJaj3M8buoT83D+nzPmCayXlxUV9hydhciCKVyIg0B/v0BtXPDE1uGqNwCPpg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.15.tgz", + "integrity": "sha512-HFZd2QNQYn1JbIi+Hpd7H+r/lkWxcfIu28nirZ6eCn2LafuvmExMlb/P96Sfx5tf7pPArw39IdhmCF8vmV+NhQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tweenjs/tween.js": { + "version": "23.1.3", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", + "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "26.6.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.5.tgz", + "integrity": "sha512-uMzsv9stDdofIZBx4UGh4Z9ZgXnGC9seRDscilBcTHAeOFk67MZg/k9bWVfO+bk4qZmG+l52hRnLwUiH2LnJTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.9.0" + } + }, + "node_modules/@types/stats.js": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz", + "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/three": { + "version": "0.186.0", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.186.0.tgz", + "integrity": "sha512-mxYSBpDC+D0pLfSP6sW4WZTcT+nrtmZcimMqnVmy36Hte3XpeYSrvgg4TRdaM1GemGog1AWzI5qL2VoIfMXbJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@dimforge/rapier3d-compat": "~0.12.0", + "@tweenjs/tween.js": "~23.1.3", + "@types/stats.js": "*", + "@types/webxr": ">=0.5.17", + "fflate": "~0.8.3", + "meshoptimizer": "~1.1.1" + } + }, + "node_modules/@types/webxr": { + "version": "0.5.24", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz", + "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/whatwg-mimetype": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-mimetype/-/whatwg-mimetype-3.0.2.tgz", + "integrity": "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.2.tgz", + "integrity": "sha512-67MQl+fpWKVTT1NYdnmo3U4sc/xPo/zQBncVnI74qmQa0z/b+1g6iYqNmGCPbxO+zz2aklb08a0oHfegiVd0/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript/typescript-aix-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", + "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", + "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", + "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", + "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", + "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", + "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", + "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-loong64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", + "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-mips64el": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", + "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", + "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-riscv64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", + "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-s390x": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", + "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", + "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", + "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", + "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", + "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-sunos-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", + "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", + "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", + "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@vitest/browser": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-5.0.5.tgz", + "integrity": "sha512-IDMoZX/iZ8rkilw7weaSgN8tJ7iZ9hUv0wYoKXyiyjWjWFwLSWAY707DcVTgxTYOudWC1E3HA9LYn7kVa9a7uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@blazediff/core": "1.10.0", + "@vitest/mocker": "5.0.5", + "@vitest/ui": "5.0.5", + "@vitest/utils": "5.0.5", + "magic-string": "^1.4.3", + "pngjs": "^7.0.0", + "sirv": "^3.0.2", + "tinyrainbow": "^3.2.0", + "ws": "^8.22.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "5.0.5" + } + }, + "node_modules/@vitest/browser-playwright": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-5.0.5.tgz", + "integrity": "sha512-lcdThFUUcMV9mGGV1SUiZXPxfjgW4CssA7o3STxzh8WK0tT2r526kc12tZIBRZfoLMwkhxjLmMXkWXONzdsDQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/browser": "5.0.5", + "@vitest/mocker": "5.0.5", + "tinyrainbow": "^3.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "playwright": "*", + "vitest": "5.0.5" + }, + "peerDependenciesMeta": { + "playwright": { + "optional": false + } + } + }, + "node_modules/@vitest/mocker": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-5.0.5.tgz", + "integrity": "sha512-xLL3lkDegJZw+MGoGaCCsFayDZthGgpAtr3Vziyfc4p7xH89K7KRPcRBBh/kEYm0Aqkt5DtTmkYpBtRV/FrHZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.31", + "@vitest/spy": "5.0.5", + "estree-walker": "^3.0.3", + "magic-string": "^1.4.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9 || ^3.0.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-5.0.5.tgz", + "integrity": "sha512-24sSdIlMA9DVPXnYiB9siwU0bTd887Y9jX3+vabztCSsvHwo7ipvJ/a2L3Rljw8+2rK1f5fCj3h5U9I/Jsqgbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-5.0.5.tgz", + "integrity": "sha512-lwJRExuH417257Q5wv9QYugN9IMJkoxcrKrYxGPQkBzl7wlNpTUxD/5yNX4ESKVUIShKPgkGchYPFMWOOk0wzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/ui": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-5.0.5.tgz", + "integrity": "sha512-dCoGUOdgmCaSB2g+WQ/spPCBkytAWdNUkFSXY4z+eYp2d8JEOY8v0uDRaJTG9qf/kTlTVZ4CuYMYMz/f1HS/qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "5.0.5", + "fflate": "^0.8.3", + "flatted": "^3.4.4", + "pathe": "^2.0.3", + "sirv": "^3.0.2", + "tinyrainbow": "^3.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "5.0.5" + } + }, + "node_modules/@vitest/utils": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-5.0.5.tgz", + "integrity": "sha512-/rBu7gzLDQI/SC79Tn98b5DwOgaHU/Gt4I9OVeP3YofzNaYtbImRCOJQmT1S6vOJg9gEIlWC+r3QxKkjuSa1nQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "5.0.5", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/buffer-image-size": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/buffer-image-size/-/buffer-image-size-0.6.4.tgz", + "integrity": "sha512-nEh+kZOPY1w+gcCMobZ6ETUp9WfibndnosbpwB1iJk/8Gt5ZF2bhS6+B6bPYz424KtwsR6Rflc3tCz1/ghX2dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/c3r": { + "resolved": "packages/c3r", + "link": true + }, + "node_modules/c3r-examples": { + "resolved": "examples", + "link": true + }, + "node_modules/c3r-three": { + "resolved": "packages/c3r-three", + "link": true + }, + "node_modules/chai": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.3.0.tgz", + "integrity": "sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-module-lexer": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fflate": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz", + "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", + "dev": true, + "license": "MIT" + }, + "node_modules/flatted": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gl-matrix": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.4.tgz", + "integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==", + "license": "MIT" + }, + "node_modules/happy-dom": { + "version": "21.0.4", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-21.0.4.tgz", + "integrity": "sha512-tFm+GaLBgo6o0awHnvHaNoraVo27qJ+2tZEtZ+cIa08hXbeitrxAJajLI05hsUy/2/YTKcUjQYzHe5mCcraLBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": ">=20.0.0", + "@types/whatwg-mimetype": "^3.0.2", + "@types/ws": "^8.18.1", + "buffer-image-size": "^0.6.4", + "entities": "^7.0.1", + "whatwg-mimetype": "^3.0.0", + "ws": "^8.21.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lint-staged": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-17.6.0.tgz", + "integrity": "sha512-nOhBfYkZEwkFtNzD5pK9s9LkcWoxJ+whLzEnhqi9nl7zTB5n7tg8+9iYgMGx2Wm3VlLu8cbNj0RACzY+nWi5iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^4.0.7", + "string-argv": "^0.3.2", + "tinyexec": "^1.3.1" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=22.22.1" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + }, + "optionalDependencies": { + "yaml": "^2.9.1" + } + }, + "node_modules/magic-string": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.3.tgz", + "integrity": "sha512-z12OxmaPGE0F4xlpGdjuAUckipLpQlTAuAmyGhNoD7ODpYUzvDfvtxUbjM/jwznyP178oju/KDdyi220wNJ0RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.6.0" + } + }, + "node_modules/meshoptimizer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-1.1.1.tgz", + "integrity": "sha512-oRFNWJRDA/WTrVj7NWvqa5HqE1t9MYDj2VaWirQCzCCrAd2GHrqR/sQezCxiWATPNlKTcRaPRHPJwIRoPBAp5g==", + "dev": true, + "license": "MIT" + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/nanoid": { + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/obug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/obug/-/obug-3.0.0.tgz", + "integrity": "sha512-5vvB5+W7ePv+p3uqxi+RcW1XAzLW0/hxt3/4X4Lc4qHudzOhmBiBwOY6DRob4WnanAEGvNcLjF+KNOufrUoEQw==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pixelmatch": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-8.0.0.tgz", + "integrity": "sha512-cIqOLfh5k52us715qf3B3+kTOxZv+WDv77HN7xokLScYQGYQHi4m/ynoDIPpvF2LvCyUJGyvzY64i0QCXtzu1g==", + "dev": true, + "license": "ISC", + "dependencies": { + "pngjs": "^7.0.0" + }, + "bin": { + "pixelmatch": "bin/pixelmatch" + } + }, + "node_modules/playwright": { + "version": "1.64.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.64.1.tgz", + "integrity": "sha512-HCrVhHr5QQuwYoswEUGTb7gGp522yflbv/ST8nF4sFWGuLjQCt17Q/EubpGGSNKYn1tsTCPZxqHhHCfVURu7UA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.64.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/playwright-core": { + "version": "1.64.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.64.1.tgz", + "integrity": "sha512-BC4s8y6SEVA6Q1rSxZTto8hI1KUI3xXlHGZgvGqP4IqPdI/a6FX9H29IDNz7vKo9l21b6LfYosScPL6M3xxyDQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/pngjs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", + "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.19.0" + } + }, + "node_modules/postcss": { + "version": "8.5.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.31.tgz", + "integrity": "sha512-YUbWYCgErwnMAVkjUnYa+KlMBzGpHwiIt/DE7f0G33AuX2LH9UcTk6KgWxd3zRU+pN3u/C+Xl3EnMLM4Hea7Sg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.20", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prettier": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.10.tgz", + "integrity": "sha512-skGHTH1Yb9QvaTC4hWnRTzEYtCpApF0UMBPz+t/0ZPzP8ihefo/btKd+QA7pUE0fEwA1SbS/NmhyEcstdXOIdA==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/rolldown": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.15.tgz", + "integrity": "sha512-6odND+fel5zVw3I4Yc2e69gvguDnX0CAAGiNDZSq4ik5WUcaLrkD2GLuog0XcODbor31hZ5ayEMgVDno+KPV5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.155.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.15", + "@rolldown/binding-android-arm64": "1.2.15", + "@rolldown/binding-darwin-arm64": "1.2.15", + "@rolldown/binding-darwin-x64": "1.2.15", + "@rolldown/binding-freebsd-x64": "1.2.15", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.15", + "@rolldown/binding-linux-arm64-gnu": "1.2.15", + "@rolldown/binding-linux-arm64-musl": "1.2.15", + "@rolldown/binding-linux-ppc64-gnu": "1.2.15", + "@rolldown/binding-linux-s390x-gnu": "1.2.15", + "@rolldown/binding-linux-x64-gnu": "1.2.15", + "@rolldown/binding-linux-x64-musl": "1.2.15", + "@rolldown/binding-openharmony-arm64": "1.2.15", + "@rolldown/binding-win32-arm64-msvc": "1.2.15", + "@rolldown/binding-win32-x64-msvc": "1.2.15" + } + }, + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/std-env": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.3.0.tgz", + "integrity": "sha512-OtU/EgQ1kIm5KwqQpBC6ZEMXrZRui11w8zgfTWp8cdO9B8OaPsbA8bTHO2P+HNo1VlUTGMVBwPhydu6poeXiag==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/three": { + "version": "0.186.1", + "resolved": "https://registry.npmjs.org/three/-/three-0.186.1.tgz", + "integrity": "sha512-blFeqb49wRCSGUGj7gtpfnSGHy2lwDk94RhUmS1c/hTby70kvChbWpkJ4Pm1390LqzzvTmzgXKHPEafJwCb8jA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-6.2.2.tgz", + "integrity": "sha512-nIZ2N2dFpjBsg2hgitKu7mA+FvsIJuGJOwysRngmVRRmWgR/UyPjwJj8c/fT/dhm8EkHnF5EOogRf+0Z2qrimA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/tinyexec": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", + "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.2.0.tgz", + "integrity": "sha512-LgO3D9yZJjApUiuUfl9iFAwrtaX4+lok3wJIqttGoKCHlWUqHqbQpnxCf82L8FjgKsh4iGo78hqJwgL8F6To2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/typescript": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc" + }, + "engines": { + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" + } + }, + "node_modules/undici-types": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", + "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.5.tgz", + "integrity": "sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.33.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.30", + "rolldown": "~1.2.14", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.7.1 || ^0.8.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-5.0.5.tgz", + "integrity": "sha512-cPODOMF8YnkiiYtDdHo6n4wWmBrOBBbOIYH2d33M4l3CdNn72h+qMmO6uXffUN6A5AZFXNND/d+krS9mgkXRfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/mocker": "5.0.5", + "chai": "^6.3.0", + "es-module-lexer": "^2.3.2", + "expect-type": "^1.4.0", + "magic-string": "^1.4.3", + "obug": "^3.0.0", + "picomatch": "^4.0.7", + "std-env": "^4.3.0", + "tinybench": "^6.2.2", + "tinyexec": "^1.3.1", + "tinyglobby": "^0.2.17", + "why-is-node-running": "3.2.1" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^22.12.0 || ^24.0.0 || >=26.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "5.0.5", + "@vitest/browser-preview": "5.0.5", + "@vitest/browser-webdriverio": "^5.0.0-beta.5 || >=5.0.0", + "@vitest/coverage-istanbul": "5.0.5", + "@vitest/coverage-v8": "5.0.5", + "@vitest/ui": "5.0.5", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.4.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/why-is-node-running": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-3.2.1.tgz", + "integrity": "sha512-Tb2FUhB4vUsGQlfSquQLYkApkuPAFQXGFzxWKHHumVz2dK+X1RUm/HnID4+TfIGYJ1kTcwOaCk/buYCEJr6YjQ==", + "dev": true, + "license": "MIT", + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=20.11" + } + }, + "node_modules/ws": { + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.22.0.tgz", + "integrity": "sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yaml": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "packages/c3r": { + "version": "0.2.0", + "license": "MIT", + "dependencies": { + "gl-matrix": "^3.4.4" + }, + "devDependencies": { + "vite": "^8.3.5" + } + }, + "packages/c3r-three": { + "version": "0.2.0", + "license": "MIT", + "dependencies": { + "c3r": "^0.2.0" + }, + "devDependencies": { + "@types/three": "^0.186.0", + "three": "^0.186.1", + "vite": "^8.3.5" + }, + "peerDependencies": { + "@types/three": ">=0.160.0", + "three": ">=0.160.0" + }, + "peerDependenciesMeta": { + "@types/three": { + "optional": true + } + } + } + } +} diff --git a/package.json b/package.json index 1b224bb..4eba089 100644 --- a/package.json +++ b/package.json @@ -1,37 +1,36 @@ { - "name": "c3r", - "version": "0.1.0", - "description": "CSS 3D Renderer", - "main": "build/C3R.min.js", - "repository": { - "type": "git", - "url": "git://github.com:deadmanswitch/CSS3D-Renderer.git" + "name": "c3r-workspace", + "private": true, + "workspaces": [ + "packages/*", + "examples" + ], + "engines": { + "node": ">=24" }, "scripts": { - "build": "rollup -c", - "build-uglify": "rollup -c && uglifyjs build/C3R.js -c -m --comments \"/license/i\" -o build/C3R.min.js", - "build-standalone": "rollup -c && uglifyjs node_modules/gl-matrix/dist/gl-matrix-min.js build/C3R.js -c -m --comments \"/license/i\" -o build/C3R.standalone.js" + "build": "npm run build --workspaces --if-present", + "dev": "npm run dev -w c3r-examples", + "typecheck": "tsc -b", + "test": "vitest run", + "test:unit": "vitest run --project unit", + "format": "prettier --write .", + "format:check": "prettier --check .", + "prepare": "husky" }, - "author": "Adam Kecskes ", - "license": "MIT", - "keywords": [ - "javascript", - "css", - "css3d", - "renderer" - ], "devDependencies": { - "babel-core": "^6.26.0", - "babel-plugin-external-helpers": "^6.22.0", - "babel-preset-es2015": "^6.24.1", - "babelrc-rollup": "^3.0.0", - "rollup": "^0.57.1", - "rollup-plugin-babel": "^3.0.3", - "rollup-plugin-license": "^0.6.0", - "uglify-js": "^3.3.18" + "@happy-dom/global-registrator": "^21.0.4", + "@vitest/browser-playwright": "^5.0.5", + "happy-dom": "^21.0.4", + "husky": "^9.1.7", + "lint-staged": "^17.6.0", + "pixelmatch": "^8.0.0", + "playwright": "^1.64.1", + "prettier": "^3.9.10", + "typescript": "^7.0.2", + "vitest": "^5.0.5" }, - "dependencies": { - "gl-matrix": "^2.4.0", - "npm": "^6.13.6" + "lint-staged": { + "*": "prettier --write --ignore-unknown" } } diff --git a/packages/c3r-three/LICENSE b/packages/c3r-three/LICENSE new file mode 100644 index 0000000..3a0d253 --- /dev/null +++ b/packages/c3r-three/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright © 2020 Adam Kecskes + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/packages/c3r-three/README.md b/packages/c3r-three/README.md new file mode 100644 index 0000000..399c204 --- /dev/null +++ b/packages/c3r-three/README.md @@ -0,0 +1,33 @@ +# c3r-three + +A CSS renderer for three.js, built on [C3R](https://www.npmjs.com/package/c3r). Like three's own `CSS3DRenderer` it renders `CSS3DObject` and `CSS3DSprite`, but it also renders meshes and sprites with colors and textures. + +Requires three.js r160 or newer. TypeScript declarations are included; install `@types/three` alongside. + +## Usage + +```sh +npm install c3r-three three +``` + +```js +import { C3RRenderer, CSS3DObject } from "c3r-three"; + +const renderer = new C3RRenderer(); +renderer.setSize(window.innerWidth, window.innerHeight); +document.body.appendChild(renderer.domElement); + +renderer.render(scene, camera); +``` + +`CSS3DObject` and `CSS3DSprite` are re-exported from `three/addons`, so their elements receive pointer events as with three's renderer. + +Perspective and orthographic cameras are supported, including `zoom`. Material `color`, `map` (image or canvas, with `repeat` and `offset`), `opacity` (when `transparent`) and `side` (`BackSide` shows both sides) are applied, and a material's style is removed on its `dispose()`. `renderer.dispose()` removes every rendered scene. + +Not supported yet: texture alpha on meshes (transparent pixels show the material color), `ImageBitmap` maps such as GLTFLoader's, `flipY: false`, and map `rotation` and `center`. + +## Node + +Set up a DOM and inline `cssText()` as described in [c3r](../c3r/README.md#node), then render and serialize `renderer.domElement.outerHTML`. `TextureLoader` needs a browser, so set the image directly: `new Texture(Object.assign(document.createElement("img"), { src }))`. See [node-render.mjs](../../examples/node-render.mjs). + +See the [examples](https://k-adam.github.io/CSS3D-Renderer/). diff --git a/packages/c3r-three/package.json b/packages/c3r-three/package.json new file mode 100644 index 0000000..b9cebf9 --- /dev/null +++ b/packages/c3r-three/package.json @@ -0,0 +1,53 @@ +{ + "name": "c3r-three", + "version": "0.2.0", + "description": "three.js CSS3DRenderer built on C3R, with geometry and texture support", + "keywords": [ + "three", + "threejs", + "css3d", + "renderer" + ], + "homepage": "https://k-adam.github.io/CSS3D-Renderer/", + "repository": { + "type": "git", + "url": "git+https://github.com/K-Adam/CSS3D-Renderer.git", + "directory": "packages/c3r-three" + }, + "license": "MIT", + "author": "Adam Kecskes ", + "type": "module", + "exports": { + ".": { + "types": "./dist/C3RRenderer.d.ts", + "default": "./dist/c3r-three.js" + } + }, + "main": "dist/c3r-three.js", + "types": "dist/C3RRenderer.d.ts", + "files": [ + "dist", + "!dist/*.tsbuildinfo" + ], + "scripts": { + "build": "vite build && tsc -b", + "prepublishOnly": "npm run build" + }, + "dependencies": { + "c3r": "^0.2.0" + }, + "peerDependencies": { + "@types/three": ">=0.160.0", + "three": ">=0.160.0" + }, + "peerDependenciesMeta": { + "@types/three": { + "optional": true + } + }, + "devDependencies": { + "@types/three": "^0.186.0", + "three": "^0.186.1", + "vite": "^8.3.5" + } +} diff --git a/packages/c3r-three/src/C3RRenderer.ts b/packages/c3r-three/src/C3RRenderer.ts new file mode 100644 index 0000000..1887746 --- /dev/null +++ b/packages/c3r-three/src/C3RRenderer.ts @@ -0,0 +1,398 @@ +import { + FrontSide, + InterleavedBufferAttribute, + Matrix4, + Mesh, + OrthographicCamera, + PerspectiveCamera, + Quaternion, + SRGBColorSpace, + Sprite, + Vector3, + type BufferAttribute, + type BufferGeometry, + type Camera, + type Color, + type Material, + type Object3D, + type Scene, + type Texture, +} from "three"; +import { + CSS3DObject, + CSS3DSprite, +} from "three/addons/renderers/CSS3DRenderer.js"; +import * as C3R from "c3r"; + +export { CSS3DObject, CSS3DSprite }; + +// The material fields we read, present on MeshBasicMaterial, SpriteMaterial etc. +type MappedMaterial = Material & { map?: Texture | null; color?: Color }; + +// Missing from @types/three +type RotatedSprite = CSS3DSprite & { rotation2D?: number }; + +interface Range { + start: number; + count: number; + materialIndex: number; +} + +interface MeshState { + key: unknown[]; + groups: { node: C3R.Group; polygons: C3R.Polygon[] }[]; +} + +interface MaterialState { + material: C3R.Material; + map: Texture | null | undefined; + version: number; +} + +const DEFAULT_CENTER = { x: 0.5, y: 0.5 }; +const _matrix = new Matrix4(); +const _parent = new Matrix4(); +const _position = new Vector3(); +const _quaternion = new Quaternion(); +const _scale = new Vector3(); +const _rgb = { r: 0, g: 0, b: 0 }; +const RAD2DEG = 180 / Math.PI; + +export class C3RRenderer { + readonly domElement: HTMLDivElement = document.createElement("div"); + + #width = 0; + #height = 0; + #containers = new Map(); // multiple scenes can overlap + #children = new WeakMap>(); + #meshes = new WeakMap(); + #materials = new WeakMap(); + + getSize(): { width: number; height: number } { + return { width: this.#width, height: this.#height }; + } + + setSize(width: number, height: number): void { + this.#width = width; + this.#height = height; + + this.domElement.style.width = `${width}px`; + this.domElement.style.height = `${height}px`; + + for (const container of this.#containers.values()) { + container.setSize(width, height); + } + } + + dispose(): void { + for (const container of this.#containers.values()) { + container.domElement.remove(); + container.camera[Symbol.dispose](); + } + this.#containers.clear(); + } + + render(scene: Scene, camera: Camera): void { + let container = this.#containers.get(scene); + if (!container) { + container = new C3R.Container(); + container.domElement.style.position = "absolute"; + container.setSize(this.#width, this.#height); + this.domElement.appendChild(container.domElement); + this.#containers.set(scene, container); + } + + if (scene.matrixWorldAutoUpdate) scene.updateMatrixWorld(); + if (camera.parent === null && camera.matrixWorldAutoUpdate) + camera.updateMatrixWorld(); + + this.#syncCamera(container, camera); + this.#syncObject(scene, container.root, container); + } + + #syncCamera(container: C3R.Container, camera: Camera): void { + const c = container.camera; + + if (camera instanceof PerspectiveCamera) { + const fov = + 2 * + RAD2DEG * + Math.atan(Math.tan(camera.fov / 2 / RAD2DEG) / camera.zoom); + if (c instanceof C3R.PerspectiveCamera) { + c.fov = fov; + } else { + c[Symbol.dispose](); // ours, never shared + container.camera = new C3R.PerspectiveCamera(fov); + } + } else if (camera instanceof OrthographicCamera) { + const { zoom } = camera; + const left = camera.left / zoom; + const right = camera.right / zoom; + const top = camera.top / zoom; + const bottom = camera.bottom / zoom; + if (c instanceof C3R.OrthographicCamera) { + Object.assign(c, { left, right, top, bottom }); + } else { + c[Symbol.dispose](); + container.camera = new C3R.OrthographicCamera(left, right, top, bottom); + } + } + + container.camera.matrix = camera.matrixWorldInverse.elements; + } + + #syncObject( + object: Object3D, + node: C3R.Group, + container: C3R.Container, + ): void { + const { style } = node.domElement; + const display = object.visible ? "" : "none"; + if (style.display !== display) style.display = display; + if (!object.visible) return; + + const isSprite = object instanceof Sprite || object instanceof CSS3DSprite; + const matrix = isSprite + ? this.#spriteMatrix(object, node, container) + : object.matrix.elements; + + node.matrix = matrix; + + this.#syncChildren(object, node, container); + + if (isSprite && node instanceof C3R.ElementObject) { + node.rotation = + object instanceof Sprite + ? object.material.rotation + : ((object as RotatedSprite).rotation2D ?? 0); + } + + if (object instanceof Sprite) this.#syncMaterial(object.material, node); + if (object instanceof Mesh) this.#syncMesh(object, node); + } + + #spriteMatrix( + object: Object3D, + node: C3R.Group, + container: C3R.Container, + ): number[] { + // Billboard in world space + _matrix.fromArray(container.camera.matrix).transpose(); + + const e = _matrix.elements; + e[3] = e[7] = e[11] = 0; + e[15] = 1; + + object.matrixWorld.decompose(_position, _quaternion, _scale); + _matrix.setPosition(_position).scale(_scale); + + // relative to the parent node + if (object.parent) + _matrix.premultiply(_parent.copy(object.parent.matrixWorld).invert()); + + if (node instanceof C3R.ElementObject) { + const { x, y } = + object instanceof Sprite ? object.center : DEFAULT_CENTER; + node.center = [x, y]; + } + + return e; + } + + #syncChildren( + object: Object3D, + node: C3R.Group, + container: C3R.Container, + ): void { + const previous = this.#children.get(node) ?? new Map(); + const current = new Map(); + + for (const child of object.children) { + let childNode = previous.get(child); + if (!childNode) { + childNode = createNode(child); + node.addChild(childNode); + } + current.set(child, childNode); + } + + for (const [child, childNode] of previous) { + if (!current.has(child)) node.removeChild(childNode); + } + + this.#children.set(node, current); + + for (const [child, childNode] of current) { + this.#syncObject(child, childNode, container); + } + } + + #syncMesh(mesh: Mesh, node: C3R.Group): void { + const { geometry } = mesh; + const { index, attributes, drawRange } = geometry; + const { position, uv } = attributes; + if (!position) return; + + const total = index ? index.count : position.count; + + const ranges: Range[] = ( + geometry.groups.length + ? geometry.groups + : [{ ...drawRange, materialIndex: 0 }] + ).map((g) => ({ + start: g.start, + count: Math.min(g.count, total - g.start), + materialIndex: g.materialIndex ?? 0, + })); + + const key: unknown[] = [ + geometry, + index, + index?.version, + position, + version(position), + uv, + version(uv), + ]; + for (const r of ranges) key.push(r.start, r.count); + + let state = this.#meshes.get(node); + if (!state || !sameKey(state.key, key)) { + state?.groups.forEach((g) => node.removeChild(g.node)); + state = { key, groups: ranges.map((r) => buildGroup(geometry, r)) }; + state.groups.forEach((g) => node.addChild(g.node)); + this.#meshes.set(node, state); + } + + const materials: MappedMaterial[] = Array.isArray(mesh.material) + ? mesh.material + : [mesh.material]; + ranges.forEach((r, i) => { + const group = state.groups[i]; + const map = this.#syncMaterial( + materials[r.materialIndex % materials.length], + group.node, + ); + + const repeat: [number, number] = map + ? [map.repeat.x, map.repeat.y] + : [1, 1]; + const offset: [number, number] = map + ? [map.offset.x, map.offset.y] + : [0, 0]; + for (const polygon of group.polygons) { + polygon.uvScale = repeat; + polygon.uvOffset = offset; + } + }); + } + + // Returns the map in use, for the caller to apply its repeat/offset + #syncMaterial( + material: MappedMaterial, + node: C3R.Group, + ): Texture | null | undefined { + let state = this.#materials.get(material); + if (!state) { + const created = { + material: new C3R.Material(), + map: undefined, + version: -1, + }; + // Not this.#materials, the listener would keep the renderer alive + const materials = this.#materials; + const onDispose = () => { + material.removeEventListener("dispose", onDispose); + created.material[Symbol.dispose](); + materials.delete(material); + }; + material.addEventListener("dispose", onDispose); + this.#materials.set(material, (state = created)); + } + + const target = state.material; + node.material = target; + + const { map } = material; + const image: unknown = map?.image; + let src: string | null = null; + if (image instanceof HTMLImageElement) { + src = image.src; + } else if (image instanceof HTMLCanvasElement && map) { + const cached = state.map === map && state.version === map.version; + src = cached ? target.backgroundImageSrc : image.toDataURL(); + state.map = map; + state.version = map.version; + } + target.backgroundImageSrc = src; + + if (material.color) { + material.color.getRGB(_rgb, SRGBColorSpace); + target.backgroundColor = [_rgb.r, _rgb.g, _rgb.b, 1]; + } else { + target.backgroundColor = null; + } + + target.opacity = material.transparent ? material.opacity : 1; + // ponytail: BackSide renders as double-sided, CSS can't cull front faces only + target.doubleSided = material.side !== FrontSide; + + return map; + } +} + +const version = ( + attribute?: BufferAttribute | InterleavedBufferAttribute | null, +) => + attribute instanceof InterleavedBufferAttribute + ? attribute.data.version + : attribute?.version; + +const sameKey = (a: unknown[], b: unknown[]) => + a.length === b.length && a.every((v, i) => v === b[i]); + +function createNode(object: Object3D): C3R.Group { + if (object instanceof CSS3DObject) { + const node = new C3R.ElementObject(object.element); + node.domElement.style.backfaceVisibility = "visible"; + return node; + } + + if (object instanceof Sprite) { + const element = document.createElement("div"); + element.style.backgroundBlendMode = "multiply"; + element.style.maskImage = "var(--c3r-background-image, none)"; + element.style.maskSize = "100% 100%"; + + const node = new C3R.ElementObject(element); + node.setSize(128, 128); + node.scale = [1 / 128, 1 / 128]; + return node; + } + + return new C3R.Group(); +} + +function buildGroup( + geometry: BufferGeometry, + { start, count }: Range, +): MeshState["groups"][number] { + const { index } = geometry; + const { position, uv } = geometry.attributes; + + const vertex = (i: number): C3R.Vertex => { + if (index) i = index.getX(i); + return { + position: [position.getX(i), position.getY(i), position.getZ(i)], + uv: uv ? [uv.getX(i), uv.getY(i)] : [0, 0], + }; + }; + + const triangles: C3R.Vertex[][] = []; + for (let i = start; i + 2 < start + count; i += 3) { + triangles.push([vertex(i), vertex(i + 1), vertex(i + 2)]); + } + + const node = new C3R.Group(); + return { node, polygons: node.addTriangles(triangles) }; +} diff --git a/packages/c3r-three/test/C3RRenderer.test.ts b/packages/c3r-three/test/C3RRenderer.test.ts new file mode 100644 index 0000000..da90356 --- /dev/null +++ b/packages/c3r-three/test/C3RRenderer.test.ts @@ -0,0 +1,234 @@ +import { expect, it } from "vitest"; +import { mat4 } from "gl-matrix"; +import { + BoxGeometry, + DoubleSide, + Group, + Mesh, + MeshBasicMaterial, + OrthographicCamera, + PerspectiveCamera, + Scene, + Sprite, + SpriteMaterial, + Vector3, +} from "three"; +import { cssText } from "c3r"; +import { C3RRenderer, CSS3DObject } from "../src/C3RRenderer.js"; + +const setup = () => { + const renderer = new C3RRenderer(); + renderer.setSize(800, 600); + const scene = new Scene(); + const camera = new PerspectiveCamera(70, 800 / 600, 1, 1000); + camera.position.set(5, 5, 20); + camera.lookAt(0, 0, 0); + const root = () => + renderer.domElement.querySelector(".c3r-view > .c3r-group")!; + return { renderer, scene, camera, root }; +}; + +const cssMatrix = (element: Element) => { + const match = /matrix3d\(([^)]*)\)/.exec( + (element as HTMLElement).style.transform, + ); + return mat4.clone(match![1].split(",").map(Number) as unknown as mat4); +}; + +it("places a nested sprite at its world position, facing the camera", () => { + const { renderer, scene, camera, root } = setup(); + + const group = new Group(); + group.position.set(10, 0, 0); + group.rotation.y = Math.PI / 3; + group.scale.setScalar(2); + scene.add(group); + + const sprite = new Sprite(new SpriteMaterial()); + sprite.position.set(1, 2, 0); + sprite.scale.set(1.5, 0.5, 1); + group.add(sprite); + + renderer.render(scene, camera); + + const groupNode = root().firstElementChild!; + const spriteNode = groupNode.firstElementChild!; + const world = mat4.mul( + mat4.create(), + cssMatrix(groupNode), + cssMatrix(spriteNode), + ); + + const position = sprite.getWorldPosition(new Vector3()); + expect(world[12]).toBeCloseTo(position.x, 6); + expect(world[13]).toBeCloseTo(position.y, 6); + expect(world[14]).toBeCloseTo(position.z, 6); + + const scale = sprite.getWorldScale(new Vector3()); + const cam = camera.matrixWorld.elements; + [scale.x, scale.y].forEach((s, i) => { + const column = [world[i * 4], world[i * 4 + 1], world[i * 4 + 2]]; + expect(Math.hypot(...column)).toBeCloseTo(s, 6); + column.forEach((c, j) => expect(c / s).toBeCloseTo(cam[i * 4 + j], 6)); + }); +}); + +it("follows visibility, geometry updates and removal", () => { + const { renderer, scene, camera, root } = setup(); + + const mesh = new Mesh(new BoxGeometry(2, 2, 2), new MeshBasicMaterial()); + scene.add(mesh); + + const polygons = () => + [...renderer.domElement.querySelectorAll("div")].filter((d) => + d.style.getPropertyValue("--c3r-width"), + ); + + renderer.render(scene, camera); + const meshNode = root().firstElementChild as HTMLElement; + const before = polygons(); + expect(before).toHaveLength(6); + + mesh.visible = false; + renderer.render(scene, camera); + expect(meshNode.style.display).toBe("none"); + + mesh.visible = true; + renderer.render(scene, camera); + expect(meshNode.style.display).toBe(""); + + const { position } = mesh.geometry.attributes; + position.setX(0, 3); + position.needsUpdate = true; + renderer.render(scene, camera); + expect(before.some((d) => d.isConnected)).toBe(false); + expect(polygons().length).toBeGreaterThanOrEqual(6); + + scene.remove(mesh); + renderer.render(scene, camera); + expect(meshNode.isConnected).toBe(false); + expect(polygons()).toHaveLength(0); +}); + +it("shares one stylesheet between renderers", () => { + const a = setup(); + const b = setup(); + a.renderer.render(a.scene, a.camera); + b.renderer.render(b.scene, b.camera); + + expect(document.adoptedStyleSheets).toHaveLength(1); + expect([...a.root().classList]).toEqual(["c3r-group"]); + expect(a.root().parentElement!.classList).toContain("c3r-view"); +}); + +it("shares one material rule between meshes, removed on dispose", () => { + const { renderer, scene, camera, root } = setup(); + + const material = new MeshBasicMaterial({ color: 0xff0000 }); + scene.add(new Mesh(new BoxGeometry(), material)); + scene.add(new Mesh(new BoxGeometry(), material)); + renderer.render(scene, camera); + + // mesh node > polygon group + const classes = [...root().children].map( + (mesh) => mesh.firstElementChild!.className, + ); + const className = /c3r-material-\d+/.exec(classes[0])![0]; + expect(classes[1]).toContain(className); + + const [sheet] = document.adoptedStyleSheets; + const rules = () => + [...sheet.cssRules].filter((r) => r.cssText.startsWith(`.${className} `)); + expect(rules()).toHaveLength(1); + expect(rules()[0].cssText).toContain("rgba(255"); + + material.dispose(); + expect(rules()).toHaveLength(0); +}); + +it("applies the camera zoom", () => { + const { renderer, scene } = setup(); + + renderer.render(scene, new OrthographicCamera(-400, 400, 300, -300)); + const container = renderer.domElement.firstElementChild!; + expect(container.classList).toContain("c3r-orthographic"); + + const ortho = new OrthographicCamera(-400, 400, 300, -300); + ortho.zoom = 2; + renderer.render(scene, ortho); + expect(cssText()).toMatch(/--c3r-camera-left: ?-200;/); + + const perspective = new PerspectiveCamera(90); + perspective.zoom = 2; + renderer.render(scene, perspective); + expect(container.classList).toContain("c3r-perspective"); + // 2 * atan(tan(45deg) / 2) + expect(cssText()).toMatch(/--c3r-camera-fov: ?53\.13/); +}); + +it("ignores opacity unless the material is transparent, as WebGL", () => { + const { renderer, scene, camera } = setup(); + + const material = new MeshBasicMaterial({ opacity: 0.5 }); + scene.add(new Mesh(new BoxGeometry(), material)); + renderer.render(scene, camera); + expect(cssText()).not.toMatch(/--c3r-opacity:/); + + material.transparent = true; + renderer.render(scene, camera); + expect(cssText()).toMatch(/--c3r-opacity: ?0\.5/); + material.dispose(); +}); + +it("keeps a sprite's material off its child elements", () => { + const { renderer, scene, camera } = setup(); + + const material = new SpriteMaterial({ color: 0xff0000 }); + const sprite = new Sprite(material); + const child = new CSS3DObject(document.createElement("div")); + sprite.add(child); + scene.add(sprite); + renderer.render(scene, camera); + + expect(child.element.closest("[class*=c3r-material-]")).toBeNull(); + material.dispose(); +}); + +it("shows back faces unless the material is FrontSide", () => { + const { renderer, scene, camera, root } = setup(); + + const front = new MeshBasicMaterial(); + const double = new MeshBasicMaterial({ side: DoubleSide }); + scene.add(new Mesh(new BoxGeometry(), front)); + scene.add(new Mesh(new BoxGeometry(), double)); + renderer.render(scene, camera); + + const [frontRule, doubleRule] = [...root().children].map((mesh) => { + const className = /c3r-material-\d+/.exec( + mesh.firstElementChild!.className, + )![0]; + return cssText() + .split("\n") + .find((r) => r.startsWith(`.${className} `))!; + }); + expect(frontRule).not.toContain("backface-visibility"); + expect(doubleRule).toMatch(/backface-visibility: ?visible/); + + front.dispose(); + double.dispose(); +}); + +it("removes the scenes and camera rules on dispose", () => { + const { renderer, scene, camera } = setup(); + renderer.render(scene, camera); + const className = [...renderer.domElement.firstElementChild!.classList].find( + (c) => c.startsWith("c3r-camera-"), + )!; + + renderer.dispose(); + expect(renderer.domElement.children).toHaveLength(0); + expect(cssText()).not.toContain(`.${className} `); + + renderer.render(scene, camera); + expect(renderer.domElement.children).toHaveLength(1); +}); diff --git a/packages/c3r-three/test/earth.browser.test.ts b/packages/c3r-three/test/earth.browser.test.ts new file mode 100644 index 0000000..5a658e0 --- /dev/null +++ b/packages/c3r-three/test/earth.browser.test.ts @@ -0,0 +1,136 @@ +import { expect, it } from "vitest"; +import { commands, page } from "vitest/browser"; +import pixelmatch from "pixelmatch"; +import { + CanvasTexture, + Color, + Group, + Mesh, + MeshBasicMaterial, + PerspectiveCamera, + PlaneGeometry, + Scene, + SphereGeometry, + SRGBColorSpace, + TextureLoader, + WebGLRenderer, +} from "three"; +import { C3RRenderer } from "../src/C3RRenderer.js"; + +const WIDTH = 400; +const HEIGHT = 300; +// Compared downscaled, as WebGL mipmaps the texture but CSS doesn't +const SCALE = 4; +const LIMIT = 0.02; // measured 0.0105 + +// From examples/three_geometry_earth.html, without animation +async function earthScene() { + const scene = new Scene(); + scene.background = new Color(0xffffff); + + const group = new Group(); + group.rotation.y = 1; + scene.add(group); + + const map = await new TextureLoader().loadAsync( + "/textures/land_ocean_ice_cloud_2048.jpg", + ); + map.colorSpace = SRGBColorSpace; + group.add( + new Mesh(new SphereGeometry(200, 16, 10), new MeshBasicMaterial({ map })), + ); + + const canvas = document.createElement("canvas"); + canvas.width = canvas.height = 128; + const context = canvas.getContext("2d")!; + const gradient = context.createRadialGradient(64, 64, 0, 64, 64, 64); + gradient.addColorStop(0.1, "rgba(210,210,210,1)"); + gradient.addColorStop(1, "rgba(255,255,255,1)"); + context.fillStyle = gradient; + context.fillRect(0, 0, 128, 128); + + const shadow = new CanvasTexture(canvas); + shadow.colorSpace = SRGBColorSpace; + const plane = new Mesh( + new PlaneGeometry(300, 300, 2, 2), + new MeshBasicMaterial({ map: shadow }), + ); + plane.position.y = -250; + plane.rotation.x = -Math.PI / 2; + group.add(plane); + + const camera = new PerspectiveCamera(60, WIDTH / HEIGHT, 1, 2000); + camera.position.set(150, 100, 500); + camera.lookAt(scene.position); + + return { scene, camera }; +} + +const W = WIDTH / SCALE; +const H = HEIGHT / SCALE; + +const canvas2d = () => { + const context = document.createElement("canvas").getContext("2d")!; + context.canvas.width = W; + context.canvas.height = H; + return context; +}; + +// Also saved to __screenshots__/ for inspection +async function pixels(element: Element, name: string) { + const { base64 } = await page.screenshot({ + element, + path: `__screenshots__/${name}.png`, + base64: true, + }); + const image = new Image(); + image.src = `data:image/png;base64,${base64}`; + await image.decode(); + expect([image.width, image.height]).toEqual([WIDTH, HEIGHT]); + + const context = canvas2d(); + context.imageSmoothingQuality = "high"; + context.drawImage(image, 0, 0, W, H); + return context.getImageData(0, 0, W, H); +} + +it("renders the earth example like WebGLRenderer", async () => { + const { scene, camera } = await earthScene(); + document.body.style.cssText = "margin:0;background:#fff"; + + const webgl = new WebGLRenderer({ antialias: true }); + webgl.setPixelRatio(1); + webgl.setSize(WIDTH, HEIGHT); + document.body.appendChild(webgl.domElement); + + const c3r = new C3RRenderer(); + c3r.setSize(WIDTH, HEIGHT); + document.body.appendChild(c3r.domElement); + + webgl.render(scene, camera); + c3r.render(scene, camera); + await new Promise((r) => + requestAnimationFrame(() => requestAnimationFrame(r)), + ); + + const expected = await pixels(webgl.domElement, "earth-webgl"); + const actual = await pixels(c3r.domElement, "earth-c3r"); + const diff = new ImageData(W, H); + const ratio = + pixelmatch(expected.data, actual.data, diff.data, W, H, { + threshold: 0.1, + }) / + (W * H); + + if (ratio >= LIMIT) { + const context = canvas2d(); + context.putImageData(diff, 0, 0); + const png = context.canvas.toDataURL().split(",")[1]; + await commands.writeFile( + "packages/c3r-three/test/__screenshots__/earth-diff.png", + png, + "base64", + ); + } + expect(ratio).toBeLessThan(LIMIT); +}); diff --git a/packages/c3r-three/tsconfig.json b/packages/c3r-three/tsconfig.json new file mode 100644 index 0000000..585fdea --- /dev/null +++ b/packages/c3r-three/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo" + }, + "include": ["src"], + "references": [{ "path": "../c3r" }] +} diff --git a/packages/c3r-three/vite.config.mjs b/packages/c3r-three/vite.config.mjs new file mode 100644 index 0000000..04a7b03 --- /dev/null +++ b/packages/c3r-three/vite.config.mjs @@ -0,0 +1,13 @@ +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + lib: { + entry: "src/C3RRenderer.ts", + formats: ["es"], + fileName: "c3r-three", + }, + minify: false, + rolldownOptions: { external: [/^three($|\/)/, "c3r"] }, + }, +}); diff --git a/packages/c3r/LICENSE b/packages/c3r/LICENSE new file mode 100644 index 0000000..3a0d253 --- /dev/null +++ b/packages/c3r/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright © 2020 Adam Kecskes + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/packages/c3r/README.md b/packages/c3r/README.md new file mode 100644 index 0000000..aa5c727 --- /dev/null +++ b/packages/c3r/README.md @@ -0,0 +1,89 @@ +# c3r + +**C3R.js** is a lightweight library for displaying 3D scenes with CSS. It is designed to be used as a CSS3D backend for existing libraries. It provides classes to construct textured polygons, nest 3D transformed elements and handle camera. + +## Usage + +With a bundler: + +```sh +npm install c3r +``` + +```js +import { Container, Polygon } from "c3r"; +``` + +Or with a script tag, using [GitHub Releases](https://github.com/K-Adam/CSS3D-Renderer/releases) or a CDN: + +```html + +``` + +It bundles gl-matrix and exposes a `C3R` global. + +TypeScript declarations are included. + +## API + +```js +import { Container, Group, Material } from "c3r"; +import { mat4 } from "gl-matrix"; + +const container = new Container(); // fills the window until setSize() +document.body.append(container.domElement); + +const cube = new Group(); +container.root.addChild(cube); +cube.addPolygon([ + { position: [-100, 100, 100], uv: [0, 1] }, + { position: [-100, -100, 100], uv: [0, 0] }, + { position: [100, -100, 100], uv: [1, 0] }, + { position: [100, 100, 100], uv: [1, 1] }, +]); + +cube.material = new Material(); +cube.material.backgroundImageSrc = "crate.jpg"; + +container.camera.matrix = mat4.fromTranslation(mat4.create(), [0, 0, -400]); +``` + +| Class | What it is | +| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Container` | The viewport: `domElement`, `root` group, `camera`, `setSize()` | +| `Group` | A transformed node: `matrix`, `addChild()`, `addPolygon()`, `addTriangles()` merges into polygons | +| `Polygon` | A flat, convex or concave textured polygon from CCW vertices, with `uvScale`, `uvOffset` | +| `ElementObject` | Any HTML element in the scene, centered on the origin, with `scale`, `center`, `rotation` | +| `Material` | `backgroundColor`, `backgroundImageSrc`, `opacity`, `doubleSided`, inherited by the object's descendants; on an `ElementObject`, its element only | +| `PerspectiveCamera`, `OrthographicCamera` | `matrix` (inverse world) and `fov`, or `left`, `right`, `top`, `bottom` | + +Every property applies on assignment; there is no `update()` to call. A polygon is laid out from its vertices on construction, so put it in a group to move it. + +A `Material` or camera is a class rule in one shared stylesheet, so the objects using it share one style. The rule stays until `[Symbol.dispose]()` is called, or the owner leaves a `using` block; otherwise it is removed once the owner and its elements are garbage-collected. + +An orthographic camera needs `setSize()`: without it the container takes the window size at construction and does not follow resizes. + +The stylesheet is adopted by `document` only, so a container inside a shadow root is unstyled. + +## Node + +C3R builds plain DOM elements, so it runs on a server-side DOM like [happy-dom](https://github.com/capricorn86/happy-dom). Stylesheets are not serialized, so inline `cssText()`, the base styles plus the material and camera rules, after building the scene. There is no layout either, so set the size explicitly. + +```sh +npm install c3r @happy-dom/global-registrator +``` + +```js +import { GlobalRegistrator } from "@happy-dom/global-registrator"; +GlobalRegistrator.register(); + +const { Container, cssText } = await import("c3r"); + +const container = new Container(); +container.setSize(800, 600); +// ... build the scene + +const html = `${container.domElement.outerHTML}`; +``` + +See the [examples](https://k-adam.github.io/CSS3D-Renderer/). diff --git a/packages/c3r/package.json b/packages/c3r/package.json new file mode 100644 index 0000000..55cb65a --- /dev/null +++ b/packages/c3r/package.json @@ -0,0 +1,44 @@ +{ + "name": "c3r", + "version": "0.2.0", + "description": "CSS 3D Renderer", + "keywords": [ + "typescript", + "css", + "css3d", + "renderer" + ], + "homepage": "https://k-adam.github.io/CSS3D-Renderer/", + "repository": { + "type": "git", + "url": "git+https://github.com/K-Adam/CSS3D-Renderer.git", + "directory": "packages/c3r" + }, + "license": "MIT", + "author": "Adam Kecskes ", + "type": "module", + "exports": { + ".": { + "types": "./dist/C3R.d.ts", + "default": "./dist/c3r.js" + } + }, + "main": "dist/c3r.js", + "types": "dist/C3R.d.ts", + "unpkg": "dist/c3r.min.js", + "jsdelivr": "dist/c3r.min.js", + "files": [ + "dist", + "!dist/*.tsbuildinfo" + ], + "scripts": { + "build": "vite build && vite build --mode min && tsc -b", + "prepublishOnly": "npm run build" + }, + "dependencies": { + "gl-matrix": "^3.4.4" + }, + "devDependencies": { + "vite": "^8.3.5" + } +} diff --git a/packages/c3r/src/C3R.ts b/packages/c3r/src/C3R.ts new file mode 100644 index 0000000..3a4d5d9 --- /dev/null +++ b/packages/c3r/src/C3R.ts @@ -0,0 +1,14 @@ +export { Material } from "./css/Material.js"; +export { cssText } from "./css/styles.js"; + +export { Object3D } from "./dom/Object3D.js"; +export { Group } from "./dom/Group.js"; +export { Container } from "./dom/Container.js"; +export { Polygon, type PolygonOptions } from "./dom/Polygon.js"; +export { ElementObject } from "./dom/ElementObject.js"; + +export type { Vertex } from "./math/Vertex.js"; + +export { Camera } from "./css/Camera.js"; +export { PerspectiveCamera } from "./css/PerspectiveCamera.js"; +export { OrthographicCamera } from "./css/OrthographicCamera.js"; diff --git a/packages/c3r/src/css/Camera.ts b/packages/c3r/src/css/Camera.ts new file mode 100644 index 0000000..dd9b35a --- /dev/null +++ b/packages/c3r/src/css/Camera.ts @@ -0,0 +1,56 @@ +import "../polyfill.js"; + +import { mat4, type ReadonlyMat4 } from "gl-matrix"; + +import { deleteRule, insertRule } from "./styles.js"; + +let nextId = 0; + +// The projection math lives in styles.css, cameras only set its variables +export abstract class Camera { + readonly className = `c3r-camera-${nextId++}`; + abstract readonly projectionClass: string; + + #matrix = mat4.create(); + #paramsRule: CSSStyleRule | null = insertRule(`.${this.className}`, this); + // Changes every frame + #viewRule: CSSStyleRule | null = insertRule( + `.${this.className} > .c3r-view`, + this, + ); + + constructor() { + this.#writeMatrix(); + } + + // Inverse world + get matrix(): ReadonlyMat4 { + return this.#matrix; + } + + set matrix(matrix: ReadonlyMat4) { + if (mat4.exactEquals(matrix, this.#matrix)) return; + mat4.copy(this.#matrix, matrix); + this.#writeMatrix(); + } + + #writeMatrix(): void { + this.#viewRule?.style.setProperty( + "--c3r-camera-view", + `matrix3d(${[...this.#matrix].join()})`, + ); + } + + // Rewriting an unchanged rule would still restyle the whole scene + protected setParam(name: string, value: string): void { + const style = this.#paramsRule?.style; + if (style && style.getPropertyValue(name) !== value) + style.setProperty(name, value); + } + + [Symbol.dispose](): void { + deleteRule(this.#paramsRule); + deleteRule(this.#viewRule); + this.#paramsRule = this.#viewRule = null; + } +} diff --git a/packages/c3r/src/css/Material.ts b/packages/c3r/src/css/Material.ts new file mode 100644 index 0000000..ff0d286 --- /dev/null +++ b/packages/c3r/src/css/Material.ts @@ -0,0 +1,82 @@ +import "../polyfill.js"; + +import { vec4, type ReadonlyVec4 } from "gl-matrix"; + +import { deleteRule, insertRule } from "./styles.js"; + +let nextId = 0; + +export class Material { + readonly className = `c3r-material-${nextId++}`; + + #backgroundImageSrc: string | null = null; + #backgroundColor: ReadonlyVec4 | null = null; + #opacity = 1; + #doubleSided = false; + + #rule: CSSStyleRule | null = insertRule(`.${this.className}`, this); + + get backgroundImageSrc(): string | null { + return this.#backgroundImageSrc; + } + + set backgroundImageSrc(src: string | null) { + if (src === this.#backgroundImageSrc) return; + this.#backgroundImageSrc = src; + this.#set( + "--c3r-background-image", + src && `url("${src.replace(/["\\]/g, "\\$&")}")`, + ); + } + + // rgba, 0-1 + get backgroundColor(): ReadonlyVec4 | null { + return this.#backgroundColor; + } + + set backgroundColor(color: ReadonlyVec4 | null) { + const old = this.#backgroundColor; + if (color === old || (color && old && vec4.exactEquals(color, old))) return; + this.#backgroundColor = color && vec4.clone(color); + + let value = null; + if (color) { + const [r, g, b, a] = color; + const rgb = [r, g, b].map((c) => Math.round(c * 255)); + value = `rgba(${rgb.join()},${a})`; + } + this.#set("--c3r-background-color", value); + } + + get opacity(): number { + return this.#opacity; + } + + set opacity(opacity: number) { + if (opacity === this.#opacity) return; + this.#opacity = opacity; + this.#set("--c3r-opacity", opacity === 1 ? null : String(opacity)); + } + + get doubleSided(): boolean { + return this.#doubleSided; + } + + set doubleSided(doubleSided: boolean) { + if (doubleSided === this.#doubleSided) return; + this.#doubleSided = doubleSided; + this.#set("backface-visibility", doubleSided ? "visible" : null); + } + + #set(name: string, value: string | null): void { + const style = this.#rule?.style; + if (!style) return; + if (value === null) style.removeProperty(name); + else style.setProperty(name, value); + } + + [Symbol.dispose](): void { + deleteRule(this.#rule); + this.#rule = null; + } +} diff --git a/packages/c3r/src/css/OrthographicCamera.ts b/packages/c3r/src/css/OrthographicCamera.ts new file mode 100644 index 0000000..3c6e2f3 --- /dev/null +++ b/packages/c3r/src/css/OrthographicCamera.ts @@ -0,0 +1,53 @@ +import { Camera } from "./Camera.js"; + +export class OrthographicCamera extends Camera { + readonly projectionClass = "c3r-orthographic"; + #left = 0; + #right = 0; + #top = 0; + #bottom = 0; + + constructor(left: number, right: number, top: number, bottom: number) { + super(); + this.left = left; + this.right = right; + this.top = top; + this.bottom = bottom; + } + + get left(): number { + return this.#left; + } + + set left(left: number) { + this.#left = left; + this.setParam("--c3r-camera-left", String(left)); + } + + get right(): number { + return this.#right; + } + + set right(right: number) { + this.#right = right; + this.setParam("--c3r-camera-right", String(right)); + } + + get top(): number { + return this.#top; + } + + set top(top: number) { + this.#top = top; + this.setParam("--c3r-camera-top", String(top)); + } + + get bottom(): number { + return this.#bottom; + } + + set bottom(bottom: number) { + this.#bottom = bottom; + this.setParam("--c3r-camera-bottom", String(bottom)); + } +} diff --git a/packages/c3r/src/css/PerspectiveCamera.ts b/packages/c3r/src/css/PerspectiveCamera.ts new file mode 100644 index 0000000..f61dd84 --- /dev/null +++ b/packages/c3r/src/css/PerspectiveCamera.ts @@ -0,0 +1,20 @@ +import { Camera } from "./Camera.js"; + +export class PerspectiveCamera extends Camera { + readonly projectionClass = "c3r-perspective"; + #fov = 0; + + constructor(fov = 70) { + super(); + this.fov = fov; + } + + get fov(): number { + return this.#fov; + } + + set fov(fov: number) { + this.#fov = fov; + this.setParam("--c3r-camera-fov", `${fov}deg`); + } +} diff --git a/packages/c3r/src/css/styles.css b/packages/c3r/src/css/styles.css new file mode 100644 index 0000000..8b26db6 --- /dev/null +++ b/packages/c3r/src/css/styles.css @@ -0,0 +1,104 @@ +/* .c3r-view must come after .c3r-group, both are on the view element */ + +/* Not inherited, so a camera move restyles only .c3r-view */ +@property --c3r-camera-view { + syntax: "*"; + inherits: false; +} + +.c3r-container { + overflow: hidden; + position: relative; + contain: strict; + --c3r-viewport-width: 100vw; + --c3r-viewport-height: 100vh; + width: var(--c3r-viewport-width); + height: var(--c3r-viewport-height); +} + +.c3r-group, +.c3r-polygon { + position: absolute; + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + transform-origin: 0 0; + -webkit-user-select: none; + user-select: none; + backface-visibility: inherit; +} + +.c3r-group { + width: 0px; + height: 0px; + transform-style: preserve-3d; +} + +.c3r-view { + width: 100%; + height: 100%; + top: 50%; + left: 50%; + pointer-events: none; + backface-visibility: hidden; +} + +.c3r-perspective { + --c3r-focal-length: calc( + var(--c3r-viewport-height) / 2 / tan(var(--c3r-camera-fov) / 2) + ); + perspective: var(--c3r-focal-length); +} + +.c3r-perspective > .c3r-view { + transform: translateZ(var(--c3r-focal-length)) scaleY(-1) + var(--c3r-camera-view); +} + +.c3r-orthographic > .c3r-view { + transform: scale( + calc( + var(--c3r-viewport-x) / + (var(--c3r-camera-right) - var(--c3r-camera-left)) + ), + calc( + var(--c3r-viewport-y) / + (var(--c3r-camera-top) - var(--c3r-camera-bottom)) + ) + ) + translate( + calc((var(--c3r-camera-right) + var(--c3r-camera-left)) * -0.5px), + calc((var(--c3r-camera-top) + var(--c3r-camera-bottom)) * 0.5px) + ) + scaleY(-1) var(--c3r-camera-view); +} + +.c3r-polygon { + width: var(--c3r-width, 0px); + height: var(--c3r-height, 0px); + opacity: var(--c3r-opacity, 1); + transform-style: flat; + overflow: hidden; +} + +.c3r-polygon-clip { + width: 100%; + height: 100%; +} + +.c3r-polygon-content { + width: 100%; + height: 100%; + background-color: var(--c3r-background-color, white); + background-image: var(--c3r-background-image, none); + background-size: 100% 100%; + background-blend-mode: multiply; + transform: matrix(1, 0, 0, 1, 0, 0); + transform-origin: 0 0; +} + +/* No specificity, so the user's own styles win */ +:where(.c3r-element) { + background-color: var(--c3r-background-color, transparent); + background-image: var(--c3r-background-image, none); + background-size: 100% 100%; + opacity: var(--c3r-opacity, 1); +} diff --git a/packages/c3r/src/css/styles.ts b/packages/c3r/src/css/styles.ts new file mode 100644 index 0000000..d4631ec --- /dev/null +++ b/packages/c3r/src/css/styles.ts @@ -0,0 +1,36 @@ +import css from "./styles.css?inline"; + +let sheet: CSSStyleSheet | undefined; + +export function ensureStyles(): CSSStyleSheet { + if (!sheet) { + sheet = new CSSStyleSheet(); + sheet.replaceSync(css); + document.adoptedStyleSheets.push(sheet); + } + return sheet; +} + +export function deleteRule(rule: CSSStyleRule | null): void { + if (!rule) return; + registry.unregister(rule); + const sheet = rule.parentStyleSheet; + const i = sheet ? Array.from(sheet.cssRules).indexOf(rule) : -1; + if (i >= 0) sheet!.deleteRule(i); +} + +// For undisposed owners +const registry = new FinalizationRegistry(deleteRule); + +// Lives until deleteRule() or owner GC +export function insertRule(selector: string, owner: object): CSSStyleRule { + const sheet = ensureStyles(); + const i = sheet.insertRule(`${selector} {}`, sheet.cssRules.length); + const rule = sheet.cssRules[i] as CSSStyleRule; + registry.register(owner, rule, rule); + return rule; +} + +// Base styles, material and camera rules, for static html +export const cssText = (): string => + Array.from(ensureStyles().cssRules, (r) => r.cssText).join("\n"); diff --git a/packages/c3r/src/dom/Container.ts b/packages/c3r/src/dom/Container.ts new file mode 100644 index 0000000..a994f5c --- /dev/null +++ b/packages/c3r/src/dom/Container.ts @@ -0,0 +1,90 @@ +import type { Camera } from "../css/Camera.js"; +import { PerspectiveCamera } from "../css/PerspectiveCamera.js"; + +import { Group } from "./Group.js"; + +// Keeps a Camera, and its rules, alive while its element is +const elementCameras = new WeakMap(); + +export class Container { + readonly domElement: HTMLDivElement = document.createElement("div"); + // Camera transform + readonly viewElement: HTMLDivElement = document.createElement("div"); + + #root: Group = new Group(); + #camera: Camera = new PerspectiveCamera(); + #width = 0; + #height = 0; + + constructor() { + this.domElement.classList.add( + "c3r-container", + this.#camera.projectionClass, + this.#camera.className, + ); + this.viewElement.classList.add("c3r-group", "c3r-view"); + elementCameras.set(this.domElement, this.#camera); + + this.domElement.appendChild(this.viewElement); + this.viewElement.appendChild(this.#root.domElement); + this.resetSize(); + } + + get root(): Group { + return this.#root; + } + + set root(root: Group) { + if (root === this.#root) return; + this.#root.domElement.replaceWith(root.domElement); + this.#root = root; + } + + get camera(): Camera { + return this.#camera; + } + + // Not disposed when replaced, cameras can be shared + set camera(camera: Camera) { + if (camera === this.#camera) return; + const { classList } = this.domElement; + classList.remove(this.#camera.projectionClass, this.#camera.className); + classList.add(camera.projectionClass, camera.className); + elementCameras.set(this.domElement, camera); + this.#camera = camera; + } + + get width(): number { + return this.#width; + } + + get height(): number { + return this.#height; + } + + setSize(width: number, height: number): void { + if (this.#width === width && this.#height === height) return; + + this.#width = width; + this.#height = height; + + const { style } = this.domElement; + style.setProperty("--c3r-viewport-width", `${width}px`); + style.setProperty("--c3r-viewport-height", `${height}px`); + // Unitless for the ortho scale, CSS can't divide lengths yet + style.setProperty("--c3r-viewport-x", String(width)); + style.setProperty("--c3r-viewport-y", String(height)); + } + + resetSize(): void { + this.#width = 0; + this.#height = 0; + + const { style } = this.domElement; + style.removeProperty("--c3r-viewport-width"); + style.removeProperty("--c3r-viewport-height"); + // ponytail: window size at reset, ortho needs setSize for other sizes or resizes + style.setProperty("--c3r-viewport-x", String(innerWidth)); + style.setProperty("--c3r-viewport-y", String(innerHeight)); + } +} diff --git a/packages/c3r/src/dom/ElementObject.ts b/packages/c3r/src/dom/ElementObject.ts new file mode 100644 index 0000000..f134ac3 --- /dev/null +++ b/packages/c3r/src/dom/ElementObject.ts @@ -0,0 +1,72 @@ +import { vec2, type ReadonlyVec2 } from "gl-matrix"; + +import { Group } from "./Group.js"; + +export class ElementObject extends Group { + readonly element: HTMLElement; + + #scale: ReadonlyVec2 = [1, 1]; + #center: ReadonlyVec2 = [0.5, 0.5]; + #rotation = 0; + + constructor(element: HTMLElement) { + super(); + + this.element = element; + this.domElement.appendChild(element); + + this.element.classList.add("c3r-element"); + + this.#updateTransform(); + } + + protected override get materialElement(): HTMLElement { + return this.element; + } + + setSize(width: number, height: number): void { + this.element.style.width = `${width}px`; + this.element.style.height = `${height}px`; + } + + get scale(): ReadonlyVec2 { + return this.#scale; + } + + set scale(scale: ReadonlyVec2) { + if (vec2.exactEquals(scale, this.#scale)) return; + this.#scale = vec2.clone(scale); + this.#updateTransform(); + } + + get center(): ReadonlyVec2 { + return this.#center; + } + + set center(center: ReadonlyVec2) { + if (vec2.exactEquals(center, this.#center)) return; + this.#center = vec2.clone(center); + this.#updateTransform(); + } + + get rotation(): number { + return this.#rotation; + } + + set rotation(rotation: number) { + if (rotation === this.#rotation) return; + this.#rotation = rotation; + this.#updateTransform(); + } + + #updateTransform(): void { + const [sx, sy] = this.#scale; + const [cx, cy] = this.#center; + + let transform = `translate(-50%,-50%)scale(${sx},${-sy})`; + transform += `translate(${(0.5 - cx) * 100}%,${(cy - 0.5) * 100}%)`; + if (this.#rotation !== 0) transform += `rotate(${this.#rotation}rad)`; + + this.element.style.transform = transform; + } +} diff --git a/packages/c3r/src/dom/Group.ts b/packages/c3r/src/dom/Group.ts new file mode 100644 index 0000000..8b7040a --- /dev/null +++ b/packages/c3r/src/dom/Group.ts @@ -0,0 +1,146 @@ +import { + vec2, + vec3, + type mat4, + type ReadonlyMat4, + type ReadonlyVec3, +} from "gl-matrix"; + +import { Triangle } from "../math/Triangle.js"; +import type { Vertex } from "../math/Vertex.js"; + +import { Object3D } from "./Object3D.js"; +import { Polygon, type PolygonOptions } from "./Polygon.js"; + +const parents = new WeakMap(); + +export class Group extends Object3D { + readonly #children: Object3D[] = []; + + constructor() { + super(); + + this.domElement.classList.add("c3r-group"); + } + + override get matrix(): ReadonlyMat4 { + return super.matrix; + } + + override set matrix(matrix: ReadonlyMat4) { + this.setMatrix(matrix); + } + + get children(): readonly Object3D[] { + return this.#children; + } + + addChild(obj: Object3D): void { + parents.get(obj)?.removeChild(obj); + parents.set(obj, this); + this.#children.push(obj); + this.domElement.appendChild(obj.domElement); + } + + removeChild(obj: Object3D): void { + const index = this.#children.indexOf(obj); + if (index < 0) return; + + this.#children.splice(index, 1); + parents.delete(obj); + obj.domElement.remove(); + } + + clear(): void { + for (const obj of [...this.#children]) this.removeChild(obj); + } + + addPolygon(vertices: readonly Vertex[], options?: PolygonOptions): Polygon { + const poly = new Polygon(vertices, options); + this.addChild(poly); + return poly; + } + + // Merges coplanar neighbours, e.g. two triangles into a quad + addTriangles( + triangles: readonly (readonly Vertex[])[], + options?: PolygonOptions, + ): Polygon[] { + const polygons: Polygon[] = []; + let current: Face | null = null; + + for (const vertices of triangles) { + const tri = new Triangle( + vertices[0].position, + vertices[1].position, + vertices[2].position, + ); + + // Skip slivers + if ( + tri.calculateArea() <= + 1e-6 * Math.max(...tri.calculateEdgeLengths()) ** 2 + ) + continue; + + if (current && vec3.equals(current.norm, tri.norm)) { + const merged = merge(current, vertices); + if (merged) { + current.vertices = merged; + continue; + } + } + + if (current) polygons.push(this.addPolygon(current.vertices, options)); + current = face(vertices, tri); + } + + if (current) polygons.push(this.addPolygon(current.vertices, options)); + return polygons; + } +} + +interface Face { + vertices: readonly Vertex[]; + norm: ReadonlyVec3; + vec2tex: mat4; +} + +const face = (vertices: readonly Vertex[], tri: Triangle): Face => { + const uvPoint = (v: Vertex) => vec3.fromValues(v.uv[0], v.uv[1], 0); + return { + vertices, + norm: tri.norm, + vec2tex: tri.getTransformationTo( + new Triangle( + uvPoint(vertices[0]), + uvPoint(vertices[1]), + uvPoint(vertices[2]), + ), + ), + }; +}; + +// Inserts the triangle into the face if the two share an edge and the texture mapping +function merge( + { vertices: face, vec2tex }: Face, + tri: readonly Vertex[], +): Vertex[] | null { + const same = (a: Vertex, b: Vertex) => + vec2.equals(a.uv, b.uv) && vec3.equals(a.position, b.position); + + for (let i = 0; i < face.length; i++) { + for (let j = 0; j < 3; j++) { + if (!same(face[i], tri[j])) continue; + if (!same(face[(i + 1) % face.length], tri[(j + 2) % 3])) continue; + + const apex = tri[(j + 1) % 3]; + const uv = vec3.transformMat4(vec3.create(), apex.position, vec2tex); + if (!vec2.equals([uv[0], uv[1]], apex.uv)) continue; + + return [...face.slice(0, i + 1), apex, ...face.slice(i + 1)]; + } + } + + return null; +} diff --git a/packages/c3r/src/dom/Object3D.ts b/packages/c3r/src/dom/Object3D.ts new file mode 100644 index 0000000..f16ffd0 --- /dev/null +++ b/packages/c3r/src/dom/Object3D.ts @@ -0,0 +1,49 @@ +import { mat4, type ReadonlyMat4 } from "gl-matrix"; + +import type { Material } from "../css/Material.js"; +import { ensureStyles } from "../css/styles.js"; + +// Keeps a Material, and its rule, alive while its element is +const elementMaterials = new WeakMap(); + +export abstract class Object3D { + readonly domElement: HTMLDivElement = document.createElement("div"); + #matrix = mat4.create(); + #material: Material | null = null; + + constructor() { + ensureStyles(); + } + + get matrix(): ReadonlyMat4 { + return this.#matrix; + } + + protected setMatrix(matrix: ReadonlyMat4): void { + if (mat4.exactEquals(matrix, this.#matrix)) return; + mat4.copy(this.#matrix, matrix); + this.domElement.style.transform = `matrix3d(${[...matrix].join()})`; + } + + get material(): Material | null { + return this.#material; + } + + protected get materialElement(): HTMLElement { + return this.domElement; + } + + set material(material: Material | null) { + if (material === this.#material) return; + const element = this.materialElement; + const { classList } = element; + if (this.#material) classList.remove(this.#material.className); + if (material) { + classList.add(material.className); + elementMaterials.set(element, material); + } else { + elementMaterials.delete(element); + } + this.#material = material; + } +} diff --git a/packages/c3r/src/dom/Polygon.ts b/packages/c3r/src/dom/Polygon.ts new file mode 100644 index 0000000..f53075f --- /dev/null +++ b/packages/c3r/src/dom/Polygon.ts @@ -0,0 +1,413 @@ +import { mat2, mat3, vec2, vec3, type ReadonlyVec2 } from "gl-matrix"; + +import { Object3D } from "./Object3D.js"; +import { Triangle } from "../math/Triangle.js"; +import type { Vertex } from "../math/Vertex.js"; + +type Bounds = [xmin: number, xmax: number, ymin: number, ymax: number]; + +const cross2 = (a: ReadonlyVec2, b: ReadonlyVec2, o: ReadonlyVec2) => + (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]); + +const bounds = (points: ReadonlyVec2[]): Bounds => + points.reduce( + ([xmin, xmax, ymin, ymax], [x, y]) => [ + Math.min(xmin, x), + Math.max(xmax, x), + Math.min(ymin, y), + Math.max(ymax, y), + ], + [Infinity, -Infinity, Infinity, -Infinity], + ); + +// Monotone chain, https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain +const convexHull = (points: ReadonlyVec2[]): ReadonlyVec2[] => { + const sorted = points + .slice() + .sort((a, b) => (a[0] === b[0] ? a[1] - b[1] : a[0] - b[0])); + + const chain = (pts: ReadonlyVec2[]) => { + const out: ReadonlyVec2[] = []; + for (const p of pts) { + while ( + out.length >= 2 && + cross2(out[out.length - 2], out[out.length - 1], p) <= 0 + ) { + out.pop(); + } + out.push(p); + } + out.pop(); + return out; + }; + + return [...chain(sorted), ...chain(sorted.slice().reverse())]; +}; + +// Newell's method +const newellNormal = (vertices: readonly Vertex[]): vec3 => { + const n = vec3.create(); + vertices.forEach(({ position: [x1, y1, z1] }, i) => { + const [x2, y2, z2] = vertices[(i + 1) % vertices.length].position; + vec3.add(n, n, [ + (y1 - y2) * (z1 + z2), + (z1 - z2) * (x1 + x2), + (x1 - x2) * (y1 + y2), + ]); + }); + return vec3.normalize(n, n); +}; + +const MITER_LIMIT = 4; + +// Offsets every edge outward by d +const dilate = (points: ReadonlyVec2[], d: number): vec2[] => { + const n = points.length; + const area = points.reduce( + (s, p, i) => s + cross2(p, points[(i + 1) % n], [0, 0]), + 0, + ); + const sign = Math.sign(area); + + const normal = (a: ReadonlyVec2, b: ReadonlyVec2) => { + const e = vec2.normalize(vec2.create(), vec2.sub(vec2.create(), b, a)); + return vec2.fromValues(e[1] * sign, -e[0] * sign); + }; + + return points.map((p, i) => { + const n1 = normal(points[(i + n - 1) % n], p); + const n2 = normal(p, points[(i + 1) % n]); + + const m = vec2.add(vec2.create(), n1, n2); + vec2.scale(m, m, d / Math.max(1 + vec2.dot(n1, n2), 1e-6)); + + const len = vec2.len(m); + if (len > MITER_LIMIT * d) vec2.scale(m, m, (MITER_LIMIT * d) / len); + + return vec2.add(m, m, p); + }); +}; + +const dedupe = (vertices: readonly Vertex[]): Vertex[] => { + const unique = vertices.filter( + (v, i) => i === 0 || !vec3.equals(v.position, vertices[i - 1].position), + ); + while ( + unique.length > 1 && + vec3.equals(unique[unique.length - 1].position, unique[0].position) + ) + unique.pop(); + return unique; +}; + +// Remove duplicate and collinear vertices +const simplify = (input: readonly Vertex[]): Vertex[] => { + const vertices = dedupe(input); + return vertices.filter((vertex, i) => { + if (i === 0) return true; + + const p1 = vertices[i - 1].position; + const p3 = vertices[(i + 1) % vertices.length].position; + + const e1 = vec3.normalize( + vec3.create(), + vec3.sub(vec3.create(), p1, vertex.position), + ); + const e2 = vec3.normalize( + vec3.create(), + vec3.sub(vec3.create(), vertex.position, p3), + ); + + return Math.abs(vec3.dot(e1, e2)) < 0.9999; + }); +}; + +export interface PolygonOptions { + contentElement?: HTMLElement; + // Base size of the dom element, too small makes the content blurry + getDomSize?: (size: number) => number; + // Outward edge offset in DOM pixels, hides seams between neighbours + edgeOverlap?: number; +} + +export class Polygon extends Object3D { + readonly vertices: readonly Vertex[]; // vertices in CCW + readonly contentElement: HTMLElement; + // Clips in a child, Chrome masks the 3d layer itself with an oversized layer (flicker) + #clipElement = document.createElement("div"); + + #uvScale: ReadonlyVec2 = [1, 1]; + #uvOffset: ReadonlyVec2 = [0, 0]; + + #getDomSize: (size: number) => number; + #edgeOverlap: number; + + #clipPath: ReadonlyVec2[] = []; // path of the dilated polygon on a rectangular element + #vertexPoints: ReadonlyVec2[] = []; + + #blockWidth = 0; + #blockHeight = 0; + + constructor( + vertices: readonly Vertex[], + { + contentElement = document.createElement("div"), + getDomSize = (size) => Math.max(250, Math.min(size, 1200)), + edgeOverlap = 1, + }: PolygonOptions = {}, + ) { + super(); + + this.vertices = simplify(vertices); + this.#getDomSize = getDomSize; + this.#edgeOverlap = edgeOverlap; + + this.domElement.classList.add("c3r-polygon"); + + this.contentElement = contentElement; + this.contentElement.classList.add("c3r-polygon-content"); + this.#clipElement.classList.add("c3r-polygon-clip"); + this.#clipElement.appendChild(this.contentElement); + this.domElement.appendChild(this.#clipElement); + + this.#fit(); + this.#updateContent(); + } + + get uvScale(): ReadonlyVec2 { + return this.#uvScale; + } + + set uvScale(scale: ReadonlyVec2) { + if (vec2.exactEquals(scale, this.#uvScale)) return; + this.#uvScale = vec2.clone(scale); + this.#updateContent(); + } + + get uvOffset(): ReadonlyVec2 { + return this.#uvOffset; + } + + set uvOffset(offset: ReadonlyVec2) { + if (vec2.exactEquals(offset, this.#uvOffset)) return; + this.#uvOffset = vec2.clone(offset); + this.#updateContent(); + } + + #fit(): void { + const [v0, v1, v2] = this.vertices; + if (!v2) throw new Error("The polygon has not enough sides"); + + // The first corner may be reflex + const norm = + this.vertices.length === 3 ? undefined : newellNormal(this.vertices); + const tri = new Triangle(v0.position, v1.position, v2.position, norm); + + if (this.vertices.length === 3) { + this.#fitTriangle(tri); + } else { + this.#fitPolygon(tri); + } + + const clip = this.#clipPath + .map((p) => `${p[0] * 100}% ${p[1] * 100}%`) + .join(); + this.#clipElement.style.clipPath = `polygon(${clip})`; + + // We need the width/height information in the childNode to properly position and scale the texture + // If we use width/height CSS values, then we can rescale this element, without calling updateContent + + this.domElement.style.setProperty("--c3r-width", `${this.#blockWidth}px`); + this.domElement.style.setProperty("--c3r-height", `${this.#blockHeight}px`); + } + + // Faster method for triangles: the longest side will be the base + #fitTriangle(tri: Triangle): void { + const ln = tri.calculateEdgeLengths(); + + const ai = ln.indexOf(Math.max(...ln)); + const bi = (ai + 1) % 3; + const ci = (ai + 2) % 3; + + const a = ln[ai]; + const b = ln[bi]; + const c = ln[ci]; + + const Ax = -(b * b - c * c - a * a) / (2 * a); + const Ay = Math.sqrt(Math.max(0, c * c - Ax * Ax)); + + const scale = this.#getDomSize(a) / a; + + const points: vec2[] = []; + points[ai] = vec2.fromValues(0, 0); + points[bi] = vec2.fromValues(a * scale, 0); + points[ci] = vec2.fromValues(Ax * scale, Ay * scale); + + this.#layout(points, tri); + } + + #fitPolygon(tri: Triangle): void { + const b1 = tri.norm; + const b2 = + Math.abs(vec3.dot(b1, [0, 0, 1])) < 0.9 + ? vec3.cross(vec3.create(), b1, [0, 0, 1]) + : vec3.cross(vec3.create(), b1, [0, 1, 0]); + const b3 = vec3.cross(vec3.create(), b2, b1); + + // Project the points to the polygon's plane + // prettier-ignore + const BT = mat3.fromValues( + b2[0], b2[1], b2[2], + b3[0], b3[1], b3[2], + b1[0], b1[1], b1[2], + ); + const BTI = mat3.invert(BT, BT); + if (!BTI) throw new Error("Degenerate polygon"); + + const points2d = this.vertices.map((v) => { + const p = vec3.transformMat3(vec3.create(), v.position, BTI); + return vec2.fromValues(p[0], p[1]); + }); + + const hull = convexHull(points2d); + + // For each edge of the hull, transform the points to make it axis aligned + // and keep the AABB with the smallest area + + let minArea = Infinity; + let minBounds: Bounds = [0, 0, 0, 0]; + let minTI = mat2.create(); + + hull.forEach((point, i) => { + const side = vec2.sub(vec2.create(), point, hull[(i + 1) % hull.length]); + vec2.normalize(side, side); + + const ATI = mat2.invert(mat2.create(), [ + side[0], + side[1], + side[1], + -side[0], + ]); + if (!ATI) return; + + const box = bounds( + hull.map((p) => vec2.transformMat2(vec2.create(), p, ATI)), + ); + + const area = (box[1] - box[0]) * (box[3] - box[2]); + if (area < minArea) { + minArea = area; + minBounds = box; + minTI = ATI; + } + }); + + const [xmin, xmax, ymin, ymax] = minBounds; + const boxWidth = xmax - xmin; + const boxHeight = ymax - ymin; + + const longest = Math.max(boxWidth, boxHeight); + const scale = this.#getDomSize(longest) / longest; + + const points = points2d.map((p) => { + const t = vec2.transformMat2(vec2.create(), p, minTI); + return vec2.fromValues((t[0] - xmin) * scale, (t[1] - ymin) * scale); + }); + + this.#layout(points, tri); + } + + // Fits the element around the dilated polygon + #layout(points: ReadonlyVec2[], tri: Triangle): void { + const dilated = dilate(points, this.#edgeOverlap); + + const [xmin, xmax, ymin, ymax] = bounds(dilated); + this.#blockWidth = xmax - xmin; + this.#blockHeight = ymax - ymin; + + const fit = ([x, y]: ReadonlyVec2) => + vec2.fromValues( + (x - xmin) / this.#blockWidth, + (y - ymin) / this.#blockHeight, + ); + + this.#clipPath = dilated.map(fit); + this.#vertexPoints = points.map(fit); + + const [c0, c1, c2] = points.map(([x, y]) => + vec3.fromValues(x - xmin, y - ymin, 0), + ); + this.setMatrix( + new Triangle(c0, c1, c2, [0, 0, 1]).getTransformationTo(tri), + ); + } + + #updateContent(): void { + const uvs = this.vertices.map((v) => { + const uv = vec2.mul(vec2.create(), v.uv, this.#uvScale); + return vec2.add(uv, uv, this.#uvOffset); + }); + + const { style } = this.contentElement; + + // No texture mapping without a UV area (e.g. a mesh without uvs), show the plain color + if (!cross2(uvs[1], uvs[2], uvs[0])) { + style.removeProperty("background-position"); + style.removeProperty("background-size"); + style.removeProperty("transform"); + return; + } + + type Point = [number, number, number]; + const point = ([x, y]: ReadonlyVec2): Point => [x, y, 1]; + + const [p0, p1, p2] = this.#vertexPoints; + const TB = mat3.fromValues(...point(p0), ...point(p1), ...point(p2)); + + // Extend the UV area to cover the dilated clip path + const TBI = mat3.invert(mat3.create(), TB); + if (!TBI) throw new Error("Degenerate polygon"); + + const UV = mat3.fromValues( + ...point(uvs[0]), + ...point(uvs[1]), + ...point(uvs[2]), + ); + const toUV = mat3.mul(TBI, UV, TBI); + const clipUVs = this.#clipPath.map((p) => + vec2.transformMat3(vec2.create(), p, toUV), + ); + + const [txmin, txmax, tymin, tymax] = bounds([...uvs, ...clipUVs]); + + const xsize = txmax - txmin; + const ysize = tymax - tymin; + + const scx = 1 / xsize; + const scy = 1 / ysize; + + style.backgroundPosition = `calc(var(--c3r-width) * ${-txmin * scx}) calc(var(--c3r-height) * ${1 + tymin * scy})`; + style.backgroundSize = `${100 * scx}% ${100 * scy}%`; + + const uvPoint = ([u, v]: vec2): Point => [ + (u - txmin) * scx, + 1 - (v - tymin) * scy, + 1, + ]; + const TA = mat3.fromValues( + ...uvPoint(uvs[0]), + ...uvPoint(uvs[1]), + ...uvPoint(uvs[2]), + ); + + const TAI = mat3.invert(TA, TA); + if (!TAI) throw new Error("Degenerate polygon"); + + const TX = mat3.mul(TAI, TB, TAI); + + const bh = this.#blockHeight / this.#blockWidth; + style.transform = + `translate(${TX[6] * 100}%,${TX[7] * 100}%)` + + `matrix(${[TX[0], TX[1] * bh, TX[3] / bh, TX[4], 0, 0].join()})`; + } +} diff --git a/packages/c3r/src/math/Triangle.ts b/packages/c3r/src/math/Triangle.ts new file mode 100644 index 0000000..d51a9e3 --- /dev/null +++ b/packages/c3r/src/math/Triangle.ts @@ -0,0 +1,62 @@ +import { mat4, vec3, type ReadonlyVec3 } from "gl-matrix"; + +export class Triangle { + readonly p1: ReadonlyVec3; + readonly p2: ReadonlyVec3; + readonly p3: ReadonlyVec3; + readonly norm: ReadonlyVec3; + + readonly #edges: [vec3, vec3, vec3]; + + constructor( + p1: ReadonlyVec3, + p2: ReadonlyVec3, + p3: ReadonlyVec3, + norm?: ReadonlyVec3, + ) { + this.p1 = p1; + this.p2 = p2; + this.p3 = p3; + + this.#edges = [ + vec3.sub(vec3.create(), p1, p2), + vec3.sub(vec3.create(), p2, p3), + vec3.sub(vec3.create(), p3, p1), + ]; + + this.norm = norm ?? this.calculateNormal(); + } + + calculateNormal(): vec3 { + const [e1, e2] = this.#edges; + return vec3.normalize(vec3.create(), vec3.cross(vec3.create(), e1, e2)); + } + + calculateEdgeLengths(): [number, number, number] { + const [e1, e2, e3] = this.#edges; + return [vec3.len(e1), vec3.len(e2), vec3.len(e3)]; + } + + calculateArea(): number { + const [e1, e2] = this.#edges; + return vec3.len(vec3.cross(vec3.create(), e1, e2)) / 2; + } + + getTransformationTo(that: Triangle): mat4 { + const A = Triangle.#basis(this); + const AI = mat4.invert(A, A); + if (!AI) throw new Error("Degenerate triangle"); + + return mat4.mul(AI, Triangle.#basis(that), AI); + } + + static #basis({ p1, p2, p3, norm }: Triangle): mat4 { + // prettier-ignore + return mat4.fromValues( + p1[0], p1[1], p1[2], 1, + p2[0], p2[1], p2[2], 1, + p3[0], p3[1], p3[2], 1, + norm[0], norm[1], norm[2], 0, + ); + } +} diff --git a/packages/c3r/src/math/Vertex.ts b/packages/c3r/src/math/Vertex.ts new file mode 100644 index 0000000..98ab429 --- /dev/null +++ b/packages/c3r/src/math/Vertex.ts @@ -0,0 +1,6 @@ +import type { ReadonlyVec2, ReadonlyVec3 } from "gl-matrix"; + +export interface Vertex { + position: ReadonlyVec3; + uv: ReadonlyVec2; +} diff --git a/packages/c3r/src/polyfill.ts b/packages/c3r/src/polyfill.ts new file mode 100644 index 0000000..6d6ba08 --- /dev/null +++ b/packages/c3r/src/polyfill.ts @@ -0,0 +1,2 @@ +// Safari +(Symbol as { dispose?: symbol }).dispose ??= Symbol.for("Symbol.dispose"); diff --git a/packages/c3r/src/vite-env.d.ts b/packages/c3r/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/packages/c3r/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/packages/c3r/test/c3r.test.ts b/packages/c3r/test/c3r.test.ts new file mode 100644 index 0000000..cf85566 --- /dev/null +++ b/packages/c3r/test/c3r.test.ts @@ -0,0 +1,352 @@ +import { describe, expect, it, vi } from "vitest"; +import { mat4, vec3, vec4 } from "gl-matrix"; +import { + Container, + cssText, + ElementObject, + Group, + Material, + OrthographicCamera, + PerspectiveCamera, + Polygon, + type Vertex, +} from "c3r"; + +const vertex = (x: number, y: number, z: number, u = 0, v = 0): Vertex => ({ + position: [x, y, z], + uv: [u, v], +}); + +// Newell's method +const polygonNormal = (points: vec3[]) => { + const n = vec3.create(); + points.forEach((p, i) => + vec3.add( + n, + n, + vec3.cross(vec3.create(), p, points[(i + 1) % points.length]), + ), + ); + return vec3.normalize(n, n); +}; + +describe("Polygon", () => { + const tilt = mat4.fromRotation(mat4.create(), 0.7, [1, 2, 3]); + const tilted = (points: number[][]) => + points.map(([x, y, z]) => { + const p = vec3.transformMat4(vec3.create(), [x, y, z], tilt); + return vertex(p[0], p[1], p[2]); + }); + + // prettier-ignore + it.each([ + ["scalene triangle", tilted([[0, 0, 0], [7, 1, 0], [2, 5, 0]])], + ["convex quad", tilted([[0, 0, 0], [4, 0, 0], [5, 3, 0], [-1, 2, 0]])], + ["concave quad, reflex at v1", tilted([[0, 0, 0], [1, 0, 0], [3, -1, 0], [0, 1, 0]])], + ])("places the element on the vertices of a %s, front side out", (_, vertices) => { + const poly = new Polygon(vertices); + + const M = poly.matrix; + const MI = mat4.invert(mat4.create(), M)!; + const width = parseFloat(poly.domElement.style.getPropertyValue("--c3r-width")); + const height = parseFloat(poly.domElement.style.getPropertyValue("--c3r-height")); + + for (const v of vertices) { + const [x, y, z] = vec3.transformMat4(vec3.create(), v.position, MI); + expect(Math.abs(z)).toBeLessThan(1e-6); + expect(x).toBeGreaterThanOrEqual(-1e-6); + expect(x).toBeLessThanOrEqual(width + 1e-6); + expect(y).toBeGreaterThanOrEqual(-1e-6); + expect(y).toBeLessThanOrEqual(height + 1e-6); + } + + // No shear + const col = (i: number) => vec3.fromValues(M[i * 4], M[i * 4 + 1], M[i * 4 + 2]); + const len = vec3.len(col(0)); + expect(vec3.dot(col(0), col(1)) / len ** 2).toBeCloseTo(0, 5); + expect(vec3.len(col(1)) / len).toBeCloseTo(1, 5); + + // Front side out + const [fx, fy, fz] = vec4.transformMat4(vec4.create(), [0, 0, 1, 0], M); + const front = vec3.normalize(vec3.create(), [fx, fy, fz]); + const normal = polygonNormal(vertices.map((v) => vec3.clone(v.position))); + expect(vec3.dot(front, normal)).toBeGreaterThan(0.999); + }); + + it("drops repeated vertices, also a repeated closing one", () => { + const poly = new Polygon([ + vertex(0, 0, 0), + vertex(0, 0, 0), + vertex(1, 0, 0), + vertex(1, 1, 0), + vertex(0, 1, 0), + vertex(0, 0, 0), + vertex(0, 0, 0), + ]); + expect(poly.vertices).toHaveLength(4); + + // A collinear midpoint next to its duplicate + const square = new Polygon([ + vertex(0, 0, 0), + vertex(0.5, 0, 0), + vertex(0.5, 0, 0), + vertex(1, 0, 0), + vertex(1, 1, 0), + vertex(0, 1, 0), + ]); + expect(square.vertices).toHaveLength(4); + }); + + it("falls back to the plain color for collinear uvs", () => { + const poly = new Polygon([ + vertex(0, 0, 0, 0, 0), + vertex(1, 0, 0, 0.5, 0.5), + vertex(0, 1, 0, 1, 1), + ]); + + expect(poly.contentElement.style.transform).toBe(""); + }); + + it("maps the texture on construction and on uv assignment", () => { + const poly = new Polygon([ + vertex(0, 0, 0, 0, 0), + vertex(1, 0, 0, 1, 0), + vertex(0, 1, 0, 0, 1), + ]); + const { style } = poly.contentElement; + const size = style.backgroundSize; + expect(style.transform).not.toBe(""); + + poly.uvScale = [2, 2]; + expect(style.backgroundSize).not.toBe(size); + }); + + // Chrome flickers with a clip-path on the 3d layer + it("clips below the 3d layer", () => { + const poly = new Polygon([ + vertex(0, 0, 0, 0, 0), + vertex(1, 0, 0, 1, 0), + vertex(0, 1, 0, 0, 1), + ]); + + expect(poly.domElement.style.clipPath).toBe(""); + expect(poly.contentElement.parentElement!.style.clipPath).toMatch( + /^polygon\(/, + ); + }); +}); + +describe("Group.addTriangles", () => { + it("merges the triangles of each cube face into a quad", () => { + // From examples/cube.html + // prettier-ignore + const positions = [100, 100, 100, 100, 100, -100, 100, -100, 100, 100, -100, -100, -100, 100, -100, -100, 100, 100, -100, -100, -100, -100, -100, 100, -100, 100, -100, 100, 100, -100, -100, 100, 100, 100, 100, 100, -100, -100, 100, 100, -100, 100, -100, -100, -100, 100, -100, -100, -100, 100, 100, 100, 100, 100, -100, -100, 100, 100, -100, 100, 100, 100, -100, -100, 100, -100, 100, -100, -100, -100, -100, -100]; + // prettier-ignore + const indices = [0, 2, 1, 2, 3, 1, 4, 6, 5, 6, 7, 5, 8, 10, 9, 10, 11, 9, 12, 14, 13, 14, 15, 13, 16, 18, 17, 18, 19, 17, 20, 22, 21, 22, 23, 21]; + // prettier-ignore + const uvs = [0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0]; + + const at = (i: number) => + vertex( + positions[i * 3], + positions[i * 3 + 1], + positions[i * 3 + 2], + uvs[i * 2], + uvs[i * 2 + 1], + ); + + const triangles = []; + for (let i = 0; i < indices.length; i += 3) { + triangles.push([at(indices[i]), at(indices[i + 1]), at(indices[i + 2])]); + } + const group = new Group(); + group.addTriangles(triangles); + + expect(group.children).toHaveLength(6); + for (const child of group.children) + expect((child as Polygon).vertices).toHaveLength(4); + }); + + it("keeps triangles apart when the texture mapping is not continuous", () => { + const group = new Group(); + group.addTriangles([ + [vertex(0, 0, 0, 0, 0), vertex(1, 0, 0, 1, 0), vertex(1, 1, 0, 1, 1)], + // Shared edge, but the third uv is off the mapping + [vertex(0, 0, 0, 0, 0), vertex(1, 1, 0, 1, 1), vertex(0, 1, 0, 0.5, 1)], + ]); + + expect(group.children).toHaveLength(2); + }); + + it("skips zero-area triangles instead of throwing", () => { + const group = new Group(); + group.addTriangles([ + [vertex(0, 0, 0), vertex(1, 0, 0), vertex(2, 0, 0)], + [vertex(0, 0, 0), vertex(1, 0, 0), vertex(0, 1, 0)], + ]); + + expect(group.children).toHaveLength(1); + }); +}); + +describe("Group", () => { + it("moves a child out of its previous parent", () => { + const a = new Group(); + const b = new Group(); + const child = new Group(); + a.addChild(child); + b.addChild(child); + + expect(a.children).toHaveLength(0); + expect(b.children).toEqual([child]); + expect(child.domElement.parentElement).toBe(b.domElement); + }); + + it("replaces the container root in the DOM", () => { + const container = new Container(); + const root = new Group(); + container.root = root; + + expect([...container.viewElement.children]).toEqual([root.domElement]); + }); +}); + +describe("ElementObject", () => { + it("applies scale, center and rotation on assignment", () => { + const node = new ElementObject(document.createElement("div")); + node.scale = [2, 3]; + node.center = [0, 1]; + node.rotation = 1; + + expect(node.element.style.transform).toBe( + "translate(-50%,-50%)scale(2,-3)translate(50%,50%)rotate(1rad)", + ); + }); + + it("applies its material to its element, not to its children", () => { + const node = new ElementObject(document.createElement("div")); + const child = new Group(); + node.addChild(child); + using material = new Material(); + node.material = material; + + expect(node.element.classList).toContain(material.className); + expect(node.domElement.classList).not.toContain(material.className); + expect(child.domElement.closest(`.${material.className}`)).toBeNull(); + }); +}); + +describe("Material", () => { + it("styles objects through a class rule, removed on dispose", () => { + const group = new Group(); + { + using material = new Material(); + material.backgroundColor = [1, 0, 0, 1]; + group.material = material; + + expect(group.domElement.classList).toContain(material.className); + expect( + group.domElement.style.getPropertyValue("--c3r-background-color"), + ).toBe(""); + expect(cssText()).toMatch( + new RegExp( + `\\.${material.className} \\{[^}]*rgba\\(255, ?0, ?0, ?1\\)`, + ), + ); + + using other = new Material(); + group.material = other; + expect([...group.domElement.classList]).toEqual([ + "c3r-group", + other.className, + ]); + + group.material = material; + } + expect(cssText()).not.toContain(`.${group.material.className} `); + }); + + it("shows back faces when double-sided", () => { + using material = new Material(); + const rule = () => + cssText() + .split("\n") + .find((r) => r.startsWith(`.${material.className} `)); + + material.doubleSided = true; + expect(rule()).toMatch(/backface-visibility: ?visible/); + + material.doubleSided = false; + expect(rule()).not.toContain("backface-visibility"); + }); +}); + +describe("server-side rendering", () => { + it("exports the stylesheet for static html", () => { + expect(cssText()).toContain(".c3r-polygon"); + }); + + it("sizes an orthographic view from setSize, without layout", () => { + const container = new Container(); + container.setSize(400, 300); + const camera = new OrthographicCamera(-200, 200, 150, -150); + container.camera = camera; + + const { classList, style } = container.domElement; + expect([...classList]).toEqual([ + "c3r-container", + "c3r-orthographic", + camera.className, + ]); + expect(style.getPropertyValue("--c3r-viewport-x")).toBe("400"); + expect(cssText()).toMatch( + new RegExp( + String.raw`\.${camera.className} \{[^}]*--c3r-camera-left: ?-200`, + ), + ); + }); +}); + +describe("cameras", () => { + it("project through stylesheet rules, removed on dispose", () => { + const container = new Container(); + { + using camera = new PerspectiveCamera(60); + camera.matrix = mat4.fromTranslation(mat4.create(), [0, 0, -400]); + container.camera = camera; + + expect(container.domElement.classList).toContain("c3r-perspective"); + expect(cssText()).toMatch( + new RegExp( + String.raw`\.${camera.className} \{[^}]*--c3r-camera-fov: ?60deg`, + ), + ); + expect(cssText()).toMatch( + new RegExp( + `\.${camera.className} > \.c3r-view \{[^}]*matrix3d\([^)]*-400,1\)`, + ), + ); + } + expect(cssText()).not.toContain(`${container.camera.className} `); + }); +}); + +it("polyfills Symbol.dispose before the classes use it", async () => { + const RealSymbol = Symbol; + const { dispose: _, ...props } = Object.getOwnPropertyDescriptors(Symbol); + const FakeSymbol = Object.defineProperties( + (description?: string) => RealSymbol(description), + props, + ); + + globalThis.Symbol = FakeSymbol as SymbolConstructor; + try { + vi.resetModules(); + const { Material, Camera } = await import("../src/C3R.ts"); + const key = RealSymbol.for("Symbol.dispose"); + expect(Object.hasOwn(Material.prototype, key)).toBe(true); + expect(Object.hasOwn(Camera.prototype, key)).toBe(true); + } finally { + globalThis.Symbol = RealSymbol; + } +}); diff --git a/packages/c3r/test/camera.browser.test.ts b/packages/c3r/test/camera.browser.test.ts new file mode 100644 index 0000000..66dd7f6 --- /dev/null +++ b/packages/c3r/test/camera.browser.test.ts @@ -0,0 +1,22 @@ +import { expect, it } from "vitest"; +import { Container, OrthographicCamera, PerspectiveCamera } from "c3r"; + +it("resolves the camera projections from styles.css", () => { + const container = new Container(); + document.body.append(container.domElement); + container.setSize(400, 300); + + const view = () => + new DOMMatrix(getComputedStyle(container.viewElement).transform); + const perspective = () => getComputedStyle(container.domElement).perspective; + + // scale 400 / 800, center at x = 300 + container.camera = new OrthographicCamera(-100, 700, 150, -150); + expect([view().m11, view().m22, view().m41]).toEqual([0.5, -1, -150]); + expect(perspective()).toBe("none"); + + // 300 / 2 / tan(45deg) + container.camera = new PerspectiveCamera(90); + expect(perspective()).toBe("150px"); + expect([view().m22, view().m43]).toEqual([-1, 150]); +}); diff --git a/packages/c3r/test/element.browser.test.ts b/packages/c3r/test/element.browser.test.ts new file mode 100644 index 0000000..26a3394 --- /dev/null +++ b/packages/c3r/test/element.browser.test.ts @@ -0,0 +1,30 @@ +import { expect, it } from "vitest"; +import { Container, ElementObject, Material } from "c3r"; + +it("keeps the element's own styles over the material defaults", () => { + const style = document.createElement("style"); + style.textContent = + ".card { background-color: rgb(255, 0, 0); opacity: 0.5 }"; + document.head.append(style); + + const container = new Container(); + document.body.append(container.domElement); + + const card = document.createElement("div"); + card.className = "card"; + container.root.addChild(new ElementObject(card)); + + const plain = new ElementObject(document.createElement("div")); + plain.material = new Material(); + plain.material.backgroundColor = [0, 0, 1, 1]; + container.root.addChild(plain); + + const computed = getComputedStyle(card); + expect([computed.backgroundColor, computed.opacity]).toEqual([ + "rgb(255, 0, 0)", + "0.5", + ]); + expect(getComputedStyle(plain.element).backgroundColor).toBe( + "rgb(0, 0, 255)", + ); +}); diff --git a/packages/c3r/tsconfig.json b/packages/c3r/tsconfig.json new file mode 100644 index 0000000..c488121 --- /dev/null +++ b/packages/c3r/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo" + }, + "include": ["src"] +} diff --git a/packages/c3r/vite.config.mjs b/packages/c3r/vite.config.mjs new file mode 100644 index 0000000..a131cad --- /dev/null +++ b/packages/c3r/vite.config.mjs @@ -0,0 +1,45 @@ +import { readFileSync } from "node:fs"; +import { createRequire } from "node:module"; +import { defineConfig } from "vite"; + +const license = (title, file) => + `/**\n * @license ${title}\n` + + readFileSync(file, "utf8") + .trim() + .split(/\r?\n/) + .map((line) => ` * ${line}`.trimEnd()) + .join("\n") + + "\n */"; + +const postBanner = license("C3R", "LICENSE"); +const glMatrixLicense = createRequire(import.meta.url).resolve( + "gl-matrix/LICENSE.md", +); + +// Two passes, because gl-matrix is external in the ESM build and bundled in the browser one +export default defineConfig(({ mode }) => ({ + build: { + lib: { entry: "src/C3R.ts" }, + minify: false, + emptyOutDir: mode !== "min", + rolldownOptions: + mode === "min" + ? { + output: [ + { + format: "umd", + name: "C3R", + entryFileNames: "c3r.min.js", + minify: true, + comments: false, + postBanner: + postBanner + "\n" + license("gl-matrix", glMatrixLicense), + }, + ], + } + : { + external: ["gl-matrix"], + output: [{ format: "es", entryFileNames: "c3r.js", postBanner }], + }, + }, +})); diff --git a/rollup.config.js b/rollup.config.js deleted file mode 100644 index 50c311c..0000000 --- a/rollup.config.js +++ /dev/null @@ -1,34 +0,0 @@ - -import babel from 'rollup-plugin-babel'; -import babelrc from 'babelrc-rollup'; - -import path from 'path'; -import fs from 'fs'; -import license from 'rollup-plugin-license'; - -export default { - input: 'src/C3R.js', - plugins: [], - // sourceMap: true, - output: [ - { - format: 'umd', - name: 'C3R', - file: 'build/C3R.js', - indent: '\t' - }, - { - format: 'es', - file: 'build/C3R.module.js', - indent: '\t' - } - ], - plugins: [ - babel(babelrc()), - license({ - sourceMap: true, - - banner: "@license\n"+fs.readFileSync(path.join(__dirname, 'LICENSE'), "utf8") - }) - ] -}; \ No newline at end of file diff --git a/src/C3R.js b/src/C3R.js deleted file mode 100644 index 6ed6c5c..0000000 --- a/src/C3R.js +++ /dev/null @@ -1,16 +0,0 @@ - -export { CSSClass } from './css/CSSClass.js'; -export { Material } from './css/Material.js'; - -export { Object3D } from './dom/Object3D.js'; -export { Group } from './dom/Group.js'; -export { RootObject } from './dom/RootObject.js'; -export { Container } from './dom/Container.js'; -export { Polygon } from './dom/Polygon.js'; -export { CustomElement } from './dom/CustomElement.js'; - -export { Triangle } from './math/Triangle.js'; -export { Vertex } from './math/Vertex.js'; - -export { PerspectiveCamera } from './math/PerspectiveCamera.js'; -export { OrthographicCamera } from './math/OrthographicCamera.js'; \ No newline at end of file diff --git a/src/css/CSSClass.js b/src/css/CSSClass.js deleted file mode 100644 index 1aa7ba4..0000000 --- a/src/css/CSSClass.js +++ /dev/null @@ -1,62 +0,0 @@ - -export class CSSClass { - - constructor() { - - this.class_name = "c3r-"+(CSSClass.id_counter++); - - this.properties = new Map(); - - this.domElement = document.createElement("style"); - - } - - init() { - document.head.appendChild(this.domElement); - } - - unload() { - document.head.removeChild(this.domElement); - } - - attach(elem) { - elem.classList.add(this.class_name); - } - - detach(elem) { - elem.classList.remove(this.class_name); - } - - setProperty(prop, val) { - this.properties.set(prop, val); - } - - setProperties(props) { - for(let i in props) { - this.setProperty(i, props[i]); - } - } - - update() { - - this.domElement.innerHTML = '.'+this.class_name+'{'+ - Array.from( - this.properties.entries() - ).map( - kv => kv.join(':') - ).join(';') - +'}'; - - } - - clone() { - - var cl = new CSSClass(); - cl.properties = new Map(this.properties); - return cl; - - } - -} - -CSSClass.id_counter = 0; diff --git a/src/css/Material.js b/src/css/Material.js deleted file mode 100644 index 9de4e6a..0000000 --- a/src/css/Material.js +++ /dev/null @@ -1,38 +0,0 @@ -export class Material { - - constructor() { - - this.backgroundImageSrc = null; - this.backgroundColor = null; // vec4 0-1 - this.opacity = 1.0; - - } - - apply(elem) { - - if(this.backgroundImageSrc) { - elem.style.setProperty("--background-image", "url('" + this.backgroundImageSrc + "')"); - } else { - elem.style.removeProperty("--background-image"); - } - - if(this.backgroundColor) { - elem.style.setProperty("--background-color", "rgba(" + [ - Math.round(this.backgroundColor[0]*255), - Math.round(this.backgroundColor[1]*255), - Math.round(this.backgroundColor[2]*255), - this.backgroundColor[3] - ].join() + ")"); - } else { - elem.style.removeProperty("--background-color"); - } - - if(this.opacity == 1.0) { - elem.style.removeProperty("--opacity"); - } else { - elem.style.setProperty("--opacity", this.opacity); - } - - } - -} \ No newline at end of file diff --git a/src/dom/Container.js b/src/dom/Container.js deleted file mode 100644 index 2d19584..0000000 --- a/src/dom/Container.js +++ /dev/null @@ -1,108 +0,0 @@ - -import { CSSClass } from '../css/CSSClass.js'; -import { RootObject } from './RootObject.js'; - -import { PerspectiveCamera } from '../math/PerspectiveCamera.js'; -import { OrthographicCamera } from '../math/OrthographicCamera.js'; - -// Firefox mobile (Android) -var perspective_calc_support = CSS.supports('perspective: calc( 512px * 2 )'); - -export class Container { - - constructor() { - - this.camera = new PerspectiveCamera(); - this.root = null; - - this.domElement = document.createElement('div'); - Container.getClass().attach(this.domElement); - - this.width = 0; - this.height = 0; - - this.addRoot(new RootObject()); - - } - - // Needs to be called on camera change and if the root was replaced - updateCamera() { - - if(this.camera instanceof PerspectiveCamera) { - - if(perspective_calc_support) { - this.domElement.style.setProperty("perspective", "calc( "+this.camera.perspective_coefficient+" * var(--viewport-height) / 2 )"); - } else { - this.domElement.style.setProperty("perspective", (this.camera.perspective_coefficient * this.domElement.offsetHeight / 2) + "px"); - } - - } else if(this.camera instanceof OrthographicCamera) { - - this.domElement.style.removeProperty("perspective"); - - } - - this.root.updateMatrix(this.camera); - - } - - addRoot(root) { - - if(this.root) { - this.domElement.removeChild(root.domElement); - } - - this.root = root; - this.domElement.appendChild(root.domElement); - - this.updateCamera(); - - } - - setSize(width, height) { - - if(this.width == width && this.height == height) { - return; - } - - this.width = width; - this.height = height; - - this.domElement.style.setProperty("--viewport-width", width+"px"); - this.domElement.style.setProperty("--viewport-height", height+"px"); - } - - resetSize() { - this.domElement.style.removeProperty("--viewport-width", width+"px"); - this.domElement.style.removeProperty("--viewport-height", height+"px"); - } - - static getClass() { - - if(!css_class) { - - css_class = new CSSClass(); - css_class.setProperties({ - "overflow": "hidden", - - "position": "relative", - - "--viewport-width": "100vw", - "--viewport-height": "100vh", - - "width": "var(--viewport-width)", - "height": "var(--viewport-height)" - - }); - css_class.update(); - css_class.init(); - - } - - return css_class; - - } - -} - -var css_class = null; \ No newline at end of file diff --git a/src/dom/CustomElement.js b/src/dom/CustomElement.js deleted file mode 100644 index c5e99e1..0000000 --- a/src/dom/CustomElement.js +++ /dev/null @@ -1,85 +0,0 @@ - -import { Group } from './Group.js'; -import { Object3D } from './Object3D.js'; -import { CSSClass } from '../css/CSSClass.js'; - -export class CustomElement extends Object3D { - - constructor(element) { - - super(); - - this.element = element; - this.domElement.appendChild(element); - - this.elementScale = vec2.fromValues(1,1); - this.elementCenter = vec2.fromValues(.5,.5); - this.elementRotation = 0; - - Group.getClass().attach(this.domElement); - CustomElement.getContentClass().attach(this.element); - - this.updateElementTransform(); - - } - - setSize(width, height) { - this.element.style.width = width+"px"; - this.element.style.height = height+"px"; - } - - setScale(scale_x, scale_y) { - this.elementScale = vec2.fromValues(scale_x,scale_y); - this.updateElementTransform(); - } - - setCenter(center_x, center_y) { - this.elementCenter = vec2.fromValues(center_x,center_y); - this.updateElementTransform(); - } - - updateElementTransform() { - - var pre_translate = "translate(-50%,-50%)"; - var scale = "scale("+(this.elementScale[0])+","+(-this.elementScale[1])+")"; - var translate = "translate("+((0.5-this.elementCenter[0])*100)+"%,"+((this.elementCenter[1]-0.5)*100)+"%)"; - - var rotate = this.elementRotation == 0 ? "" : "rotate("+this.elementRotation+"rad)"; - - this.element.style.transform = pre_translate+scale+translate+rotate; - } - - enablePointer() { - this.element.style.pointerEvents = "auto"; - } - - disablePointer() { - this.element.style.pointerEvents = ""; - } - - static getContentClass() { - - if(!css_content_class) { - - css_content_class = new CSSClass(); - css_content_class.setProperties({ - - "background-color": "var(--background-color, transparent)", - "background-image": "var(--background-image, white)", - "background-size": "100% 100%", - - "opacity": "var(--opacity, 1)" - - }); - css_content_class.update(); - css_content_class.init(); - - } - - return css_content_class; - - } - -} - -var css_content_class = null; \ No newline at end of file diff --git a/src/dom/Group.js b/src/dom/Group.js deleted file mode 100644 index 0c8cef7..0000000 --- a/src/dom/Group.js +++ /dev/null @@ -1,216 +0,0 @@ - -import { CSSClass } from '../css/CSSClass.js'; - -import { Triangle } from '../math/Triangle.js'; - -import { Object3D } from './Object3D.js'; -import { Polygon } from './Polygon.js'; - -export class Group extends Object3D { - - constructor() { - - super(); - - Group.getClass().attach(this.domElement); - - this.children = []; - - // - this.vert_cache = null; - this.norm_cache = null; - this.vec2tex = null; - - } - - addChild(obj) { - - this.children.push(obj); - this.domElement.appendChild(obj.domElement); - - } - - removeChild(obj) { - - let index = this.children.indexOf(obj); - - if(index > -1) { - this.removeChildIndex(index); - } - - } - - removeChildIndex(index) { - - var obj = this.children[index]; - - this.children.splice(index, 1); - this.domElement.removeChild(obj.domElement); - - } - - clear() { - - var i = this.children.length; - while( i --> 0 ) { - this.removeChildIndex(i); - } - - } - - // - addPolygon(vertices, element=null) { - - let poly = new Polygon(vertices, element); - - poly.updateMatrix(); - poly.updateContent(); - - this.addChild(poly); - - return poly; - - } - - // Adding triangles with this method makes it possible to reconstruct polygons (like quads) - // The polygon (defined by vertices) will be added at last when flushPolygons() is called - pushPolygon(vertices) { - - // TODO: if vertices.length > 3, then we should compare more than 1 edge - - // Calculate the normal from vertices - let norm = (new Triangle( - vertices[0].position, - vertices[1].position, - vertices[2].position - )).norm; - - // If there is already a polygon in the cache, compare the current vertices with it - if(this.vert_cache) { - - let same_plane = vec3.equals(this.norm_cache, norm); - - // Check if they are on the same plane - if(same_plane) { - - // Check if the two polygon shares an edge - let shares_edge = false; - for(let i=0; i { - - let uv = vec3.transformMat4(vec3.create(), v.position, this.vec2tex).slice(0,2); - - return vec2.equals(uv, v.uv); - - })) { - continue; - } - - this.vert_cache = start.concat(ins, end); - - shares_edge = true; - break; - - } - - } - - } - - if(shares_edge) { - break; - } - - } - - if(!shares_edge) { - this.flushPolygons(); - } - - } else { - this.flushPolygons(); - } - } - - // If it was empty or flushed, store verts in cache - if(!this.vert_cache) { - this.vert_cache = vertices; - this.norm_cache = norm; - - this.vec2tex = (new Triangle( - vertices[0].position, - vertices[1].position, - vertices[2].position, - norm - )).getTransformationTo(new Triangle( - vec3.fromValues(this.vert_cache[0].uv[0], this.vert_cache[0].uv[1], 0), - vec3.fromValues(this.vert_cache[1].uv[0], this.vert_cache[1].uv[1], 0), - vec3.fromValues(this.vert_cache[2].uv[0], this.vert_cache[2].uv[1], 0) - )); - - } - - } - - flushPolygons() { - - if(this.vert_cache) { - this.addPolygon(this.vert_cache); - - this.vert_cache = null; - this.norm_cache = null; - this.vec2tex = null; - } - - } - - static getClass() { - - if(!css_class) { - css_class = new CSSClass(); - css_class.setProperties({ - /* Center element */ - "width": "0px", - "height": "0px", - - "transform-style": "preserve-3d", - "overflow": "visible" - }); - css_class.setProperties(Object3D.getCommonAttributes()); - css_class.update(); - css_class.init(); - } - - return css_class; - - } - -} - -var css_class = null; \ No newline at end of file diff --git a/src/dom/Object3D.js b/src/dom/Object3D.js deleted file mode 100644 index 9bf6519..0000000 --- a/src/dom/Object3D.js +++ /dev/null @@ -1,54 +0,0 @@ - -import { CSSClass } from '../css/CSSClass.js'; -import { Material } from '../css/Material.js'; - -export class Object3D { - - constructor() { - - this.matrix = mat4.create(); - - this.domElement = document.createElement('div'); - - this.material = null; - - } - - // set transform property - updateMatrix() { - this.domElement.style.transform = 'matrix3d('+this.matrix.join()+')'; - } - - clearMatrix() { - this.matrix = mat4.create(); - this.domElement.style.transform = ""; - } - - updateMaterial() { - if(this.material) { - this.material.apply(this.domElement); - } - } - - // Used in Group and Polygon - static getCommonAttributes() { - return { - "position": "absolute", - "display": "block", - - "transform": "matrix3d(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1)", - "transform-origin": "0 0", - - /* disable selection */ - "-webkit-user-select": "none", - "-moz-user-select": "none", - "-ms-user-select": "none", - "user-select": "none", - - /* Prefix still needed for Safari? */ - "-webkit-backface-visibility": "inherit", - "backface-visibility": "inherit", - }; - } - -} \ No newline at end of file diff --git a/src/dom/Polygon.js b/src/dom/Polygon.js deleted file mode 100644 index 13cbd6f..0000000 --- a/src/dom/Polygon.js +++ /dev/null @@ -1,472 +0,0 @@ - -import { CSSClass } from '../css/CSSClass.js'; -import { Object3D } from './Object3D.js'; -import { Triangle } from '../math/Triangle.js'; - -var isWebKit = 'WebkitAppearance' in document.documentElement.style; - -var css_mask = CSS.supports("mask-image: var(--background-image, none)"); -var css_webkit_mask = CSS.supports("-webkit-mask-image: var(--background-image, none)"); - -var css_clip_path = CSS.supports("clip-path: polygon(50% 0%, 0% 100%, 100% 100%)"); -var css_webkit_clip_path = CSS.supports("-webkit-clip-path: polygon(50% 0%, 0% 100%, 100% 100%)"); - -// Avoid scaling issues. If the content element is initially too small, the result will be blurry -var default_dom_size = (num) => Math.max(250, Math.min(num, 1200)); - -var cross2 = function(a, b, o) { - return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]) -}; - -export class Polygon extends Object3D { - - constructor(vertices, contentElement=null) { - - super(); - - this.vertices = vertices; // vertices in CCW - this.clipPath = []; // path of the polygon on a rectangular element - - this.simplify(); - - Polygon.getClass().attach(this.domElement); - - // Base size of the dom element ( in case of a triangle, it will be the length of the longest side) - this.getDomSize = default_dom_size; - - // Actual size of the dom element - this.block_width = 0; - this.block_height = 0; - - // texture / element / etc - this.contentElement = contentElement ? contentElement : document.createElement('div'); - Polygon.getContentClass().attach(this.contentElement); - this.domElement.appendChild(this.contentElement); - - this.uv_scale = vec2.fromValues(1,1); - this.uv_offset = vec2.fromValues(0,0); - - // triangle only data - this.maxi = 0;// Index of the longest side - - } - - // remove redundant vertices ( which are on the same line ) - simplify() { - var vertices = [this.vertices[0]]; - - for(let i=1; i 3) { - - ////////////////////////////////////////////// - // Project polygon points to the 2D plane - ////////////////////////////////////////////// - - // get new bases - let b1 = tri.norm; - let b2 = (Math.abs(vec3.dot(b1, [0,0,1])) < 0.9) ? vec3.cross(vec3.create(), b1, [0,0,1]) : vec3.cross(vec3.create(), b1, [0,1,0]); - let b3 = vec3.cross(vec3.create(), b2, b1); - - // Base change matrices - let BT = mat3.fromValues( - b2[0], b2[1], b2[2], - b3[0], b3[1], b3[2], - b1[0], b1[1], b1[2] - ); - - let BTI = mat3.invert(mat3.create(), BT); - - if(BTI === null) { - throw new Error("Degenerate triangle?"); - } - - // Transform points with the matrices - let points2d = this.vertices.map( - v => { - let pp = vec3.transformMat3(vec3.create(), v.position, BTI); - return pp.slice(0, 2); - } - ); - - ////////////////////////////////////////////// - // Find convex hull - ////////////////////////////////////////////// - - // https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain - - let points = points2d.slice().sort(function(a, b) { - return a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]; - }); - - let lower = []; - for (let i = 0; i < points.length; i++) { - while (lower.length >= 2 && cross2(lower[lower.length - 2], lower[lower.length - 1], points[i]) <= 0) { - lower.pop(); - } - lower.push(points[i]); - } - - let upper = []; - for (let i = points.length - 1; i >= 0; i--) { - while (upper.length >= 2 && cross2(upper[upper.length - 2], upper[upper.length - 1], points[i]) <= 0) { - upper.pop(); - } - upper.push(points[i]); - } - - upper.pop(); - lower.pop(); - - let hull = lower.concat(upper); - - ////////////////////////////////////////////// - // Find bounding box - ////////////////////////////////////////////// - - // For each edge (of the hull), transform the points to make it axis aligned - // Find the AABB with the smallest area - - let min_area = Number.POSITIVE_INFINITY; - //let corners = []; - let min_bounds = []; - let min_T = mat2.create(); - let min_TI = mat2.create(); - - for(var i=0; i vec2.transformMat2(vec2.create(), p, ATI) - ); - - // [xmin, xmax, ymin, ymax] - let bounds = tpoints.map( - p => [p[0],p[0],p[1],p[1]] - ).reduce( - (a, b) => [ - Math.min(a[0],b[0]), - Math.max(a[1],b[1]), - Math.min(a[2],b[2]), - Math.max(a[3],b[3]) - ] - ); - - let area = (bounds[1]-bounds[0])*(bounds[3]-bounds[2]); - if(area < min_area) { - min_area = area; - - min_bounds = bounds; - min_TI = ATI; - - } - - } - - // - - let box_width = min_bounds[1]-min_bounds[0]; - let box_height = min_bounds[3]-min_bounds[2]; - - let scale_ratio = 1; - - // scale the element, to avoid blurry texture - if(box_width > box_height) { - scale_ratio = this.getDomSize(box_width) / box_width; - } else { - scale_ratio = this.getDomSize(box_height) / box_height; - } - - this.block_width = box_width*scale_ratio; - this.block_height = box_height*scale_ratio; - - - let clipPoints = points2d.map( - p => vec2.sub( - vec2.create(), - vec2.transformMat2(vec2.create(), p, min_TI), - [min_bounds[0], min_bounds[2]] - ) - ); - - this.clipPath = clipPoints.map( - p2 => vec2.fromValues(p2[0]/box_width, p2[1]/box_height) - ); - - this.matrix = new Triangle( - vec3.fromValues(clipPoints[0][0]*scale_ratio, clipPoints[0][1]*scale_ratio, 0), - vec3.fromValues(clipPoints[1][0]*scale_ratio, clipPoints[1][1]*scale_ratio, 0), - vec3.fromValues(clipPoints[2][0]*scale_ratio, clipPoints[2][1]*scale_ratio, 0) - ).getTransformationTo(tri); - - - } else { - - throw new Error("The polygon has not enough sides"); - - } - - let clipData = 'polygon('+this.clipPath.map(p=>(p[0]*100)+'% '+(p[1]*100)+'%').join()+')'; - if(css_clip_path) { - this.domElement.style.clipPath = clipData; - } else if(css_webkit_clip_path) { - this.domElement.style['-webkit-clip-path'] = clipData; - } - - //this.domElement.style.width = this.block_width+"px"; - //this.domElement.style.height = this.block_height+"px"; - - // We need the width/height information in the childNode to properly position and scale the texture - // If we use width/height CSS values, then we can rescale this element, without calling updateContent - - this.domElement.style.setProperty("--width", this.block_width+"px"); - this.domElement.style.setProperty("--height", this.block_height+"px"); - - super.updateMatrix(); - - } - - updateContent() { - - // uv_scale - let uvs = this.vertices.map(v => { - let ret = vec2.mul(vec2.create(),v.uv,this.uv_scale); - vec2.add(ret, ret, this.uv_offset); - return ret; - }); - - // handle texture repeat - let tex_bounds = uvs.map( - // [xmin, xmax, ymin, ymax] - uv => [uv[0],uv[0],uv[1],uv[1]] - ).reduce( - (a, b) => [ - Math.min(a[0],b[0]), - Math.max(a[1],b[1]), - Math.min(a[2],b[2]), - Math.max(a[3],b[3]) - ] - ); - - let txmin = tex_bounds[0]; - let txmax = tex_bounds[1]; - let tymin = tex_bounds[2]; - let tymax = tex_bounds[3]; - - let xsize = txmax - txmin; - let ysize = tymax - tymin; - - let scx = 1/xsize, - scy = 1/ysize; - - - this.contentElement.style.backgroundPosition = 'calc(var(--width) * '+(-txmin*scx)+') calc(var(--height) * '+(1+tymin*scy)+')'; - this.contentElement.style.backgroundSize = (100*scx) + '% ' + (100*scy) + '%'; - - let TA = mat3.fromValues( - (uvs[0][0]-txmin)/xsize, 1-(uvs[0][1]-tymin)/ysize, 1, - (uvs[1][0]-txmin)/xsize, 1-(uvs[1][1]-tymin)/ysize, 1, - (uvs[2][0]-txmin)/xsize, 1-(uvs[2][1]-tymin)/ysize, 1 - ); - - let ai, bi, ci; - // use the longest side as base if it is a triangle - if(this.vertices.length == 3) { - ai = this.maxi; - bi = (this.maxi+1)%3; - ci = (this.maxi+2)%3; - } else { - ai = 0; - bi = 1; - ci = 2; - } - - let TB = mat3.fromValues( - this.clipPath[ai][0], this.clipPath[ai][1], 1, - this.clipPath[bi][0], this.clipPath[bi][1], 1, - this.clipPath[ci][0], this.clipPath[ci][1], 1 - ); - - let TX = mat3.mul( - mat3.create(), - TB, - mat3.invert( - mat3.create(), - TA - ) - ); - - let bh = this.block_height/this.block_width; - this.contentElement.style.transform = "translate("+[ - (TX[6] * 100)+"%", - (TX[7] * 100)+"%" - ].join()+")"+"matrix("+[ - TX[0], TX[1]*bh, - TX[3]/bh, TX[4], - 0,0 - ].join()+")"; - - } - - - - static getClass() { - - if(!css_class) { - css_class = new CSSClass(); - css_class.setProperties({ - "width": "var(--width, 0px)", - "height": "var(--height, 0px)", - - "opacity": "var(--opacity, 1)", - - "transform-style": "flat", - "overflow": "hidden" - }); - css_class.setProperties(Object3D.getCommonAttributes()); - css_class.update(); - css_class.init(); - } - - return css_class; - - } - - static getContentClass() { - - if(!css_content_class) { - - css_content_class = new CSSClass(); - css_content_class.setProperties({ - "width": "100%", - "height": "100%", - - "background-color": "var(--background-color, white)", - "background-image": "var(--background-image, none)", - "background-size": "100% 100%", - - "background-blend-mode": "multiply", - - "transform": "matrix(1, 0, 0, 1, 0, 0)", - "transform-origin": "0 0" - }); - - /* - if(css_mask) { - css_content_class.setProperties({ - 'mask-image': 'var(--background-image, none)', - 'mask-size': '100% 100%' - }); - } else if(css_webkit_mask) { - css_content_class.setProperties({ - '-webkit-mask-image': 'var(--background-image, none)', - '-webkit-mask-size': '100% 100%' - }); - }*/ - - css_content_class.update(); - css_content_class.init(); - - } - - return css_content_class; - - } - - -} - -var css_class = null; -var css_content_class = null; diff --git a/src/dom/RootObject.js b/src/dom/RootObject.js deleted file mode 100644 index d0eeda3..0000000 --- a/src/dom/RootObject.js +++ /dev/null @@ -1,77 +0,0 @@ - -import { CSSClass } from '../css/CSSClass.js'; -import { Group } from './Group.js'; - -import { PerspectiveCamera } from '../math/PerspectiveCamera.js'; -import { OrthographicCamera } from '../math/OrthographicCamera.js'; - -// Edge -var transform_value_support = CSS.supports("transform: translateZ(calc(100px * var(--mult-value,1)))"); - -export class RootObject extends Group { - - constructor() { - - super(); - - RootObject.getClass().attach(this.domElement); - } - - updateMatrix(camera) { - - if(camera instanceof PerspectiveCamera) { - let p_coeff = camera.perspective_coefficient; - let pshift; - - if(transform_value_support) { - pshift = 'calc( '+p_coeff+' * var(--viewport-height) / 2 )'; - } else { - pshift = (p_coeff * this.domElement.parentNode.offsetHeight / 2) + "px"; - } - - this.domElement.style.transform = 'translateZ('+pshift+')scaleY(-1)matrix3d('+camera.matrix.join() + ')matrix3d(' + this.matrix.join() + ')'; - } else if(camera instanceof OrthographicCamera) { - - let xsize = camera.right - camera.left; - let ysize = camera.top - camera.bottom; - - let xcenter = (camera.right + camera.left)/2; - let ycenter = (camera.top + camera.bottom)/2; - - let pwidth = this.domElement.parentNode.offsetWidth; - let pheight = this.domElement.parentNode.offsetHeight; - - this.domElement.style.transform = 'scale('+[pwidth/xsize,pheight/ysize].join()+')translate('+(-xcenter)+','+(-ycenter)+')scaleY(-1)matrix3d('+camera.matrix.join() + ')matrix3d(' + this.matrix.join() + ')'; - - } - - } - - static getClass() { - - if(!css_class) { - css_class = new CSSClass(); - css_class.setProperties({ - "width": "100% !important", - "height": "100% !important", - - "top": "50%", - "left": "50%", - - /* Click trough */ - "pointer-events": "none", - - /* Prefix still needed for Safari? */ - "-webkit-backface-visibility": "hidden !important", - "backface-visibility": "hidden !important" - }); - css_class.update(); - css_class.init(); - } - - return css_class; - } - -} - -var css_class = null; diff --git a/src/math/OrthographicCamera.js b/src/math/OrthographicCamera.js deleted file mode 100644 index d0835f1..0000000 --- a/src/math/OrthographicCamera.js +++ /dev/null @@ -1,15 +0,0 @@ -export class OrthographicCamera { - - constructor(left, right, top, bottom) { - - this.left = left; - this.right = right; - this.top = top; - this.bottom = bottom; - - // Inverse world - this.matrix = mat4.create(); - - } - -} \ No newline at end of file diff --git a/src/math/PerspectiveCamera.js b/src/math/PerspectiveCamera.js deleted file mode 100644 index 40b14c2..0000000 --- a/src/math/PerspectiveCamera.js +++ /dev/null @@ -1,16 +0,0 @@ -export class PerspectiveCamera { - - constructor(fov = 70) { - - this.fov = fov; - - // Inverse world - this.matrix = mat4.create(); - - } - - get perspective_coefficient() { - return 1.0 / Math.tan(this.fov * Math.PI / 360); - } - -} \ No newline at end of file diff --git a/src/math/Triangle.js b/src/math/Triangle.js deleted file mode 100644 index 020e1f1..0000000 --- a/src/math/Triangle.js +++ /dev/null @@ -1,71 +0,0 @@ - -// 3D triangle, represented by 3 points -export class Triangle { - - constructor(p1, p2, p3, norm) { - this.p1 = p1; - this.p2 = p2; - this.p3 = p3; - - this.edges = null; - - this.norm = norm ? norm : this.calculateNormal(); - } - - updateEdges() { - - if(this.edges) return; - - this.edges = [ - vec3.sub(vec3.create(), this.p1, this.p2), - vec3.sub(vec3.create(), this.p2, this.p3), - vec3.sub(vec3.create(), this.p3, this.p1) - ]; - } - - calculateNormal() { - - this.updateEdges(); - - return vec3.normalize(vec3.create(), vec3.cross( - vec3.create(), this.edges[0], this.edges[1] - )); - - } - - calculateEdgeLengths() { - return vec3.fromValues( - vec3.len(this.edges[0]), - vec3.len(this.edges[1]), - vec3.len(this.edges[2]) - ); - } - - getTransformationTo(that) { - - let A = mat4.fromValues( - this.p1[0], this.p1[1], this.p1[2], 1, - this.p2[0], this.p2[1], this.p2[2], 1, - this.p3[0], this.p3[1], this.p3[2], 1, - this.norm[0], this.norm[1], this.norm[2], 0 - ); - - let B = mat4.fromValues( - that.p1[0], that.p1[1], that.p1[2], 1, - that.p2[0], that.p2[1], that.p2[2], 1, - that.p3[0], that.p3[1], that.p3[2], 1, - that.norm[0], that.norm[1], that.norm[2], 0 - ); - - return mat4.mul( - mat4.create(), - B, - mat4.invert( - mat4.create(), - A - ) - ); - - } - -} \ No newline at end of file diff --git a/src/math/Vertex.js b/src/math/Vertex.js deleted file mode 100644 index 1a4381e..0000000 --- a/src/math/Vertex.js +++ /dev/null @@ -1,8 +0,0 @@ -export class Vertex { - - constructor(position, uv) { - this.position = position ? position : vec3.create(); - this.uv = uv ? uv : vec2.create(); - } - -}; \ No newline at end of file diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..0ea3455 --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES2023", + "lib": ["ES2023", "ESNext.Disposable", "DOM"], + "module": "preserve", + "verbatimModuleSyntax": true, + "erasableSyntaxOnly": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noImplicitOverride": true, + "noFallthroughCasesInSwitch": true, + "allowUnreachableCode": false, + "composite": true, + "declaration": true, + "emitDeclarationOnly": true, + "skipLibCheck": true + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..ffc47e4 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,4 @@ +{ + "files": [], + "references": [{ "path": "packages/c3r" }, { "path": "packages/c3r-three" }] +} diff --git a/vitest.config.mjs b/vitest.config.mjs new file mode 100644 index 0000000..c239f3d --- /dev/null +++ b/vitest.config.mjs @@ -0,0 +1,39 @@ +import { resolve } from "node:path"; +import { playwright } from "@vitest/browser-playwright"; +import { defineConfig } from "vitest/config"; + +const resolveConfig = { + alias: { c3r: resolve(import.meta.dirname, "packages/c3r/src/C3R.ts") }, +}; + +export default defineConfig({ + test: { + projects: [ + { + resolve: resolveConfig, + test: { + name: "unit", + environment: "happy-dom", + css: true, // for the exported stylesheet string + include: ["packages/*/test/**/*.test.ts"], + exclude: ["**/*.browser.test.ts"], + }, + }, + { + resolve: resolveConfig, + publicDir: "examples/public", + test: { + name: "browser", + include: ["packages/*/test/**/*.browser.test.ts"], + browser: { + enabled: true, + provider: playwright(), + headless: true, + instances: [{ browser: "chromium" }], + viewport: { width: 1000, height: 400 }, + }, + }, + }, + ], + }, +});