From c46b4a919a698025a4fcf9362f55938e0f0e39c8 Mon Sep 17 00:00:00 2001 From: John Haugabook Date: Wed, 29 Jul 2026 23:32:55 -0400 Subject: [PATCH] Add flight-map-canvas extension (#2482) * Add flight-map-canvas extension A canvas port of the Flight Map VSCode extension: a first-person satellite terrain map flown with flight simulator controls, for session breaks while an agent works. The simulator under game/ is copied verbatim from the source extension's media/ folder. That page already reached its host through one seam - an acquireVsCodeApi() object and a placeholder in its head - so extension.mjs fills that seam for the canvas: a loopback server that injects a policy, the render configuration, and a shim translating Server-Sent Events into the messages the page already handles. Two agent actions: fly_to sends the flight to a capital, a geocoded city, or a raw lat/lng, and picks a random capital when called with no input; report_job shows the current job step under the HUD. Adds the vendored three.min.js to the codespell skip list, matching the existing entry for arcade-canvas's phaser.min.js. Co-Authored-By: Claude Opus 5 * Apply suggestions from code review --------- Co-authored-by: Claude Opus 5 --- .codespellrc | 7 +- .github/plugin/marketplace.json | 6 + .../.github/plugin/plugin.json | 20 + extensions/flight-map-canvas/README.md | 116 ++ extensions/flight-map-canvas/assets/icon.png | Bin 0 -> 12346 bytes .../flight-map-canvas/assets/preview.png | Bin 0 -> 261518 bytes .../flight-map-canvas/copilot-extension.json | 4 + extensions/flight-map-canvas/extension.mjs | 632 ++++++++++ extensions/flight-map-canvas/game/app.js | 1057 +++++++++++++++++ extensions/flight-map-canvas/game/capitals.js | 94 ++ .../game/destinationInput.js | 310 +++++ .../flight-map-canvas/game/flightControls.js | 385 ++++++ extensions/flight-map-canvas/game/geocoder.js | 314 +++++ .../flight-map-canvas/game/hostBridge.js | 73 ++ extensions/flight-map-canvas/game/index.html | 284 +++++ .../flight-map-canvas/game/renderConfig.js | 269 +++++ extensions/flight-map-canvas/game/styles.css | 846 +++++++++++++ .../flight-map-canvas/game/terrainFill.js | 441 +++++++ .../game/vendor/three.min.js | 6 + .../flight-map-canvas/package-lock.json | 475 ++++++++ extensions/flight-map-canvas/package.json | 21 + extensions/flight-map-canvas/renderMap.json | 37 + 22 files changed, 5394 insertions(+), 3 deletions(-) create mode 100644 extensions/flight-map-canvas/.github/plugin/plugin.json create mode 100644 extensions/flight-map-canvas/README.md create mode 100644 extensions/flight-map-canvas/assets/icon.png create mode 100644 extensions/flight-map-canvas/assets/preview.png create mode 100644 extensions/flight-map-canvas/copilot-extension.json create mode 100644 extensions/flight-map-canvas/extension.mjs create mode 100644 extensions/flight-map-canvas/game/app.js create mode 100644 extensions/flight-map-canvas/game/capitals.js create mode 100644 extensions/flight-map-canvas/game/destinationInput.js create mode 100644 extensions/flight-map-canvas/game/flightControls.js create mode 100644 extensions/flight-map-canvas/game/geocoder.js create mode 100644 extensions/flight-map-canvas/game/hostBridge.js create mode 100644 extensions/flight-map-canvas/game/index.html create mode 100644 extensions/flight-map-canvas/game/renderConfig.js create mode 100644 extensions/flight-map-canvas/game/styles.css create mode 100644 extensions/flight-map-canvas/game/terrainFill.js create mode 100644 extensions/flight-map-canvas/game/vendor/three.min.js create mode 100644 extensions/flight-map-canvas/package-lock.json create mode 100644 extensions/flight-map-canvas/package.json create mode 100644 extensions/flight-map-canvas/renderMap.json diff --git a/.codespellrc b/.codespellrc index abc16cec..6a20d6e8 100644 --- a/.codespellrc +++ b/.codespellrc @@ -45,9 +45,9 @@ # Wee, Sherif - proper name (Wee, Sherif, contributor names should not be flagged as typos) # queston - intentional misspelling example in skills/arize-dataset/SKILL.md demonstrating typo detection in field names - + # extenions - intentional misspelled key name used in plugin validators to detect invalid manifests - + # nin - MongoDB $nin operator in security instructions NoSQL injection detection regex # Vertexes - FreeCAD shape sub-elements used as property of obj.Shape @@ -67,6 +67,7 @@ ignore-words-list = numer,wit,aks,edn,ser,ois,gir,rouge,categor,aline,ative,afterall,deques,dateA,dateB,TE,FillIn,alle,vai,LOD,InOut,pixelX,aNULL,Wee,Sherif,queston,extenions,Vertexes,nin,FO,CAF,Parth,ans,gud,Vally,vally,ACI # Skip certain files and directories + # *.tm7 - MTM DataContract exports; embedded base64 icon blobs trigger false positives -skip = .git,node_modules,package-lock.json,*.lock,website/build,website/.docusaurus,.all-contributorrc,./skills/geofeed-tuner/assets/*.json,./skills/geofeed-tuner/references/*.txt,./plugins/fastah-ip-geo-tools/skills/geofeed-tuner/assets/*.json,./plugins/fastah-ip-geo-tools/skills/geofeed-tuner/references/*.txt,./extensions/arcade-canvas/game/phaser.min.js,./extensions/pr-artifact-explorer/assets/asciinema-player.min.js,./extensions/pr-artifact-explorer/assets/asciinema-player-worker.min.js,./extensions/pr-artifact-explorer/assets/primer-*.css,*.tm7 +skip = .git,node_modules,package-lock.json,*.lock,website/build,website/.docusaurus,.all-contributorrc,./skills/geofeed-tuner/assets/*.json,./skills/geofeed-tuner/references/*.txt,./plugins/fastah-ip-geo-tools/skills/geofeed-tuner/assets/*.json,./plugins/fastah-ip-geo-tools/skills/geofeed-tuner/references/*.txt,./extensions/arcade-canvas/game/phaser.min.js,./extensions/pr-artifact-explorer/assets/asciinema-player.min.js,./extensions/pr-artifact-explorer/assets/asciinema-player-worker.min.js,./extensions/pr-artifact-explorer/assets/primer-*.css,./extensions/flight-map-canvas/game/vendor/three.min.js,*.tm7 diff --git a/.github/plugin/marketplace.json b/.github/plugin/marketplace.json index 1b7ab953..2d219235 100644 --- a/.github/plugin/marketplace.json +++ b/.github/plugin/marketplace.json @@ -599,6 +599,12 @@ "repo": "figma/mcp-server-guide" } }, + { + "name": "flight-map-canvas", + "source": "extensions/flight-map-canvas", + "description": "A GitHub Copilot canvas that generates a view where Google Maps can be explored using 3D controls, as if a flight simulator. Agents can send the flight anywhere and report what they are working on.", + "version": "1.0.0" + }, { "name": "flowstudio-power-automate", "source": "plugins/flowstudio-power-automate", diff --git a/extensions/flight-map-canvas/.github/plugin/plugin.json b/extensions/flight-map-canvas/.github/plugin/plugin.json new file mode 100644 index 00000000..fce346f6 --- /dev/null +++ b/extensions/flight-map-canvas/.github/plugin/plugin.json @@ -0,0 +1,20 @@ +{ + "name": "flight-map-canvas", + "description": "A GitHub Copilot canvas that generates a view where Google Maps can be explored using 3D controls, as if a flight simulator. Agents can send the flight anywhere and report what they are working on.", + "version": "1.0.0", + "author": { + "name": "John Haugabook", + "url": "https://github.com/jhauga" + }, + "keywords": [ + "copilot-canvas", + "flight-simulator", + "geography", + "google-maps", + "interactive-canvas", + "session-breaks", + "threejs" + ], + "logo": "assets/preview.png", + "extensions": "." +} diff --git a/extensions/flight-map-canvas/README.md b/extensions/flight-map-canvas/README.md new file mode 100644 index 00000000..3cf0861f --- /dev/null +++ b/extensions/flight-map-canvas/README.md @@ -0,0 +1,116 @@ +# Flight Map Canvas + +A GitHub Copilot canvas that generates a view where Google Maps can be explored using 3D controls, as if a flight simulator. No 3D plane model as the focus is the aerial landscape. Fly around in 1st person for several minutes, starting from a capital city while Copilot works. + +It is a canvas port of the [Flight Map VSCode extension](https://github.com/isocialPractice/vscode-flight-map). Satellite imagery tiles stream in around the camera as it moves, unloaded gaps are filled with color sampled from the viewport, and drifting procedural clouds sit over the fill. The HUD reads heading, speed, altitude, pitch, and live coordinates, with the city, region, and country under the camera looked up as it flies. + +While an agent works in the session, it can send the flight somewhere new and report what it is doing on a status strip under the HUD. + +## Files + +- `extension.mjs` — canvas declaration, loopback game server, the host shim it injects into the page, destination resolution, and agent actions. +- `game/` — the simulator itself, byte for byte the VSCode extension's `media/` folder. `index.html` is its `flightMap.html`; the rest is the Three.js scene, tile loader, flight controls, terrain fill, HUD, and configuration panel. +- `game/vendor/three.min.js` — vendored Three.js r128, so the only remote requests are the ones the simulation makes for imagery and place names. +- `renderMap.json` — the render configuration the canvas starts on. +- `assets/` — app icon and `preview.png` for the extensions gallery. +- `package.json` — declares the Copilot SDK dependency and ESM entry point. +- `copilot-extension.json` — Copilot extension name/version metadata. + +## Prerequisites + +- **Node.js 20.19 or newer**, because the Copilot SDK requires `node ^20.19.0 || >=22.12.0`. +- A WebGL-capable canvas surface; the scene is rendered through Three.js. +- Network access. Satellite tiles, the location label, and destination lookups are all fetched at runtime. +- The GitHub Copilot app canvas / UI-extensions experiment enabled. + +## Install + +Drop this folder at `~/.copilot/extensions/flight-map-canvas/` for user scope, or in a repository at `.github/extensions/flight-map-canvas/` for project scope. Then install dependencies from inside the copied folder: + +```sh +# User scope +cd ~/.copilot/extensions/flight-map-canvas + +# Or project scope, from the repository root +cd .github/extensions/flight-map-canvas + +npm install +``` + +Reload extensions in the GitHub Copilot app, then open the `flight-map-canvas` canvas. Pick a destination from the menu, click the view to start flying, and use the controls below. + +The canvas accepts optional open inputs, resolved the same way `fly_to` resolves them: + +| Input | Type | Description | +| --- | --- | --- | +| `capital` | string | A world capital by city or country name. Matched against the capitals the canvas ships with. | +| `city` | string | City name for anywhere that is not a shipped capital. Geocoded on the way in. | +| `state` | string | State, region, province, or district that narrows the city. | +| `country` | string | Country that narrows the city. | +| `lat` / `lng` | number | Raw coordinates, which skip the geocoder entirely. Latitude runs -85.0511 to 85.0511, the limit of the Web Mercator tile imagery; longitude runs -180 to 180. Give both or neither. | + +Opened with no input, the canvas starts on its own welcome screen and waits for a destination. + +## Controls + +| Input | Action | +| --- | --- | +| `W` / `S` or `Up` / `Down` | Throttle | +| Mouse (after clicking the view) | Pitch and yaw | +| `A` / `D` or `Left` / `Right` | Roll | +| `Q` / `E` | Rudder yaw | +| `R` / `F` | Climb / descend | +| `Space` | Auto-level | +| `Shift` | Boost | +| `P` | Pause / resume | +| `Esc` | Release the view | + +Mouse look prefers pointer lock. If the canvas host refuses it, the controls fall back to drag look: hold the left mouse button and move to steer. The on-screen help says which mode is active. + +The **Destination** menu lists the world capitals grouped by continent and opens with **Input Destination**, which takes a typed state/region and city plus a country from a menu, then lists what matched so one can be selected. **Config** opens live rendering sliders, and **Export JSON** downloads the current configuration as `renderMap.json`. + +## Agent actions + +- `fly_to { capital?, city?, state?, country?, lat?, lng? }` — send the flight to a destination. A capital is matched against the shipped list, a city is geocoded, and a lat/lng pair is flown to directly. Called with no input it picks a random world capital, which is the way to say "take me somewhere else". +- `report_job { status, tokens?, done? }` — report the current job step. The status shows on a strip under the HUD and the token count runs beside it. Call it when work starts, again on each new step, and once more with `done: true` when finished. + +To have the agent narrate itself automatically, reference these actions from a `.github/copilot-instructions.md` so it calls `report_job` on each step of a chat request. + +## How the port works + +The simulator under `game/` is unchanged from the VSCode extension. That page was already written to run in two places, and it reaches whatever is hosting it through one seam: an `acquireVsCodeApi()` object for messaging, and a `` placeholder in its `` that the host fills with a content security policy and its render configuration. + +`extension.mjs` fills that seam for the canvas: + +- A loopback HTTP server serves the page and its assets, replacing the placeholder with a policy, the render configuration read from `renderMap.json`, and a shim that defines `acquireVsCodeApi()`. +- Agent activity is streamed to the page over Server-Sent Events at `/events`. The shim translates those events into the exact `flyTo` and `jobStatus` commands the page already registers handlers for. +- The page's export button has no save dialog to reach here, so the shim falls back to the browser download the standalone page uses. +- Destinations are resolved server-side before broadcasting, against the page's own `capitals.js` for shipped capitals and OpenStreetMap Nominatim for everything else. + +This mirrors the [`backrooms-canvas`](../backrooms-canvas) and [`arcade-canvas`](../arcade-canvas) architecture: a static frontend served from a loopback server, with the agent driving it through canvas actions. + +## Development + +The port is a copy, not a fork. Everything under `game/` comes from the VSCode extension's `media/` folder, so edits belong there. + +In that repository the two are held together by symlinks, which means there is only ever one copy to edit and the port cannot go stale. Submission needs real files, though, because a link pointing at a sibling repository resolves to nothing anywhere else, so the stage command resolves every link on the way out: + +```sh +# In the vscode-flight-map repository +npm run canvas:link # create or repair the symlinks +npm run canvas:check # verify them; non-zero when stale +npm run canvas:stage -- # real-file copy for submission +``` + +`media/flightMap.html` is linked as `game/index.html`; nothing else is renamed and no file is rewritten. To run the simulator outside a canvas while working on it, open `media/flightMap.html` in a browser. + +## Credits + +- Source extension and canvas port: [vscode-flight-map](https://github.com/isocialPractice/vscode-flight-map) by John Haugabook. +- Satellite imagery: Google Maps tiles, with Esri World Imagery as the fallback provider. The imagery is served by, and remains the property of, those providers; this canvas only displays it, subject to their respective terms of service. +- Place names and destination lookups: [OpenStreetMap Nominatim](https://nominatim.openstreetmap.org/). Data © OpenStreetMap contributors, available under the [Open Database License](https://www.openstreetmap.org/copyright). +- 3D rendering: [Three.js](https://threejs.org/) r128. + +## License + +MIT diff --git a/extensions/flight-map-canvas/assets/icon.png b/extensions/flight-map-canvas/assets/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..9e76b2be01a3b2c47a74007d783229e43a2305ca GIT binary patch literal 12346 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 literal 0 HcmV?d00001 diff --git a/extensions/flight-map-canvas/assets/preview.png b/extensions/flight-map-canvas/assets/preview.png new file mode 100644 index 0000000000000000000000000000000000000000..7b1a85069221f34d09e33901dee10c9386fdd7e1 GIT binary patch literal 261518 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%0A3SkYsAu2uQ6V{wq}Awgu@!vMCY>%T=91 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

oP9mipx3`ZiYv;FybW@mLUCw*+7`9KH`OAUm5& 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

IsF@8Ab)k;n0e>O^ccZoc{Rj<^k4=Fr|`m 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 MNyVHPQi?fxRM88MXmD!{i8FWXo@sT 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 U*#4V71poj507*qoM6N<$g7T|qkN^Mx literal 0 HcmV?d00001 diff --git a/extensions/flight-map-canvas/copilot-extension.json b/extensions/flight-map-canvas/copilot-extension.json new file mode 100644 index 00000000..30adeba5 --- /dev/null +++ b/extensions/flight-map-canvas/copilot-extension.json @@ -0,0 +1,4 @@ +{ + "name": "flight-map-canvas", + "version": 1 +} diff --git a/extensions/flight-map-canvas/extension.mjs b/extensions/flight-map-canvas/extension.mjs new file mode 100644 index 00000000..dd8598f1 --- /dev/null +++ b/extensions/flight-map-canvas/extension.mjs @@ -0,0 +1,632 @@ +/** + * Copilot canvas entry point for Flight Map. + * + * The simulator itself is the same page the VS Code extension ships: a + * plain Three.js document under game/ that loads satellite tiles, flies a + * first-person camera over them, and reads its render configuration off + * `window.__flightMapConfig`. This file is only the host. It runs a + * loopback HTTP server that serves that page, and registers a canvas so + * an agent can steer the flight and report what it is working on. + * + * The page carries a `` placeholder that each host + * fills with whatever only it can supply. The VS Code panel puts a + * content security policy, webview asset URIs, and the render config + * there. This server puts a policy, the render config, and a shim that + * stands in for `acquireVsCodeApi()`, so the page runs unchanged in both. + * + * Messages the shim relays, matching the commands the page already + * registers through media/hostBridge.js: + * + * host -> page : { command: 'flyTo', destination } + * { command: 'jobStatus', job } + * page -> host : { command: 'ready' } + * { command: 'exportConfig', json } // handled in the shim + */ +import { createReadStream } from "node:fs"; +import { readFile, stat } from "node:fs/promises"; +import { createServer } from "node:http"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { randomBytes } from "node:crypto"; + +import { CanvasError, createCanvas, joinSession } from "@github/copilot-sdk/extension"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const gameRoot = path.join(__dirname, "game"); +const assetsRoot = path.join(__dirname, "assets"); +const indexPath = path.join(gameRoot, "index.html"); + +/** Idle agent job; the status strip hides itself. */ +const IDLE_JOB = { working: false, status: "", tokens: 0 }; + +/** + * Nominatim asks every client to identify itself. The canvas makes at most + * one lookup per fly_to, well inside the one-request-per-second policy. + */ +const USER_AGENT = "flight-map-canvas (https://github.com/isocialPractice/vscode-flight-map)"; +const NOMINATIM = "https://nominatim.openstreetmap.org/search"; + +/** + * The tile imagery the page flies over is Web Mercator, which runs out of + * projection at about 85.0511 degrees. Past that there are no tiles to + * fetch, so a latitude beyond it is rejected rather than flown to a blank. + */ +const MAX_LATITUDE = 85.0511; + +const servers = new Map(); + +/** + * The capitals the page ships with, read out of its own data file rather + * than duplicated here. game/capitals.js is a plain script that assigns + * one `var`, so evaluating it and returning that binding keeps this + * server and the page reading from a single list. + */ +const CAPITALS = await (async () => { + const source = await readFile(path.join(gameRoot, "capitals.js"), "utf8"); + const regions = new Function(`${source}\nreturn CAPITALS_BY_REGION;`)(); + return regions.flatMap((region) => + region.capitals.map((capital) => ({ ...capital, region: region.region })), + ); +})(); + +/** The render configuration the page starts on, or defaults when absent. */ +async function readRenderConfig() { + try { + return JSON.parse(await readFile(path.join(__dirname, "renderMap.json"), "utf8")); + } catch { + // Missing or malformed: the page falls back to its own defaults + return {}; + } +} + +function contentType(filePath) { + switch (path.extname(filePath).toLowerCase()) { + case ".html": + return "text/html; charset=utf-8"; + case ".js": + return "text/javascript; charset=utf-8"; + case ".css": + return "text/css; charset=utf-8"; + case ".json": + return "application/json; charset=utf-8"; + case ".png": + return "image/png"; + case ".jpg": + case ".jpeg": + return "image/jpeg"; + case ".svg": + return "image/svg+xml"; + case ".webp": + return "image/webp"; + default: + return "application/octet-stream"; + } +} + +/** Resolves a request path under a root, refusing anything that escapes it. */ +function resolveUnder(root, requestPath) { + const resolved = path.resolve(root, `.${requestPath}`); + if (resolved !== root && !resolved.startsWith(`${root}${path.sep}`)) { + throw new CanvasError("invalid_path", "Requested path is outside the flight map assets."); + } + return resolved; +} + +function sendNotFound(res) { + res.writeHead(404, { "content-type": "text/plain; charset=utf-8" }); + res.end("Not found"); +} + +function sendSse(res, event, data) { + res.write(`event: ${event}\n`); + res.write(`data: ${JSON.stringify(data)}\n\n`); +} + +function broadcast(entry, event, data) { + for (const client of entry.clients) { + sendSse(client, event, data); + } +} + +/* ============================================================ + Destination resolution + ============================================================ */ + +function normalizeText(value) { + return typeof value === "string" ? value.trim() : ""; +} + +function randomCapital() { + return CAPITALS[Math.floor(Math.random() * CAPITALS.length)]; +} + +function asDestination(capital) { + return { + capital: capital.capital, + country: capital.country, + lat: capital.lat, + lng: capital.lng, + label: `${capital.capital}, ${capital.country}`, + }; +} + +/** Matches a name against the shipped capitals, by city or by country. */ +function findCapital(name) { + const needle = name.toLowerCase(); + return ( + CAPITALS.find((c) => c.capital.toLowerCase() === needle) ?? + CAPITALS.find((c) => c.country.toLowerCase() === needle) ?? + CAPITALS.find((c) => c.capital.toLowerCase().includes(needle)) ?? + CAPITALS.find((c) => c.country.toLowerCase().includes(needle)) + ); +} + +/** + * Forward geocodes typed fields the same way the page's own destination + * dialog does: structured Nominatim parameters rather than one + * concatenated string, so a city that also exists elsewhere does not + * outrank the intended match. + */ +async function geocode(fields) { + const params = new URLSearchParams({ format: "jsonv2", addressdetails: "1", limit: "1" }); + for (const key of ["city", "state", "country"]) { + if (fields[key]) params.set(key, fields[key]); + } + + let response; + try { + response = await fetch(`${NOMINATIM}?${params}`, { + headers: { "user-agent": USER_AGENT, accept: "application/json" }, + }); + } catch (error) { + throw new CanvasError("geocode_unreachable", `Could not reach the geocoding service: ${error.message}`); + } + + if (!response.ok) { + throw new CanvasError("geocode_failed", `Geocoding failed with status ${response.status}.`); + } + + const [match] = await response.json(); + if (!match) { + return null; + } + + const address = match.address ?? {}; + const city = address.city || address.town || address.village || address.municipality || match.name; + const state = address.state || address.province || address.region || address.county; + const code = address.country_code ? address.country_code.toUpperCase() : ""; + const label = [state, city && city !== state ? city : null, code].filter(Boolean).join(", "); + + return { + capital: city || "Destination", + country: address.country || "", + lat: Number.parseFloat(match.lat), + lng: Number.parseFloat(match.lon), + label: label || match.display_name, + }; +} + +/** + * Turns fly_to / open input into a destination the page can load. + * + * lat + lng flown to directly + * capital matched against the shipped capitals + * city/state/country geocoded + * nothing a random capital, so "take me somewhere" works + */ +async function resolveDestination(input) { + const fields = { + capital: normalizeText(input?.capital), + city: normalizeText(input?.city), + state: normalizeText(input?.state), + country: normalizeText(input?.country), + }; + + const lat = typeof input?.lat === "number" ? input.lat : undefined; + const lng = typeof input?.lng === "number" ? input.lng : undefined; + + if (lat !== undefined || lng !== undefined) { + if (lat === undefined || lng === undefined) { + throw new CanvasError("incomplete_coordinates", "Give both lat and lng, or neither."); + } + if (!Number.isFinite(lat) || lat < -MAX_LATITUDE || lat > MAX_LATITUDE) { + throw new CanvasError( + "invalid_latitude", + `lat must be between -${MAX_LATITUDE} and ${MAX_LATITUDE}, the limit of the Web Mercator tile imagery.`, + ); + } + if (!Number.isFinite(lng) || lng < -180 || lng > 180) { + throw new CanvasError("invalid_longitude", "lng must be between -180 and 180."); + } + return { + capital: fields.city || fields.capital || "Waypoint", + country: fields.country, + lat, + lng, + label: fields.city || fields.capital + ? `${fields.city || fields.capital}${fields.country ? `, ${fields.country}` : ""}` + : `${Math.abs(lat).toFixed(4)}°${lat >= 0 ? "N" : "S"} ` + + `${Math.abs(lng).toFixed(4)}°${lng >= 0 ? "E" : "W"}`, + }; + } + + if (fields.capital) { + const capital = findCapital(fields.capital); + if (capital) return asDestination(capital); + // Not one of the shipped capitals: treat it as a place name + fields.city ||= fields.capital; + } + + if (fields.city || fields.state || fields.country) { + const resolved = await geocode(fields); + if (resolved) return resolved; + + // A country with no city still has a capital in the shipped list + const fallback = fields.country && findCapital(fields.country); + if (fallback) return asDestination(fallback); + + throw new CanvasError("destination_not_found", "No destination matched that description."); + } + + return asDestination(randomCapital()); +} + +/* ============================================================ + Page serving + ============================================================ */ + +/** + * Builds the head the page's placeholder expects: a policy, the render + * configuration, and the host shim. The shim must run before the page's + * own scripts, which is why it goes in the head rather than after them. + */ +function buildHead(entry, nonce) { + const csp = [ + "default-src 'self'", + // Satellite tiles are remote images; the terrain fill samples the + // canvas, so the tile textures are read back and need to be clean + "img-src 'self' https: data: blob:", + "style-src 'self' 'unsafe-inline'", + `script-src 'self' 'nonce-${nonce}'`, + // 'self' for the event stream below, https: for the geocoder the + // page's own destination dialog calls + "connect-src 'self' https:", + ].join("; "); + + const init = { + config: entry.config, + job: entry.job, + destination: entry.destination, + }; + + return ( + `\n` + + ` ` + ); +} + +/** + * Stands in for the VS Code webview host. The page reaches its host + * through `acquireVsCodeApi()` and a window `message` listener, so + * defining that API and translating the server's Server-Sent Events into + * those messages is the whole port. + */ +function hostShim(init) { + return ` (function () { + var init = ${JSON.stringify(init).replace(/ page channel for agent activity + try { + var events = new EventSource('/events'); + events.addEventListener('flyTo', function (event) { + try { dispatch({ command: 'flyTo', destination: JSON.parse(event.data).destination }); } catch (e) {} + }); + events.addEventListener('jobStatus', function (event) { + try { dispatch({ command: 'jobStatus', job: JSON.parse(event.data).job }); } catch (e) {} + }); + } catch (e) { + // No EventSource: the simulator still flies, just without agent activity + } + })();`; +} + +async function renderIndex(entry) { + const html = await readFile(indexPath, "utf8"); + const nonce = randomBytes(16).toString("base64url"); + return html.replace("", buildHead(entry, nonce)); +} + +async function streamFile(res, filePath) { + const fileStat = await stat(filePath).catch(() => undefined); + if (!fileStat?.isFile()) { + sendNotFound(res); + return; + } + res.writeHead(200, { + "content-type": contentType(filePath), + "cache-control": "no-cache", + }); + const stream = createReadStream(filePath); + stream.on("error", () => { + if (!res.headersSent) { + sendNotFound(res); + } else { + res.destroy(); + } + }); + stream.pipe(res); +} + +async function handleRequest(entry, req, res) { + const url = new URL(req.url ?? "/", entry.url); + + if (url.pathname === "/events") { + res.writeHead(200, { + "content-type": "text/event-stream; charset=utf-8", + "cache-control": "no-cache", + connection: "keep-alive", + }); + entry.clients.add(res); + // Catch a fresh or reconnecting client up to the live state + sendSse(res, "jobStatus", { job: entry.job }); + if (entry.destination) { + sendSse(res, "flyTo", { destination: entry.destination }); + } + req.on("close", () => entry.clients.delete(res)); + return; + } + + if (url.pathname === "/favicon.ico") { + await streamFile(res, path.join(assetsRoot, "icon.png")); + return; + } + + try { + if (url.pathname === "/" || url.pathname === "/index.html") { + res.writeHead(200, { + "content-type": "text/html; charset=utf-8", + "cache-control": "no-cache", + }); + res.end(await renderIndex(entry)); + return; + } + + const staticPath = url.pathname.startsWith("/assets/") + ? resolveUnder(assetsRoot, url.pathname.slice("/assets".length)) + : resolveUnder(gameRoot, url.pathname); + await streamFile(res, staticPath); + } catch (error) { + if (error instanceof CanvasError) { + res.writeHead(400, { "content-type": "text/plain; charset=utf-8" }); + res.end(error.message); + return; + } + throw error; + } +} + +async function startServer(instanceId, destination) { + const entry = { + clients: new Set(), + config: await readRenderConfig(), + job: { ...IDLE_JOB }, + destination, + server: undefined, + url: undefined, + }; + + const server = createServer((req, res) => { + handleRequest(entry, req, res).catch((error) => { + res.writeHead(500, { "content-type": "text/plain; charset=utf-8" }); + res.end(error instanceof Error ? error.message : "Flight map canvas server error"); + }); + }); + entry.server = server; + + await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); + const address = server.address(); + const port = typeof address === "object" && address ? address.port : 0; + entry.url = `http://127.0.0.1:${port}/`; + servers.set(instanceId, entry); + return entry; +} + +function getOpenEntry(instanceId) { + const entry = servers.get(instanceId); + if (!entry) { + throw new CanvasError("flight_map_not_open", "Open the Flight Map canvas before invoking this action."); + } + return entry; +} + +/** + * Coerces report_job input into the job shape the status strip reads. + * A call that omits tokens keeps the count already on screen, so the + * final done=true call settles the job without wiping its total. + */ +function normalizeJob(input, previous) { + if (!input || typeof input !== "object") { + return { ...IDLE_JOB }; + } + return { + working: input.done !== true, + status: typeof input.status === "string" ? input.status.slice(0, 120) : "", + tokens: + typeof input.tokens === "number" && Number.isFinite(input.tokens) + ? Math.max(0, Math.floor(input.tokens)) + : (previous?.tokens ?? 0), + }; +} + +const DESTINATION_PROPERTIES = { + capital: { + type: "string", + description: + "A world capital to fly to, by city or country name (e.g. 'Wellington', 'New Zealand'). Matched against the capitals the canvas ships with.", + }, + city: { + type: "string", + description: "City name for anywhere that is not a shipped capital. Geocoded on the way in.", + }, + state: { + type: "string", + description: "State, region, province, or district that narrows the city.", + }, + country: { + type: "string", + description: "Country that narrows the city.", + }, + lat: { + type: "number", + description: `Latitude in degrees, -${MAX_LATITUDE} to ${MAX_LATITUDE} (the limit of the Web Mercator tile imagery). Give lng as well to skip the geocoder entirely.`, + minimum: -MAX_LATITUDE, + maximum: MAX_LATITUDE, + }, + lng: { + type: "number", + description: "Longitude in degrees, -180 to 180. Give lat as well.", + minimum: -180, + maximum: 180, + }, +}; + +await joinSession({ + canvases: [ + createCanvas({ + id: "flight-map-canvas", + displayName: "Flight Map", + description: + "Fly a first-person satellite terrain map of the world while agents work. The agent can send the flight anywhere and report what it is doing.", + inputSchema: { + type: "object", + properties: DESTINATION_PROPERTIES, + additionalProperties: false, + }, + actions: [ + { + name: "fly_to", + description: + "Send the flight to a destination. Give a capital by name, a city with an optional state and country, or a raw lat/lng. Called with no input it picks a random world capital, which is the way to say 'take me somewhere else'.", + inputSchema: { + type: "object", + properties: DESTINATION_PROPERTIES, + additionalProperties: false, + }, + handler: async (ctx) => { + const entry = getOpenEntry(ctx.instanceId); + const destination = await resolveDestination(ctx.input); + // Held so a reload, or a client that connects later, + // arrives at the same place the agent sent the flight + entry.destination = destination; + broadcast(entry, "flyTo", { destination }); + return destination; + }, + }, + { + name: "report_job", + description: + "Report your current job status to the flight map. Call it when you start a chat request, again on each new step, and once more with done=true when finished. The status shows on a strip under the HUD and the token count runs beside it.", + inputSchema: { + type: "object", + properties: { + status: { + type: "string", + description: + "Short status text to show under the HUD (e.g. 'reading the codebase', 'rewriting the parser').", + }, + tokens: { + type: "number", + description: "Approximate tokens consumed by the current job so far.", + }, + done: { + type: "boolean", + description: + "Set true when the job is finished; the activity indicator stills and the last status stays readable.", + }, + }, + required: ["status"], + additionalProperties: false, + }, + handler: (ctx) => { + const entry = getOpenEntry(ctx.instanceId); + entry.job = normalizeJob(ctx.input, entry.job); + broadcast(entry, "jobStatus", { job: entry.job }); + return { job: entry.job }; + }, + }, + ], + open: async (ctx) => { + const hasInput = ctx.input && Object.keys(ctx.input).length > 0; + // Only resolve when asked for somewhere; otherwise the page + // opens on its own welcome screen and the menu picks + const destination = hasInput ? await resolveDestination(ctx.input) : undefined; + + let entry = servers.get(ctx.instanceId); + if (!entry) { + entry = await startServer(ctx.instanceId, destination); + } else if (destination) { + entry.destination = destination; + broadcast(entry, "flyTo", { destination }); + } + + return { + title: "Flight Map", + status: entry.job.working && entry.job.status + ? entry.job.status + : (entry.destination?.label ?? "Pick a destination"), + url: entry.url, + }; + }, + onClose: async (ctx) => { + const entry = servers.get(ctx.instanceId); + if (!entry) return; + servers.delete(ctx.instanceId); + for (const client of entry.clients) { + client.end(); + } + await new Promise((resolve) => entry.server.close(() => resolve())); + }, + }), + ], +}); diff --git a/extensions/flight-map-canvas/game/app.js b/extensions/flight-map-canvas/game/app.js new file mode 100644 index 00000000..c0ce7e15 --- /dev/null +++ b/extensions/flight-map-canvas/game/app.js @@ -0,0 +1,1057 @@ +/***************************************************************** + * Flight Map - Main Application * + * * + * Three.js scene with satellite imagery terrain tiles, * + * flight simulator controls, dynamic tile loading, and HUD. * + ****************************************************************/ + +/* ============================================================ + Configuration + ============================================================ */ + +var TILE_ZOOM = 15; +var TILE_SIZE = 100; // Three.js world units per tile +var LOAD_RADIUS = 6; // Tiles to load around camera +var UNLOAD_RADIUS = 9; // Tiles to unload beyond this distance +var START_ALTITUDE = 200; // Starting camera height +var FOG_DENSITY = 0.00018; // Exponential fog density +var RADIUS_FEATHER = 3; // Tiles to feather at load radius edge +var MAX_TILES = 600; // Maximum loaded tiles (memory cap) + +/* ============================================================ + State + ============================================================ */ + +var scene, camera, renderer, clock; +var controls; // FlightControls instance +var terrainFill; // TerrainFill instance + +var textureLoader; +var loadedTiles = {}; +var centerTileX = 0; +var centerTileY = 0; +var originLat = 0; +var originLng = 0; +var currentMetersPerTile = 1000; +var currentCapitalName = ''; + +// Sentinel value of the destination menu entry that opens the keyboard +// input dialog, and the capital the menu falls back to afterwards +var INPUT_DESTINATION_VALUE = '__input__'; +var lastCapitalValue = ''; + +// Group the menu collects typed and geocoded destinations under, so they +// read as somewhere the user went rather than a capital that ships +var ENTERED_GROUP_LABEL = 'Entered'; + +var tilesLoaded = 0; +var tilesRequested = 0; +var initialLoadDone = false; +var tileUpdateCounter = 0; +var isPaused = false; + +/* ============================================================ + Tile Math Utilities + ============================================================ */ + +function latLngToTile(lat, lng, zoom) { + var n = Math.pow(2, zoom); + var x = Math.floor((lng + 180) / 360 * n); + var latRad = lat * Math.PI / 180; + var y = Math.floor((1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) / 2 * n); + return { x: x, y: y }; +} + +function tileToLatLng(x, y, zoom) { + var n = Math.pow(2, zoom); + var lng = x / n * 360 - 180; + var latRad = Math.atan(Math.sinh(Math.PI * (1 - 2 * y / n))); + var lat = latRad * 180 / Math.PI; + return { lat: lat, lng: lng }; +} + +function metersPerTile(lat, zoom) { + return 156543.03392 * Math.cos(lat * Math.PI / 180) / Math.pow(2, zoom) * 256; +} + +/** + * Wraps a tile column into the [0, 2^zoom - 1] range the providers serve. + * + * Tile coordinates are kept unwrapped everywhere else: they double as the + * world grid, and a flight that crosses the antimeridian has to keep + * counting past the edge of the map for its tiles to stay put relative to + * each other. Only the URL needs the column the provider recognizes. + */ +function wrapTileX(x, zoom) { + var n = Math.pow(2, zoom); + return ((x % n) + n) % n; +} + +/** Wraps a longitude into [-180, 180) after a crossing carried it past. */ +function wrapLongitude(lng) { + return ((lng + 180) % 360 + 360) % 360 - 180; +} + +/** + * Formats a position for the coordinate readout. The two spaces between + * the latitude and the longitude are what separates them on screen; + * #hud-coords sets white-space: pre so they survive to the render. + */ +function formatCoords(lat, lng) { + return Math.abs(lat).toFixed(4) + '°' + (lat >= 0 ? 'N' : 'S') + ' ' + + Math.abs(lng).toFixed(4) + '°' + (lng >= 0 ? 'E' : 'W'); +} + +function positionToLatLng(worldX, worldZ) { + var metersPerUnit = currentMetersPerTile / TILE_SIZE; + var dMetersX = worldX * metersPerUnit; + var dMetersZ = worldZ * metersPerUnit; + var dLng = dMetersX / (111320 * Math.cos(originLat * Math.PI / 180)); + var dLat = -dMetersZ / 110574; + return { + lat: originLat + dLat, + lng: wrapLongitude(originLng + dLng) + }; +} + +/* ============================================================ + Tile URL Providers + ============================================================ */ + +// Esri World Imagery (reliable CORS, high quality satellite) +function getEsriTileUrl(x, y, z) { + return 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/' + z + '/' + y + '/' + x; +} + +// Google Maps satellite tiles (may have CORS restrictions) +function getGoogleTileUrl(x, y, z) { + var server = ['mt0', 'mt1', 'mt2', 'mt3'][Math.abs(x + y) % 4]; + return 'https://' + server + '.google.com/vt/lyrs=s&x=' + x + '&y=' + y + '&z=' + z; +} + +// Active tile provider - defaults to Google, falls back to Esri +var tileProvider = 'google'; + +function getTileUrl(x, y, z) { + if (tileProvider === 'google') { + return getGoogleTileUrl(x, y, z); + } + return getEsriTileUrl(x, y, z); +} + +/* ============================================================ + Tile Provider Detection + ============================================================ */ + +function detectTileProvider(callback) { + var testImg = new Image(); + testImg.crossOrigin = 'anonymous'; + var done = false; + + testImg.onload = function () { + if (done) return; + done = true; + // Test if we can actually read pixel data (CORS check) + try { + var canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + var ctx = canvas.getContext('2d'); + ctx.drawImage(testImg, 0, 0, 1, 1); + ctx.getImageData(0, 0, 1, 1); // Throws if CORS tainted + tileProvider = 'google'; + } catch (e) { + tileProvider = 'esri'; + } + callback(); + }; + + testImg.onerror = function () { + if (done) return; + done = true; + tileProvider = 'esri'; + callback(); + }; + + setTimeout(function () { + if (done) return; + done = true; + tileProvider = 'esri'; + callback(); + }, 4000); + + testImg.src = getGoogleTileUrl(0, 0, 1); +} + +/* ============================================================ + Scene Setup + ============================================================ */ + +function initScene() { + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x87CEEB); + scene.fog = new THREE.FogExp2(0x87CEEB, FOG_DENSITY); + + camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 50000); + camera.position.set(0, START_ALTITUDE, 150); + camera.lookAt(0, 0, 0); + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); + document.getElementById('canvas-container').appendChild(renderer.domElement); + + // Lighting + var hemiLight = new THREE.HemisphereLight(0x87CEEB, 0x8B6914, 0.4); + scene.add(hemiLight); + + var dirLight = new THREE.DirectionalLight(0xffffff, 0.8); + dirLight.position.set(200, 400, 100); + scene.add(dirLight); + + var ambLight = new THREE.AmbientLight(0x404040, 0.3); + scene.add(ambLight); + + // Water plane (visible below terrain tiles) + var waterGeo = new THREE.PlaneGeometry(80000, 80000); + var waterMat = new THREE.MeshBasicMaterial({ color: 0x1a4a7a }); + var waterPlane = new THREE.Mesh(waterGeo, waterMat); + waterPlane.rotation.x = -Math.PI / 2; + waterPlane.position.y = -2; + scene.add(waterPlane); + + // Texture loader + textureLoader = new THREE.TextureLoader(); + textureLoader.crossOrigin = 'anonymous'; + + // Clock + clock = new THREE.Clock(); + + // Flight controls + controls = new FlightControls(camera, renderer.domElement); + + // Terrain fill (samples viewport colors to fill unloaded tile gaps) + terrainFill = new TerrainFill(renderer, scene, camera); + + // Panel resizes are handled by initLayout, which reapplies the + // render resolution against the new panel shape +} + +/* ============================================================ + Terrain Tile System + ============================================================ */ + +function loadTile(tileX, tileY) { + var key = tileX + ',' + tileY; + if (loadedTiles[key]) return; + + var worldX = (tileX - centerTileX) * TILE_SIZE; + var worldZ = (tileY - centerTileY) * TILE_SIZE; + + var geometry = new THREE.PlaneGeometry(TILE_SIZE, TILE_SIZE); + var material = new THREE.MeshBasicMaterial({ color: 0x2a3a2a, transparent: true }); + var mesh = new THREE.Mesh(geometry, material); + mesh.rotation.x = -Math.PI / 2; + mesh.position.set(worldX, 0, worldZ); + scene.add(mesh); + + loadedTiles[key] = { mesh: mesh, tileX: tileX, tileY: tileY, loaded: false }; + tilesRequested++; + + // The mesh keeps its unwrapped world column; the request uses the + // column the provider serves, so a flight can cross the antimeridian + // without every tile after it 404ing + var urlX = wrapTileX(tileX, TILE_ZOOM); + var url = getTileUrl(urlX, tileY, TILE_ZOOM); + + textureLoader.load(url, function (texture) { + if (!loadedTiles[key]) return; // Already unloaded + texture.minFilter = THREE.LinearFilter; + texture.magFilter = THREE.LinearFilter; + mesh.material.map = texture; + mesh.material.color.set(0xffffff); + mesh.material.needsUpdate = true; + loadedTiles[key].loaded = true; + tilesLoaded++; + updateLoadingProgress(); + }, undefined, function () { + // Primary failed, try fallback provider + var fallbackUrl = (tileProvider === 'google') + ? getEsriTileUrl(urlX, tileY, TILE_ZOOM) + : getGoogleTileUrl(urlX, tileY, TILE_ZOOM); + + textureLoader.load(fallbackUrl, function (texture) { + if (!loadedTiles[key]) return; + texture.minFilter = THREE.LinearFilter; + texture.magFilter = THREE.LinearFilter; + mesh.material.map = texture; + mesh.material.color.set(0xffffff); + mesh.material.needsUpdate = true; + loadedTiles[key].loaded = true; + tilesLoaded++; + updateLoadingProgress(); + }, undefined, function () { + if (!loadedTiles[key]) return; + loadedTiles[key].loaded = true; + tilesLoaded++; + updateLoadingProgress(); + }); + }); +} + +function unloadTile(key) { + var tile = loadedTiles[key]; + if (!tile) return; + + scene.remove(tile.mesh); + tile.mesh.geometry.dispose(); + if (tile.mesh.material.map) tile.mesh.material.map.dispose(); + tile.mesh.material.dispose(); + + delete loadedTiles[key]; + + // A tile evicted before its texture arrived still counts as resolved, + // otherwise the loading progress can stall below its completion threshold + if (!tile.loaded) { + tilesLoaded++; + updateLoadingProgress(); + } +} + +function clearAllTiles() { + var keys = Object.keys(loadedTiles); + for (var i = 0; i < keys.length; i++) { + unloadTile(keys[i]); + } + loadedTiles = {}; + tilesLoaded = 0; + tilesRequested = 0; + initialLoadDone = false; +} + +/** + * How far the loader may actually reach, as a squared tile distance. + * + * loadRadius asks for a terrain disk of a given width and maxTiles caps + * how many tiles may exist at once. A disk of radius r holds about + * pi * r^2 tiles, so a radius asking for more than the cap allows is a + * radius the cap takes straight back: the reach is whichever is smaller. + * + * loadRadius keeps its other job either way. updateTileFeather() scales + * the opacity ramp against it, so a loadRadius wider than this reach + * stretches the fade across the terrain that does fit rather than + * widening the terrain itself. + */ +function tileReachSq() { + return Math.min(LOAD_RADIUS * LOAD_RADIUS, MAX_TILES / Math.PI); +} + +function updateTiles() { + if (!currentCapitalName) return; + + var camTileX = centerTileX + Math.round(controls.position.x / TILE_SIZE); + var camTileY = centerTileY + Math.round(controls.position.z / TILE_SIZE); + + var reachSq = tileReachSq(); + var reach = Math.ceil(Math.sqrt(reachSq)); + + // Everything in play this pass, gathered before anything is requested: + // the tiles the camera wants, plus the tiles already around it that it + // has not left behind yet. Ranking one pool by distance is what lets + // the cap be spent on the nearest tiles whether they are loaded yet or + // not, so no tile is requested only for the same pass to evict it. + var pool = []; + var wanted = {}; + + for (var dx = -reach; dx <= reach; dx++) { + for (var dy = -reach; dy <= reach; dy++) { + var distSq = dx * dx + dy * dy; + if (distSq > reachSq) continue; + var tx = camTileX + dx; + var ty = camTileY + dy; + var key = tx + ',' + ty; + wanted[key] = true; + pool.push({ key: key, tileX: tx, tileY: ty, distSq: distSq }); + } + } + + var loadedKeys = Object.keys(loadedTiles); + for (var i = 0; i < loadedKeys.length; i++) { + if (wanted[loadedKeys[i]]) continue; + var tile = loadedTiles[loadedKeys[i]]; + var ddx = tile.tileX - camTileX; + var ddy = tile.tileY - camTileY; + var loadedDistSq = ddx * ddx + ddy * ddy; + + // Out of range for good; the unload radius has the last word on + // what is too far behind to be worth ranking at all + if (loadedDistSq > UNLOAD_RADIUS * UNLOAD_RADIUS) { + unloadTile(loadedKeys[i]); + continue; + } + + pool.push({ + key: loadedKeys[i], + tileX: tile.tileX, + tileY: tile.tileY, + distSq: loadedDistSq + }); + } + + pool.sort(function (a, b) { return a.distSq - b.distSq; }); + + // Spend the cap nearest first: request what is missing while there is + // room, and evict whatever the room ran out on + for (var i = 0; i < pool.length; i++) { + var entry = pool[i]; + if (i < MAX_TILES) { + if (!loadedTiles[entry.key]) { + loadTile(entry.tileX, entry.tileY); + } + } else if (loadedTiles[entry.key]) { + unloadTile(entry.key); + } + } + + // Apply feather opacity to tiles near the load radius edge + updateTileFeather(camTileX, camTileY); +} + +/** + * Applies smooth opacity falloff to tiles near the load radius edge, + * creating a feathered border effect. Tiles within the feather zone + * transition from full opacity to transparent using smoothstep. + */ +function updateTileFeather(camTileX, camTileY) { + if (RADIUS_FEATHER <= 0) { + // No feather: ensure all tiles are fully opaque + var keys = Object.keys(loadedTiles); + for (var i = 0; i < keys.length; i++) { + var tile = loadedTiles[keys[i]]; + if (tile.mesh.material.opacity !== 1) { + tile.mesh.material.opacity = 1; + tile.mesh.material.needsUpdate = true; + } + } + return; + } + + // Clamp so a feather wider than the load radius still yields a valid zone + var featherStart = Math.max(0, LOAD_RADIUS - RADIUS_FEATHER); + var featherWidth = LOAD_RADIUS - featherStart; + var keys = Object.keys(loadedTiles); + for (var i = 0; i < keys.length; i++) { + var tile = loadedTiles[keys[i]]; + var ddx = tile.tileX - camTileX; + var ddy = tile.tileY - camTileY; + var dist = Math.sqrt(ddx * ddx + ddy * ddy); + + var opacity; + if (dist <= featherStart) { + opacity = 1; + } else if (dist >= LOAD_RADIUS) { + opacity = 0; + } else { + // Smoothstep falloff from 1 to 0 across the feather zone + var t = (dist - featherStart) / featherWidth; + opacity = 1 - t * t * (3 - 2 * t); + } + + if (tile.mesh.material.opacity !== opacity) { + tile.mesh.material.opacity = opacity; + tile.mesh.material.needsUpdate = true; + } + } +} + +/* ============================================================ + Capital Loading + ============================================================ */ + +function loadCapital(capitalData) { + clearAllTiles(); + + originLat = capitalData.lat; + originLng = capitalData.lng; + + // Typed destinations arrive with the label the geocoder built for + // them; capitals are named from their two known fields + currentCapitalName = capitalData.label || + (capitalData.capital + ', ' + capitalData.country); + currentMetersPerTile = metersPerTile(originLat, TILE_ZOOM); + + var tile = latLngToTile(originLat, originLng, TILE_ZOOM); + centerTileX = tile.x; + centerTileY = tile.y; + + // Show loading + document.getElementById('loading-overlay').classList.remove('hidden'); + document.getElementById('welcome').classList.add('hidden'); + document.getElementById('fly-prompt').classList.add('hidden'); + + // Reset terrain fill for new location + if (terrainFill) terrainFill.reset(); + + // Reset geocoder so the location label refreshes for the new area + Geocoder.reset(); + + // Load initial tiles + updateTiles(); + + // Position camera above the capital + controls.resetTo( + new THREE.Vector3(0, START_ALTITUDE, 150), + new THREE.Vector3(0, 0, 0) + ); + + // Update HUD capital name + document.getElementById('hud-capital').textContent = currentCapitalName; +} + +/* ============================================================ + Host-Driven Updates + + A host (the VS Code extension, or the Copilot canvas server) + can steer the flight and report what it is working on. Both + arrive as HostBridge commands, so a page with no host simply + never receives them. + ============================================================ */ + +/** + * Finds the menu entry for a destination, by position rather than by + * name: the same place reached from the capitals list, from the input + * dialog, or from a host command should resolve to one entry. Returns + * the option's value, or '' when the menu has no entry for it. + */ +function findDestinationOption(select, destination) { + for (var i = 0; i < select.options.length; i++) { + var value = select.options[i].value; + if (!value || value === INPUT_DESTINATION_VALUE) continue; + + var option; + try { + option = JSON.parse(value); + } catch (e) { + continue; // Not a destination entry + } + + if (option.lat === destination.lat && option.lng === destination.lng) { + return value; + } + } + + return ''; +} + +/** + * Adds a typed or geocoded destination to the menu so it can be flown + * back to without retyping it. + * + * The entry carries the whole destination as its value, in the shape the + * capitals use, so re-selecting it goes through the same change handler + * and lands in the same place. Entries collect under their own group, + * which is created the first time one is needed. + */ +function rememberDestination(select, destination) { + var group = null; + for (var i = 0; i < select.children.length; i++) { + if (select.children[i].label === ENTERED_GROUP_LABEL) { + group = select.children[i]; + break; + } + } + + if (!group) { + group = document.createElement('optgroup'); + group.label = ENTERED_GROUP_LABEL; + // Above the capitals, next to the entry that creates these + select.insertBefore(group, select.querySelector('optgroup')); + } + + // Geocoded places arrive with the label the HUD shows, so the menu + // names them the same way. A bare waypoint has only its own name. + var text = destination.label; + if (!text) { + text = destination.country + ? destination.capital + ' - ' + destination.country + : destination.capital; + } + + var option = document.createElement('option'); + option.value = JSON.stringify(destination); + option.textContent = text; + group.appendChild(option); + + return option.value; +} + +/** + * Flies to a destination and names it in the menu. Accepts the same + * shape loadCapital takes, so a place from the capitals list, the input + * dialog, or a host command works unchanged. + */ +function flyToDestination(destination) { + if (!destination || + typeof destination.lat !== 'number' || + typeof destination.lng !== 'number') return; + + loadCapital(destination); + + // Keep the menu honest about where the camera actually is, rather + // than leaving it on the capital that was left behind + var select = document.getElementById('capital-select'); + if (!select) return; + + var value = findDestinationOption(select, destination) || + rememberDestination(select, destination); + + lastCapitalValue = value; + select.value = value; +} + +/** + * Shows what the host's agent is working on. job is + * { working, status, tokens }; a job that is not working leaves the last + * status on screen with the activity indicator stilled. + */ +function showAgentStatus(job) { + var panel = document.getElementById('agent-status'); + if (!panel || !job) return; + + var status = typeof job.status === 'string' ? job.status : ''; + if (!status && !job.working) { + panel.classList.add('hidden'); + return; + } + + document.getElementById('agent-status-text').textContent = status; + document.getElementById('agent-status-tokens').textContent = + (typeof job.tokens === 'number' && job.tokens > 0) + ? job.tokens.toLocaleString() + ' tok' + : ''; + + panel.classList.toggle('idle', !job.working); + panel.classList.remove('hidden'); +} + +/* ============================================================ + Loading Progress + ============================================================ */ + +function updateLoadingProgress() { + var pct = Math.min(100, Math.round((tilesLoaded / Math.max(1, tilesRequested)) * 100)); + + document.getElementById('loading-bar').style.width = pct + '%'; + document.getElementById('loading-progress').textContent = pct + '%'; + + if (!initialLoadDone && pct >= 40) { + initialLoadDone = true; + document.getElementById('loading-overlay').classList.add('hidden'); + document.getElementById('fly-prompt').classList.remove('hidden'); + document.getElementById('hud').classList.remove('hidden'); + document.getElementById('hud-location').classList.remove('hidden'); + document.getElementById('controls-list').classList.remove('hidden'); + + // The readout joining the top bar can change its height + updateTopBarLayout(); + } +} + +/* ============================================================ + HUD Updates + ============================================================ */ + +function updateHUD() { + if (!controls || !controls.isEnabled) return; + + var heading = controls.getHeading(); + var pitch = controls.getPitch(); + var speed = controls.getSpeed(); + var altitude = controls.getAltitude(); + + // Convert speed from world units/frame to approximate km/h + var metersPerUnit = currentMetersPerTile / TILE_SIZE; + var speedKmh = Math.round(speed * 60 * metersPerUnit * 3.6); + var altMeters = Math.round(altitude * metersPerUnit); + + // Heading cardinal direction + var cardinals = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'N']; + var cardinalIdx = Math.round(heading / 45); + var cardinal = cardinals[cardinalIdx]; + + document.getElementById('hud-heading-value').textContent = + cardinal + ' ' + Math.round(heading) + '°'; + + document.getElementById('hud-speed-value').textContent = speedKmh; + document.getElementById('hud-altitude-value').textContent = altMeters; + document.getElementById('hud-pitch-value').textContent = + (pitch >= 0 ? '+' : '') + Math.round(pitch) + '°'; + + // Update coordinates + var coords = positionToLatLng(controls.position.x, controls.position.z); + document.getElementById('hud-coords').textContent = + formatCoords(coords.lat, coords.lng); + + // Update the location label as the camera moves (throttled internally) + Geocoder.update(coords.lat, coords.lng, function (label) { + document.getElementById('hud-capital').textContent = label; + }); +} + +/* ============================================================ + Responsive Layout + ============================================================ */ + +// Mirrors the flex-basis of #hud-location in styles.css +var LOCATION_MIN_WIDTH = 240; + +// Mirrors the gap and padding of #top-bar in styles.css +var TOP_BAR_GAP = 12; + +var layoutFrame = null; + +/** + * Measures the top bar and publishes what the rest of the layout needs. + * + * The location readout shares a row with the capital selector, so the + * bar mirrors the selector's width as right padding to keep the readout + * centered on the panel instead of on the space beside the menu. Three + * arrangements, chosen by measured width: + * + * 1. Selector, readout, and a mirror of the selector all fit: the + * readout is centered on the panel. + * 2. Only the selector and readout fit: the mirror is dropped and the + * readout centers in the space beside the menu. + * 3. Neither fits: the readout takes its own row underneath. + * + * The arrangement is decided from measured widths rather than from an + * observed wrap, so the padding it toggles cannot feed back into the + * decision that produced it. + */ +function updateTopBarLayout() { + var topBar = document.getElementById('top-bar'); + var selector = document.getElementById('selector-panel'); + if (!topBar || !selector) return; + + var root = document.documentElement; + var available = window.innerWidth; + var selectorWidth = Math.ceil(selector.getBoundingClientRect().width); + + var mirrorFits = (2 * selectorWidth) + LOCATION_MIN_WIDTH + (3 * TOP_BAR_GAP) <= available; + var rowFits = selectorWidth + LOCATION_MIN_WIDTH + (3 * TOP_BAR_GAP) <= available; + + topBar.classList.toggle('stacked', !rowFits); + root.style.setProperty('--selector-width', (mirrorFits ? selectorWidth : 0) + 'px'); + + // Read back after the writes above so the heading readout and the + // config panel clear the bar at whatever height it settled on + root.style.setProperty( + '--top-bar-height', + Math.ceil(topBar.getBoundingClientRect().height) + 'px' + ); +} + +/** + * Coalesces panel resizes into one pass per frame. Dragging the editor + * layout fires a burst of resize events, and each one would otherwise + * reallocate the WebGL drawing buffer. + */ +function scheduleViewportLayout() { + if (layoutFrame !== null) return; + layoutFrame = requestAnimationFrame(function () { + layoutFrame = null; + updateTopBarLayout(); + RenderConfig.apply(); + }); +} + +/** + * Binds the layout to every source of a size change: the panel being + * resized, the editor layout shifting around it, and the selector panel + * reflowing its own contents. + */ +function initLayout() { + updateTopBarLayout(); + + window.addEventListener('resize', scheduleViewportLayout); + + if (typeof ResizeObserver === 'undefined') return; + + // Panel resizes that do not raise a window resize event, such as the + // file explorer being collapsed beside a docked panel + new ResizeObserver(scheduleViewportLayout).observe(document.body); + + // The selector panel reflows when the panel gets too narrow for its + // dropdown and buttons, which changes the width the bar mirrors + new ResizeObserver(updateTopBarLayout).observe( + document.getElementById('selector-panel') + ); +} + +/* ============================================================ + UI Setup + ============================================================ */ + +/** + * Rewrites the look-control wording for the mode the controls settled + * on, so the on-screen help never promises pointer lock the host + * refused to grant. + */ +function applyLookMode(mode) { + var lookText = (mode === 'drag') ? 'Drag: Look' : 'Mouse: Look'; + var lookHint = (mode === 'drag') ? 'Drag' : 'Mouse'; + + var helpLine = document.getElementById('controls-help-look'); + if (helpLine) helpLine.textContent = lookText; + + var listLine = document.getElementById('controls-list-look'); + if (listLine) listLine.textContent = lookHint; + + var promptHint = document.getElementById('fly-prompt-hint'); + if (promptHint) { + promptHint.textContent = (mode === 'drag') + ? 'Hold the left mouse button to look around' + : 'Press Escape to release the cursor'; + } +} + +function setupUI() { + var select = document.getElementById('capital-select'); + + // Populate dropdown + for (var i = 0; i < CAPITALS_BY_REGION.length; i++) { + var region = CAPITALS_BY_REGION[i]; + var optgroup = document.createElement('optgroup'); + optgroup.label = region.region; + + for (var j = 0; j < region.capitals.length; j++) { + var cap = region.capitals[j]; + var option = document.createElement('option'); + option.value = JSON.stringify(cap); + option.textContent = cap.capital + ' - ' + cap.country; + optgroup.appendChild(option); + } + + select.appendChild(optgroup); + } + + // Keyboard entry for anywhere the capitals list does not cover. + // Results go through flyToDestination so an entered place joins the + // menu, the same way one sent by a host does. + DestinationInput.init({ + onSelect: function (destination) { + flyToDestination(destination); + }, + onOpen: function () { + // Stop flying behind the dialog and give up the cursor + if (controls) controls.release(); + }, + onClose: function () { + select.focus(); + } + }); + + // Selection handler + select.addEventListener('change', function (e) { + var value = e.target.value; + if (!value) return; + + // The action entry is not a destination: reset the menu to the + // capital still loaded so re-picking it opens the dialog again + if (value === INPUT_DESTINATION_VALUE) { + e.target.value = lastCapitalValue; + DestinationInput.open(); + return; + } + + lastCapitalValue = value; + loadCapital(JSON.parse(value)); + }); + + // Pause toggle (P key): freezes flight, tile updates, HUD, and clouds + document.addEventListener('keydown', function (e) { + if (e.code !== 'KeyP') return; + // A "p" typed into a destination field is not a pause request + if (FlightControls.isTextEntryTarget(e.target)) return; + togglePause(); + }); + + // Flight controls lock/unlock + document.addEventListener('flightcontrols', function (e) { + applyLookMode(e.detail.mode); + + if (e.detail.locked) { + document.getElementById('fly-prompt').classList.add('hidden'); + document.getElementById('controls-help').classList.remove('hidden'); + + // Fade out controls help after 5 seconds + setTimeout(function () { + document.getElementById('controls-help').classList.add('fade-out'); + }, 5000); + } else { + document.getElementById('controls-help').classList.add('hidden'); + document.getElementById('controls-help').classList.remove('fade-out'); + if (initialLoadDone) { + document.getElementById('fly-prompt').classList.remove('hidden'); + } + } + }); +} + +/* ============================================================ + Animation Loop + ============================================================ */ + +function togglePause() { + isPaused = !isPaused; + var indicator = document.getElementById('pause-indicator'); + if (isPaused) { + indicator.classList.remove('hidden'); + } else { + indicator.classList.add('hidden'); + // Discard input and time accumulated while paused so the + // camera does not jump on resume + if (controls) { + controls.mouseMovementX = 0; + controls.mouseMovementY = 0; + } + if (clock) clock.getDelta(); + } +} + +function animate() { + requestAnimationFrame(animate); + + // Common pause state: keep rendering the frozen scene only + if (isPaused) { + renderer.render(scene, camera); + return; + } + + var delta = clock.getDelta(); + + // Update flight controls + controls.update(delta); + + // Periodically update tiles + tileUpdateCounter++; + if (tileUpdateCounter >= 30) { + tileUpdateCounter = 0; + updateTiles(); + } + + // Update HUD + updateHUD(); + + // Render + renderer.render(scene, camera); + + // Update terrain fill after main render (samples viewport, generates fill for next frame) + if (terrainFill && initialLoadDone) { + terrainFill.update(controls ? controls.getHeading() : 0); + } +} + +/* ============================================================ + Tile Zoom Reload + ============================================================ */ + +/** + * Recalculates tile coordinates and reloads all tiles at the current + * zoom level. Preserves the camera's geographic position so the view + * stays in place while tiles reload in the background. + */ +function reloadTilesAtCurrentZoom() { + if (!currentCapitalName) return; + + // Determine camera's current geographic position before clearing + var camGeo = positionToLatLng(controls.position.x, controls.position.z); + + clearAllTiles(); + + // Re-center on the camera's current geographic location at new zoom + originLat = camGeo.lat; + originLng = camGeo.lng; + currentMetersPerTile = metersPerTile(originLat, TILE_ZOOM); + + var tile = latLngToTile(originLat, originLng, TILE_ZOOM); + centerTileX = tile.x; + centerTileY = tile.y; + + // Camera is now at geographic center, so world position resets to origin + controls.position.x = 0; + controls.position.z = 0; + camera.position.x = 0; + camera.position.z = 0; + + if (terrainFill) terrainFill.reset(); + updateTiles(); + + // Update HUD with the new center coordinates + document.getElementById('hud-coords').textContent = + formatCoords(camGeo.lat, camGeo.lng); +} + +/* ============================================================ + Initialize + ============================================================ */ + +function init() { + detectTileProvider(function () { + RenderConfig.load(function (cfg) { + initScene(); + RenderConfig.apply(); + setupUI(); + RenderConfig.bindSliders(); + initLayout(); + + // React to config changes that require special handling. + // Debounce the zoom reload so dragging the slider does not + // trigger a full tile clear + refetch on every input tick. + var zoomReloadTimer = null; + RenderConfig.onChange(function (path) { + if (path === 'map.tileZoom') { + clearTimeout(zoomReloadTimer); + zoomReloadTimer = setTimeout(reloadTilesAtCurrentZoom, 400); + } + }); + + // Export JSON button + var exportBtn = document.getElementById('btn-export-json'); + if (exportBtn) { + exportBtn.addEventListener('click', function () { + RenderConfig.exportJSON(); + }); + } + + // Config panel toggle + var toggleBtn = document.getElementById('btn-toggle-config'); + var configPanel = document.getElementById('config-panel'); + if (toggleBtn && configPanel) { + toggleBtn.addEventListener('click', function () { + configPanel.classList.toggle('hidden'); + }); + } + + // Commands issued from the extension host + HostBridge.on('exportConfig', function () { + RenderConfig.exportJSON(); + }); + HostBridge.on('toggleConfigPanel', function () { + if (configPanel) configPanel.classList.toggle('hidden'); + }); + HostBridge.on('flyTo', function (message) { + flyToDestination(message.destination); + }); + HostBridge.on('jobStatus', function (message) { + showAgentStatus(message.job); + }); + + HostBridge.post({ command: 'ready' }); + + animate(); + }); + }); +} + +document.addEventListener('DOMContentLoaded', init); diff --git a/extensions/flight-map-canvas/game/capitals.js b/extensions/flight-map-canvas/game/capitals.js new file mode 100644 index 00000000..26701637 --- /dev/null +++ b/extensions/flight-map-canvas/game/capitals.js @@ -0,0 +1,94 @@ +/************************************************************** + * World Capitals organized by continent/region. * + * Each capital includes country, city name, and coordinates. * + *************************************************************/ +var CAPITALS_BY_REGION = [ + { + region: "North America", + capitals: [ + { country: "United States", capital: "Washington, D.C.", lat: 38.8951, lng: -77.0364 }, + { country: "Canada", capital: "Ottawa", lat: 45.4215, lng: -75.6972 }, + { country: "Mexico", capital: "Mexico City", lat: 19.4326, lng: -99.1332 }, + { country: "Cuba", capital: "Havana", lat: 23.1136, lng: -82.3666 }, + { country: "Guatemala", capital: "Guatemala City", lat: 14.6349, lng: -90.5069 }, + { country: "Costa Rica", capital: "San Jose", lat: 9.9281, lng: -84.0907 }, + { country: "Panama", capital: "Panama City", lat: 8.9824, lng: -79.5199 }, + { country: "Jamaica", capital: "Kingston", lat: 18.0179, lng: -76.8099 } + ] + }, + { + region: "South America", + capitals: [ + { country: "Brazil", capital: "Brasilia", lat: -15.7975, lng: -47.8919 }, + { country: "Argentina", capital: "Buenos Aires", lat: -34.6037, lng: -58.3816 }, + { country: "Chile", capital: "Santiago", lat: -33.4489, lng: -70.6693 }, + { country: "Colombia", capital: "Bogota", lat: 4.7110, lng: -74.0721 }, + { country: "Peru", capital: "Lima", lat: -12.0464, lng: -77.0428 }, + { country: "Venezuela", capital: "Caracas", lat: 10.4806, lng: -66.9036 }, + { country: "Ecuador", capital: "Quito", lat: -0.1807, lng: -78.4678 }, + { country: "Uruguay", capital: "Montevideo", lat: -34.9011, lng: -56.1645 } + ] + }, + { + region: "Europe", + capitals: [ + { country: "United Kingdom", capital: "London", lat: 51.5074, lng: -0.1278 }, + { country: "France", capital: "Paris", lat: 48.8566, lng: 2.3522 }, + { country: "Germany", capital: "Berlin", lat: 52.5200, lng: 13.4050 }, + { country: "Italy", capital: "Rome", lat: 41.9028, lng: 12.4964 }, + { country: "Spain", capital: "Madrid", lat: 40.4168, lng: -3.7038 }, + { country: "Russia", capital: "Moscow", lat: 55.7558, lng: 37.6173 }, + { country: "Netherlands", capital: "Amsterdam", lat: 52.3676, lng: 4.9041 }, + { country: "Greece", capital: "Athens", lat: 37.9838, lng: 23.7275 }, + { country: "Sweden", capital: "Stockholm", lat: 59.3293, lng: 18.0686 }, + { country: "Norway", capital: "Oslo", lat: 59.9139, lng: 10.7522 }, + { country: "Portugal", capital: "Lisbon", lat: 38.7223, lng: -9.1393 }, + { country: "Czech Republic", capital: "Prague", lat: 50.0755, lng: 14.4378 }, + { country: "Austria", capital: "Vienna", lat: 48.2082, lng: 16.3738 }, + { country: "Switzerland", capital: "Bern", lat: 46.9480, lng: 7.4474 }, + { country: "Poland", capital: "Warsaw", lat: 52.2297, lng: 21.0122 }, + { country: "Turkey", capital: "Ankara", lat: 39.9334, lng: 32.8597 } + ] + }, + { + region: "Asia", + capitals: [ + { country: "Japan", capital: "Tokyo", lat: 35.6762, lng: 139.6503 }, + { country: "China", capital: "Beijing", lat: 39.9042, lng: 116.4074 }, + { country: "India", capital: "New Delhi", lat: 28.6139, lng: 77.2090 }, + { country: "South Korea", capital: "Seoul", lat: 37.5665, lng: 126.9780 }, + { country: "Thailand", capital: "Bangkok", lat: 13.7563, lng: 100.5018 }, + { country: "Vietnam", capital: "Hanoi", lat: 21.0285, lng: 105.8542 }, + { country: "Indonesia", capital: "Jakarta", lat: -6.2088, lng: 106.8456 }, + { country: "Philippines", capital: "Manila", lat: 14.5995, lng: 120.9842 }, + { country: "Singapore", capital: "Singapore", lat: 1.3521, lng: 103.8198 }, + { country: "Malaysia", capital: "Kuala Lumpur", lat: 3.1390, lng: 101.6869 }, + { country: "Pakistan", capital: "Islamabad", lat: 33.6844, lng: 73.0479 }, + { country: "Israel", capital: "Jerusalem", lat: 31.7683, lng: 35.2137 }, + { country: "UAE", capital: "Abu Dhabi", lat: 24.4539, lng: 54.3773 }, + { country: "Saudi Arabia", capital: "Riyadh", lat: 24.7136, lng: 46.6753 } + ] + }, + { + region: "Africa", + capitals: [ + { country: "Egypt", capital: "Cairo", lat: 30.0444, lng: 31.2357 }, + { country: "South Africa", capital: "Pretoria", lat: -25.7479, lng: 28.2293 }, + { country: "Kenya", capital: "Nairobi", lat: -1.2921, lng: 36.8219 }, + { country: "Nigeria", capital: "Abuja", lat: 9.0579, lng: 7.4951 }, + { country: "Morocco", capital: "Rabat", lat: 34.0209, lng: -6.8416 }, + { country: "Ethiopia", capital: "Addis Ababa", lat: 9.0250, lng: 38.7469 }, + { country: "Tanzania", capital: "Dodoma", lat: -6.1630, lng: 35.7516 }, + { country: "Ghana", capital: "Accra", lat: 5.6037, lng: -0.1870 } + ] + }, + { + region: "Oceania", + capitals: [ + { country: "Australia", capital: "Canberra", lat: -35.2809, lng: 149.1300 }, + { country: "New Zealand", capital: "Wellington", lat: -41.2865, lng: 174.7762 }, + { country: "Fiji", capital: "Suva", lat: -18.1416, lng: 178.4419 }, + { country: "Papua New Guinea", capital: "Port Moresby", lat: -6.3149, lng: 143.9556 } + ] + } +]; diff --git a/extensions/flight-map-canvas/game/destinationInput.js b/extensions/flight-map-canvas/game/destinationInput.js new file mode 100644 index 00000000..b0bd013d --- /dev/null +++ b/extensions/flight-map-canvas/game/destinationInput.js @@ -0,0 +1,310 @@ +/*********************************************************************** + * DestinationInput - Keyboard entry for destinations that are not one * + * of the built-in capitals. * + * * + * Opened from the "Input Destination" entry at the top of the * + * destination menu. The dialog runs in two stages: * + * * + * 1. Form - state/region and city are typed, country is picked * + * from the menu. Any one of the three is enough. * + * 2. Results - the matches the geocoder returned, one per row. * + * Picking one and pressing Select flies there. * + * * + * The dialog owns the keyboard while it is open: flight input already * + * ignores events from form fields, and the shortcuts below stop at * + * the dialog so a typed letter never reaches the simulator. * + ***********************************************************************/ +var DestinationInput = (function () { + + var dialog, formStage, resultsStage; + var stateInput, cityInput, countrySelect; + var formMessage, resultsMessage, resultList; + var searchBtn, selectBtn; + + var onSelect = null; + var onOpen = null; + var onClose = null; + + var results = []; + var activeIndex = -1; + var searching = false; + var isOpen = false; + + /* ------------------------------------------------------------ + Country menu + ------------------------------------------------------------ */ + + /** + * Fills the country menu from the capitals dataset, which is the + * only list of country names the page ships with. Leaving the menu + * on its first entry searches without a country filter. + */ + function populateCountries() { + if (typeof CAPITALS_BY_REGION === 'undefined') return; + + var seen = {}; + var names = []; + + for (var i = 0; i < CAPITALS_BY_REGION.length; i++) { + var capitals = CAPITALS_BY_REGION[i].capitals; + for (var j = 0; j < capitals.length; j++) { + var country = capitals[j].country; + if (seen[country]) continue; + seen[country] = true; + names.push(country); + } + } + + names.sort(); + + for (var k = 0; k < names.length; k++) { + var option = document.createElement('option'); + option.value = names[k]; + option.textContent = names[k]; + countrySelect.appendChild(option); + } + } + + /* ------------------------------------------------------------ + Stage switching + ------------------------------------------------------------ */ + + function showForm() { + formStage.classList.remove('hidden'); + resultsStage.classList.add('hidden'); + resultsMessage.textContent = ''; + } + + function showResults() { + formStage.classList.add('hidden'); + resultsStage.classList.remove('hidden'); + formMessage.textContent = ''; + } + + function setSearching(active) { + searching = active; + searchBtn.disabled = active; + searchBtn.textContent = active ? 'Searching...' : 'Search'; + } + + /* ------------------------------------------------------------ + Results list + ------------------------------------------------------------ */ + + function renderResults() { + resultList.innerHTML = ''; + + for (var i = 0; i < results.length; i++) { + var row = document.createElement('li'); + row.className = 'dest-result'; + // Focus stays on the listbox, so each option needs an id for + // the list's aria-activedescendant to point a reader at it + row.id = 'dest-result-' + i; + row.setAttribute('role', 'option'); + row.setAttribute('aria-selected', 'false'); + row.dataset.index = String(i); + row.textContent = results[i].label; + resultList.appendChild(row); + } + + setActiveIndex(results.length ? 0 : -1); + } + + function setActiveIndex(index) { + activeIndex = index; + var rows = resultList.children; + + for (var i = 0; i < rows.length; i++) { + var active = i === index; + rows[i].classList.toggle('active', active); + rows[i].setAttribute('aria-selected', active ? 'true' : 'false'); + } + + selectBtn.disabled = index < 0; + + // Point the listbox at the option the arrow keys landed on, and + // drop the reference entirely when nothing is active + if (index >= 0 && rows[index]) { + resultList.setAttribute('aria-activedescendant', rows[index].id); + if (rows[index].scrollIntoView) { + rows[index].scrollIntoView({ block: 'nearest' }); + } + } else { + resultList.removeAttribute('aria-activedescendant'); + } + } + + function moveActive(step) { + if (!results.length) return; + var next = activeIndex + step; + if (next < 0) next = 0; + if (next > results.length - 1) next = results.length - 1; + setActiveIndex(next); + } + + /* ------------------------------------------------------------ + Actions + ------------------------------------------------------------ */ + + function runSearch() { + if (searching) return; + + formMessage.textContent = ''; + setSearching(true); + + Geocoder.search({ + state: stateInput.value, + city: cityInput.value, + country: countrySelect.value + }, function (error, found) { + setSearching(false); + + if (error) { + formMessage.textContent = error; + return; + } + + results = found; + renderResults(); + showResults(); + + resultsMessage.textContent = found.length + ? '' + : 'No matching destination was found. Cancel to adjust the search.'; + + if (found.length) resultList.focus(); + }); + } + + function commitSelection() { + if (activeIndex < 0 || !results[activeIndex]) return; + var chosen = results[activeIndex]; + close(); + if (onSelect) onSelect(chosen); + } + + /* ------------------------------------------------------------ + Open / close + ------------------------------------------------------------ */ + + function open() { + if (isOpen) return; + isOpen = true; + + results = []; + activeIndex = -1; + // Rows from the previous search are stale the moment the form + // reopens, so nothing should still be pointing at one of them + resultList.removeAttribute('aria-activedescendant'); + formMessage.textContent = ''; + setSearching(false); + showForm(); + + dialog.classList.remove('hidden'); + if (onOpen) onOpen(); + stateInput.focus(); + stateInput.select(); + } + + function close() { + if (!isOpen) return; + isOpen = false; + + dialog.classList.add('hidden'); + if (onClose) onClose(); + } + + /* ------------------------------------------------------------ + Wiring + ------------------------------------------------------------ */ + + /** + * Binds the dialog. options: + * onSelect(destination) - a result the user picked + * onOpen() - the dialog became visible + * onClose() - the dialog was dismissed or committed + */ + function init(options) { + options = options || {}; + onSelect = options.onSelect || null; + onOpen = options.onOpen || null; + onClose = options.onClose || null; + + dialog = document.getElementById('destination-dialog'); + if (!dialog) return; + + formStage = document.getElementById('destination-form'); + resultsStage = document.getElementById('destination-results'); + stateInput = document.getElementById('dest-state'); + cityInput = document.getElementById('dest-city'); + countrySelect = document.getElementById('dest-country'); + formMessage = document.getElementById('dest-form-message'); + resultsMessage = document.getElementById('dest-results-message'); + resultList = document.getElementById('dest-result-list'); + searchBtn = document.getElementById('dest-search'); + selectBtn = document.getElementById('dest-select'); + + populateCountries(); + + searchBtn.addEventListener('click', runSearch); + selectBtn.addEventListener('click', commitSelection); + document.getElementById('dest-cancel').addEventListener('click', close); + document.getElementById('dest-results-cancel').addEventListener('click', close); + + // Enter submits from any field in the form stage + formStage.addEventListener('keydown', function (e) { + if (e.key === 'Enter') { + e.preventDefault(); + runSearch(); + } + }); + + // Click a row to highlight it, double click to fly straight there + resultList.addEventListener('click', function (e) { + var row = e.target.closest ? e.target.closest('.dest-result') : null; + if (!row) return; + setActiveIndex(parseInt(row.dataset.index, 10)); + }); + + resultList.addEventListener('dblclick', function (e) { + var row = e.target.closest ? e.target.closest('.dest-result') : null; + if (!row) return; + setActiveIndex(parseInt(row.dataset.index, 10)); + commitSelection(); + }); + + resultList.addEventListener('keydown', function (e) { + if (e.key === 'ArrowDown') { + e.preventDefault(); + moveActive(1); + } else if (e.key === 'ArrowUp') { + e.preventDefault(); + moveActive(-1); + } else if (e.key === 'Enter') { + e.preventDefault(); + commitSelection(); + } + }); + + // Escape closes from anywhere inside the dialog, and clicking the + // backdrop outside the card does the same + dialog.addEventListener('keydown', function (e) { + if (e.key === 'Escape') { + e.preventDefault(); + e.stopPropagation(); + close(); + } + }); + + dialog.addEventListener('mousedown', function (e) { + if (e.target === dialog) close(); + }); + } + + return { + init: init, + open: open, + close: close, + isOpen: function () { return isOpen; } + }; +})(); diff --git a/extensions/flight-map-canvas/game/flightControls.js b/extensions/flight-map-canvas/game/flightControls.js new file mode 100644 index 00000000..38cc6e44 --- /dev/null +++ b/extensions/flight-map-canvas/game/flightControls.js @@ -0,0 +1,385 @@ +/******************************************************************* + * FlightControls - Flight simulator camera controls for Three.js. * + * * + * Controls: * + * Mouse (pointer lock): Pitch and Yaw * + * W / Up Arrow: Increase speed * + * S / Down Arrow: Decrease speed * + * A / Left Arrow: Roll left * + * D / Right Arrow: Roll right * + * Q: Yaw left (rudder) * + * E: Yaw right (rudder) * + * R: Climb * + * F: Descend * + * Space: Auto-level (stabilize) * + * Shift: Boost speed * + * * + * Look modes: * + * pointer - pointer lock captures the cursor (preferred) * + * drag - hold the left mouse button and drag to look * + * * + * Drag mode is the fallback for hosts that deny pointer lock, * + * such as an embedded panel whose frame withholds the permission. * + * Escape releases drag mode the way it releases pointer lock. * + ******************************************************************/ + +/** + * True when a key event belongs to the page rather than to the + * simulator: the user is typing, choosing a value, or working inside a + * dialog. Flight input listens on the document, so without this guard a + * space typed into a destination field would trigger auto-level and + * have its default suppressed. + */ +function isTextEntryTarget(target) { + if (!target || !target.tagName) return false; + + var tag = target.tagName.toLowerCase(); + if (tag === 'input' || tag === 'textarea' || tag === 'select') return true; + if (target.isContentEditable === true) return true; + + return !!(target.closest && target.closest('[role="dialog"]')); +} + +function FlightControls(camera, domElement) { + this.camera = camera; + this.domElement = domElement; + + // Position and orientation + this.position = camera.position.clone(); + this.quaternion = new THREE.Quaternion(); + + // Speed + this.speed = 0; + this.targetSpeed = 0; + this.minSpeed = 0; + this.maxSpeed = 12; + this.boostMultiplier = 3; + this.acceleration = 4.0; + this.deceleration = 3.0; + + // Rotation + this.rollSpeed = 1.8; + this.yawSpeed = 1.0; + this.mouseSensitivity = 0.002; + + // Altitude + this.verticalSpeed = 0; + this.verticalAccel = 4.0; + this.minAltitude = 8; + + // Input state + this.keys = {}; + this.mouseMovementX = 0; + this.mouseMovementY = 0; + this.isPointerLocked = false; + this.isEnabled = false; + + // Look mode: 'pointer' until a lock request is refused, then 'drag' + this.lookMode = 'pointer'; + this.isDragging = false; + this.lockTimeoutMs = 700; + this._lockTimer = null; + + // Auto-level + this.autoLevel = false; + this.autoLevelSpeed = 3.0; + + this._init(); +} + +FlightControls.prototype._init = function () { + var self = this; + + document.addEventListener('keydown', function (e) { + if (isTextEntryTarget(e.target)) return; + self.keys[e.code] = true; + if (e.code === 'Space') { + self.autoLevel = true; + e.preventDefault(); + } + // Pointer lock exits on Escape by itself; drag mode needs releasing + if (e.code === 'Escape' && self.lookMode === 'drag') { + self._release(); + } + }); + + document.addEventListener('keyup', function (e) { + if (isTextEntryTarget(e.target)) return; + self.keys[e.code] = false; + if (e.code === 'Space') { + self.autoLevel = false; + } + }); + + this.domElement.addEventListener('click', function () { + if (self.isEnabled) return; + if (self.lookMode === 'drag') { + self._engage(); + } else if (!self.isPointerLocked) { + self._requestLock(); + } + }); + + this.domElement.addEventListener('mousedown', function (e) { + if (self.lookMode !== 'drag' || !self.isEnabled) return; + if (e.button !== 0) return; + self.isDragging = true; + // Suppress the text selection drag that would otherwise start + e.preventDefault(); + }); + + document.addEventListener('mouseup', function () { + self.isDragging = false; + }); + + document.addEventListener('mousemove', function (e) { + var capturing = self.isPointerLocked || + (self.lookMode === 'drag' && self.isEnabled && self.isDragging); + if (!capturing) return; + self.mouseMovementX += e.movementX || 0; + self.mouseMovementY += e.movementY || 0; + }); + + document.addEventListener('pointerlockchange', function () { + self.isPointerLocked = document.pointerLockElement === self.domElement; + clearTimeout(self._lockTimer); + if (self.isPointerLocked) { + self.lookMode = 'pointer'; + self._engage(); + } else { + self._release(); + } + }); + + document.addEventListener('pointerlockerror', function () { + self._fallbackToDrag(); + }); + + this.domElement.addEventListener('contextmenu', function (e) { + e.preventDefault(); + }); +}; + +/** + * Requests pointer lock, falling back to drag look when the host + * refuses the request, throws, or ignores it without an error event. + */ +FlightControls.prototype._requestLock = function () { + var self = this; + + if (!this.domElement.requestPointerLock) { + this._fallbackToDrag(); + return; + } + + var request; + try { + request = this.domElement.requestPointerLock(); + } catch (e) { + this._fallbackToDrag(); + return; + } + + // Newer browsers resolve a promise; older ones return undefined and + // report failure through the pointerlockerror event + if (request && typeof request.catch === 'function') { + request.catch(function () { + self._fallbackToDrag(); + }); + } + + clearTimeout(this._lockTimer); + this._lockTimer = setTimeout(function () { + if (!self.isPointerLocked) self._fallbackToDrag(); + }, this.lockTimeoutMs); +}; + +/** + * Switches to drag look and engages immediately, so the click that + * asked for pointer lock still starts the flight. + */ +FlightControls.prototype._fallbackToDrag = function () { + clearTimeout(this._lockTimer); + if (this.lookMode !== 'drag') { + this.lookMode = 'drag'; + } + this._engage(); +}; + +/** + * Enables flight input and notifies the UI. + */ +FlightControls.prototype._engage = function () { + if (this.isEnabled) return; + this.isEnabled = true; + this._dispatch(true); +}; + +/** + * Disables flight input and clears any state that could read as stuck. + */ +FlightControls.prototype._release = function () { + if (!this.isEnabled) return; + this.isEnabled = false; + this.isDragging = false; + + // Keyup events can be missed while released; clear input state + // so no key reads as stuck on the next engage + this.keys = {}; + this.autoLevel = false; + this.mouseMovementX = 0; + this.mouseMovementY = 0; + + this._dispatch(false); +}; + +FlightControls.prototype._dispatch = function (locked) { + document.dispatchEvent(new CustomEvent('flightcontrols', { + detail: { locked: locked, mode: this.lookMode } + })); +}; + +FlightControls.prototype.update = function (delta) { + if (!this.isEnabled) return; + delta = Math.min(delta, 0.1); + + // --- Mouse look: pitch and yaw --- + if (this.mouseMovementX !== 0 || this.mouseMovementY !== 0) { + var pitchAngle = -this.mouseMovementY * this.mouseSensitivity; + var yawAngle = -this.mouseMovementX * this.mouseSensitivity; + + // Pitch around camera's local X axis + var right = new THREE.Vector3(1, 0, 0).applyQuaternion(this.quaternion); + var pitchQuat = new THREE.Quaternion().setFromAxisAngle(right, pitchAngle); + this.quaternion.premultiply(pitchQuat); + + // Yaw around world Y axis for stability + var worldUp = new THREE.Vector3(0, 1, 0); + var yawQuat = new THREE.Quaternion().setFromAxisAngle(worldUp, yawAngle); + this.quaternion.premultiply(yawQuat); + + this.quaternion.normalize(); + this.mouseMovementX = 0; + this.mouseMovementY = 0; + } + + // --- Keyboard roll (A/D, Left/Right) --- + var rollDelta = 0; + if (this.keys['KeyA'] || this.keys['ArrowLeft']) rollDelta += this.rollSpeed * delta; + if (this.keys['KeyD'] || this.keys['ArrowRight']) rollDelta -= this.rollSpeed * delta; + + if (rollDelta !== 0) { + var forward = new THREE.Vector3(0, 0, -1).applyQuaternion(this.quaternion); + var rollQuat = new THREE.Quaternion().setFromAxisAngle(forward, rollDelta); + this.quaternion.premultiply(rollQuat); + this.quaternion.normalize(); + } + + // --- Keyboard yaw / rudder (Q/E) --- + var yawDelta = 0; + if (this.keys['KeyQ']) yawDelta += this.yawSpeed * delta; + if (this.keys['KeyE']) yawDelta -= this.yawSpeed * delta; + + if (yawDelta !== 0) { + var localUp = new THREE.Vector3(0, 1, 0).applyQuaternion(this.quaternion); + var rudderQuat = new THREE.Quaternion().setFromAxisAngle(localUp, yawDelta); + this.quaternion.premultiply(rudderQuat); + this.quaternion.normalize(); + } + + // --- Throttle (W/S, Up/Down) --- + var boost = (this.keys['ShiftLeft'] || this.keys['ShiftRight']) ? this.boostMultiplier : 1; + + if (this.keys['KeyW'] || this.keys['ArrowUp']) { + this.targetSpeed = Math.min(this.targetSpeed + this.acceleration * delta, this.maxSpeed * boost); + } else if (this.keys['KeyS'] || this.keys['ArrowDown']) { + this.targetSpeed = Math.max(this.targetSpeed - this.deceleration * delta, this.minSpeed); + } + + this.targetSpeed = Math.min(this.targetSpeed, this.maxSpeed * boost); + this.speed += (this.targetSpeed - this.speed) * Math.min(5 * delta, 1); + + // --- Altitude (R/F) --- + if (this.keys['KeyR']) this.verticalSpeed += this.verticalAccel * delta; + if (this.keys['KeyF']) this.verticalSpeed -= this.verticalAccel * delta; + this.verticalSpeed *= Math.pow(0.93, delta * 60); + + // --- Auto-level (Space held) --- + if (this.autoLevel) { + var currentUp = new THREE.Vector3(0, 1, 0).applyQuaternion(this.quaternion); + var targetUp = new THREE.Vector3(0, 1, 0); + var correction = new THREE.Quaternion().setFromUnitVectors(currentUp, targetUp); + var t = Math.min(this.autoLevelSpeed * delta, 1); + correction.slerp(new THREE.Quaternion(), 1 - t); + this.quaternion.premultiply(correction); + this.quaternion.normalize(); + } + + // --- Update position --- + var fwd = new THREE.Vector3(0, 0, -1).applyQuaternion(this.quaternion); + this.position.addScaledVector(fwd, this.speed * delta * 60); + this.position.y += this.verticalSpeed * delta * 60; + + if (this.position.y < this.minAltitude) { + this.position.y = this.minAltitude; + this.verticalSpeed = Math.max(this.verticalSpeed, 0); + } + + // --- Apply to camera --- + this.camera.position.copy(this.position); + this.camera.quaternion.copy(this.quaternion); +}; + +FlightControls.prototype.getHeading = function () { + var fwd = new THREE.Vector3(0, 0, -1).applyQuaternion(this.quaternion); + var heading = Math.atan2(fwd.x, -fwd.z) * 180 / Math.PI; + return ((heading % 360) + 360) % 360; +}; + +FlightControls.prototype.getPitch = function () { + var fwd = new THREE.Vector3(0, 0, -1).applyQuaternion(this.quaternion); + return Math.asin(Math.max(-1, Math.min(1, fwd.y))) * 180 / Math.PI; +}; + +FlightControls.prototype.getRoll = function () { + var right = new THREE.Vector3(1, 0, 0).applyQuaternion(this.quaternion); + return Math.asin(Math.max(-1, Math.min(1, right.y))) * 180 / Math.PI; +}; + +FlightControls.prototype.getSpeed = function () { + return this.speed; +}; + +FlightControls.prototype.getAltitude = function () { + return this.position.y; +}; + +/** + * Hands control back to the page. Used when a dialog opens over the + * canvas so the aircraft is not still flying behind it. + */ +FlightControls.prototype.release = function () { + if (this.isPointerLocked && document.exitPointerLock) { + document.exitPointerLock(); + } + this._release(); +}; + +FlightControls.prototype.resetTo = function (position, lookAt) { + this.position.copy(position); + this.speed = 0; + this.targetSpeed = 0; + this.verticalSpeed = 0; + + var tempCam = new THREE.PerspectiveCamera(); + tempCam.position.copy(position); + tempCam.lookAt(lookAt); + this.quaternion.copy(tempCam.quaternion); + + this.camera.position.copy(this.position); + this.camera.quaternion.copy(this.quaternion); +}; + +// Shared with the rest of the page so every document-level shortcut +// applies the same rule about what counts as typing +FlightControls.isTextEntryTarget = isTextEntryTarget; diff --git a/extensions/flight-map-canvas/game/geocoder.js b/extensions/flight-map-canvas/game/geocoder.js new file mode 100644 index 00000000..642afcce --- /dev/null +++ b/extensions/flight-map-canvas/game/geocoder.js @@ -0,0 +1,314 @@ +/************************************************************************ + * Geocoder - Talks to the OpenStreetMap Nominatim API in both * + * directions. * + * * + * update() reverse geocodes the camera's latitude/longitude into a * + * human-readable location label ("City, State, Country"), falling back * + * to "Rural , " when the position is not within a * + * city/town/village boundary. Requests are throttled by time and by * + * minimum movement so the HUD label costs as few lookups as possible. * + * * + * search() forward geocodes a typed state/city/country into a list of * + * candidate destinations for the destination input dialog. * + * * + * Both directions go out through one queue, so the module holds to the * + * Nominatim usage policy (absolute maximum of 1 request per second) * + * whichever direction is asking. * + ***********************************************************************/ +var Geocoder = (function () { + + var NOMINATIM = 'https://nominatim.openstreetmap.org/'; + + var MIN_REQUEST_INTERVAL_MS = 1000; // Nominatim policy: 1 request/second + var MIN_INTERVAL_MS = 5000; // Minimum time between reverse lookups + var MIN_MOVE_DEG = 0.005; // Minimum movement (~500m) before a new lookup + var SEARCH_LIMIT = 10; // Candidates shown in the results list + + var lastLat = null; + var lastLng = null; + var lastRequestTime = 0; + var lastLabel = ''; + var pending = false; + + // Bumped by reset(). A reverse lookup carries the value it was queued + // under, so a response that belongs to the location left behind is + // recognized as stale instead of overwriting the HUD with it. + var generation = 0; + + /* ------------------------------------------------------------ + Shared request queue + + Nominatim counts requests per client across its endpoints, so + reverse lookups and searches cannot each keep their own pace. + One request is in flight at a time and consecutive sends are + spaced by MIN_REQUEST_INTERVAL_MS. + ------------------------------------------------------------ */ + + var queue = []; + var inFlight = null; + var lastSendTime = 0; + var drainTimer = null; + + /** + * Queues one request. job is + * { url, success(data), failure(reason), stale() }, where reason is + * { status, malformed } and the optional stale() predicate lets a + * job whose result is no longer wanted be dropped before it is sent. + */ + function enqueue(job) { + queue.push(job); + drain(); + } + + function drain() { + if (inFlight) return; + + // Drop abandoned jobs before they spend a request slot + while (queue.length && queue[0].stale && queue[0].stale()) { + queue.shift(); + } + if (!queue.length) return; + + var wait = MIN_REQUEST_INTERVAL_MS - (performance.now() - lastSendTime); + if (wait > 0) { + if (drainTimer === null) { + drainTimer = setTimeout(function () { + drainTimer = null; + drain(); + }, wait); + } + return; + } + + send(queue.shift()); + } + + function send(job) { + var settled = false; + var xhr = new XMLHttpRequest(); + + inFlight = xhr; + lastSendTime = performance.now(); + + // A network failure raises both onerror and a readyState 4 with no + // status, so the first outcome to arrive is the one that counts + function finish(handler, argument) { + if (settled) return; + settled = true; + inFlight = null; + handler(argument); + drain(); + } + + xhr.open('GET', job.url, true); + xhr.onreadystatechange = function () { + if (xhr.readyState !== 4) return; + + if (xhr.status !== 200) { + finish(job.failure, { status: xhr.status, malformed: false }); + return; + } + + var data; + try { + data = JSON.parse(xhr.responseText); + } catch (e) { + finish(job.failure, { status: xhr.status, malformed: true }); + return; + } + + finish(job.success, data); + }; + xhr.onerror = function () { + finish(job.failure, { status: 0, malformed: false }); + }; + xhr.send(); + } + + /** + * Builds a display label from a Nominatim address object. + * Within a city boundary: "City, State, Country". + * Outside one: "Rural State, Country" (e.g. "Rural New York, United States"). + */ + function buildLabel(address) { + // Only city/town count as being "within a city"; villages, hamlets, + // and US civil townships ("Town of X" -> village) read as rural + var city = address.city || address.town; + var state = address.state || address.province || address.region || + address.county; + var country = address.country; + var parts = []; + + if (city) { + parts.push(city); + if (state) parts.push(state); + if (country) parts.push(country); + } else { + var area = state || country; + if (!area) return ''; + parts.push('Rural ' + area); + if (state && country) parts.push(country); + } + + return parts.join(', '); + } + + /** + * Requests a label for the given position. Throttled internally, + * so it is safe to call every frame. Invokes callback(label) only + * when the label has changed. + */ + function update(lat, lng, callback) { + var now = performance.now(); + if (pending || now - lastRequestTime < MIN_INTERVAL_MS) return; + if (lastLat !== null && + Math.abs(lat - lastLat) < MIN_MOVE_DEG && + Math.abs(lng - lastLng) < MIN_MOVE_DEG) return; + + pending = true; + lastRequestTime = now; + + var token = generation; + function abandoned() { + return token !== generation; + } + + enqueue({ + url: NOMINATIM + 'reverse?format=jsonv2&zoom=10' + + '&lat=' + encodeURIComponent(lat) + + '&lon=' + encodeURIComponent(lng), + stale: abandoned, + success: function (data) { + // Switched location while this was in flight: the label and + // the position it describes belong to somewhere else now + if (abandoned()) return; + pending = false; + + var label = buildLabel((data && data.address) || {}); + lastLat = lat; + lastLng = lng; + if (label && label !== lastLabel) { + lastLabel = label; + callback(label); + } + }, + failure: function () { + if (abandoned()) return; + pending = false; + // Keep the last label on failure or a malformed response + } + }); + } + + /** + * Clears cached state when switching capitals so the next lookup + * runs immediately for the new location. Lookups already queued or + * in flight for the old location are abandoned rather than allowed + * to report back over the new one. + */ + function reset() { + generation++; + lastLat = null; + lastLng = null; + lastRequestTime = 0; + lastLabel = ''; + pending = false; + } + + /** + * Builds the label shown for one search result: + * "State, City, CC" (e.g. "New York, New York City, US"). + * + * Nominatim omits whichever administrative levels a place does not + * have, so the parts that exist are joined and the raw display_name + * covers a result that carries no structured address at all. + */ + function buildResultLabel(item) { + var address = item.address || {}; + var city = address.city || address.town || address.village || + address.municipality || address.hamlet; + var state = address.state || address.province || address.region || + address.county; + var code = address.country_code ? address.country_code.toUpperCase() : ''; + var parts = []; + + if (state) parts.push(state); + if (city && city !== state) parts.push(city); + if (code) parts.push(code); + + if (!parts.length) return item.display_name || 'Unknown location'; + return parts.join(', '); + } + + /** + * Forward geocodes a destination typed into the input dialog. + * + * Fields are optional individually but at least one must be filled; + * they are sent as Nominatim's structured query parameters rather + * than concatenated into a free-text string, which keeps a city name + * that also exists in another country from outranking the match. + * + * Calls callback(error, results), where each result is + * { label, lat, lng, city, country } ready for loadCapital(). + */ + function search(fields, callback) { + var params = []; + var keys = ['state', 'city', 'country']; + + for (var i = 0; i < keys.length; i++) { + var value = (fields[keys[i]] || '').trim(); + if (value) params.push(keys[i] + '=' + encodeURIComponent(value)); + } + + if (!params.length) { + callback('Enter a state/region, a city, or a country to search.', []); + return; + } + + enqueue({ + url: NOMINATIM + 'search?format=jsonv2&addressdetails=1' + + '&limit=' + SEARCH_LIMIT + '&' + params.join('&'), + success: function (data) { + if (!data || !data.length) { + callback(null, []); + return; + } + + var results = []; + for (var i = 0; i < data.length; i++) { + var item = data[i]; + var lat = parseFloat(item.lat); + var lng = parseFloat(item.lon); + if (isNaN(lat) || isNaN(lng)) continue; + + var address = item.address || {}; + results.push({ + label: buildResultLabel(item), + lat: lat, + lng: lng, + city: address.city || address.town || address.village || + item.name || 'Destination', + country: address.country || '' + }); + } + + callback(null, results); + }, + failure: function (reason) { + if (reason.malformed) { + callback('Search returned a malformed response.', []); + } else if (!reason.status) { + callback('Search could not reach the geocoding service.', []); + } else { + callback('Search failed (' + reason.status + ').', []); + } + } + }); + } + + return { + update: update, + reset: reset, + search: search + }; +})(); diff --git a/extensions/flight-map-canvas/game/hostBridge.js b/extensions/flight-map-canvas/game/hostBridge.js new file mode 100644 index 00000000..05e918a2 --- /dev/null +++ b/extensions/flight-map-canvas/game/hostBridge.js @@ -0,0 +1,73 @@ +/************************************************************************ + * HostBridge - Thin abstraction over the VS Code webview messaging API. * + * * + * The simulator runs in two places: inside a VS Code webview panel and * + * as a plain page in a browser. Everything that needs the extension * + * host (config injection, saving renderMap.json) goes through here so * + * the rest of the code stays identical in both environments. * + * * + * In the browser the API is absent and every call degrades to a no-op, * + * leaving the original web behavior in place. * + ***********************************************************************/ +var HostBridge = (function () { + + var api = null; + var handlers = {}; + + // acquireVsCodeApi exists only inside a webview, and may be called + // exactly once per page load + if (typeof acquireVsCodeApi === 'function') { + try { + api = acquireVsCodeApi(); + } catch (e) { + api = null; + } + } + + if (api) { + window.addEventListener('message', function (event) { + var message = event.data; + if (!message || !message.command) return; + var fn = handlers[message.command]; + if (fn) fn(message); + }); + } + + /** + * True when running inside the VS Code webview panel. + */ + function isHosted() { + return api !== null; + } + + /** + * Send a message to the extension host. No-op in the browser. + */ + function post(message) { + if (api) api.postMessage(message); + } + + /** + * Register a handler for a command sent by the extension host. + */ + function on(command, fn) { + handlers[command] = fn; + } + + /** + * Render configuration injected by the extension host, or null when + * running as a standalone page. + */ + function getInjectedConfig() { + return (window.__flightMapConfig && typeof window.__flightMapConfig === 'object') + ? window.__flightMapConfig + : null; + } + + return { + isHosted: isHosted, + post: post, + on: on, + getInjectedConfig: getInjectedConfig + }; +})(); diff --git a/extensions/flight-map-canvas/game/index.html b/extensions/flight-map-canvas/game/index.html new file mode 100644 index 00000000..89eb2063 --- /dev/null +++ b/extensions/flight-map-canvas/game/index.html @@ -0,0 +1,284 @@ + + + + + + + Flight Map + + + + + +
+
+ + + + + +
+ + +
+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+

3D Flight Simulator

+

Satellite Terrain Viewer - World Capitals

+

Select a capital city to begin

+
+ + + + + + + + + + + + diff --git a/extensions/flight-map-canvas/game/renderConfig.js b/extensions/flight-map-canvas/game/renderConfig.js new file mode 100644 index 00000000..e75012b1 --- /dev/null +++ b/extensions/flight-map-canvas/game/renderConfig.js @@ -0,0 +1,269 @@ +/*************************************************************************** + * RenderConfig - Loads, applies, and exports map rendering configuration. * + * * + * Inside the VS Code panel the extension host reads renderMap.json and * + * injects it before the page scripts run. As a standalone page the * + * config is fetched from renderMap.json in the project root. Either way * + * the values are merged over the defaults and applied to the live * + * simulation. * + * * + * Export hands the current configuration to the extension host, which * + * writes it through a save dialog. In the browser it falls back to a * + * plain file download. * + **************************************************************************/ +var RenderConfig = (function () { + + var defaults = { + map: { + width: 1920, + height: 1080, + tileZoom: 15, + tileSize: 100, + loadRadius: 6, + unloadRadius: 9, + startAltitude: 200, + fogDensity: 0.00018, + radiusFeather: 3, + maxTiles: 600 + }, + filler: { + sampleInterval: 45, + updateIntervalSec: 10, + perimeter: { patchCount: 10, patchSize: 10 }, + center: { patchCount: 5, patchSize: 10 }, + padding: { patchCount: 4, patchSize: 5 } + }, + cloud: { + enabled: true, + opacity: 0.35, + speed: 0.0004, + coverage: 0.5, + scale: 0.008 + } + }; + + var config = JSON.parse(JSON.stringify(defaults)); + var listeners = []; + + /** + * Deep merge source into target, preserving existing keys. + */ + function merge(target, source) { + for (var key in source) { + if (!source.hasOwnProperty(key)) continue; + if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) { + if (!target[key]) target[key] = {}; + merge(target[key], source[key]); + } else { + target[key] = source[key]; + } + } + return target; + } + + function freshDefaults() { + return JSON.parse(JSON.stringify(defaults)); + } + + /** + * Load configuration, merged over defaults. Prefers the config the + * extension host injected; otherwise reads renderMap.json from the + * project root relative to this page. + */ + function load(callback) { + var injected = HostBridge.getInjectedConfig(); + if (injected) { + config = merge(freshDefaults(), injected); + if (callback) callback(config); + return; + } + + var xhr = new XMLHttpRequest(); + xhr.open('GET', '../renderMap.json', true); + xhr.onreadystatechange = function () { + if (xhr.readyState !== 4) return; + if (xhr.status === 200) { + try { + var data = JSON.parse(xhr.responseText); + config = merge(freshDefaults(), data); + } catch (e) { + console.warn('RenderConfig: invalid JSON, using defaults'); + config = freshDefaults(); + } + } else { + console.warn('RenderConfig: could not load renderMap.json, using defaults'); + config = freshDefaults(); + } + if (callback) callback(config); + }; + xhr.send(); + } + + /** + * Get the full config object. + */ + function get() { + return config; + } + + /** + * Set a config value by dot-notation path (e.g. "cloud.opacity"). + */ + function set(path, value) { + var keys = path.split('.'); + var obj = config; + for (var i = 0; i < keys.length - 1; i++) { + if (!obj[keys[i]]) obj[keys[i]] = {}; + obj = obj[keys[i]]; + } + obj[keys[keys.length - 1]] = value; + apply(); + notify(path, value); + } + + /** + * Subscribe to config changes. + */ + function onChange(fn) { + listeners.push(fn); + } + + function notify(path, value) { + for (var i = 0; i < listeners.length; i++) { + listeners[i](path, value, config); + } + } + + /** + * Apply current config values to the live simulation globals. + */ + function apply() { + // Map globals + TILE_ZOOM = config.map.tileZoom; + TILE_SIZE = config.map.tileSize; + LOAD_RADIUS = config.map.loadRadius; + UNLOAD_RADIUS = Math.max(config.map.unloadRadius, LOAD_RADIUS + 3); + START_ALTITUDE = config.map.startAltitude; + FOG_DENSITY = config.map.fogDensity; + RADIUS_FEATHER = config.map.radiusFeather; + MAX_TILES = config.map.maxTiles; + + // Apply fog density to scene + if (typeof scene !== 'undefined' && scene && scene.fog) { + scene.fog.density = config.map.fogDensity; + } + + // Apply render resolution. CSS stretches the canvas buffer over + // the panel, so a buffer shaped differently from the panel would + // render distorted. Keep the configured width x height as the + // pixel budget and reshape it to the panel's aspect ratio, so + // resizing the panel changes how much is in frame rather than + // how the frame is squashed. + if (typeof renderer !== 'undefined' && renderer && + typeof camera !== 'undefined' && camera && + config.map.width > 0 && config.map.height > 0) { + + var aspect = (window.innerWidth > 0 && window.innerHeight > 0) + ? window.innerWidth / window.innerHeight + : config.map.width / config.map.height; + + var pixelBudget = config.map.width * config.map.height; + var height = Math.max(1, Math.round(Math.sqrt(pixelBudget / aspect))); + var width = Math.max(1, Math.round(height * aspect)); + + renderer.setSize(width, height, false); + camera.aspect = aspect; + camera.updateProjectionMatrix(); + } + + // Apply filler settings to TerrainFill instance + if (typeof terrainFill !== 'undefined' && terrainFill) { + terrainFill.sampleInterval = config.filler.sampleInterval; + terrainFill.updateIntervalSec = config.filler.updateIntervalSec; + terrainFill.perimeterPatchCount = config.filler.perimeter.patchCount; + terrainFill.perimeterPatchSize = config.filler.perimeter.patchSize; + terrainFill.centerPatchCount = config.filler.center.patchCount; + terrainFill.centerPatchSize = config.filler.center.patchSize; + terrainFill.paddingPatchCount = config.filler.padding.patchCount; + terrainFill.paddingPatchSize = config.filler.padding.patchSize; + } + + // Apply cloud settings + if (typeof terrainFill !== 'undefined' && terrainFill && terrainFill.cloudOverlay) { + terrainFill.cloudOverlay.enabled = config.cloud.enabled; + terrainFill.cloudOverlay.opacity = config.cloud.opacity; + terrainFill.cloudOverlay.speed = config.cloud.speed; + terrainFill.cloudOverlay.coverage = config.cloud.coverage; + terrainFill.cloudOverlay.scale = config.cloud.scale; + } + } + + /** + * Export the current configuration as renderMap.json. The extension + * host owns the file write so the save lands in the workspace; a + * standalone page falls back to a browser download. + */ + function exportJSON() { + var json = JSON.stringify(config, null, 4); + + if (HostBridge.isHosted()) { + HostBridge.post({ command: 'exportConfig', json: json }); + return; + } + + var blob = new Blob([json], { type: 'application/json' }); + var url = URL.createObjectURL(blob); + var a = document.createElement('a'); + a.href = url; + a.download = 'renderMap.json'; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + } + + /** + * Populate slider/input elements from the current config and bind change events. + */ + function bindSliders() { + var sliders = document.querySelectorAll('[data-config]'); + for (var i = 0; i < sliders.length; i++) { + (function (el) { + var path = el.getAttribute('data-config'); + var keys = path.split('.'); + var val = config; + for (var k = 0; k < keys.length; k++) { + val = val[keys[k]]; + } + el.value = val; + var display = document.getElementById(el.id + '-val'); + if (display) display.textContent = val; + + el.addEventListener('input', function () { + var v = parseFloat(el.value); + set(path, v); + if (display) display.textContent = v; + }); + })(sliders[i]); + } + + // Cloud enabled checkbox + var cloudToggle = document.getElementById('cfg-cloud-enabled'); + if (cloudToggle) { + cloudToggle.checked = config.cloud.enabled; + cloudToggle.addEventListener('change', function () { + set('cloud.enabled', cloudToggle.checked); + }); + } + } + + return { + load: load, + get: get, + set: set, + apply: apply, + exportJSON: exportJSON, + bindSliders: bindSliders, + onChange: onChange + }; +})(); diff --git a/extensions/flight-map-canvas/game/styles.css b/extensions/flight-map-canvas/game/styles.css new file mode 100644 index 00000000..dc8439df --- /dev/null +++ b/extensions/flight-map-canvas/game/styles.css @@ -0,0 +1,846 @@ +/* ============================================================ + 3D Flight Simulator - Styles + ============================================================ */ + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Consolas', 'Monaco', 'Courier New', monospace; + background: #000; + color: #e0e0e0; + overflow: hidden; + width: 100vw; + height: 100vh; +} + +/* ---- Canvas Container ---- */ +#canvas-container { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1; +} + +#canvas-container canvas { + display: block; + width: 100%; + height: 100%; +} + +/* ---- Top Bar ---- */ + +/* + The selector panel and the location readout share one row. The bar + mirrors the selector panel's measured width as right padding so the + readout reads as centered in the panel rather than in the space left + over beside the menu. When the panel is too narrow for both, app.js + adds .stacked and the readout takes its own row underneath. + + --selector-width and --top-bar-height are published by app.js. +*/ +#top-bar { + position: fixed; + top: 0; + left: 0; + width: auto; + z-index: 100; + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px 12px; + padding: 12px; + padding-right: calc(12px + var(--selector-width, 0px)); + pointer-events: none; +} + +#top-bar.stacked { + padding-right: 12px; +} + +/* ---- Capital Selector ---- */ +#selector-panel { + flex: 0 1 auto; + min-width: 0; + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 8px; + background: rgba(0, 0, 0, 0.65); + padding: 8px 14px; + border-radius: 6px; + border: 1px solid rgba(100, 200, 255, 0.2); + backdrop-filter: blur(8px); + pointer-events: auto; +} + +#selector-panel label { + font-size: 0.75rem; + color: #88bbdd; + text-transform: uppercase; + letter-spacing: 1px; +} + +#capital-select { + padding: 5px 10px; + font-size: 0.85rem; + font-family: inherit; + border: 1px solid rgba(100, 200, 255, 0.3); + border-radius: 3px; + background: rgba(10, 20, 40, 0.9); + color: #c0e0f0; + cursor: pointer; + flex: 1 1 auto; + min-width: 140px; + max-width: 100%; + outline: none; +} + +#capital-select:focus { + border-color: rgba(100, 200, 255, 0.6); +} + +#capital-select optgroup { + color: #66aacc; + font-weight: bold; +} + +#capital-select option { + color: #c0e0f0; + background: #0a1428; +} + +/* ---- HUD Overlay ---- */ +#hud { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 50; + pointer-events: none; +} + +/* Location display (lives in #top-bar; the flex basis below is mirrored + by LOCATION_MIN_WIDTH in app.js, which decides when to stack) */ +#hud-location { + /* flex: 1 1 240px; */ + min-width: 0; + text-align: center; +} + +/* Both lines sit over bright satellite imagery, so they carry a hard + 1px drop shadow rather than a blurred glow. A blur radius spreads the + dark halo through the glyphs themselves and softens the strokes, which + is what made the coordinates unreadable against a pale sky. */ +#hud-capital { + font-size: calc(1rem + 2pt); + color: rgb(235, 246, 255); + font-weight: bold; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.85); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* white-space: pre keeps the two spaces that separate the latitude from + the longitude; normal whitespace handling would collapse them to one */ +#hud-coords { + font-size: calc(0.72rem + 2pt); + color: rgb(214, 234, 250); + margin-top: 2px; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.85); + overflow: hidden; + text-overflow: ellipsis; + white-space: pre; +} + +/* Heading: sits under the top bar at whatever height it settled on */ +#hud-heading { + position: absolute; + top: calc(var(--top-bar-height, 56px) + 6px); + left: 50%; + transform: translateX(-50%); + background: rgba(0, 0, 0, 0.35); + padding: 3px 16px; + border-radius: 3px; + border: 1px solid rgba(100, 200, 255, 0.15); +} + +#hud-heading-value { + font-size: 0.9rem; + color: rgba(100, 220, 255, 0.85); + text-shadow: 0 0 6px rgba(0, 100, 200, 0.3); +} + +/* Speed (left side) */ +#hud-speed { + position: absolute; + left: 30px; + top: 50%; + transform: translateY(-50%); + text-align: center; + background: rgba(0, 0, 0, 0.35); + padding: 10px 14px; + border-radius: 4px; + border: 1px solid rgba(100, 200, 255, 0.15); +} + +#hud-speed .hud-label { + font-size: 0.65rem; + color: rgba(100, 200, 255, 0.5); + letter-spacing: 2px; + margin-bottom: 4px; +} + +#hud-speed-value { + font-size: 1.6rem; + color: rgba(100, 255, 180, 0.9); + font-weight: bold; + text-shadow: 0 0 10px rgba(0, 200, 100, 0.3); +} + +#hud-speed .hud-unit { + font-size: 0.6rem; + color: rgba(100, 200, 255, 0.4); + margin-top: 2px; +} + +/* Altitude (right side) */ +#hud-altitude { + position: absolute; + right: 30px; + top: 50%; + transform: translateY(-50%); + text-align: center; + background: rgba(0, 0, 0, 0.35); + padding: 10px 14px; + border-radius: 4px; + border: 1px solid rgba(100, 200, 255, 0.15); +} + +#hud-altitude .hud-label { + font-size: 0.65rem; + color: rgba(100, 200, 255, 0.5); + letter-spacing: 2px; + margin-bottom: 4px; +} + +#hud-altitude-value { + font-size: 1.6rem; + color: rgba(255, 200, 100, 0.9); + font-weight: bold; + text-shadow: 0 0 10px rgba(200, 150, 0, 0.3); +} + +#hud-altitude .hud-unit { + font-size: 0.6rem; + color: rgba(100, 200, 255, 0.4); + margin-top: 2px; +} + +/* Crosshair */ +#hud-crosshair { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 1.5rem; + color: rgba(200, 230, 255, 0.4); + text-shadow: 0 0 4px rgba(0, 0, 0, 0.5); + line-height: 1; +} + +/* Pitch indicator */ +#hud-pitch { + position: absolute; + right: 30px; + top: 50%; + transform: translateY(80px); + text-align: center; +} + +#hud-pitch-value { + font-size: 0.75rem; + color: rgba(180, 200, 255, 0.6); +} + +/* ---- Click to Fly Prompt ---- */ +#fly-prompt { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 80; + text-align: center; + pointer-events: none; +} + +#fly-prompt .prompt-text { + font-size: 1.8rem; + color: rgba(180, 220, 255, 0.9); + text-shadow: 0 0 20px rgba(50, 150, 255, 0.5); + animation: pulse 2s ease-in-out infinite; + letter-spacing: 2px; + text-transform: uppercase; +} + +#fly-prompt .prompt-hint { + margin-top: 8px; + font-size: 0.72rem; + letter-spacing: 1px; + color: rgba(120, 170, 210, 0.6); +} + +@keyframes pulse { + 0%, 100% { opacity: 0.7; } + 50% { opacity: 1; } +} + +/* ---- Controls Help ---- */ +#controls-help { + position: fixed; + bottom: 20px; + left: 50%; + transform: translateX(-50%); + z-index: 80; + text-align: center; + background: rgba(0, 0, 0, 0.5); + padding: 8px 20px; + border-radius: 6px; + border: 1px solid rgba(100, 200, 255, 0.15); + pointer-events: none; + font-size: 0.72rem; + color: rgba(160, 200, 230, 0.8); + line-height: 1.6; + transition: opacity 2s ease; +} + +#controls-help.fade-out { + opacity: 0; +} + +/* ---- Static Controls List ---- */ +#controls-list { + position: fixed; + left: 12px; + bottom: 20px; + z-index: 60; + background: rgba(0, 0, 0, 0.3); + border: 1px solid rgba(100, 200, 255, 0.1); + border-radius: 4px; + padding: 8px 12px; + pointer-events: none; + font-size: 0.62rem; + color: rgba(150, 190, 220, 0.6); +} + +#controls-list .controls-title { + font-size: 0.58rem; + color: rgba(120, 170, 210, 0.5); + text-transform: uppercase; + letter-spacing: 2px; + margin-bottom: 5px; +} + +#controls-list ul { + list-style: none; +} + +#controls-list li { + line-height: 1.55; + white-space: nowrap; +} + +#controls-list li span { + display: inline-block; + width: 52px; + color: rgba(120, 210, 255, 0.7); +} + +/* ---- Pause Indicator ---- */ +#pause-indicator { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 95; + background: rgba(0, 0, 0, 0.45); + padding: 12px 28px; + border-radius: 8px; + border: 1px solid rgba(255, 220, 120, 0.3); + pointer-events: none; + font-size: 1.6rem; + letter-spacing: 6px; + text-transform: uppercase; + color: rgba(255, 220, 120, 0.9); + text-shadow: 0 0 20px rgba(0, 0, 0, 0.8); +} + +/* ---- Loading Overlay ---- */ +#loading-overlay { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 90; + text-align: center; + background: rgba(0, 10, 30, 0.85); + padding: 30px 50px; + border-radius: 10px; + border: 1px solid rgba(100, 200, 255, 0.2); + backdrop-filter: blur(10px); +} + +#loading-text { + font-size: 1rem; + color: rgba(150, 200, 240, 0.9); + margin-bottom: 14px; + text-transform: uppercase; + letter-spacing: 2px; +} + +#loading-bar-container { + width: 240px; + height: 4px; + background: rgba(50, 80, 120, 0.5); + border-radius: 2px; + overflow: hidden; + margin: 0 auto; +} + +#loading-bar { + width: 0%; + height: 100%; + background: linear-gradient(90deg, #2288cc, #44ccff); + border-radius: 2px; + transition: width 0.3s ease; +} + +#loading-progress { + font-size: 0.8rem; + color: rgba(100, 180, 230, 0.7); + margin-top: 8px; +} + +/* ---- Welcome Screen ---- */ +#welcome { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 70; + text-align: center; + pointer-events: none; +} + +#welcome h1 { + font-size: 2.2rem; + color: rgba(180, 220, 255, 0.9); + font-weight: 300; + letter-spacing: 4px; + text-transform: uppercase; + text-shadow: 0 0 30px rgba(50, 150, 255, 0.3); + margin-bottom: 8px; +} + +#welcome p { + font-size: 0.85rem; + color: rgba(130, 170, 210, 0.6); + letter-spacing: 1px; +} + +#welcome .welcome-hint { + margin-top: 20px; + font-size: 0.75rem; + color: rgba(100, 150, 200, 0.5); + animation: pulse 3s ease-in-out infinite; +} + +/* ---- Agent Status ---- */ + +/* Clears the controls help that sits at the bottom edge, so both can be + on screen during the five seconds before the help fades */ +#agent-status { + position: fixed; + bottom: 64px; + left: 50%; + transform: translateX(-50%); + z-index: 90; + max-width: min(560px, calc(100vw - 24px)); + display: flex; + align-items: center; + gap: 8px; + padding: 7px 14px; + border-radius: 20px; + background: rgba(0, 8, 24, 0.8); + border: 1px solid rgba(100, 200, 255, 0.25); + font-size: 0.75rem; + color: rgba(200, 230, 255, 0.9); + pointer-events: none; +} + +#agent-status-dot { + flex: 0 0 auto; + width: 8px; + height: 8px; + border-radius: 50%; + background: #66ddaa; + animation: pulse 1.6s ease-in-out infinite; +} + +/* A finished job leaves the last status readable but stops the pulse */ +#agent-status.idle #agent-status-dot { + background: rgba(120, 170, 210, 0.5); + animation: none; +} + +#agent-status-text { + flex: 1 1 auto; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +#agent-status-tokens { + flex: 0 0 auto; + color: rgba(120, 200, 255, 0.65); +} + +#agent-status-tokens:empty { + display: none; +} + +/* ---- Utility ---- */ +.hidden { + display: none !important; +} + +/* ---- Destination Input Dialog ---- */ + +/* The "Input Destination" entry is the only action in the menu, so it + is set apart from the capitals listed under it. */ +#opt-input-destination { + background: #e8edf1; + color: #16283f; + font-weight: bold; +} + +/* Sits above the top bar so the dialog is never partly behind the menu, + and covers the canvas so a click cannot engage flight behind it. The + card hangs from just under the bar rather than centering, so it stays + next to the menu entry that opened it. */ +#destination-dialog { + position: fixed; + inset: 0; + z-index: 200; + display: flex; + align-items: flex-start; + justify-content: center; + padding: 24px; + padding-top: calc(var(--top-bar-height, 56px) + 16px); + background: rgba(4, 12, 24, 0.45); +} + +.destination-card { + width: 100%; + max-width: 400px; + max-height: calc(100vh - var(--top-bar-height, 56px) - 40px); + overflow-y: auto; + display: flex; + flex-direction: column; + gap: 12px; + padding: 18px; + border-radius: 14px; + background: rgba(238, 242, 245, 0.97); + border: 1px solid rgba(120, 160, 200, 0.45); + box-shadow: 0 18px 40px rgba(0, 0, 0, 0.45); +} + +#destination-form, +#destination-results { + display: flex; + flex-direction: column; + gap: 10px; +} + +.dest-row { + display: flex; + align-items: center; + gap: 10px; +} + +/* Fixed basis keeps the three fields on one left edge regardless of + how wide the individual label text is */ +.dest-label { + flex: 0 0 92px; + padding: 8px 10px; + border-radius: 8px; + background: #ccd4da; + color: #1c2b3d; + font-size: 0.7rem; + letter-spacing: 0.5px; + text-align: center; +} + +.dest-row input, +.dest-row select { + flex: 1 1 auto; + min-width: 0; + padding: 9px 12px; + font-family: inherit; + font-size: 0.9rem; + border-radius: 8px; + border: 1px solid rgba(80, 130, 180, 0.35); + background: #16283f; + color: #dceaf6; + outline: none; +} + +.dest-row input::placeholder { + color: rgba(190, 215, 235, 0.55); +} + +.dest-row input:focus, +.dest-row select:focus { + border-color: rgba(120, 200, 255, 0.85); +} + +.dest-row select option { + background: #16283f; + color: #dceaf6; +} + +#dest-result-list { + list-style: none; + max-height: 210px; + overflow-y: auto; + padding: 6px 4px; + border-radius: 10px; + border: 1px solid rgba(80, 130, 180, 0.35); + background: #16283f; + outline: none; +} + +#dest-result-list:focus { + border-color: rgba(120, 200, 255, 0.85); +} + +/* The dashed rule between rows is a bottom border on every row but the + last, so the list reads as separated entries rather than a paragraph */ +.dest-result { + padding: 9px 10px; + border-radius: 6px; + color: #dceaf6; + font-size: 0.85rem; + cursor: pointer; + border-bottom: 1px dashed rgba(140, 185, 225, 0.4); +} + +.dest-result:last-child { + border-bottom: none; +} + +.dest-result:hover { + background: rgba(90, 140, 190, 0.25); +} + +.dest-result.active { + background: rgba(110, 165, 215, 0.45); + color: #ffffff; +} + +.dest-message { + min-height: 1em; + font-size: 0.72rem; + color: #7a1f1f; +} + +#dest-results-message { + color: #33465c; +} + +.dest-actions { + display: flex; + gap: 12px; +} + +.dest-actions button { + flex: 1 1 0; + padding: 10px 12px; + font-family: inherit; + font-size: 0.85rem; + border-radius: 8px; + border: 1px solid rgba(80, 130, 180, 0.35); + background: #16283f; + color: #dceaf6; + cursor: pointer; + transition: background 0.2s, border-color 0.2s; +} + +.dest-actions button:hover:not(:disabled) { + background: #21395a; + border-color: rgba(120, 200, 255, 0.7); +} + +.dest-actions button:disabled { + opacity: 0.5; + cursor: default; +} + +/* ---- Selector Panel Buttons ---- */ +#selector-panel button { + padding: 5px 12px; + font-size: 0.75rem; + font-family: inherit; + border: 1px solid rgba(100, 200, 255, 0.3); + border-radius: 3px; + background: rgba(10, 20, 40, 0.9); + color: #c0e0f0; + cursor: pointer; + text-transform: uppercase; + letter-spacing: 1px; + transition: border-color 0.2s, background 0.2s; +} + +#selector-panel button:hover { + border-color: rgba(100, 200, 255, 0.6); + background: rgba(20, 40, 70, 0.9); +} + +#btn-export-json { + color: #88ddaa !important; + border-color: rgba(100, 255, 160, 0.3) !important; +} + +#btn-export-json:hover { + border-color: rgba(100, 255, 160, 0.6) !important; +} + +/* ---- Render Config Panel ---- */ +#config-panel { + position: fixed; + top: calc(var(--top-bar-height, 56px) + 12px); + left: 12px; + z-index: 100; + width: 320px; + max-width: calc(100vw - 24px); + max-height: calc(100vh - var(--top-bar-height, 56px) - 36px); + overflow-y: auto; + background: rgba(0, 8, 24, 0.88); + padding: 14px 16px; + border-radius: 6px; + border: 1px solid rgba(100, 200, 255, 0.2); + backdrop-filter: blur(10px); + font-size: 0.72rem; +} + +#config-panel h3 { + font-size: 0.85rem; + color: rgba(180, 220, 255, 0.9); + font-weight: 600; + letter-spacing: 1px; + text-transform: uppercase; + margin-bottom: 4px; +} + +#config-panel .config-hint { + font-size: 0.65rem; + color: rgba(120, 170, 210, 0.6); + margin-bottom: 12px; + line-height: 1.4; +} + +#config-panel fieldset { + border: 1px solid rgba(100, 200, 255, 0.12); + border-radius: 4px; + padding: 8px 10px; + margin-bottom: 10px; +} + +#config-panel legend { + font-size: 0.7rem; + color: #66aacc; + font-weight: bold; + text-transform: uppercase; + letter-spacing: 1px; + padding: 0 6px; +} + +.cfg-row { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 6px; +} + +.cfg-row label { + flex: 0 0 100px; + font-size: 0.68rem; + color: rgba(160, 200, 230, 0.8); + text-align: right; +} + +.cfg-row input[type="range"] { + flex: 1; + height: 4px; + -webkit-appearance: none; + appearance: none; + background: rgba(50, 80, 120, 0.5); + border-radius: 2px; + outline: none; +} + +.cfg-row input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: none; + width: 12px; + height: 12px; + border-radius: 50%; + background: #44ccff; + cursor: pointer; + border: 1px solid rgba(0, 0, 0, 0.3); +} + +.cfg-row input[type="range"]::-moz-range-thumb { + width: 12px; + height: 12px; + border-radius: 50%; + background: #44ccff; + cursor: pointer; + border: 1px solid rgba(0, 0, 0, 0.3); +} + +.cfg-row input[type="checkbox"] { + width: 14px; + height: 14px; + cursor: pointer; + accent-color: #44ccff; +} + +.cfg-row span { + flex: 0 0 50px; + font-size: 0.65rem; + color: rgba(100, 220, 255, 0.85); + text-align: right; + font-variant-numeric: tabular-nums; +} + +/* Scrollbar has styling for config panel */ +#config-panel::-webkit-scrollbar { + width: 4px; +} + +#config-panel::-webkit-scrollbar-track { + background: transparent; +} + +#config-panel::-webkit-scrollbar-thumb { + background: rgba(100, 200, 255, 0.2); + border-radius: 2px; +} diff --git a/extensions/flight-map-canvas/game/terrainFill.js b/extensions/flight-map-canvas/game/terrainFill.js new file mode 100644 index 00000000..2fb4c9a7 --- /dev/null +++ b/extensions/flight-map-canvas/game/terrainFill.js @@ -0,0 +1,441 @@ +/************************************************************************************ + * TerrainFill - Fills unloaded terrain gaps using sampled colors * + * from the rendered viewport. * + * * + * Algorithm: * + * 1. Render scene (without fill) to a low-res offscreen target * + * 2. Sample 10x10px patches from each of the 4 viewport borders (40 samples) * + * 3. Sample 10x10px patches from the middle area (5 samples) * + * 4. Sample 5x5px patches from padding perimeter in flight direction (4 samples) * + * 5. Filter out placeholder/sky/water colors * + * 6. Generate a fill texture by blending sampled colors with value noise * + * 7. Apply the texture to a large fill plane between tiles and water * + ***********************************************************************************/ +function TerrainFill(renderer, scene, camera) { + this.renderer = renderer; + this.scene = scene; + this.camera = camera; + + // Low-res render target for viewport sampling + this.sampleW = 256; + this.sampleH = 256; + this.sampleTarget = new THREE.WebGLRenderTarget(this.sampleW, this.sampleH); + this.sampleBuffer = new Uint8Array(this.sampleW * this.sampleH * 4); + + // Fill texture canvas + this.texW = 256; + this.texH = 256; + this.fillCanvas = document.createElement('canvas'); + this.fillCanvas.width = this.texW; + this.fillCanvas.height = this.texH; + this.fillCtx = this.fillCanvas.getContext('2d'); + + // Initialize with placeholder color + this.fillCtx.fillStyle = '#2a3a2a'; + this.fillCtx.fillRect(0, 0, this.texW, this.texH); + + // Three.js canvas texture for the fill plane + this.fillTexture = new THREE.CanvasTexture(this.fillCanvas); + this.fillTexture.wrapS = THREE.RepeatWrapping; + this.fillTexture.wrapT = THREE.RepeatWrapping; + this.fillTexture.repeat.set(50, 50); + + // Fill plane mesh sitting between tile meshes (y=0) and water (y=-2) + var geo = new THREE.PlaneGeometry(30000, 30000); + var mat = new THREE.MeshBasicMaterial({ map: this.fillTexture }); + this.fillMesh = new THREE.Mesh(geo, mat); + this.fillMesh.rotation.x = -Math.PI / 2; + this.fillMesh.position.y = -0.5; + scene.add(this.fillMesh); + + // Collected sample colors (array of {r,g,b} objects) + this.sampleColors = []; + + // Timing + this.frameCount = 0; + this.sampleInterval = 45; // Sample every N frames + + // Time-based filler pattern update interval (seconds) + this.updateIntervalSec = 10; + this.lastUpdateTime = 0; + + // Configurable patch counts and sizes (overridden by RenderConfig) + this.perimeterPatchCount = 10; + this.perimeterPatchSize = 10; + this.centerPatchCount = 5; + this.centerPatchSize = 10; + this.paddingPatchCount = 4; + this.paddingPatchSize = 5; + + // Cloud overlay effect applied to the fill area + this.cloudOverlay = { + enabled: true, + opacity: 0.35, + speed: 0.0004, + coverage: 0.5, + scale: 0.008, + time: 0 + }; + + // Cloud canvas and texture (rendered on top of fill plane) + this.cloudCanvas = document.createElement('canvas'); + this.cloudCanvas.width = this.texW; + this.cloudCanvas.height = this.texH; + this.cloudCtx = this.cloudCanvas.getContext('2d'); + + this.cloudTexture = new THREE.CanvasTexture(this.cloudCanvas); + this.cloudTexture.wrapS = THREE.RepeatWrapping; + this.cloudTexture.wrapT = THREE.RepeatWrapping; + this.cloudTexture.repeat.set(50, 50); + + var cloudGeo = new THREE.PlaneGeometry(30000, 30000); + var cloudMat = new THREE.MeshBasicMaterial({ + map: this.cloudTexture, + transparent: true, + depthWrite: false, + opacity: 1.0 + }); + this.cloudMesh = new THREE.Mesh(cloudGeo, cloudMat); + this.cloudMesh.rotation.x = -Math.PI / 2; + this.cloudMesh.position.y = -0.3; + scene.add(this.cloudMesh); + + // Pre-compute noise permutation table + this.perm = new Array(512); + var p = new Array(256); + for (var i = 0; i < 256; i++) p[i] = i; + for (var i = 255; i > 0; i--) { + var j = Math.floor(Math.random() * (i + 1)); + var tmp = p[i]; p[i] = p[j]; p[j] = tmp; + } + for (var i = 0; i < 512; i++) this.perm[i] = p[i & 255]; + + // Second permutation for cloud noise (different seed) + this.cloudPerm = new Array(512); + var cp = new Array(256); + for (var i = 0; i < 256; i++) cp[i] = i; + for (var i = 255; i > 0; i--) { + var j = Math.floor(Math.random() * (i + 1)); + var tmp = cp[i]; cp[i] = cp[j]; cp[j] = tmp; + } + for (var i = 0; i < 512; i++) this.cloudPerm[i] = cp[i & 255]; + + // Pre-compute noise map (noise values won't change, only color mapping does) + this.noiseMap = new Float32Array(this.texW * this.texH); + for (var y = 0; y < this.texH; y++) { + for (var x = 0; x < this.texW; x++) { + var n1 = this._noise2d(x * 0.012, y * 0.012); + var n2 = this._noise2d(x * 0.035 + 97.3, y * 0.035 + 97.3) * 0.5; + var n3 = this._noise2d(x * 0.08 + 231.7, y * 0.08 + 231.7) * 0.25; + this.noiseMap[y * this.texW + x] = (n1 + n2 + n3) / 1.75; + } + } +} + +/** + * Called each frame after main render. Periodically samples the viewport + * and regenerates the fill texture. + */ +TerrainFill.prototype.update = function (flightHeading) { + // Keep fill plane centered on camera + this.fillMesh.position.x = this.camera.position.x; + this.fillMesh.position.z = this.camera.position.z; + + // Keep cloud mesh centered on camera + this.cloudMesh.position.x = this.camera.position.x; + this.cloudMesh.position.z = this.camera.position.z; + + this.frameCount++; + if (this.frameCount % this.sampleInterval !== 0) return; + + // Collect viewport samples every sampleInterval frames + this._collectSamples(flightHeading); + + // Regenerate fill texture on a time-based interval (seconds) + var now = performance.now() / 1000; + if (this.sampleColors.length > 20 && (now - this.lastUpdateTime) >= this.updateIntervalSec) { + this._generateFillTexture(); + this.lastUpdateTime = now; + } + + // Update cloud effect + this._updateCloud(); +}; + +/** + * Samples colors from the rendered viewport at border, middle, + * and padding perimeter positions. + */ +TerrainFill.prototype._collectSamples = function (flightHeading) { + // Hide generated overlays so we only sample actual terrain + sky + var cloudWasVisible = this.cloudMesh.visible; + this.fillMesh.visible = false; + this.cloudMesh.visible = false; + + // Render scene to low-res offscreen target + this.renderer.setRenderTarget(this.sampleTarget); + this.renderer.render(this.scene, this.camera); + this.renderer.setRenderTarget(null); + + this.fillMesh.visible = true; + this.cloudMesh.visible = cloudWasVisible; + + // Read pixels from the render target + this.renderer.readRenderTargetPixels( + this.sampleTarget, 0, 0, + this.sampleW, this.sampleH, + this.sampleBuffer + ); + + var w = this.sampleW; + var h = this.sampleH; + var buf = this.sampleBuffer; + var self = this; + this.sampleColors = []; + + // Helper: extract valid (non-placeholder/sky/water) colors from a patch + function extractPatch(px, py, size) { + var result = []; + for (var dy = 0; dy < size; dy++) { + for (var dx = 0; dx < size; dx++) { + var sx = Math.max(0, Math.min(px + dx, w - 1)); + var sy = Math.max(0, Math.min(py + dy, h - 1)); + var idx = (sy * w + sx) * 4; + var r = buf[idx], g = buf[idx + 1], b = buf[idx + 2]; + if (!self._isSkipColor(r, g, b)) { + result.push({ r: r, g: g, b: b }); + } + } + } + return result; + } + + var borderDepth = Math.max(Math.floor(h * 0.08), 8); + var patchSize = this.perimeterPatchSize; + var smallPatch = this.paddingPatchSize; + var perimCount = this.perimeterPatchCount; + var centerCount = this.centerPatchCount; + var centerSize = this.centerPatchSize; + var padCount = this.paddingPatchCount; + + // ---- Border samples: perimCount per border ---- + + // Top border + for (var i = 0; i < perimCount; i++) { + var x = Math.floor(Math.random() * (w - patchSize)); + var y = Math.floor(Math.random() * borderDepth); + this.sampleColors = this.sampleColors.concat(extractPatch(x, y, patchSize)); + } + // Bottom border + for (var i = 0; i < perimCount; i++) { + var x = Math.floor(Math.random() * (w - patchSize)); + var y = h - borderDepth + Math.floor(Math.random() * Math.max(1, borderDepth - patchSize)); + this.sampleColors = this.sampleColors.concat(extractPatch(x, y, patchSize)); + } + // Left border + for (var i = 0; i < perimCount; i++) { + var x = Math.floor(Math.random() * borderDepth); + var y = Math.floor(Math.random() * (h - patchSize)); + this.sampleColors = this.sampleColors.concat(extractPatch(x, y, patchSize)); + } + // Right border + for (var i = 0; i < perimCount; i++) { + var x = w - borderDepth + Math.floor(Math.random() * Math.max(1, borderDepth - patchSize)); + var y = Math.floor(Math.random() * (h - patchSize)); + this.sampleColors = this.sampleColors.concat(extractPatch(x, y, patchSize)); + } + + // ---- Middle area: centerCount samples ---- + var midRange = Math.min(w, h) / 4; + for (var i = 0; i < centerCount; i++) { + var x = Math.floor(w / 2 - midRange / 2 + Math.random() * midRange); + var y = Math.floor(h / 2 - midRange / 2 + Math.random() * midRange); + this.sampleColors = this.sampleColors.concat(extractPatch(x, y, centerSize)); + } + + // ---- Padding perimeter: padCount samples toward flight direction ---- + var headRad = ((flightHeading || 0)) * Math.PI / 180; + var dirX = Math.sin(headRad); + var dirY = -Math.cos(headRad); + for (var i = 0; i < padCount; i++) { + var dist = 0.25 + Math.random() * 0.35; + var spread = (Math.random() - 0.5) * 0.4; + var sx = Math.floor(w / 2 + (dirX * dist + dirY * spread) * w * 0.45); + var sy = Math.floor(h / 2 + (dirY * dist - dirX * spread) * h * 0.45); + sx = Math.max(0, Math.min(sx, w - smallPatch)); + sy = Math.max(0, Math.min(sy, h - smallPatch)); + this.sampleColors = this.sampleColors.concat(extractPatch(sx, sy, smallPatch)); + } +}; + +/** + * Checks whether a pixel color should be skipped during sampling + * (placeholder tiles, sky, water, or black). + */ +TerrainFill.prototype._isSkipColor = function (r, g, b) { + // Placeholder dark green: #2a3a2a (42, 58, 42) + if (Math.abs(r - 42) < 20 && Math.abs(g - 58) < 20 && Math.abs(b - 42) < 20) return true; + // Sky blue: #87CEEB (135, 206, 235) + if (Math.abs(r - 135) < 35 && Math.abs(g - 206) < 35 && Math.abs(b - 235) < 35) return true; + // Water blue: #1a4a7a (26, 74, 122) + if (Math.abs(r - 26) < 25 && Math.abs(g - 74) < 25 && Math.abs(b - 122) < 25) return true; + // Near-black + if (r < 8 && g < 8 && b < 8) return true; + // Fill plane color itself (dark placeholder) + if (r < 50 && g < 65 && b < 50 && Math.abs(r - b) < 10) return true; + return false; +}; + +/** + * Generates the fill texture by mapping sampled colors through + * a pre-computed noise map. Produces a natural-looking blend of + * terrain colors that fills gaps between loaded tiles. + */ +TerrainFill.prototype._generateFillTexture = function () { + var colors = this.sampleColors; + if (colors.length < 10) return; + + var ctx = this.fillCtx; + var w = this.texW; + var h = this.texH; + var imgData = ctx.createImageData(w, h); + var data = imgData.data; + var numColors = colors.length; + + for (var y = 0; y < h; y++) { + for (var x = 0; x < w; x++) { + // Look up pre-computed noise value (0-1) + var noise = this.noiseMap[y * w + x]; + + // Map noise to color index range and blend between neighbors + var fidx = noise * (numColors - 1); + var idx1 = Math.floor(fidx); + var idx2 = Math.min(idx1 + 1, numColors - 1); + var blend = fidx - idx1; + + var c1 = colors[idx1]; + var c2 = colors[idx2]; + + var px = (y * w + x) * 4; + data[px] = Math.round(c1.r + (c2.r - c1.r) * blend); + data[px + 1] = Math.round(c1.g + (c2.g - c1.g) * blend); + data[px + 2] = Math.round(c1.b + (c2.b - c1.b) * blend); + data[px + 3] = 255; + } + } + + ctx.putImageData(imgData, 0, 0); + this.fillTexture.needsUpdate = true; +}; + +/** + * 2D value noise using the pre-computed permutation table. + */ +TerrainFill.prototype._noise2d = function (x, y) { + var xi = Math.floor(x) & 255; + var yi = Math.floor(y) & 255; + var xf = x - Math.floor(x); + var yf = y - Math.floor(y); + + // Smoothstep fade curves + var u = xf * xf * (3 - 2 * xf); + var v = yf * yf * (3 - 2 * yf); + + // Hash four corners + var aa = this.perm[this.perm[xi] + yi] / 255; + var ab = this.perm[this.perm[xi] + yi + 1] / 255; + var ba = this.perm[this.perm[xi + 1] + yi] / 255; + var bb = this.perm[this.perm[xi + 1] + yi + 1] / 255; + + // Bilinear interpolation + var x1 = aa * (1 - u) + ba * u; + var x2 = ab * (1 - u) + bb * u; + return x1 * (1 - v) + x2 * v; +}; + +/** + * Generates animated cloud overlay texture using time-offset noise. + * The cloud effect applies a semi-transparent white layer over the + * fill area, simulating drifting cloud cover. + */ +TerrainFill.prototype._updateCloud = function () { + if (!this.cloudOverlay.enabled) { + this.cloudMesh.visible = false; + return; + } + this.cloudMesh.visible = true; + this.cloudOverlay.time += this.cloudOverlay.speed * this.sampleInterval; + + var ctx = this.cloudCtx; + var w = this.texW; + var h = this.texH; + var imgData = ctx.createImageData(w, h); + var data = imgData.data; + var t = this.cloudOverlay.time; + var scale = this.cloudOverlay.scale; + var coverage = this.cloudOverlay.coverage; + var opacity = this.cloudOverlay.opacity; + + for (var y = 0; y < h; y++) { + for (var x = 0; x < w; x++) { + // Multi-octave noise with time offset for drift + var n1 = this._cloudNoise2d(x * scale + t, y * scale + t * 0.7); + var n2 = this._cloudNoise2d(x * scale * 2.3 + 50 + t * 1.3, y * scale * 2.3 + 50 + t * 0.9) * 0.5; + var n3 = this._cloudNoise2d(x * scale * 5.1 + 120 - t * 0.5, y * scale * 5.1 + 120 + t * 0.3) * 0.25; + var noise = (n1 + n2 + n3) / 1.75; + + // Apply coverage threshold: lower coverage = fewer clouds + var cloudDensity = Math.max(0, noise - (1 - coverage)) / coverage; + cloudDensity = Math.min(1, cloudDensity); + + // Smooth edges + cloudDensity = cloudDensity * cloudDensity * (3 - 2 * cloudDensity); + + var alpha = Math.round(cloudDensity * opacity * 255); + var px = (y * w + x) * 4; + data[px] = 255; // White clouds + data[px + 1] = 255; + data[px + 2] = 255; + data[px + 3] = alpha; + } + } + + ctx.putImageData(imgData, 0, 0); + this.cloudTexture.needsUpdate = true; +}; + +/** + * 2D value noise using the cloud-specific permutation table. + */ +TerrainFill.prototype._cloudNoise2d = function (x, y) { + var xi = Math.floor(x) & 255; + var yi = Math.floor(y) & 255; + var xf = x - Math.floor(x); + var yf = y - Math.floor(y); + + var u = xf * xf * (3 - 2 * xf); + var v = yf * yf * (3 - 2 * yf); + + var aa = this.cloudPerm[this.cloudPerm[xi] + yi] / 255; + var ab = this.cloudPerm[this.cloudPerm[xi] + yi + 1] / 255; + var ba = this.cloudPerm[this.cloudPerm[xi + 1] + yi] / 255; + var bb = this.cloudPerm[this.cloudPerm[xi + 1] + yi + 1] / 255; + + var x1 = aa * (1 - u) + ba * u; + var x2 = ab * (1 - u) + bb * u; + return x1 * (1 - v) + x2 * v; +}; + +/** + * Reset fill state when switching capitals. + */ +TerrainFill.prototype.reset = function () { + this.sampleColors = []; + this.frameCount = 0; + this.fillCtx.fillStyle = '#2a3a2a'; + this.fillCtx.fillRect(0, 0, this.texW, this.texH); + this.fillTexture.needsUpdate = true; + this.cloudOverlay.time = 0; + this.cloudCtx.clearRect(0, 0, this.texW, this.texH); + this.cloudTexture.needsUpdate = true; +}; diff --git a/extensions/flight-map-canvas/game/vendor/three.min.js b/extensions/flight-map-canvas/game/vendor/three.min.js new file mode 100644 index 00000000..b14f47c0 --- /dev/null +++ b/extensions/flight-map-canvas/game/vendor/three.min.js @@ -0,0 +1,6 @@ +/** + * @license + * Copyright 2010-2021 Three.js Authors + * SPDX-License-Identifier: MIT + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).THREE={})}(this,(function(t){"use strict";const e="128",n=100,i=300,r=301,s=302,a=303,o=304,l=306,c=307,h=1e3,u=1001,d=1002,p=1003,m=1004,f=1005,g=1006,v=1007,y=1008,x=1009,_=1012,w=1014,b=1015,M=1016,S=1020,T=1022,E=1023,A=1026,L=1027,R=33776,C=33777,P=33778,D=33779,I=35840,N=35841,B=35842,z=35843,F=37492,O=37496,H=2300,G=2301,U=2302,k=2400,V=2401,W=2402,j=2500,q=2501,X=3e3,Y=3001,Z=3007,J=3002,Q=3004,K=3005,$=3006,tt=7680,et=35044,nt=35048,it="300 es";class rt{addEventListener(t,e){void 0===this._listeners&&(this._listeners={});const n=this._listeners;void 0===n[t]&&(n[t]=[]),-1===n[t].indexOf(e)&&n[t].push(e)}hasEventListener(t,e){if(void 0===this._listeners)return!1;const n=this._listeners;return void 0!==n[t]&&-1!==n[t].indexOf(e)}removeEventListener(t,e){if(void 0===this._listeners)return;const n=this._listeners[t];if(void 0!==n){const t=n.indexOf(e);-1!==t&&n.splice(t,1)}}dispatchEvent(t){if(void 0===this._listeners)return;const e=this._listeners[t.type];if(void 0!==e){t.target=this;const n=e.slice(0);for(let e=0,i=n.length;e>8&255]+st[t>>16&255]+st[t>>24&255]+"-"+st[255&e]+st[e>>8&255]+"-"+st[e>>16&15|64]+st[e>>24&255]+"-"+st[63&n|128]+st[n>>8&255]+"-"+st[n>>16&255]+st[n>>24&255]+st[255&i]+st[i>>8&255]+st[i>>16&255]+st[i>>24&255]).toUpperCase()}function ht(t,e,n){return Math.max(e,Math.min(n,t))}function ut(t,e){return(t%e+e)%e}function dt(t,e,n){return(1-n)*t+n*e}function pt(t){return 0==(t&t-1)&&0!==t}function mt(t){return Math.pow(2,Math.ceil(Math.log(t)/Math.LN2))}function ft(t){return Math.pow(2,Math.floor(Math.log(t)/Math.LN2))}var gt=Object.freeze({__proto__:null,DEG2RAD:ot,RAD2DEG:lt,generateUUID:ct,clamp:ht,euclideanModulo:ut,mapLinear:function(t,e,n,i,r){return i+(t-e)*(r-i)/(n-e)},inverseLerp:function(t,e,n){return t!==e?(n-t)/(e-t):0},lerp:dt,damp:function(t,e,n,i){return dt(t,e,1-Math.exp(-n*i))},pingpong:function(t,e=1){return e-Math.abs(ut(t,2*e)-e)},smoothstep:function(t,e,n){return t<=e?0:t>=n?1:(t=(t-e)/(n-e))*t*(3-2*t)},smootherstep:function(t,e,n){return t<=e?0:t>=n?1:(t=(t-e)/(n-e))*t*t*(t*(6*t-15)+10)},randInt:function(t,e){return t+Math.floor(Math.random()*(e-t+1))},randFloat:function(t,e){return t+Math.random()*(e-t)},randFloatSpread:function(t){return t*(.5-Math.random())},seededRandom:function(t){return void 0!==t&&(at=t%2147483647),at=16807*at%2147483647,(at-1)/2147483646},degToRad:function(t){return t*ot},radToDeg:function(t){return t*lt},isPowerOfTwo:pt,ceilPowerOfTwo:mt,floorPowerOfTwo:ft,setQuaternionFromProperEuler:function(t,e,n,i,r){const s=Math.cos,a=Math.sin,o=s(n/2),l=a(n/2),c=s((e+i)/2),h=a((e+i)/2),u=s((e-i)/2),d=a((e-i)/2),p=s((i-e)/2),m=a((i-e)/2);switch(r){case"XYX":t.set(o*h,l*u,l*d,o*c);break;case"YZY":t.set(l*d,o*h,l*u,o*c);break;case"ZXZ":t.set(l*u,l*d,o*h,o*c);break;case"XZX":t.set(o*h,l*m,l*p,o*c);break;case"YXY":t.set(l*p,o*h,l*m,o*c);break;case"ZYZ":t.set(l*m,l*p,o*h,o*c);break;default:console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+r)}}});class vt{constructor(t=0,e=0){this.x=t,this.y=e}get width(){return this.x}set width(t){this.x=t}get height(){return this.y}set height(t){this.y=t}set(t,e){return this.x=t,this.y=e,this}setScalar(t){return this.x=t,this.y=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;default:throw new Error("index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y)}copy(t){return this.x=t.x,this.y=t.y,this}add(t,e){return void 0!==e?(console.warn("THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(t,e)):(this.x+=t.x,this.y+=t.y,this)}addScalar(t){return this.x+=t,this.y+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this}sub(t,e){return void 0!==e?(console.warn("THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(t,e)):(this.x-=t.x,this.y-=t.y,this)}subScalar(t){return this.x-=t,this.y-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this}multiply(t){return this.x*=t.x,this.y*=t.y,this}multiplyScalar(t){return this.x*=t,this.y*=t,this}divide(t){return this.x/=t.x,this.y/=t.y,this}divideScalar(t){return this.multiplyScalar(1/t)}applyMatrix3(t){const e=this.x,n=this.y,i=t.elements;return this.x=i[0]*e+i[3]*n+i[6],this.y=i[1]*e+i[4]*n+i[7],this}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this}clamp(t,e){return this.x=Math.max(t.x,Math.min(e.x,this.x)),this.y=Math.max(t.y,Math.min(e.y,this.y)),this}clampScalar(t,e){return this.x=Math.max(t,Math.min(e,this.x)),this.y=Math.max(t,Math.min(e,this.y)),this}clampLength(t,e){const n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(t,Math.min(e,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}roundToZero(){return this.x=this.x<0?Math.ceil(this.x):Math.floor(this.x),this.y=this.y<0?Math.ceil(this.y):Math.floor(this.y),this}negate(){return this.x=-this.x,this.y=-this.y,this}dot(t){return this.x*t.x+this.y*t.y}cross(t){return this.x*t.y-this.y*t.x}lengthSq(){return this.x*this.x+this.y*this.y}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)}normalize(){return this.divideScalar(this.length()||1)}angle(){return Math.atan2(-this.y,-this.x)+Math.PI}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,n=this.y-t.y;return e*e+n*n}manhattanDistanceTo(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this}lerpVectors(t,e,n){return this.x=t.x+(e.x-t.x)*n,this.y=t.y+(e.y-t.y)*n,this}equals(t){return t.x===this.x&&t.y===this.y}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t}fromBufferAttribute(t,e,n){return void 0!==n&&console.warn("THREE.Vector2: offset has been removed from .fromBufferAttribute()."),this.x=t.getX(e),this.y=t.getY(e),this}rotateAround(t,e){const n=Math.cos(e),i=Math.sin(e),r=this.x-t.x,s=this.y-t.y;return this.x=r*n-s*i+t.x,this.y=r*i+s*n+t.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}}vt.prototype.isVector2=!0;class yt{constructor(){this.elements=[1,0,0,0,1,0,0,0,1],arguments.length>0&&console.error("THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.")}set(t,e,n,i,r,s,a,o,l){const c=this.elements;return c[0]=t,c[1]=i,c[2]=a,c[3]=e,c[4]=r,c[5]=o,c[6]=n,c[7]=s,c[8]=l,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(t){const e=this.elements,n=t.elements;return e[0]=n[0],e[1]=n[1],e[2]=n[2],e[3]=n[3],e[4]=n[4],e[5]=n[5],e[6]=n[6],e[7]=n[7],e[8]=n[8],this}extractBasis(t,e,n){return t.setFromMatrix3Column(this,0),e.setFromMatrix3Column(this,1),n.setFromMatrix3Column(this,2),this}setFromMatrix4(t){const e=t.elements;return this.set(e[0],e[4],e[8],e[1],e[5],e[9],e[2],e[6],e[10]),this}multiply(t){return this.multiplyMatrices(this,t)}premultiply(t){return this.multiplyMatrices(t,this)}multiplyMatrices(t,e){const n=t.elements,i=e.elements,r=this.elements,s=n[0],a=n[3],o=n[6],l=n[1],c=n[4],h=n[7],u=n[2],d=n[5],p=n[8],m=i[0],f=i[3],g=i[6],v=i[1],y=i[4],x=i[7],_=i[2],w=i[5],b=i[8];return r[0]=s*m+a*v+o*_,r[3]=s*f+a*y+o*w,r[6]=s*g+a*x+o*b,r[1]=l*m+c*v+h*_,r[4]=l*f+c*y+h*w,r[7]=l*g+c*x+h*b,r[2]=u*m+d*v+p*_,r[5]=u*f+d*y+p*w,r[8]=u*g+d*x+p*b,this}multiplyScalar(t){const e=this.elements;return e[0]*=t,e[3]*=t,e[6]*=t,e[1]*=t,e[4]*=t,e[7]*=t,e[2]*=t,e[5]*=t,e[8]*=t,this}determinant(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],s=t[4],a=t[5],o=t[6],l=t[7],c=t[8];return e*s*c-e*a*l-n*r*c+n*a*o+i*r*l-i*s*o}invert(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],s=t[4],a=t[5],o=t[6],l=t[7],c=t[8],h=c*s-a*l,u=a*o-c*r,d=l*r-s*o,p=e*h+n*u+i*d;if(0===p)return this.set(0,0,0,0,0,0,0,0,0);const m=1/p;return t[0]=h*m,t[1]=(i*l-c*n)*m,t[2]=(a*n-i*s)*m,t[3]=u*m,t[4]=(c*e-i*o)*m,t[5]=(i*r-a*e)*m,t[6]=d*m,t[7]=(n*o-l*e)*m,t[8]=(s*e-n*r)*m,this}transpose(){let t;const e=this.elements;return t=e[1],e[1]=e[3],e[3]=t,t=e[2],e[2]=e[6],e[6]=t,t=e[5],e[5]=e[7],e[7]=t,this}getNormalMatrix(t){return this.setFromMatrix4(t).invert().transpose()}transposeIntoArray(t){const e=this.elements;return 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],this}setUvTransform(t,e,n,i,r,s,a){const o=Math.cos(r),l=Math.sin(r);return this.set(n*o,n*l,-n*(o*s+l*a)+s+t,-i*l,i*o,-i*(-l*s+o*a)+a+e,0,0,1),this}scale(t,e){const n=this.elements;return n[0]*=t,n[3]*=t,n[6]*=t,n[1]*=e,n[4]*=e,n[7]*=e,this}rotate(t){const e=Math.cos(t),n=Math.sin(t),i=this.elements,r=i[0],s=i[3],a=i[6],o=i[1],l=i[4],c=i[7];return i[0]=e*r+n*o,i[3]=e*s+n*l,i[6]=e*a+n*c,i[1]=-n*r+e*o,i[4]=-n*s+e*l,i[7]=-n*a+e*c,this}translate(t,e){const n=this.elements;return n[0]+=t*n[2],n[3]+=t*n[5],n[6]+=t*n[8],n[1]+=e*n[2],n[4]+=e*n[5],n[7]+=e*n[8],this}equals(t){const e=this.elements,n=t.elements;for(let t=0;t<9;t++)if(e[t]!==n[t])return!1;return!0}fromArray(t,e=0){for(let n=0;n<9;n++)this.elements[n]=t[n+e];return this}toArray(t=[],e=0){const n=this.elements;return t[e]=n[0],t[e+1]=n[1],t[e+2]=n[2],t[e+3]=n[3],t[e+4]=n[4],t[e+5]=n[5],t[e+6]=n[6],t[e+7]=n[7],t[e+8]=n[8],t}clone(){return(new this.constructor).fromArray(this.elements)}}let xt;yt.prototype.isMatrix3=!0;class _t{static getDataURL(t){if(/^data:/i.test(t.src))return t.src;if("undefined"==typeof HTMLCanvasElement)return t.src;let e;if(t instanceof HTMLCanvasElement)e=t;else{void 0===xt&&(xt=document.createElementNS("http://www.w3.org/1999/xhtml","canvas")),xt.width=t.width,xt.height=t.height;const n=xt.getContext("2d");t instanceof ImageData?n.putImageData(t,0,0):n.drawImage(t,0,0,t.width,t.height),e=xt}return e.width>2048||e.height>2048?(console.warn("THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons",t),e.toDataURL("image/jpeg",.6)):e.toDataURL("image/png")}}let wt=0;class bt extends rt{constructor(t=bt.DEFAULT_IMAGE,e=bt.DEFAULT_MAPPING,n=1001,i=1001,r=1006,s=1008,a=1023,o=1009,l=1,c=3e3){super(),Object.defineProperty(this,"id",{value:wt++}),this.uuid=ct(),this.name="",this.image=t,this.mipmaps=[],this.mapping=e,this.wrapS=n,this.wrapT=i,this.magFilter=r,this.minFilter=s,this.anisotropy=l,this.format=a,this.internalFormat=null,this.type=o,this.offset=new vt(0,0),this.repeat=new vt(1,1),this.center=new vt(0,0),this.rotation=0,this.matrixAutoUpdate=!0,this.matrix=new yt,this.generateMipmaps=!0,this.premultiplyAlpha=!1,this.flipY=!0,this.unpackAlignment=4,this.encoding=c,this.version=0,this.onUpdate=null}updateMatrix(){this.matrix.setUvTransform(this.offset.x,this.offset.y,this.repeat.x,this.repeat.y,this.rotation,this.center.x,this.center.y)}clone(){return(new this.constructor).copy(this)}copy(t){return this.name=t.name,this.image=t.image,this.mipmaps=t.mipmaps.slice(0),this.mapping=t.mapping,this.wrapS=t.wrapS,this.wrapT=t.wrapT,this.magFilter=t.magFilter,this.minFilter=t.minFilter,this.anisotropy=t.anisotropy,this.format=t.format,this.internalFormat=t.internalFormat,this.type=t.type,this.offset.copy(t.offset),this.repeat.copy(t.repeat),this.center.copy(t.center),this.rotation=t.rotation,this.matrixAutoUpdate=t.matrixAutoUpdate,this.matrix.copy(t.matrix),this.generateMipmaps=t.generateMipmaps,this.premultiplyAlpha=t.premultiplyAlpha,this.flipY=t.flipY,this.unpackAlignment=t.unpackAlignment,this.encoding=t.encoding,this}toJSON(t){const e=void 0===t||"string"==typeof t;if(!e&&void 0!==t.textures[this.uuid])return t.textures[this.uuid];const n={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],format:this.format,type:this.type,encoding:this.encoding,minFilter:this.minFilter,magFilter:this.magFilter,anisotropy:this.anisotropy,flipY:this.flipY,premultiplyAlpha:this.premultiplyAlpha,unpackAlignment:this.unpackAlignment};if(void 0!==this.image){const i=this.image;if(void 0===i.uuid&&(i.uuid=ct()),!e&&void 0===t.images[i.uuid]){let e;if(Array.isArray(i)){e=[];for(let t=0,n=i.length;t1)switch(this.wrapS){case h:t.x=t.x-Math.floor(t.x);break;case u:t.x=t.x<0?0:1;break;case d:1===Math.abs(Math.floor(t.x)%2)?t.x=Math.ceil(t.x)-t.x:t.x=t.x-Math.floor(t.x)}if(t.y<0||t.y>1)switch(this.wrapT){case h:t.y=t.y-Math.floor(t.y);break;case u:t.y=t.y<0?0:1;break;case d:1===Math.abs(Math.floor(t.y)%2)?t.y=Math.ceil(t.y)-t.y:t.y=t.y-Math.floor(t.y)}return this.flipY&&(t.y=1-t.y),t}set needsUpdate(t){!0===t&&this.version++}}function Mt(t){return"undefined"!=typeof HTMLImageElement&&t instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&t instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&t instanceof ImageBitmap?_t.getDataURL(t):t.data?{data:Array.prototype.slice.call(t.data),width:t.width,height:t.height,type:t.data.constructor.name}:(console.warn("THREE.Texture: Unable to serialize Texture."),{})}bt.DEFAULT_IMAGE=void 0,bt.DEFAULT_MAPPING=i,bt.prototype.isTexture=!0;class St{constructor(t=0,e=0,n=0,i=1){this.x=t,this.y=e,this.z=n,this.w=i}get width(){return this.z}set width(t){this.z=t}get height(){return this.w}set height(t){this.w=t}set(t,e,n,i){return this.x=t,this.y=e,this.z=n,this.w=i,this}setScalar(t){return this.x=t,this.y=t,this.z=t,this.w=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setZ(t){return this.z=t,this}setW(t){return this.w=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;case 3:this.w=e;break;default:throw new Error("index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y,this.z,this.w)}copy(t){return this.x=t.x,this.y=t.y,this.z=t.z,this.w=void 0!==t.w?t.w:1,this}add(t,e){return void 0!==e?(console.warn("THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(t,e)):(this.x+=t.x,this.y+=t.y,this.z+=t.z,this.w+=t.w,this)}addScalar(t){return this.x+=t,this.y+=t,this.z+=t,this.w+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this.w=t.w+e.w,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this.w+=t.w*e,this}sub(t,e){return void 0!==e?(console.warn("THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(t,e)):(this.x-=t.x,this.y-=t.y,this.z-=t.z,this.w-=t.w,this)}subScalar(t){return this.x-=t,this.y-=t,this.z-=t,this.w-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this.w=t.w-e.w,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this.w*=t.w,this}multiplyScalar(t){return this.x*=t,this.y*=t,this.z*=t,this.w*=t,this}applyMatrix4(t){const e=this.x,n=this.y,i=this.z,r=this.w,s=t.elements;return this.x=s[0]*e+s[4]*n+s[8]*i+s[12]*r,this.y=s[1]*e+s[5]*n+s[9]*i+s[13]*r,this.z=s[2]*e+s[6]*n+s[10]*i+s[14]*r,this.w=s[3]*e+s[7]*n+s[11]*i+s[15]*r,this}divideScalar(t){return this.multiplyScalar(1/t)}setAxisAngleFromQuaternion(t){this.w=2*Math.acos(t.w);const e=Math.sqrt(1-t.w*t.w);return e<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=t.x/e,this.y=t.y/e,this.z=t.z/e),this}setAxisAngleFromRotationMatrix(t){let e,n,i,r;const s=.01,a=.1,o=t.elements,l=o[0],c=o[4],h=o[8],u=o[1],d=o[5],p=o[9],m=o[2],f=o[6],g=o[10];if(Math.abs(c-u)o&&t>v?tv?o=0?1:-1,i=1-e*e;if(i>Number.EPSILON){const r=Math.sqrt(i),s=Math.atan2(r,e*n);t=Math.sin(t*s)/r,a=Math.sin(a*s)/r}const r=a*n;if(o=o*t+u*r,l=l*t+d*r,c=c*t+p*r,h=h*t+m*r,t===1-a){const t=1/Math.sqrt(o*o+l*l+c*c+h*h);o*=t,l*=t,c*=t,h*=t}}t[e]=o,t[e+1]=l,t[e+2]=c,t[e+3]=h}static multiplyQuaternionsFlat(t,e,n,i,r,s){const a=n[i],o=n[i+1],l=n[i+2],c=n[i+3],h=r[s],u=r[s+1],d=r[s+2],p=r[s+3];return t[e]=a*p+c*h+o*d-l*u,t[e+1]=o*p+c*u+l*h-a*d,t[e+2]=l*p+c*d+a*u-o*h,t[e+3]=c*p-a*h-o*u-l*d,t}get x(){return this._x}set x(t){this._x=t,this._onChangeCallback()}get y(){return this._y}set y(t){this._y=t,this._onChangeCallback()}get z(){return this._z}set z(t){this._z=t,this._onChangeCallback()}get w(){return this._w}set w(t){this._w=t,this._onChangeCallback()}set(t,e,n,i){return this._x=t,this._y=e,this._z=n,this._w=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._w)}copy(t){return this._x=t.x,this._y=t.y,this._z=t.z,this._w=t.w,this._onChangeCallback(),this}setFromEuler(t,e){if(!t||!t.isEuler)throw new Error("THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.");const n=t._x,i=t._y,r=t._z,s=t._order,a=Math.cos,o=Math.sin,l=a(n/2),c=a(i/2),h=a(r/2),u=o(n/2),d=o(i/2),p=o(r/2);switch(s){case"XYZ":this._x=u*c*h+l*d*p,this._y=l*d*h-u*c*p,this._z=l*c*p+u*d*h,this._w=l*c*h-u*d*p;break;case"YXZ":this._x=u*c*h+l*d*p,this._y=l*d*h-u*c*p,this._z=l*c*p-u*d*h,this._w=l*c*h+u*d*p;break;case"ZXY":this._x=u*c*h-l*d*p,this._y=l*d*h+u*c*p,this._z=l*c*p+u*d*h,this._w=l*c*h-u*d*p;break;case"ZYX":this._x=u*c*h-l*d*p,this._y=l*d*h+u*c*p,this._z=l*c*p-u*d*h,this._w=l*c*h+u*d*p;break;case"YZX":this._x=u*c*h+l*d*p,this._y=l*d*h+u*c*p,this._z=l*c*p-u*d*h,this._w=l*c*h-u*d*p;break;case"XZY":this._x=u*c*h-l*d*p,this._y=l*d*h-u*c*p,this._z=l*c*p+u*d*h,this._w=l*c*h+u*d*p;break;default:console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: "+s)}return!1!==e&&this._onChangeCallback(),this}setFromAxisAngle(t,e){const n=e/2,i=Math.sin(n);return this._x=t.x*i,this._y=t.y*i,this._z=t.z*i,this._w=Math.cos(n),this._onChangeCallback(),this}setFromRotationMatrix(t){const e=t.elements,n=e[0],i=e[4],r=e[8],s=e[1],a=e[5],o=e[9],l=e[2],c=e[6],h=e[10],u=n+a+h;if(u>0){const t=.5/Math.sqrt(u+1);this._w=.25/t,this._x=(c-o)*t,this._y=(r-l)*t,this._z=(s-i)*t}else if(n>a&&n>h){const t=2*Math.sqrt(1+n-a-h);this._w=(c-o)/t,this._x=.25*t,this._y=(i+s)/t,this._z=(r+l)/t}else if(a>h){const t=2*Math.sqrt(1+a-n-h);this._w=(r-l)/t,this._x=(i+s)/t,this._y=.25*t,this._z=(o+c)/t}else{const t=2*Math.sqrt(1+h-n-a);this._w=(s-i)/t,this._x=(r+l)/t,this._y=(o+c)/t,this._z=.25*t}return this._onChangeCallback(),this}setFromUnitVectors(t,e){let n=t.dot(e)+1;return nMath.abs(t.z)?(this._x=-t.y,this._y=t.x,this._z=0,this._w=n):(this._x=0,this._y=-t.z,this._z=t.y,this._w=n)):(this._x=t.y*e.z-t.z*e.y,this._y=t.z*e.x-t.x*e.z,this._z=t.x*e.y-t.y*e.x,this._w=n),this.normalize()}angleTo(t){return 2*Math.acos(Math.abs(ht(this.dot(t),-1,1)))}rotateTowards(t,e){const n=this.angleTo(t);if(0===n)return this;const i=Math.min(1,e/n);return this.slerp(t,i),this}identity(){return this.set(0,0,0,1)}invert(){return this.conjugate()}conjugate(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this}dot(t){return this._x*t._x+this._y*t._y+this._z*t._z+this._w*t._w}lengthSq(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w}length(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)}normalize(){let t=this.length();return 0===t?(this._x=0,this._y=0,this._z=0,this._w=1):(t=1/t,this._x=this._x*t,this._y=this._y*t,this._z=this._z*t,this._w=this._w*t),this._onChangeCallback(),this}multiply(t,e){return void 0!==e?(console.warn("THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."),this.multiplyQuaternions(t,e)):this.multiplyQuaternions(this,t)}premultiply(t){return this.multiplyQuaternions(t,this)}multiplyQuaternions(t,e){const n=t._x,i=t._y,r=t._z,s=t._w,a=e._x,o=e._y,l=e._z,c=e._w;return this._x=n*c+s*a+i*l-r*o,this._y=i*c+s*o+r*a-n*l,this._z=r*c+s*l+n*o-i*a,this._w=s*c-n*a-i*o-r*l,this._onChangeCallback(),this}slerp(t,e){if(0===e)return this;if(1===e)return this.copy(t);const n=this._x,i=this._y,r=this._z,s=this._w;let a=s*t._w+n*t._x+i*t._y+r*t._z;if(a<0?(this._w=-t._w,this._x=-t._x,this._y=-t._y,this._z=-t._z,a=-a):this.copy(t),a>=1)return this._w=s,this._x=n,this._y=i,this._z=r,this;const o=1-a*a;if(o<=Number.EPSILON){const t=1-e;return this._w=t*s+e*this._w,this._x=t*n+e*this._x,this._y=t*i+e*this._y,this._z=t*r+e*this._z,this.normalize(),this._onChangeCallback(),this}const l=Math.sqrt(o),c=Math.atan2(l,a),h=Math.sin((1-e)*c)/l,u=Math.sin(e*c)/l;return this._w=s*h+this._w*u,this._x=n*h+this._x*u,this._y=i*h+this._y*u,this._z=r*h+this._z*u,this._onChangeCallback(),this}slerpQuaternions(t,e,n){this.copy(t).slerp(e,n)}equals(t){return t._x===this._x&&t._y===this._y&&t._z===this._z&&t._w===this._w}fromArray(t,e=0){return this._x=t[e],this._y=t[e+1],this._z=t[e+2],this._w=t[e+3],this._onChangeCallback(),this}toArray(t=[],e=0){return t[e]=this._x,t[e+1]=this._y,t[e+2]=this._z,t[e+3]=this._w,t}fromBufferAttribute(t,e){return this._x=t.getX(e),this._y=t.getY(e),this._z=t.getZ(e),this._w=t.getW(e),this}_onChange(t){return this._onChangeCallback=t,this}_onChangeCallback(){}}At.prototype.isQuaternion=!0;class Lt{constructor(t=0,e=0,n=0){this.x=t,this.y=e,this.z=n}set(t,e,n){return void 0===n&&(n=this.z),this.x=t,this.y=e,this.z=n,this}setScalar(t){return this.x=t,this.y=t,this.z=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setZ(t){return this.z=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;default:throw new Error("index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y,this.z)}copy(t){return this.x=t.x,this.y=t.y,this.z=t.z,this}add(t,e){return void 0!==e?(console.warn("THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(t,e)):(this.x+=t.x,this.y+=t.y,this.z+=t.z,this)}addScalar(t){return this.x+=t,this.y+=t,this.z+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this}sub(t,e){return void 0!==e?(console.warn("THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(t,e)):(this.x-=t.x,this.y-=t.y,this.z-=t.z,this)}subScalar(t){return this.x-=t,this.y-=t,this.z-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this}multiply(t,e){return void 0!==e?(console.warn("THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."),this.multiplyVectors(t,e)):(this.x*=t.x,this.y*=t.y,this.z*=t.z,this)}multiplyScalar(t){return this.x*=t,this.y*=t,this.z*=t,this}multiplyVectors(t,e){return this.x=t.x*e.x,this.y=t.y*e.y,this.z=t.z*e.z,this}applyEuler(t){return t&&t.isEuler||console.error("THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order."),this.applyQuaternion(Ct.setFromEuler(t))}applyAxisAngle(t,e){return this.applyQuaternion(Ct.setFromAxisAngle(t,e))}applyMatrix3(t){const e=this.x,n=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[3]*n+r[6]*i,this.y=r[1]*e+r[4]*n+r[7]*i,this.z=r[2]*e+r[5]*n+r[8]*i,this}applyNormalMatrix(t){return this.applyMatrix3(t).normalize()}applyMatrix4(t){const e=this.x,n=this.y,i=this.z,r=t.elements,s=1/(r[3]*e+r[7]*n+r[11]*i+r[15]);return this.x=(r[0]*e+r[4]*n+r[8]*i+r[12])*s,this.y=(r[1]*e+r[5]*n+r[9]*i+r[13])*s,this.z=(r[2]*e+r[6]*n+r[10]*i+r[14])*s,this}applyQuaternion(t){const e=this.x,n=this.y,i=this.z,r=t.x,s=t.y,a=t.z,o=t.w,l=o*e+s*i-a*n,c=o*n+a*e-r*i,h=o*i+r*n-s*e,u=-r*e-s*n-a*i;return this.x=l*o+u*-r+c*-a-h*-s,this.y=c*o+u*-s+h*-r-l*-a,this.z=h*o+u*-a+l*-s-c*-r,this}project(t){return this.applyMatrix4(t.matrixWorldInverse).applyMatrix4(t.projectionMatrix)}unproject(t){return this.applyMatrix4(t.projectionMatrixInverse).applyMatrix4(t.matrixWorld)}transformDirection(t){const e=this.x,n=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[4]*n+r[8]*i,this.y=r[1]*e+r[5]*n+r[9]*i,this.z=r[2]*e+r[6]*n+r[10]*i,this.normalize()}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this}divideScalar(t){return this.multiplyScalar(1/t)}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this.z=Math.min(this.z,t.z),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this.z=Math.max(this.z,t.z),this}clamp(t,e){return this.x=Math.max(t.x,Math.min(e.x,this.x)),this.y=Math.max(t.y,Math.min(e.y,this.y)),this.z=Math.max(t.z,Math.min(e.z,this.z)),this}clampScalar(t,e){return this.x=Math.max(t,Math.min(e,this.x)),this.y=Math.max(t,Math.min(e,this.y)),this.z=Math.max(t,Math.min(e,this.z)),this}clampLength(t,e){const n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(t,Math.min(e,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this}roundToZero(){return this.x=this.x<0?Math.ceil(this.x):Math.floor(this.x),this.y=this.y<0?Math.ceil(this.y):Math.floor(this.y),this.z=this.z<0?Math.ceil(this.z):Math.floor(this.z),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this}dot(t){return this.x*t.x+this.y*t.y+this.z*t.z}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)}normalize(){return this.divideScalar(this.length()||1)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this.z+=(t.z-this.z)*e,this}lerpVectors(t,e,n){return this.x=t.x+(e.x-t.x)*n,this.y=t.y+(e.y-t.y)*n,this.z=t.z+(e.z-t.z)*n,this}cross(t,e){return void 0!==e?(console.warn("THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(t,e)):this.crossVectors(this,t)}crossVectors(t,e){const n=t.x,i=t.y,r=t.z,s=e.x,a=e.y,o=e.z;return this.x=i*o-r*a,this.y=r*s-n*o,this.z=n*a-i*s,this}projectOnVector(t){const e=t.lengthSq();if(0===e)return this.set(0,0,0);const n=t.dot(this)/e;return this.copy(t).multiplyScalar(n)}projectOnPlane(t){return Rt.copy(this).projectOnVector(t),this.sub(Rt)}reflect(t){return this.sub(Rt.copy(t).multiplyScalar(2*this.dot(t)))}angleTo(t){const e=Math.sqrt(this.lengthSq()*t.lengthSq());if(0===e)return Math.PI/2;const n=this.dot(t)/e;return Math.acos(ht(n,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,n=this.y-t.y,i=this.z-t.z;return e*e+n*n+i*i}manhattanDistanceTo(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)+Math.abs(this.z-t.z)}setFromSpherical(t){return this.setFromSphericalCoords(t.radius,t.phi,t.theta)}setFromSphericalCoords(t,e,n){const i=Math.sin(e)*t;return this.x=i*Math.sin(n),this.y=Math.cos(e)*t,this.z=i*Math.cos(n),this}setFromCylindrical(t){return this.setFromCylindricalCoords(t.radius,t.theta,t.y)}setFromCylindricalCoords(t,e,n){return this.x=t*Math.sin(e),this.y=n,this.z=t*Math.cos(e),this}setFromMatrixPosition(t){const e=t.elements;return this.x=e[12],this.y=e[13],this.z=e[14],this}setFromMatrixScale(t){const e=this.setFromMatrixColumn(t,0).length(),n=this.setFromMatrixColumn(t,1).length(),i=this.setFromMatrixColumn(t,2).length();return this.x=e,this.y=n,this.z=i,this}setFromMatrixColumn(t,e){return this.fromArray(t.elements,4*e)}setFromMatrix3Column(t,e){return this.fromArray(t.elements,3*e)}equals(t){return t.x===this.x&&t.y===this.y&&t.z===this.z}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this.z=t[e+2],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t[e+2]=this.z,t}fromBufferAttribute(t,e,n){return void 0!==n&&console.warn("THREE.Vector3: offset has been removed from .fromBufferAttribute()."),this.x=t.getX(e),this.y=t.getY(e),this.z=t.getZ(e),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this}}Lt.prototype.isVector3=!0;const Rt=new Lt,Ct=new At;class Pt{constructor(t=new Lt(1/0,1/0,1/0),e=new Lt(-1/0,-1/0,-1/0)){this.min=t,this.max=e}set(t,e){return this.min.copy(t),this.max.copy(e),this}setFromArray(t){let e=1/0,n=1/0,i=1/0,r=-1/0,s=-1/0,a=-1/0;for(let o=0,l=t.length;or&&(r=l),c>s&&(s=c),h>a&&(a=h)}return this.min.set(e,n,i),this.max.set(r,s,a),this}setFromBufferAttribute(t){let e=1/0,n=1/0,i=1/0,r=-1/0,s=-1/0,a=-1/0;for(let o=0,l=t.count;or&&(r=l),c>s&&(s=c),h>a&&(a=h)}return this.min.set(e,n,i),this.max.set(r,s,a),this}setFromPoints(t){this.makeEmpty();for(let e=0,n=t.length;ethis.max.x||t.ythis.max.y||t.zthis.max.z)}containsBox(t){return this.min.x<=t.min.x&&t.max.x<=this.max.x&&this.min.y<=t.min.y&&t.max.y<=this.max.y&&this.min.z<=t.min.z&&t.max.z<=this.max.z}getParameter(t,e){return void 0===e&&(console.warn("THREE.Box3: .getParameter() target is now required"),e=new Lt),e.set((t.x-this.min.x)/(this.max.x-this.min.x),(t.y-this.min.y)/(this.max.y-this.min.y),(t.z-this.min.z)/(this.max.z-this.min.z))}intersectsBox(t){return!(t.max.xthis.max.x||t.max.ythis.max.y||t.max.zthis.max.z)}intersectsSphere(t){return this.clampPoint(t.center,It),It.distanceToSquared(t.center)<=t.radius*t.radius}intersectsPlane(t){let e,n;return t.normal.x>0?(e=t.normal.x*this.min.x,n=t.normal.x*this.max.x):(e=t.normal.x*this.max.x,n=t.normal.x*this.min.x),t.normal.y>0?(e+=t.normal.y*this.min.y,n+=t.normal.y*this.max.y):(e+=t.normal.y*this.max.y,n+=t.normal.y*this.min.y),t.normal.z>0?(e+=t.normal.z*this.min.z,n+=t.normal.z*this.max.z):(e+=t.normal.z*this.max.z,n+=t.normal.z*this.min.z),e<=-t.constant&&n>=-t.constant}intersectsTriangle(t){if(this.isEmpty())return!1;this.getCenter(Ut),kt.subVectors(this.max,Ut),Bt.subVectors(t.a,Ut),zt.subVectors(t.b,Ut),Ft.subVectors(t.c,Ut),Ot.subVectors(zt,Bt),Ht.subVectors(Ft,zt),Gt.subVectors(Bt,Ft);let e=[0,-Ot.z,Ot.y,0,-Ht.z,Ht.y,0,-Gt.z,Gt.y,Ot.z,0,-Ot.x,Ht.z,0,-Ht.x,Gt.z,0,-Gt.x,-Ot.y,Ot.x,0,-Ht.y,Ht.x,0,-Gt.y,Gt.x,0];return!!jt(e,Bt,zt,Ft,kt)&&(e=[1,0,0,0,1,0,0,0,1],!!jt(e,Bt,zt,Ft,kt)&&(Vt.crossVectors(Ot,Ht),e=[Vt.x,Vt.y,Vt.z],jt(e,Bt,zt,Ft,kt)))}clampPoint(t,e){return void 0===e&&(console.warn("THREE.Box3: .clampPoint() target is now required"),e=new Lt),e.copy(t).clamp(this.min,this.max)}distanceToPoint(t){return It.copy(t).clamp(this.min,this.max).sub(t).length()}getBoundingSphere(t){return void 0===t&&console.error("THREE.Box3: .getBoundingSphere() target is now required"),this.getCenter(t.center),t.radius=.5*this.getSize(It).length(),t}intersect(t){return this.min.max(t.min),this.max.min(t.max),this.isEmpty()&&this.makeEmpty(),this}union(t){return this.min.min(t.min),this.max.max(t.max),this}applyMatrix4(t){return this.isEmpty()||(Dt[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(t),Dt[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(t),Dt[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(t),Dt[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(t),Dt[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(t),Dt[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(t),Dt[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(t),Dt[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(t),this.setFromPoints(Dt)),this}translate(t){return this.min.add(t),this.max.add(t),this}equals(t){return t.min.equals(this.min)&&t.max.equals(this.max)}}Pt.prototype.isBox3=!0;const Dt=[new Lt,new Lt,new Lt,new Lt,new Lt,new Lt,new Lt,new Lt],It=new Lt,Nt=new Pt,Bt=new Lt,zt=new Lt,Ft=new Lt,Ot=new Lt,Ht=new Lt,Gt=new Lt,Ut=new Lt,kt=new Lt,Vt=new Lt,Wt=new Lt;function jt(t,e,n,i,r){for(let s=0,a=t.length-3;s<=a;s+=3){Wt.fromArray(t,s);const a=r.x*Math.abs(Wt.x)+r.y*Math.abs(Wt.y)+r.z*Math.abs(Wt.z),o=e.dot(Wt),l=n.dot(Wt),c=i.dot(Wt);if(Math.max(-Math.max(o,l,c),Math.min(o,l,c))>a)return!1}return!0}const qt=new Pt,Xt=new Lt,Yt=new Lt,Zt=new Lt;class Jt{constructor(t=new Lt,e=-1){this.center=t,this.radius=e}set(t,e){return this.center.copy(t),this.radius=e,this}setFromPoints(t,e){const n=this.center;void 0!==e?n.copy(e):qt.setFromPoints(t).getCenter(n);let i=0;for(let e=0,r=t.length;ethis.radius*this.radius&&(e.sub(this.center).normalize(),e.multiplyScalar(this.radius).add(this.center)),e}getBoundingBox(t){return void 0===t&&(console.warn("THREE.Sphere: .getBoundingBox() target is now required"),t=new Pt),this.isEmpty()?(t.makeEmpty(),t):(t.set(this.center,this.center),t.expandByScalar(this.radius),t)}applyMatrix4(t){return this.center.applyMatrix4(t),this.radius=this.radius*t.getMaxScaleOnAxis(),this}translate(t){return this.center.add(t),this}expandByPoint(t){Zt.subVectors(t,this.center);const e=Zt.lengthSq();if(e>this.radius*this.radius){const t=Math.sqrt(e),n=.5*(t-this.radius);this.center.add(Zt.multiplyScalar(n/t)),this.radius+=n}return this}union(t){return Yt.subVectors(t.center,this.center).normalize().multiplyScalar(t.radius),this.expandByPoint(Xt.copy(t.center).add(Yt)),this.expandByPoint(Xt.copy(t.center).sub(Yt)),this}equals(t){return t.center.equals(this.center)&&t.radius===this.radius}clone(){return(new this.constructor).copy(this)}}const Qt=new Lt,Kt=new Lt,$t=new Lt,te=new Lt,ee=new Lt,ne=new Lt,ie=new Lt;class re{constructor(t=new Lt,e=new Lt(0,0,-1)){this.origin=t,this.direction=e}set(t,e){return this.origin.copy(t),this.direction.copy(e),this}copy(t){return this.origin.copy(t.origin),this.direction.copy(t.direction),this}at(t,e){return void 0===e&&(console.warn("THREE.Ray: .at() target is now required"),e=new Lt),e.copy(this.direction).multiplyScalar(t).add(this.origin)}lookAt(t){return this.direction.copy(t).sub(this.origin).normalize(),this}recast(t){return this.origin.copy(this.at(t,Qt)),this}closestPointToPoint(t,e){void 0===e&&(console.warn("THREE.Ray: .closestPointToPoint() target is now required"),e=new Lt),e.subVectors(t,this.origin);const n=e.dot(this.direction);return n<0?e.copy(this.origin):e.copy(this.direction).multiplyScalar(n).add(this.origin)}distanceToPoint(t){return Math.sqrt(this.distanceSqToPoint(t))}distanceSqToPoint(t){const e=Qt.subVectors(t,this.origin).dot(this.direction);return e<0?this.origin.distanceToSquared(t):(Qt.copy(this.direction).multiplyScalar(e).add(this.origin),Qt.distanceToSquared(t))}distanceSqToSegment(t,e,n,i){Kt.copy(t).add(e).multiplyScalar(.5),$t.copy(e).sub(t).normalize(),te.copy(this.origin).sub(Kt);const r=.5*t.distanceTo(e),s=-this.direction.dot($t),a=te.dot(this.direction),o=-te.dot($t),l=te.lengthSq(),c=Math.abs(1-s*s);let h,u,d,p;if(c>0)if(h=s*o-a,u=s*a-o,p=r*c,h>=0)if(u>=-p)if(u<=p){const t=1/c;h*=t,u*=t,d=h*(h+s*u+2*a)+u*(s*h+u+2*o)+l}else u=r,h=Math.max(0,-(s*u+a)),d=-h*h+u*(u+2*o)+l;else u=-r,h=Math.max(0,-(s*u+a)),d=-h*h+u*(u+2*o)+l;else u<=-p?(h=Math.max(0,-(-s*r+a)),u=h>0?-r:Math.min(Math.max(-r,-o),r),d=-h*h+u*(u+2*o)+l):u<=p?(h=0,u=Math.min(Math.max(-r,-o),r),d=u*(u+2*o)+l):(h=Math.max(0,-(s*r+a)),u=h>0?r:Math.min(Math.max(-r,-o),r),d=-h*h+u*(u+2*o)+l);else u=s>0?-r:r,h=Math.max(0,-(s*u+a)),d=-h*h+u*(u+2*o)+l;return n&&n.copy(this.direction).multiplyScalar(h).add(this.origin),i&&i.copy($t).multiplyScalar(u).add(Kt),d}intersectSphere(t,e){Qt.subVectors(t.center,this.origin);const n=Qt.dot(this.direction),i=Qt.dot(Qt)-n*n,r=t.radius*t.radius;if(i>r)return null;const s=Math.sqrt(r-i),a=n-s,o=n+s;return a<0&&o<0?null:a<0?this.at(o,e):this.at(a,e)}intersectsSphere(t){return this.distanceSqToPoint(t.center)<=t.radius*t.radius}distanceToPlane(t){const e=t.normal.dot(this.direction);if(0===e)return 0===t.distanceToPoint(this.origin)?0:null;const n=-(this.origin.dot(t.normal)+t.constant)/e;return n>=0?n:null}intersectPlane(t,e){const n=this.distanceToPlane(t);return null===n?null:this.at(n,e)}intersectsPlane(t){const e=t.distanceToPoint(this.origin);if(0===e)return!0;return t.normal.dot(this.direction)*e<0}intersectBox(t,e){let n,i,r,s,a,o;const l=1/this.direction.x,c=1/this.direction.y,h=1/this.direction.z,u=this.origin;return l>=0?(n=(t.min.x-u.x)*l,i=(t.max.x-u.x)*l):(n=(t.max.x-u.x)*l,i=(t.min.x-u.x)*l),c>=0?(r=(t.min.y-u.y)*c,s=(t.max.y-u.y)*c):(r=(t.max.y-u.y)*c,s=(t.min.y-u.y)*c),n>s||r>i?null:((r>n||n!=n)&&(n=r),(s=0?(a=(t.min.z-u.z)*h,o=(t.max.z-u.z)*h):(a=(t.max.z-u.z)*h,o=(t.min.z-u.z)*h),n>o||a>i?null:((a>n||n!=n)&&(n=a),(o=0?n:i,e)))}intersectsBox(t){return null!==this.intersectBox(t,Qt)}intersectTriangle(t,e,n,i,r){ee.subVectors(e,t),ne.subVectors(n,t),ie.crossVectors(ee,ne);let s,a=this.direction.dot(ie);if(a>0){if(i)return null;s=1}else{if(!(a<0))return null;s=-1,a=-a}te.subVectors(this.origin,t);const o=s*this.direction.dot(ne.crossVectors(te,ne));if(o<0)return null;const l=s*this.direction.dot(ee.cross(te));if(l<0)return null;if(o+l>a)return null;const c=-s*te.dot(ie);return c<0?null:this.at(c/a,r)}applyMatrix4(t){return this.origin.applyMatrix4(t),this.direction.transformDirection(t),this}equals(t){return t.origin.equals(this.origin)&&t.direction.equals(this.direction)}clone(){return(new this.constructor).copy(this)}}class se{constructor(){this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],arguments.length>0&&console.error("THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.")}set(t,e,n,i,r,s,a,o,l,c,h,u,d,p,m,f){const g=this.elements;return g[0]=t,g[4]=e,g[8]=n,g[12]=i,g[1]=r,g[5]=s,g[9]=a,g[13]=o,g[2]=l,g[6]=c,g[10]=h,g[14]=u,g[3]=d,g[7]=p,g[11]=m,g[15]=f,this}identity(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this}clone(){return(new se).fromArray(this.elements)}copy(t){const e=this.elements,n=t.elements;return e[0]=n[0],e[1]=n[1],e[2]=n[2],e[3]=n[3],e[4]=n[4],e[5]=n[5],e[6]=n[6],e[7]=n[7],e[8]=n[8],e[9]=n[9],e[10]=n[10],e[11]=n[11],e[12]=n[12],e[13]=n[13],e[14]=n[14],e[15]=n[15],this}copyPosition(t){const e=this.elements,n=t.elements;return e[12]=n[12],e[13]=n[13],e[14]=n[14],this}setFromMatrix3(t){const e=t.elements;return this.set(e[0],e[3],e[6],0,e[1],e[4],e[7],0,e[2],e[5],e[8],0,0,0,0,1),this}extractBasis(t,e,n){return t.setFromMatrixColumn(this,0),e.setFromMatrixColumn(this,1),n.setFromMatrixColumn(this,2),this}makeBasis(t,e,n){return this.set(t.x,e.x,n.x,0,t.y,e.y,n.y,0,t.z,e.z,n.z,0,0,0,0,1),this}extractRotation(t){const e=this.elements,n=t.elements,i=1/ae.setFromMatrixColumn(t,0).length(),r=1/ae.setFromMatrixColumn(t,1).length(),s=1/ae.setFromMatrixColumn(t,2).length();return e[0]=n[0]*i,e[1]=n[1]*i,e[2]=n[2]*i,e[3]=0,e[4]=n[4]*r,e[5]=n[5]*r,e[6]=n[6]*r,e[7]=0,e[8]=n[8]*s,e[9]=n[9]*s,e[10]=n[10]*s,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,this}makeRotationFromEuler(t){t&&t.isEuler||console.error("THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.");const e=this.elements,n=t.x,i=t.y,r=t.z,s=Math.cos(n),a=Math.sin(n),o=Math.cos(i),l=Math.sin(i),c=Math.cos(r),h=Math.sin(r);if("XYZ"===t.order){const t=s*c,n=s*h,i=a*c,r=a*h;e[0]=o*c,e[4]=-o*h,e[8]=l,e[1]=n+i*l,e[5]=t-r*l,e[9]=-a*o,e[2]=r-t*l,e[6]=i+n*l,e[10]=s*o}else if("YXZ"===t.order){const t=o*c,n=o*h,i=l*c,r=l*h;e[0]=t+r*a,e[4]=i*a-n,e[8]=s*l,e[1]=s*h,e[5]=s*c,e[9]=-a,e[2]=n*a-i,e[6]=r+t*a,e[10]=s*o}else if("ZXY"===t.order){const t=o*c,n=o*h,i=l*c,r=l*h;e[0]=t-r*a,e[4]=-s*h,e[8]=i+n*a,e[1]=n+i*a,e[5]=s*c,e[9]=r-t*a,e[2]=-s*l,e[6]=a,e[10]=s*o}else if("ZYX"===t.order){const t=s*c,n=s*h,i=a*c,r=a*h;e[0]=o*c,e[4]=i*l-n,e[8]=t*l+r,e[1]=o*h,e[5]=r*l+t,e[9]=n*l-i,e[2]=-l,e[6]=a*o,e[10]=s*o}else if("YZX"===t.order){const t=s*o,n=s*l,i=a*o,r=a*l;e[0]=o*c,e[4]=r-t*h,e[8]=i*h+n,e[1]=h,e[5]=s*c,e[9]=-a*c,e[2]=-l*c,e[6]=n*h+i,e[10]=t-r*h}else if("XZY"===t.order){const t=s*o,n=s*l,i=a*o,r=a*l;e[0]=o*c,e[4]=-h,e[8]=l*c,e[1]=t*h+r,e[5]=s*c,e[9]=n*h-i,e[2]=i*h-n,e[6]=a*c,e[10]=r*h+t}return e[3]=0,e[7]=0,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,this}makeRotationFromQuaternion(t){return this.compose(le,t,ce)}lookAt(t,e,n){const i=this.elements;return de.subVectors(t,e),0===de.lengthSq()&&(de.z=1),de.normalize(),he.crossVectors(n,de),0===he.lengthSq()&&(1===Math.abs(n.z)?de.x+=1e-4:de.z+=1e-4,de.normalize(),he.crossVectors(n,de)),he.normalize(),ue.crossVectors(de,he),i[0]=he.x,i[4]=ue.x,i[8]=de.x,i[1]=he.y,i[5]=ue.y,i[9]=de.y,i[2]=he.z,i[6]=ue.z,i[10]=de.z,this}multiply(t,e){return void 0!==e?(console.warn("THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."),this.multiplyMatrices(t,e)):this.multiplyMatrices(this,t)}premultiply(t){return this.multiplyMatrices(t,this)}multiplyMatrices(t,e){const n=t.elements,i=e.elements,r=this.elements,s=n[0],a=n[4],o=n[8],l=n[12],c=n[1],h=n[5],u=n[9],d=n[13],p=n[2],m=n[6],f=n[10],g=n[14],v=n[3],y=n[7],x=n[11],_=n[15],w=i[0],b=i[4],M=i[8],S=i[12],T=i[1],E=i[5],A=i[9],L=i[13],R=i[2],C=i[6],P=i[10],D=i[14],I=i[3],N=i[7],B=i[11],z=i[15];return r[0]=s*w+a*T+o*R+l*I,r[4]=s*b+a*E+o*C+l*N,r[8]=s*M+a*A+o*P+l*B,r[12]=s*S+a*L+o*D+l*z,r[1]=c*w+h*T+u*R+d*I,r[5]=c*b+h*E+u*C+d*N,r[9]=c*M+h*A+u*P+d*B,r[13]=c*S+h*L+u*D+d*z,r[2]=p*w+m*T+f*R+g*I,r[6]=p*b+m*E+f*C+g*N,r[10]=p*M+m*A+f*P+g*B,r[14]=p*S+m*L+f*D+g*z,r[3]=v*w+y*T+x*R+_*I,r[7]=v*b+y*E+x*C+_*N,r[11]=v*M+y*A+x*P+_*B,r[15]=v*S+y*L+x*D+_*z,this}multiplyScalar(t){const e=this.elements;return e[0]*=t,e[4]*=t,e[8]*=t,e[12]*=t,e[1]*=t,e[5]*=t,e[9]*=t,e[13]*=t,e[2]*=t,e[6]*=t,e[10]*=t,e[14]*=t,e[3]*=t,e[7]*=t,e[11]*=t,e[15]*=t,this}determinant(){const t=this.elements,e=t[0],n=t[4],i=t[8],r=t[12],s=t[1],a=t[5],o=t[9],l=t[13],c=t[2],h=t[6],u=t[10],d=t[14];return t[3]*(+r*o*h-i*l*h-r*a*u+n*l*u+i*a*d-n*o*d)+t[7]*(+e*o*d-e*l*u+r*s*u-i*s*d+i*l*c-r*o*c)+t[11]*(+e*l*h-e*a*d-r*s*h+n*s*d+r*a*c-n*l*c)+t[15]*(-i*a*c-e*o*h+e*a*u+i*s*h-n*s*u+n*o*c)}transpose(){const t=this.elements;let e;return e=t[1],t[1]=t[4],t[4]=e,e=t[2],t[2]=t[8],t[8]=e,e=t[6],t[6]=t[9],t[9]=e,e=t[3],t[3]=t[12],t[12]=e,e=t[7],t[7]=t[13],t[13]=e,e=t[11],t[11]=t[14],t[14]=e,this}setPosition(t,e,n){const i=this.elements;return t.isVector3?(i[12]=t.x,i[13]=t.y,i[14]=t.z):(i[12]=t,i[13]=e,i[14]=n),this}invert(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],s=t[4],a=t[5],o=t[6],l=t[7],c=t[8],h=t[9],u=t[10],d=t[11],p=t[12],m=t[13],f=t[14],g=t[15],v=h*f*l-m*u*l+m*o*d-a*f*d-h*o*g+a*u*g,y=p*u*l-c*f*l-p*o*d+s*f*d+c*o*g-s*u*g,x=c*m*l-p*h*l+p*a*d-s*m*d-c*a*g+s*h*g,_=p*h*o-c*m*o-p*a*u+s*m*u+c*a*f-s*h*f,w=e*v+n*y+i*x+r*_;if(0===w)return this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);const b=1/w;return t[0]=v*b,t[1]=(m*u*r-h*f*r-m*i*d+n*f*d+h*i*g-n*u*g)*b,t[2]=(a*f*r-m*o*r+m*i*l-n*f*l-a*i*g+n*o*g)*b,t[3]=(h*o*r-a*u*r-h*i*l+n*u*l+a*i*d-n*o*d)*b,t[4]=y*b,t[5]=(c*f*r-p*u*r+p*i*d-e*f*d-c*i*g+e*u*g)*b,t[6]=(p*o*r-s*f*r-p*i*l+e*f*l+s*i*g-e*o*g)*b,t[7]=(s*u*r-c*o*r+c*i*l-e*u*l-s*i*d+e*o*d)*b,t[8]=x*b,t[9]=(p*h*r-c*m*r-p*n*d+e*m*d+c*n*g-e*h*g)*b,t[10]=(s*m*r-p*a*r+p*n*l-e*m*l-s*n*g+e*a*g)*b,t[11]=(c*a*r-s*h*r-c*n*l+e*h*l+s*n*d-e*a*d)*b,t[12]=_*b,t[13]=(c*m*i-p*h*i+p*n*u-e*m*u-c*n*f+e*h*f)*b,t[14]=(p*a*i-s*m*i-p*n*o+e*m*o+s*n*f-e*a*f)*b,t[15]=(s*h*i-c*a*i+c*n*o-e*h*o-s*n*u+e*a*u)*b,this}scale(t){const e=this.elements,n=t.x,i=t.y,r=t.z;return e[0]*=n,e[4]*=i,e[8]*=r,e[1]*=n,e[5]*=i,e[9]*=r,e[2]*=n,e[6]*=i,e[10]*=r,e[3]*=n,e[7]*=i,e[11]*=r,this}getMaxScaleOnAxis(){const t=this.elements,e=t[0]*t[0]+t[1]*t[1]+t[2]*t[2],n=t[4]*t[4]+t[5]*t[5]+t[6]*t[6],i=t[8]*t[8]+t[9]*t[9]+t[10]*t[10];return Math.sqrt(Math.max(e,n,i))}makeTranslation(t,e,n){return this.set(1,0,0,t,0,1,0,e,0,0,1,n,0,0,0,1),this}makeRotationX(t){const e=Math.cos(t),n=Math.sin(t);return this.set(1,0,0,0,0,e,-n,0,0,n,e,0,0,0,0,1),this}makeRotationY(t){const e=Math.cos(t),n=Math.sin(t);return this.set(e,0,n,0,0,1,0,0,-n,0,e,0,0,0,0,1),this}makeRotationZ(t){const e=Math.cos(t),n=Math.sin(t);return this.set(e,-n,0,0,n,e,0,0,0,0,1,0,0,0,0,1),this}makeRotationAxis(t,e){const n=Math.cos(e),i=Math.sin(e),r=1-n,s=t.x,a=t.y,o=t.z,l=r*s,c=r*a;return this.set(l*s+n,l*a-i*o,l*o+i*a,0,l*a+i*o,c*a+n,c*o-i*s,0,l*o-i*a,c*o+i*s,r*o*o+n,0,0,0,0,1),this}makeScale(t,e,n){return this.set(t,0,0,0,0,e,0,0,0,0,n,0,0,0,0,1),this}makeShear(t,e,n){return this.set(1,e,n,0,t,1,n,0,t,e,1,0,0,0,0,1),this}compose(t,e,n){const i=this.elements,r=e._x,s=e._y,a=e._z,o=e._w,l=r+r,c=s+s,h=a+a,u=r*l,d=r*c,p=r*h,m=s*c,f=s*h,g=a*h,v=o*l,y=o*c,x=o*h,_=n.x,w=n.y,b=n.z;return i[0]=(1-(m+g))*_,i[1]=(d+x)*_,i[2]=(p-y)*_,i[3]=0,i[4]=(d-x)*w,i[5]=(1-(u+g))*w,i[6]=(f+v)*w,i[7]=0,i[8]=(p+y)*b,i[9]=(f-v)*b,i[10]=(1-(u+m))*b,i[11]=0,i[12]=t.x,i[13]=t.y,i[14]=t.z,i[15]=1,this}decompose(t,e,n){const i=this.elements;let r=ae.set(i[0],i[1],i[2]).length();const s=ae.set(i[4],i[5],i[6]).length(),a=ae.set(i[8],i[9],i[10]).length();this.determinant()<0&&(r=-r),t.x=i[12],t.y=i[13],t.z=i[14],oe.copy(this);const o=1/r,l=1/s,c=1/a;return oe.elements[0]*=o,oe.elements[1]*=o,oe.elements[2]*=o,oe.elements[4]*=l,oe.elements[5]*=l,oe.elements[6]*=l,oe.elements[8]*=c,oe.elements[9]*=c,oe.elements[10]*=c,e.setFromRotationMatrix(oe),n.x=r,n.y=s,n.z=a,this}makePerspective(t,e,n,i,r,s){void 0===s&&console.warn("THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.");const a=this.elements,o=2*r/(e-t),l=2*r/(n-i),c=(e+t)/(e-t),h=(n+i)/(n-i),u=-(s+r)/(s-r),d=-2*s*r/(s-r);return a[0]=o,a[4]=0,a[8]=c,a[12]=0,a[1]=0,a[5]=l,a[9]=h,a[13]=0,a[2]=0,a[6]=0,a[10]=u,a[14]=d,a[3]=0,a[7]=0,a[11]=-1,a[15]=0,this}makeOrthographic(t,e,n,i,r,s){const a=this.elements,o=1/(e-t),l=1/(n-i),c=1/(s-r),h=(e+t)*o,u=(n+i)*l,d=(s+r)*c;return a[0]=2*o,a[4]=0,a[8]=0,a[12]=-h,a[1]=0,a[5]=2*l,a[9]=0,a[13]=-u,a[2]=0,a[6]=0,a[10]=-2*c,a[14]=-d,a[3]=0,a[7]=0,a[11]=0,a[15]=1,this}equals(t){const e=this.elements,n=t.elements;for(let t=0;t<16;t++)if(e[t]!==n[t])return!1;return!0}fromArray(t,e=0){for(let n=0;n<16;n++)this.elements[n]=t[n+e];return this}toArray(t=[],e=0){const n=this.elements;return t[e]=n[0],t[e+1]=n[1],t[e+2]=n[2],t[e+3]=n[3],t[e+4]=n[4],t[e+5]=n[5],t[e+6]=n[6],t[e+7]=n[7],t[e+8]=n[8],t[e+9]=n[9],t[e+10]=n[10],t[e+11]=n[11],t[e+12]=n[12],t[e+13]=n[13],t[e+14]=n[14],t[e+15]=n[15],t}}se.prototype.isMatrix4=!0;const ae=new Lt,oe=new se,le=new Lt(0,0,0),ce=new Lt(1,1,1),he=new Lt,ue=new Lt,de=new Lt,pe=new se,me=new At;class fe{constructor(t=0,e=0,n=0,i=fe.DefaultOrder){this._x=t,this._y=e,this._z=n,this._order=i}get x(){return this._x}set x(t){this._x=t,this._onChangeCallback()}get y(){return this._y}set y(t){this._y=t,this._onChangeCallback()}get z(){return this._z}set z(t){this._z=t,this._onChangeCallback()}get order(){return this._order}set order(t){this._order=t,this._onChangeCallback()}set(t,e,n,i){return this._x=t,this._y=e,this._z=n,this._order=i||this._order,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._order)}copy(t){return this._x=t._x,this._y=t._y,this._z=t._z,this._order=t._order,this._onChangeCallback(),this}setFromRotationMatrix(t,e,n){const i=t.elements,r=i[0],s=i[4],a=i[8],o=i[1],l=i[5],c=i[9],h=i[2],u=i[6],d=i[10];switch(e=e||this._order){case"XYZ":this._y=Math.asin(ht(a,-1,1)),Math.abs(a)<.9999999?(this._x=Math.atan2(-c,d),this._z=Math.atan2(-s,r)):(this._x=Math.atan2(u,l),this._z=0);break;case"YXZ":this._x=Math.asin(-ht(c,-1,1)),Math.abs(c)<.9999999?(this._y=Math.atan2(a,d),this._z=Math.atan2(o,l)):(this._y=Math.atan2(-h,r),this._z=0);break;case"ZXY":this._x=Math.asin(ht(u,-1,1)),Math.abs(u)<.9999999?(this._y=Math.atan2(-h,d),this._z=Math.atan2(-s,l)):(this._y=0,this._z=Math.atan2(o,r));break;case"ZYX":this._y=Math.asin(-ht(h,-1,1)),Math.abs(h)<.9999999?(this._x=Math.atan2(u,d),this._z=Math.atan2(o,r)):(this._x=0,this._z=Math.atan2(-s,l));break;case"YZX":this._z=Math.asin(ht(o,-1,1)),Math.abs(o)<.9999999?(this._x=Math.atan2(-c,l),this._y=Math.atan2(-h,r)):(this._x=0,this._y=Math.atan2(a,d));break;case"XZY":this._z=Math.asin(-ht(s,-1,1)),Math.abs(s)<.9999999?(this._x=Math.atan2(u,l),this._y=Math.atan2(a,r)):(this._x=Math.atan2(-c,d),this._y=0);break;default:console.warn("THREE.Euler: .setFromRotationMatrix() encountered an unknown order: "+e)}return this._order=e,!1!==n&&this._onChangeCallback(),this}setFromQuaternion(t,e,n){return pe.makeRotationFromQuaternion(t),this.setFromRotationMatrix(pe,e,n)}setFromVector3(t,e){return this.set(t.x,t.y,t.z,e||this._order)}reorder(t){return me.setFromEuler(this),this.setFromQuaternion(me,t)}equals(t){return t._x===this._x&&t._y===this._y&&t._z===this._z&&t._order===this._order}fromArray(t){return this._x=t[0],this._y=t[1],this._z=t[2],void 0!==t[3]&&(this._order=t[3]),this._onChangeCallback(),this}toArray(t=[],e=0){return t[e]=this._x,t[e+1]=this._y,t[e+2]=this._z,t[e+3]=this._order,t}toVector3(t){return t?t.set(this._x,this._y,this._z):new Lt(this._x,this._y,this._z)}_onChange(t){return this._onChangeCallback=t,this}_onChangeCallback(){}}fe.prototype.isEuler=!0,fe.DefaultOrder="XYZ",fe.RotationOrders=["XYZ","YZX","ZXY","XZY","YXZ","ZYX"];class ge{constructor(){this.mask=1}set(t){this.mask=1<1){for(let t=0;t1){for(let t=0;t0){i.children=[];for(let e=0;e0){i.animations=[];for(let e=0;e0&&(n.geometries=e),i.length>0&&(n.materials=i),r.length>0&&(n.textures=r),a.length>0&&(n.images=a),o.length>0&&(n.shapes=o),l.length>0&&(n.skeletons=l),c.length>0&&(n.animations=c)}return n.object=i,n;function s(t){const e=[];for(const n in t){const i=t[n];delete i.metadata,e.push(i)}return e}}clone(t){return(new this.constructor).copy(this,t)}copy(t,e=!0){if(this.name=t.name,this.up.copy(t.up),this.position.copy(t.position),this.rotation.order=t.rotation.order,this.quaternion.copy(t.quaternion),this.scale.copy(t.scale),this.matrix.copy(t.matrix),this.matrixWorld.copy(t.matrixWorld),this.matrixAutoUpdate=t.matrixAutoUpdate,this.matrixWorldNeedsUpdate=t.matrixWorldNeedsUpdate,this.layers.mask=t.layers.mask,this.visible=t.visible,this.castShadow=t.castShadow,this.receiveShadow=t.receiveShadow,this.frustumCulled=t.frustumCulled,this.renderOrder=t.renderOrder,this.userData=JSON.parse(JSON.stringify(t.userData)),!0===e)for(let e=0;e1?null:e.copy(n).multiplyScalar(r).add(t.start)}intersectsLine(t){const e=this.distanceToPoint(t.start),n=this.distanceToPoint(t.end);return e<0&&n>0||n<0&&e>0}intersectsBox(t){return t.intersectsPlane(this)}intersectsSphere(t){return t.intersectsPlane(this)}coplanarPoint(t){return void 0===t&&(console.warn("THREE.Plane: .coplanarPoint() target is now required"),t=new Lt),t.copy(this.normal).multiplyScalar(-this.constant)}applyMatrix4(t,e){const n=e||Ie.getNormalMatrix(t),i=this.coplanarPoint(Pe).applyMatrix4(t),r=this.normal.applyMatrix3(n).normalize();return this.constant=-i.dot(r),this}translate(t){return this.constant-=t.dot(this.normal),this}equals(t){return t.normal.equals(this.normal)&&t.constant===this.constant}clone(){return(new this.constructor).copy(this)}}Ne.prototype.isPlane=!0;const Be=new Lt,ze=new Lt,Fe=new Lt,Oe=new Lt,He=new Lt,Ge=new Lt,Ue=new Lt,ke=new Lt,Ve=new Lt,We=new Lt;class je{constructor(t=new Lt,e=new Lt,n=new Lt){this.a=t,this.b=e,this.c=n}static getNormal(t,e,n,i){void 0===i&&(console.warn("THREE.Triangle: .getNormal() target is now required"),i=new Lt),i.subVectors(n,e),Be.subVectors(t,e),i.cross(Be);const r=i.lengthSq();return r>0?i.multiplyScalar(1/Math.sqrt(r)):i.set(0,0,0)}static getBarycoord(t,e,n,i,r){Be.subVectors(i,e),ze.subVectors(n,e),Fe.subVectors(t,e);const s=Be.dot(Be),a=Be.dot(ze),o=Be.dot(Fe),l=ze.dot(ze),c=ze.dot(Fe),h=s*l-a*a;if(void 0===r&&(console.warn("THREE.Triangle: .getBarycoord() target is now required"),r=new Lt),0===h)return r.set(-2,-1,-1);const u=1/h,d=(l*o-a*c)*u,p=(s*c-a*o)*u;return r.set(1-d-p,p,d)}static containsPoint(t,e,n,i){return this.getBarycoord(t,e,n,i,Oe),Oe.x>=0&&Oe.y>=0&&Oe.x+Oe.y<=1}static getUV(t,e,n,i,r,s,a,o){return this.getBarycoord(t,e,n,i,Oe),o.set(0,0),o.addScaledVector(r,Oe.x),o.addScaledVector(s,Oe.y),o.addScaledVector(a,Oe.z),o}static isFrontFacing(t,e,n,i){return Be.subVectors(n,e),ze.subVectors(t,e),Be.cross(ze).dot(i)<0}set(t,e,n){return this.a.copy(t),this.b.copy(e),this.c.copy(n),this}setFromPointsAndIndices(t,e,n,i){return this.a.copy(t[e]),this.b.copy(t[n]),this.c.copy(t[i]),this}clone(){return(new this.constructor).copy(this)}copy(t){return this.a.copy(t.a),this.b.copy(t.b),this.c.copy(t.c),this}getArea(){return Be.subVectors(this.c,this.b),ze.subVectors(this.a,this.b),.5*Be.cross(ze).length()}getMidpoint(t){return void 0===t&&(console.warn("THREE.Triangle: .getMidpoint() target is now required"),t=new Lt),t.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)}getNormal(t){return je.getNormal(this.a,this.b,this.c,t)}getPlane(t){return void 0===t&&(console.warn("THREE.Triangle: .getPlane() target is now required"),t=new Ne),t.setFromCoplanarPoints(this.a,this.b,this.c)}getBarycoord(t,e){return je.getBarycoord(t,this.a,this.b,this.c,e)}getUV(t,e,n,i,r){return je.getUV(t,this.a,this.b,this.c,e,n,i,r)}containsPoint(t){return je.containsPoint(t,this.a,this.b,this.c)}isFrontFacing(t){return je.isFrontFacing(this.a,this.b,this.c,t)}intersectsBox(t){return t.intersectsTriangle(this)}closestPointToPoint(t,e){void 0===e&&(console.warn("THREE.Triangle: .closestPointToPoint() target is now required"),e=new Lt);const n=this.a,i=this.b,r=this.c;let s,a;He.subVectors(i,n),Ge.subVectors(r,n),ke.subVectors(t,n);const o=He.dot(ke),l=Ge.dot(ke);if(o<=0&&l<=0)return e.copy(n);Ve.subVectors(t,i);const c=He.dot(Ve),h=Ge.dot(Ve);if(c>=0&&h<=c)return e.copy(i);const u=o*h-c*l;if(u<=0&&o>=0&&c<=0)return s=o/(o-c),e.copy(n).addScaledVector(He,s);We.subVectors(t,r);const d=He.dot(We),p=Ge.dot(We);if(p>=0&&d<=p)return e.copy(r);const m=d*l-o*p;if(m<=0&&l>=0&&p<=0)return a=l/(l-p),e.copy(n).addScaledVector(Ge,a);const f=c*p-d*h;if(f<=0&&h-c>=0&&d-p>=0)return Ue.subVectors(r,i),a=(h-c)/(h-c+(d-p)),e.copy(i).addScaledVector(Ue,a);const g=1/(f+m+u);return s=m*g,a=u*g,e.copy(n).addScaledVector(He,s).addScaledVector(Ge,a)}equals(t){return t.a.equals(this.a)&&t.b.equals(this.b)&&t.c.equals(this.c)}}let qe=0;function Xe(){Object.defineProperty(this,"id",{value:qe++}),this.uuid=ct(),this.name="",this.type="Material",this.fog=!0,this.blending=1,this.side=0,this.vertexColors=!1,this.opacity=1,this.transparent=!1,this.blendSrc=204,this.blendDst=205,this.blendEquation=n,this.blendSrcAlpha=null,this.blendDstAlpha=null,this.blendEquationAlpha=null,this.depthFunc=3,this.depthTest=!0,this.depthWrite=!0,this.stencilWriteMask=255,this.stencilFunc=519,this.stencilRef=0,this.stencilFuncMask=255,this.stencilFail=tt,this.stencilZFail=tt,this.stencilZPass=tt,this.stencilWrite=!1,this.clippingPlanes=null,this.clipIntersection=!1,this.clipShadows=!1,this.shadowSide=null,this.colorWrite=!0,this.precision=null,this.polygonOffset=!1,this.polygonOffsetFactor=0,this.polygonOffsetUnits=0,this.dithering=!1,this.alphaTest=0,this.alphaToCoverage=!1,this.premultipliedAlpha=!1,this.visible=!0,this.toneMapped=!0,this.userData={},this.version=0}Xe.prototype=Object.assign(Object.create(rt.prototype),{constructor:Xe,isMaterial:!0,onBuild:function(){},onBeforeCompile:function(){},customProgramCacheKey:function(){return this.onBeforeCompile.toString()},setValues:function(t){if(void 0!==t)for(const e in t){const n=t[e];if(void 0===n){console.warn("THREE.Material: '"+e+"' parameter is undefined.");continue}if("shading"===e){console.warn("THREE."+this.type+": .shading has been removed. Use the boolean .flatShading instead."),this.flatShading=1===n;continue}const i=this[e];void 0!==i?i&&i.isColor?i.set(n):i&&i.isVector3&&n&&n.isVector3?i.copy(n):this[e]=n:console.warn("THREE."+this.type+": '"+e+"' is not a property of this material.")}},toJSON:function(t){const e=void 0===t||"string"==typeof t;e&&(t={textures:{},images:{}});const n={metadata:{version:4.5,type:"Material",generator:"Material.toJSON"}};function i(t){const e=[];for(const n in t){const i=t[n];delete i.metadata,e.push(i)}return e}if(n.uuid=this.uuid,n.type=this.type,""!==this.name&&(n.name=this.name),this.color&&this.color.isColor&&(n.color=this.color.getHex()),void 0!==this.roughness&&(n.roughness=this.roughness),void 0!==this.metalness&&(n.metalness=this.metalness),this.sheen&&this.sheen.isColor&&(n.sheen=this.sheen.getHex()),this.emissive&&this.emissive.isColor&&(n.emissive=this.emissive.getHex()),this.emissiveIntensity&&1!==this.emissiveIntensity&&(n.emissiveIntensity=this.emissiveIntensity),this.specular&&this.specular.isColor&&(n.specular=this.specular.getHex()),void 0!==this.shininess&&(n.shininess=this.shininess),void 0!==this.clearcoat&&(n.clearcoat=this.clearcoat),void 0!==this.clearcoatRoughness&&(n.clearcoatRoughness=this.clearcoatRoughness),this.clearcoatMap&&this.clearcoatMap.isTexture&&(n.clearcoatMap=this.clearcoatMap.toJSON(t).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(n.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(t).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(n.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(t).uuid,n.clearcoatNormalScale=this.clearcoatNormalScale.toArray()),this.map&&this.map.isTexture&&(n.map=this.map.toJSON(t).uuid),this.matcap&&this.matcap.isTexture&&(n.matcap=this.matcap.toJSON(t).uuid),this.alphaMap&&this.alphaMap.isTexture&&(n.alphaMap=this.alphaMap.toJSON(t).uuid),this.lightMap&&this.lightMap.isTexture&&(n.lightMap=this.lightMap.toJSON(t).uuid,n.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(n.aoMap=this.aoMap.toJSON(t).uuid,n.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(n.bumpMap=this.bumpMap.toJSON(t).uuid,n.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(n.normalMap=this.normalMap.toJSON(t).uuid,n.normalMapType=this.normalMapType,n.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(n.displacementMap=this.displacementMap.toJSON(t).uuid,n.displacementScale=this.displacementScale,n.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(n.roughnessMap=this.roughnessMap.toJSON(t).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(n.metalnessMap=this.metalnessMap.toJSON(t).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(n.emissiveMap=this.emissiveMap.toJSON(t).uuid),this.specularMap&&this.specularMap.isTexture&&(n.specularMap=this.specularMap.toJSON(t).uuid),this.envMap&&this.envMap.isTexture&&(n.envMap=this.envMap.toJSON(t).uuid,void 0!==this.combine&&(n.combine=this.combine)),void 0!==this.envMapIntensity&&(n.envMapIntensity=this.envMapIntensity),void 0!==this.reflectivity&&(n.reflectivity=this.reflectivity),void 0!==this.refractionRatio&&(n.refractionRatio=this.refractionRatio),this.gradientMap&&this.gradientMap.isTexture&&(n.gradientMap=this.gradientMap.toJSON(t).uuid),void 0!==this.size&&(n.size=this.size),null!==this.shadowSide&&(n.shadowSide=this.shadowSide),void 0!==this.sizeAttenuation&&(n.sizeAttenuation=this.sizeAttenuation),1!==this.blending&&(n.blending=this.blending),0!==this.side&&(n.side=this.side),this.vertexColors&&(n.vertexColors=!0),this.opacity<1&&(n.opacity=this.opacity),!0===this.transparent&&(n.transparent=this.transparent),n.depthFunc=this.depthFunc,n.depthTest=this.depthTest,n.depthWrite=this.depthWrite,n.colorWrite=this.colorWrite,n.stencilWrite=this.stencilWrite,n.stencilWriteMask=this.stencilWriteMask,n.stencilFunc=this.stencilFunc,n.stencilRef=this.stencilRef,n.stencilFuncMask=this.stencilFuncMask,n.stencilFail=this.stencilFail,n.stencilZFail=this.stencilZFail,n.stencilZPass=this.stencilZPass,this.rotation&&0!==this.rotation&&(n.rotation=this.rotation),!0===this.polygonOffset&&(n.polygonOffset=!0),0!==this.polygonOffsetFactor&&(n.polygonOffsetFactor=this.polygonOffsetFactor),0!==this.polygonOffsetUnits&&(n.polygonOffsetUnits=this.polygonOffsetUnits),this.linewidth&&1!==this.linewidth&&(n.linewidth=this.linewidth),void 0!==this.dashSize&&(n.dashSize=this.dashSize),void 0!==this.gapSize&&(n.gapSize=this.gapSize),void 0!==this.scale&&(n.scale=this.scale),!0===this.dithering&&(n.dithering=!0),this.alphaTest>0&&(n.alphaTest=this.alphaTest),!0===this.alphaToCoverage&&(n.alphaToCoverage=this.alphaToCoverage),!0===this.premultipliedAlpha&&(n.premultipliedAlpha=this.premultipliedAlpha),!0===this.wireframe&&(n.wireframe=this.wireframe),this.wireframeLinewidth>1&&(n.wireframeLinewidth=this.wireframeLinewidth),"round"!==this.wireframeLinecap&&(n.wireframeLinecap=this.wireframeLinecap),"round"!==this.wireframeLinejoin&&(n.wireframeLinejoin=this.wireframeLinejoin),!0===this.morphTargets&&(n.morphTargets=!0),!0===this.morphNormals&&(n.morphNormals=!0),!0===this.skinning&&(n.skinning=!0),!0===this.flatShading&&(n.flatShading=this.flatShading),!1===this.visible&&(n.visible=!1),!1===this.toneMapped&&(n.toneMapped=!1),"{}"!==JSON.stringify(this.userData)&&(n.userData=this.userData),e){const e=i(t.textures),r=i(t.images);e.length>0&&(n.textures=e),r.length>0&&(n.images=r)}return n},clone:function(){return(new this.constructor).copy(this)},copy:function(t){this.name=t.name,this.fog=t.fog,this.blending=t.blending,this.side=t.side,this.vertexColors=t.vertexColors,this.opacity=t.opacity,this.transparent=t.transparent,this.blendSrc=t.blendSrc,this.blendDst=t.blendDst,this.blendEquation=t.blendEquation,this.blendSrcAlpha=t.blendSrcAlpha,this.blendDstAlpha=t.blendDstAlpha,this.blendEquationAlpha=t.blendEquationAlpha,this.depthFunc=t.depthFunc,this.depthTest=t.depthTest,this.depthWrite=t.depthWrite,this.stencilWriteMask=t.stencilWriteMask,this.stencilFunc=t.stencilFunc,this.stencilRef=t.stencilRef,this.stencilFuncMask=t.stencilFuncMask,this.stencilFail=t.stencilFail,this.stencilZFail=t.stencilZFail,this.stencilZPass=t.stencilZPass,this.stencilWrite=t.stencilWrite;const e=t.clippingPlanes;let n=null;if(null!==e){const t=e.length;n=new Array(t);for(let i=0;i!==t;++i)n[i]=e[i].clone()}return this.clippingPlanes=n,this.clipIntersection=t.clipIntersection,this.clipShadows=t.clipShadows,this.shadowSide=t.shadowSide,this.colorWrite=t.colorWrite,this.precision=t.precision,this.polygonOffset=t.polygonOffset,this.polygonOffsetFactor=t.polygonOffsetFactor,this.polygonOffsetUnits=t.polygonOffsetUnits,this.dithering=t.dithering,this.alphaTest=t.alphaTest,this.alphaToCoverage=t.alphaToCoverage,this.premultipliedAlpha=t.premultipliedAlpha,this.visible=t.visible,this.toneMapped=t.toneMapped,this.userData=JSON.parse(JSON.stringify(t.userData)),this},dispose:function(){this.dispatchEvent({type:"dispose"})}}),Object.defineProperty(Xe.prototype,"needsUpdate",{set:function(t){!0===t&&this.version++}});const Ye={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},Ze={h:0,s:0,l:0},Je={h:0,s:0,l:0};function Qe(t,e,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?t+6*(e-t)*n:n<.5?e:n<2/3?t+6*(e-t)*(2/3-n):t}function Ke(t){return t<.04045?.0773993808*t:Math.pow(.9478672986*t+.0521327014,2.4)}function $e(t){return t<.0031308?12.92*t:1.055*Math.pow(t,.41666)-.055}class tn{constructor(t,e,n){return void 0===e&&void 0===n?this.set(t):this.setRGB(t,e,n)}set(t){return t&&t.isColor?this.copy(t):"number"==typeof t?this.setHex(t):"string"==typeof t&&this.setStyle(t),this}setScalar(t){return this.r=t,this.g=t,this.b=t,this}setHex(t){return t=Math.floor(t),this.r=(t>>16&255)/255,this.g=(t>>8&255)/255,this.b=(255&t)/255,this}setRGB(t,e,n){return this.r=t,this.g=e,this.b=n,this}setHSL(t,e,n){if(t=ut(t,1),e=ht(e,0,1),n=ht(n,0,1),0===e)this.r=this.g=this.b=n;else{const i=n<=.5?n*(1+e):n+e-n*e,r=2*n-i;this.r=Qe(r,i,t+1/3),this.g=Qe(r,i,t),this.b=Qe(r,i,t-1/3)}return this}setStyle(t){function e(e){void 0!==e&&parseFloat(e)<1&&console.warn("THREE.Color: Alpha component of "+t+" will be ignored.")}let n;if(n=/^((?:rgb|hsl)a?)\(([^\)]*)\)/.exec(t)){let t;const i=n[1],r=n[2];switch(i){case"rgb":case"rgba":if(t=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(r))return this.r=Math.min(255,parseInt(t[1],10))/255,this.g=Math.min(255,parseInt(t[2],10))/255,this.b=Math.min(255,parseInt(t[3],10))/255,e(t[4]),this;if(t=/^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(r))return this.r=Math.min(100,parseInt(t[1],10))/100,this.g=Math.min(100,parseInt(t[2],10))/100,this.b=Math.min(100,parseInt(t[3],10))/100,e(t[4]),this;break;case"hsl":case"hsla":if(t=/^\s*(\d*\.?\d+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(r)){const n=parseFloat(t[1])/360,i=parseInt(t[2],10)/100,r=parseInt(t[3],10)/100;return e(t[4]),this.setHSL(n,i,r)}}}else if(n=/^\#([A-Fa-f\d]+)$/.exec(t)){const t=n[1],e=t.length;if(3===e)return this.r=parseInt(t.charAt(0)+t.charAt(0),16)/255,this.g=parseInt(t.charAt(1)+t.charAt(1),16)/255,this.b=parseInt(t.charAt(2)+t.charAt(2),16)/255,this;if(6===e)return this.r=parseInt(t.charAt(0)+t.charAt(1),16)/255,this.g=parseInt(t.charAt(2)+t.charAt(3),16)/255,this.b=parseInt(t.charAt(4)+t.charAt(5),16)/255,this}return t&&t.length>0?this.setColorName(t):this}setColorName(t){const e=Ye[t.toLowerCase()];return void 0!==e?this.setHex(e):console.warn("THREE.Color: Unknown color "+t),this}clone(){return new this.constructor(this.r,this.g,this.b)}copy(t){return this.r=t.r,this.g=t.g,this.b=t.b,this}copyGammaToLinear(t,e=2){return this.r=Math.pow(t.r,e),this.g=Math.pow(t.g,e),this.b=Math.pow(t.b,e),this}copyLinearToGamma(t,e=2){const n=e>0?1/e:1;return this.r=Math.pow(t.r,n),this.g=Math.pow(t.g,n),this.b=Math.pow(t.b,n),this}convertGammaToLinear(t){return this.copyGammaToLinear(this,t),this}convertLinearToGamma(t){return this.copyLinearToGamma(this,t),this}copySRGBToLinear(t){return this.r=Ke(t.r),this.g=Ke(t.g),this.b=Ke(t.b),this}copyLinearToSRGB(t){return this.r=$e(t.r),this.g=$e(t.g),this.b=$e(t.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(){return 255*this.r<<16^255*this.g<<8^255*this.b<<0}getHexString(){return("000000"+this.getHex().toString(16)).slice(-6)}getHSL(t){void 0===t&&(console.warn("THREE.Color: .getHSL() target is now required"),t={h:0,s:0,l:0});const e=this.r,n=this.g,i=this.b,r=Math.max(e,n,i),s=Math.min(e,n,i);let a,o;const l=(s+r)/2;if(s===r)a=0,o=0;else{const t=r-s;switch(o=l<=.5?t/(r+s):t/(2-r-s),r){case e:a=(n-i)/t+(ne&&(e=t[n]);return e}const vn={Int8Array:Int8Array,Uint8Array:Uint8Array,Uint8ClampedArray:Uint8ClampedArray,Int16Array:Int16Array,Uint16Array:Uint16Array,Int32Array:Int32Array,Uint32Array:Uint32Array,Float32Array:Float32Array,Float64Array:Float64Array};function yn(t,e){return new vn[t](e)}let xn=0;const _n=new se,wn=new Ce,bn=new Lt,Mn=new Pt,Sn=new Pt,Tn=new Lt;class En extends rt{constructor(){super(),Object.defineProperty(this,"id",{value:xn++}),this.uuid=ct(),this.name="",this.type="BufferGeometry",this.index=null,this.attributes={},this.morphAttributes={},this.morphTargetsRelative=!1,this.groups=[],this.boundingBox=null,this.boundingSphere=null,this.drawRange={start:0,count:1/0},this.userData={}}getIndex(){return this.index}setIndex(t){return Array.isArray(t)?this.index=new(gn(t)>65535?dn:hn)(t,1):this.index=t,this}getAttribute(t){return this.attributes[t]}setAttribute(t,e){return this.attributes[t]=e,this}deleteAttribute(t){return delete this.attributes[t],this}hasAttribute(t){return void 0!==this.attributes[t]}addGroup(t,e,n=0){this.groups.push({start:t,count:e,materialIndex:n})}clearGroups(){this.groups=[]}setDrawRange(t,e){this.drawRange.start=t,this.drawRange.count=e}applyMatrix4(t){const e=this.attributes.position;void 0!==e&&(e.applyMatrix4(t),e.needsUpdate=!0);const n=this.attributes.normal;if(void 0!==n){const e=(new yt).getNormalMatrix(t);n.applyNormalMatrix(e),n.needsUpdate=!0}const i=this.attributes.tangent;return void 0!==i&&(i.transformDirection(t),i.needsUpdate=!0),null!==this.boundingBox&&this.computeBoundingBox(),null!==this.boundingSphere&&this.computeBoundingSphere(),this}rotateX(t){return _n.makeRotationX(t),this.applyMatrix4(_n),this}rotateY(t){return _n.makeRotationY(t),this.applyMatrix4(_n),this}rotateZ(t){return _n.makeRotationZ(t),this.applyMatrix4(_n),this}translate(t,e,n){return _n.makeTranslation(t,e,n),this.applyMatrix4(_n),this}scale(t,e,n){return _n.makeScale(t,e,n),this.applyMatrix4(_n),this}lookAt(t){return wn.lookAt(t),wn.updateMatrix(),this.applyMatrix4(wn.matrix),this}center(){return this.computeBoundingBox(),this.boundingBox.getCenter(bn).negate(),this.translate(bn.x,bn.y,bn.z),this}setFromPoints(t){const e=[];for(let n=0,i=t.length;n0&&(t.userData=this.userData),void 0!==this.parameters){const e=this.parameters;for(const n in e)void 0!==e[n]&&(t[n]=e[n]);return t}t.data={attributes:{}};const e=this.index;null!==e&&(t.data.index={type:e.array.constructor.name,array:Array.prototype.slice.call(e.array)});const n=this.attributes;for(const e in n){const i=n[e];t.data.attributes[e]=i.toJSON(t.data)}const i={};let r=!1;for(const e in this.morphAttributes){const n=this.morphAttributes[e],s=[];for(let e=0,i=n.length;e0&&(i[e]=s,r=!0)}r&&(t.data.morphAttributes=i,t.data.morphTargetsRelative=this.morphTargetsRelative);const s=this.groups;s.length>0&&(t.data.groups=JSON.parse(JSON.stringify(s)));const a=this.boundingSphere;return null!==a&&(t.data.boundingSphere={center:a.center.toArray(),radius:a.radius}),t}clone(){return(new En).copy(this)}copy(t){this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null;const e={};this.name=t.name;const n=t.index;null!==n&&this.setIndex(n.clone(e));const i=t.attributes;for(const t in i){const n=i[t];this.setAttribute(t,n.clone(e))}const r=t.morphAttributes;for(const t in r){const n=[],i=r[t];for(let t=0,r=i.length;t0){const t=e[n[0]];if(void 0!==t){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let e=0,n=t.length;e0&&console.error("THREE.Mesh.updateMorphTargets() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.")}}raycast(t,e){const n=this.geometry,i=this.material,r=this.matrixWorld;if(void 0===i)return;if(null===n.boundingSphere&&n.computeBoundingSphere(),Rn.copy(n.boundingSphere),Rn.applyMatrix4(r),!1===t.ray.intersectsSphere(Rn))return;if(An.copy(r).invert(),Ln.copy(t.ray).applyMatrix4(An),null!==n.boundingBox&&!1===Ln.intersectsBox(n.boundingBox))return;let s;if(n.isBufferGeometry){const r=n.index,a=n.attributes.position,o=n.morphAttributes.position,l=n.morphTargetsRelative,c=n.attributes.uv,h=n.attributes.uv2,u=n.groups,d=n.drawRange;if(null!==r)if(Array.isArray(i))for(let n=0,p=u.length;nn.far?null:{distance:c,point:Vn.clone(),object:t}}(t,e,n,i,Cn,Pn,Dn,kn);if(p){o&&(Hn.fromBufferAttribute(o,c),Gn.fromBufferAttribute(o,h),Un.fromBufferAttribute(o,u),p.uv=je.getUV(kn,Cn,Pn,Dn,Hn,Gn,Un,new vt)),l&&(Hn.fromBufferAttribute(l,c),Gn.fromBufferAttribute(l,h),Un.fromBufferAttribute(l,u),p.uv2=je.getUV(kn,Cn,Pn,Dn,Hn,Gn,Un,new vt));const t={a:c,b:h,c:u,normal:new Lt,materialIndex:0};je.getNormal(Cn,Pn,Dn,t.normal),p.face=t}return p}Wn.prototype.isMesh=!0;class qn extends En{constructor(t=1,e=1,n=1,i=1,r=1,s=1){super(),this.type="BoxGeometry",this.parameters={width:t,height:e,depth:n,widthSegments:i,heightSegments:r,depthSegments:s};const a=this;i=Math.floor(i),r=Math.floor(r),s=Math.floor(s);const o=[],l=[],c=[],h=[];let u=0,d=0;function p(t,e,n,i,r,s,p,m,f,g,v){const y=s/f,x=p/g,_=s/2,w=p/2,b=m/2,M=f+1,S=g+1;let T=0,E=0;const A=new Lt;for(let s=0;s0?1:-1,c.push(A.x,A.y,A.z),h.push(o/f),h.push(1-s/g),T+=1}}for(let t=0;t0&&(e.defines=this.defines),e.vertexShader=this.vertexShader,e.fragmentShader=this.fragmentShader;const n={};for(const t in this.extensions)!0===this.extensions[t]&&(n[t]=!0);return Object.keys(n).length>0&&(e.extensions=n),e}}Jn.prototype.isShaderMaterial=!0;class Qn extends Ce{constructor(){super(),this.type="Camera",this.matrixWorldInverse=new se,this.projectionMatrix=new se,this.projectionMatrixInverse=new se}copy(t,e){return super.copy(t,e),this.matrixWorldInverse.copy(t.matrixWorldInverse),this.projectionMatrix.copy(t.projectionMatrix),this.projectionMatrixInverse.copy(t.projectionMatrixInverse),this}getWorldDirection(t){void 0===t&&(console.warn("THREE.Camera: .getWorldDirection() target is now required"),t=new Lt),this.updateWorldMatrix(!0,!1);const e=this.matrixWorld.elements;return t.set(-e[8],-e[9],-e[10]).normalize()}updateMatrixWorld(t){super.updateMatrixWorld(t),this.matrixWorldInverse.copy(this.matrixWorld).invert()}updateWorldMatrix(t,e){super.updateWorldMatrix(t,e),this.matrixWorldInverse.copy(this.matrixWorld).invert()}clone(){return(new this.constructor).copy(this)}}Qn.prototype.isCamera=!0;class Kn extends Qn{constructor(t=50,e=1,n=.1,i=2e3){super(),this.type="PerspectiveCamera",this.fov=t,this.zoom=1,this.near=n,this.far=i,this.focus=10,this.aspect=e,this.view=null,this.filmGauge=35,this.filmOffset=0,this.updateProjectionMatrix()}copy(t,e){return super.copy(t,e),this.fov=t.fov,this.zoom=t.zoom,this.near=t.near,this.far=t.far,this.focus=t.focus,this.aspect=t.aspect,this.view=null===t.view?null:Object.assign({},t.view),this.filmGauge=t.filmGauge,this.filmOffset=t.filmOffset,this}setFocalLength(t){const e=.5*this.getFilmHeight()/t;this.fov=2*lt*Math.atan(e),this.updateProjectionMatrix()}getFocalLength(){const t=Math.tan(.5*ot*this.fov);return.5*this.getFilmHeight()/t}getEffectiveFOV(){return 2*lt*Math.atan(Math.tan(.5*ot*this.fov)/this.zoom)}getFilmWidth(){return this.filmGauge*Math.min(this.aspect,1)}getFilmHeight(){return this.filmGauge/Math.max(this.aspect,1)}setViewOffset(t,e,n,i,r,s){this.aspect=t/e,null===this.view&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=t,this.view.fullHeight=e,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=s,this.updateProjectionMatrix()}clearViewOffset(){null!==this.view&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const t=this.near;let e=t*Math.tan(.5*ot*this.fov)/this.zoom,n=2*e,i=this.aspect*n,r=-.5*i;const s=this.view;if(null!==this.view&&this.view.enabled){const t=s.fullWidth,a=s.fullHeight;r+=s.offsetX*i/t,e-=s.offsetY*n/a,i*=s.width/t,n*=s.height/a}const a=this.filmOffset;0!==a&&(r+=t*a/this.getFilmWidth()),this.projectionMatrix.makePerspective(r,r+i,e,e-n,t,this.far),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(t){const e=super.toJSON(t);return e.object.fov=this.fov,e.object.zoom=this.zoom,e.object.near=this.near,e.object.far=this.far,e.object.focus=this.focus,e.object.aspect=this.aspect,null!==this.view&&(e.object.view=Object.assign({},this.view)),e.object.filmGauge=this.filmGauge,e.object.filmOffset=this.filmOffset,e}}Kn.prototype.isPerspectiveCamera=!0;const $n=90;class ti extends Ce{constructor(t,e,n){if(super(),this.type="CubeCamera",!0!==n.isWebGLCubeRenderTarget)return void console.error("THREE.CubeCamera: The constructor now expects an instance of WebGLCubeRenderTarget as third parameter.");this.renderTarget=n;const i=new Kn($n,1,t,e);i.layers=this.layers,i.up.set(0,-1,0),i.lookAt(new Lt(1,0,0)),this.add(i);const r=new Kn($n,1,t,e);r.layers=this.layers,r.up.set(0,-1,0),r.lookAt(new Lt(-1,0,0)),this.add(r);const s=new Kn($n,1,t,e);s.layers=this.layers,s.up.set(0,0,1),s.lookAt(new Lt(0,1,0)),this.add(s);const a=new Kn($n,1,t,e);a.layers=this.layers,a.up.set(0,0,-1),a.lookAt(new Lt(0,-1,0)),this.add(a);const o=new Kn($n,1,t,e);o.layers=this.layers,o.up.set(0,-1,0),o.lookAt(new Lt(0,0,1)),this.add(o);const l=new Kn($n,1,t,e);l.layers=this.layers,l.up.set(0,-1,0),l.lookAt(new Lt(0,0,-1)),this.add(l)}update(t,e){null===this.parent&&this.updateMatrixWorld();const n=this.renderTarget,[i,r,s,a,o,l]=this.children,c=t.xr.enabled,h=t.getRenderTarget();t.xr.enabled=!1;const u=n.texture.generateMipmaps;n.texture.generateMipmaps=!1,t.setRenderTarget(n,0),t.render(e,i),t.setRenderTarget(n,1),t.render(e,r),t.setRenderTarget(n,2),t.render(e,s),t.setRenderTarget(n,3),t.render(e,a),t.setRenderTarget(n,4),t.render(e,o),n.texture.generateMipmaps=u,t.setRenderTarget(n,5),t.render(e,l),t.setRenderTarget(h),t.xr.enabled=c}}class ei extends bt{constructor(t,e,n,i,s,a,o,l,c,h){super(t=void 0!==t?t:[],e=void 0!==e?e:r,n,i,s,a,o=void 0!==o?o:T,l,c,h),this._needsFlipEnvMap=!0,this.flipY=!1}get images(){return this.image}set images(t){this.image=t}}ei.prototype.isCubeTexture=!0;class ni extends Tt{constructor(t,e,n){Number.isInteger(e)&&(console.warn("THREE.WebGLCubeRenderTarget: constructor signature is now WebGLCubeRenderTarget( size, options )"),e=n),super(t,t,e),e=e||{},this.texture=new ei(void 0,e.mapping,e.wrapS,e.wrapT,e.magFilter,e.minFilter,e.format,e.type,e.anisotropy,e.encoding),this.texture.generateMipmaps=void 0!==e.generateMipmaps&&e.generateMipmaps,this.texture.minFilter=void 0!==e.minFilter?e.minFilter:g,this.texture._needsFlipEnvMap=!1}fromEquirectangularTexture(t,e){this.texture.type=e.type,this.texture.format=E,this.texture.encoding=e.encoding,this.texture.generateMipmaps=e.generateMipmaps,this.texture.minFilter=e.minFilter,this.texture.magFilter=e.magFilter;const n={uniforms:{tEquirect:{value:null}},vertexShader:"\n\n\t\t\t\tvarying vec3 vWorldDirection;\n\n\t\t\t\tvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\n\t\t\t\t\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n\n\t\t\t\t}\n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvWorldDirection = transformDirection( position, modelMatrix );\n\n\t\t\t\t\t#include \n\t\t\t\t\t#include \n\n\t\t\t\t}\n\t\t\t",fragmentShader:"\n\n\t\t\t\tuniform sampler2D tEquirect;\n\n\t\t\t\tvarying vec3 vWorldDirection;\n\n\t\t\t\t#include \n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvec3 direction = normalize( vWorldDirection );\n\n\t\t\t\t\tvec2 sampleUV = equirectUv( direction );\n\n\t\t\t\t\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\n\t\t\t\t}\n\t\t\t"},i=new qn(5,5,5),r=new Jn({name:"CubemapFromEquirect",uniforms:Xn(n.uniforms),vertexShader:n.vertexShader,fragmentShader:n.fragmentShader,side:1,blending:0});r.uniforms.tEquirect.value=e;const s=new Wn(i,r),a=e.minFilter;e.minFilter===y&&(e.minFilter=g);return new ti(1,10,this).update(t,s),e.minFilter=a,s.geometry.dispose(),s.material.dispose(),this}clear(t,e,n,i){const r=t.getRenderTarget();for(let r=0;r<6;r++)t.setRenderTarget(this,r),t.clear(e,n,i);t.setRenderTarget(r)}}ni.prototype.isWebGLCubeRenderTarget=!0;class ii extends bt{constructor(t,e,n,i,r,s,a,o,l,c,h,u){super(null,s,a,o,l,c,i,r,h,u),this.image={data:t||null,width:e||1,height:n||1},this.magFilter=void 0!==l?l:p,this.minFilter=void 0!==c?c:p,this.generateMipmaps=!1,this.flipY=!1,this.unpackAlignment=1,this.needsUpdate=!0}}ii.prototype.isDataTexture=!0;const ri=new Jt,si=new Lt;class ai{constructor(t=new Ne,e=new Ne,n=new Ne,i=new Ne,r=new Ne,s=new Ne){this.planes=[t,e,n,i,r,s]}set(t,e,n,i,r,s){const a=this.planes;return a[0].copy(t),a[1].copy(e),a[2].copy(n),a[3].copy(i),a[4].copy(r),a[5].copy(s),this}copy(t){const e=this.planes;for(let n=0;n<6;n++)e[n].copy(t.planes[n]);return this}setFromProjectionMatrix(t){const e=this.planes,n=t.elements,i=n[0],r=n[1],s=n[2],a=n[3],o=n[4],l=n[5],c=n[6],h=n[7],u=n[8],d=n[9],p=n[10],m=n[11],f=n[12],g=n[13],v=n[14],y=n[15];return e[0].setComponents(a-i,h-o,m-u,y-f).normalize(),e[1].setComponents(a+i,h+o,m+u,y+f).normalize(),e[2].setComponents(a+r,h+l,m+d,y+g).normalize(),e[3].setComponents(a-r,h-l,m-d,y-g).normalize(),e[4].setComponents(a-s,h-c,m-p,y-v).normalize(),e[5].setComponents(a+s,h+c,m+p,y+v).normalize(),this}intersectsObject(t){const e=t.geometry;return null===e.boundingSphere&&e.computeBoundingSphere(),ri.copy(e.boundingSphere).applyMatrix4(t.matrixWorld),this.intersectsSphere(ri)}intersectsSprite(t){return ri.center.set(0,0,0),ri.radius=.7071067811865476,ri.applyMatrix4(t.matrixWorld),this.intersectsSphere(ri)}intersectsSphere(t){const e=this.planes,n=t.center,i=-t.radius;for(let t=0;t<6;t++){if(e[t].distanceToPoint(n)0?t.max.x:t.min.x,si.y=i.normal.y>0?t.max.y:t.min.y,si.z=i.normal.z>0?t.max.z:t.min.z,i.distanceToPoint(si)<0)return!1}return!0}containsPoint(t){const e=this.planes;for(let n=0;n<6;n++)if(e[n].distanceToPoint(t)<0)return!1;return!0}clone(){return(new this.constructor).copy(this)}}function oi(){let t=null,e=!1,n=null,i=null;function r(e,s){n(e,s),i=t.requestAnimationFrame(r)}return{start:function(){!0!==e&&null!==n&&(i=t.requestAnimationFrame(r),e=!0)},stop:function(){t.cancelAnimationFrame(i),e=!1},setAnimationLoop:function(t){n=t},setContext:function(e){t=e}}}function li(t,e){const n=e.isWebGL2,i=new WeakMap;return{get:function(t){return t.isInterleavedBufferAttribute&&(t=t.data),i.get(t)},remove:function(e){e.isInterleavedBufferAttribute&&(e=e.data);const n=i.get(e);n&&(t.deleteBuffer(n.buffer),i.delete(e))},update:function(e,r){if(e.isGLBufferAttribute){const t=i.get(e);return void((!t||t.version 0.0 ) {\n\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t}\n\treturn distanceFalloff;\n#else\n\tif( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t}\n\treturn 1.0;\n#endif\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}\nvec3 F_Schlick_RoughnessDependent( const in vec3 F0, const in float dotNV, const in float roughness ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotNV - 6.98316 ) * dotNV );\n\tvec3 Fr = max( vec3( 1.0 - roughness ), F0 ) - F0;\n\treturn Fr * fresnel + F0;\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 vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + viewDir );\n\tfloat dotNL = saturate( dot( normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( 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 vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tvec2 brdf = integrateSpecularBRDF( dotNV, roughness );\n\treturn specularColor * brdf.x + brdf.y;\n}\nvoid BRDF_Specular_Multiscattering_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tvec3 F = F_Schlick_RoughnessDependent( specularColor, dotNV, roughness );\n\tvec2 brdf = integrateSpecularBRDF( dotNV, roughness );\n\tvec3 FssEss = F * brdf.x + brdf.y;\n\tfloat Ess = brdf.x + brdf.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = specularColor + ( 1.0 - specularColor ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\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#if defined( USE_SHEEN )\nfloat D_Charlie(float roughness, float NoH) {\n\tfloat invAlpha = 1.0 / roughness;\n\tfloat cos2h = NoH * NoH;\n\tfloat sin2h = max(1.0 - cos2h, 0.0078125);\treturn (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI);\n}\nfloat V_Neubelt(float NoV, float NoL) {\n\treturn saturate(1.0 / (4.0 * (NoL + NoV - NoL * NoV)));\n}\nvec3 BRDF_Specular_Sheen( const in float roughness, const in vec3 L, const in GeometricContext geometry, vec3 specularColor ) {\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 H = normalize( V + L );\n\tfloat dotNH = saturate( dot( N, H ) );\n\treturn specularColor * D_Charlie( roughness, dotNH ) * V_Neubelt( dot(N, V), dot(N, L) );\n}\n#endif",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, float faceDirection ) {\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 ) * faceDirection;\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",clipping_planes_fragment:"#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#pragma unroll_loop_end\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\tif ( clipped ) discard;\n\t#endif\n#endif",clipping_planes_pars_fragment:"#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif",clipping_planes_pars_vertex:"#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif",clipping_planes_vertex:"#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif",color_fragment:"#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif",color_pars_fragment:"#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif",color_pars_vertex:"#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvarying vec3 vColor;\n#endif",color_vertex:"#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif",common:"#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement(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}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat max3( vec3 v ) { return max( max( v.x, v.y ), v.z ); }\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\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#ifdef CLEARCOAT\n\tvec3 clearcoatNormal;\n#endif\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}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}",cube_uv_reflection_fragment:"#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_maxMipLevel 8.0\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_maxTileSize 256.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\tfloat texelSize = 1.0 / ( 3.0 * cubeUV_maxTileSize );\n\t\tvec2 uv = getUV( direction, face ) * ( faceSize - 1.0 );\n\t\tvec2 f = fract( uv );\n\t\tuv += 0.5 - f;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tif ( mipInt < cubeUV_maxMipLevel ) {\n\t\t\tuv.y += 2.0 * cubeUV_maxTileSize;\n\t\t}\n\t\tuv.y += filterInt * 2.0 * cubeUV_minTileSize;\n\t\tuv.x += 3.0 * max( 0.0, cubeUV_maxTileSize - 2.0 * faceSize );\n\t\tuv *= texelSize;\n\t\tvec3 tl = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.x += texelSize;\n\t\tvec3 tr = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.y += texelSize;\n\t\tvec3 br = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.x -= texelSize;\n\t\tvec3 bl = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tvec3 tm = mix( tl, tr, f.x );\n\t\tvec3 bm = mix( bl, br, f.x );\n\t\treturn mix( tm, bm, f.y );\n\t}\n\t#define r0 1.0\n\t#define v0 0.339\n\t#define m0 - 2.0\n\t#define r1 0.8\n\t#define v1 0.276\n\t#define m1 - 1.0\n\t#define r4 0.4\n\t#define v4 0.046\n\t#define m4 2.0\n\t#define r5 0.305\n\t#define v5 0.016\n\t#define m5 3.0\n\t#define r6 0.21\n\t#define v6 0.0038\n\t#define m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= r1 ) {\n\t\t\tmip = ( r0 - roughness ) * ( m1 - m0 ) / ( r0 - r1 ) + m0;\n\t\t} else if ( roughness >= r4 ) {\n\t\t\tmip = ( r1 - roughness ) * ( m4 - m1 ) / ( r1 - r4 ) + m1;\n\t\t} else if ( roughness >= r5 ) {\n\t\t\tmip = ( r4 - roughness ) * ( m5 - m4 ) / ( r4 - r5 ) + m4;\n\t\t} else if ( roughness >= r6 ) {\n\t\t\tmip = ( r5 - roughness ) * ( m6 - m5 ) / ( r5 - r6 ) + m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), m0, cubeUV_maxMipLevel );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif",defaultnormal_vertex:"vec3 transformedNormal = objectNormal;\n#ifdef USE_INSTANCING\n\tmat3 m = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) );\n\ttransformedNormal = m * transformedNormal;\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif",displacementmap_pars_vertex:"#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif",displacementmap_vertex:"#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vUv ).x * displacementScale + displacementBias );\n#endif",emissivemap_fragment:"#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif",emissivemap_pars_fragment:"#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif",encodings_fragment:"gl_FragColor = linearToOutputTexel( gl_FragColor );",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.rgb, vec3( gammaFactor ) ), value.a );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( 1.0 / gammaFactor ) ), value.a );\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.a );\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.a );\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.rgb * value.a * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, 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.r, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = clamp( floor( D ) / 255.0, 0.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 = cLogLuvM * value.rgb;\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 = cLogLuvInverseM * Xp_Y_XYZp.rgb;\n\treturn vec4( max( vRGB, 0.0 ), 1.0 );\n}",envmap_fragment:"#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, 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_CUBE_UV )\n\t\tvec4 envColor = textureCubeUV( envMap, reflectVec, 0.0 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifndef ENVMAP_TYPE_CUBE_UV\n\t\tenvColor = envMapTexelToLinear( envColor );\n\t#endif\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",envmap_common_pars_fragment:"#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\tuniform int maxMipLevel;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif",envmap_pars_fragment:"#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif",envmap_pars_vertex:"#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) ||defined( PHONG )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif",envmap_physical_pars_fragment:"#if defined( USE_ENVMAP )\n\t#ifdef ENVMAP_MODE_REFRACTION\n\t\tuniform float refractionRatio;\n\t#endif\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\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 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 roughness, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat sigma = PI * roughness * roughness / ( 1.0 + roughness );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar + log2( sigma );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( -viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( -viewDir, normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( roughness, 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\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif",envmap_vertex:"#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\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",fog_vertex:"#ifdef USE_FOG\n\tfogDepth = - mvPosition.z;\n#endif",fog_pars_vertex:"#ifdef USE_FOG\n\tvarying float fogDepth;\n#endif",fog_fragment:"#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * fogDepth * fogDepth );\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",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",gradientmap_pars_fragment:"#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn texture2D( gradientMap, coord ).rgb;\n\t#else\n\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t#endif\n}",lightmap_fragment:"#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\treflectedLight.indirectDiffuse += PI * lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n#endif",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 = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\nvIndirectFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n\tvIndirectBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\nvIndirectFront += getAmbientLightIrradiance( ambientLightColor );\nvIndirectFront += getLightProbeIrradiance( lightProbe, geometry );\n#ifdef DOUBLE_SIDED\n\tvIndirectBack += getAmbientLightIrradiance( ambientLightColor );\n\tvIndirectBack += getLightProbeIrradiance( lightProbe, backGeometry );\n#endif\n#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop_start\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\t#pragma unroll_loop_end\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop_start\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\t#pragma unroll_loop_end\n#endif\n#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop_start\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\t#pragma unroll_loop_end\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvIndirectFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvIndirectBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif",lights_pars_begin:"uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\nuniform vec3 lightProbe[ 9 ];\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in GeometricContext geometry ) {\n\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\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};\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};\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};\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",lights_toon_fragment:"ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;",lights_toon_pars_fragment:"varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon\n#define Material_LightProbeLOD( material )\t(0)",lights_phong_fragment:"BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;",lights_phong_pars_fragment:"varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial 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\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)",lights_physical_fragment:"PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.specularRoughness = max( roughnessFactor, 0.0525 );material.specularRoughness += geometryRoughness;\nmaterial.specularRoughness = min( material.specularRoughness, 1.0 );\n#ifdef REFLECTIVITY\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#endif\n#ifdef CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheen;\n#endif",lights_physical_pars_fragment:"struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat specularRoughness;\n\tvec3 specularColor;\n#ifdef CLEARCOAT\n\tfloat clearcoat;\n\tfloat clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tvec3 sheenColor;\n#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(\t\t0, 1,\t\t0 ),\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#ifdef CLEARCOAT\n\t\tfloat ccDotNL = saturate( dot( geometry.clearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = ccDotNL * directLight.color;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tccIrradiance *= PI;\n\t\t#endif\n\t\tfloat clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );\n\t\treflectedLight.directSpecular += ccIrradiance * material.clearcoat * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );\n\t#else\n\t\tfloat clearcoatDHR = 0.0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\treflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_Sheen(\n\t\t\tmaterial.specularRoughness,\n\t\t\tdirectLight.direction,\n\t\t\tgeometry,\n\t\t\tmaterial.sheenColor\n\t\t);\n\t#else\n\t\treflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness);\n\t#endif\n\treflectedLight.directDiffuse += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\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 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef CLEARCOAT\n\t\tfloat ccDotNV = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular += clearcoatRadiance * material.clearcoat * BRDF_Specular_GGX_Environment( geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );\n\t\tfloat ccDotNL = ccDotNV;\n\t\tfloat clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );\n\t#else\n\t\tfloat clearcoatDHR = 0.0;\n\t#endif\n\tfloat clearcoatInv = 1.0 - clearcoatDHR;\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\tBRDF_Specular_Multiscattering_Environment( geometry, material.specularColor, material.specularRoughness, singleScattering, multiScattering );\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - ( singleScattering + multiScattering ) );\n\treflectedLight.indirectSpecular += clearcoatInv * radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\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\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}",lights_fragment_begin:"\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n#ifdef CLEARCOAT\n\tgeometry.clearcoatNormal = clearcoatNormal;\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\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\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\tirradiance += getLightProbeIrradiance( lightProbe, geometry );\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif",lights_fragment_maps:"#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\t\tvec3 lightMapIrradiance = lightMapTexelToLinear( lightMapTexel ).rgb * 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 defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getLightProbeIndirectIrradiance( geometry, maxMipLevel );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getLightProbeIndirectRadiance( geometry.viewDir, geometry.normal, material.specularRoughness, maxMipLevel );\n\t#ifdef CLEARCOAT\n\t\tclearcoatRadiance += getLightProbeIndirectRadiance( geometry.viewDir, geometry.clearcoatNormal, material.clearcoatRoughness, maxMipLevel );\n\t#endif\n#endif",lights_fragment_end:"#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometry, material, reflectedLight );\n#endif",logdepthbuf_fragment:"#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif",logdepthbuf_pars_fragment:"#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif",logdepthbuf_pars_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t\tvarying float vIsPerspective;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif",logdepthbuf_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif",map_fragment:"#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif",map_pars_fragment:"#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif",map_particle_fragment:"#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n#endif\n#ifdef USE_MAP\n\tvec4 mapTexel = texture2D( map, uv );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif",map_particle_pars_fragment:"#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tuniform mat3 uvTransform;\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif",metalnessmap_fragment:"float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif",metalnessmap_pars_fragment:"#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n#endif",morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifndef USE_MORPHNORMALS\n\t\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\t\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif",morphtarget_vertex:"#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t#endif\n#endif",normal_fragment_begin:"float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#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 * faceDirection;\n\t#endif\n\t#ifdef USE_TANGENT\n\t\tvec3 tangent = normalize( vTangent );\n\t\tvec3 bitangent = normalize( vBitangent );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\ttangent = tangent * faceDirection;\n\t\t\tbitangent = bitangent * faceDirection;\n\t\t#endif\n\t\t#if defined( TANGENTSPACE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tmat3 vTBN = mat3( tangent, bitangent, normal );\n\t\t#endif\n\t#endif\n#endif\nvec3 geometryNormal = normal;",normal_fragment_maps:"#ifdef OBJECTSPACE_NORMALMAP\n\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( TANGENTSPACE_NORMALMAP )\n\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\t#ifdef USE_TANGENT\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( -vViewPosition, normal, mapN, faceDirection );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif",normalmap_pars_fragment:"#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN, float faceDirection ) {\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 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : faceDirection * inversesqrt( det );\n\t\treturn normalize( T * ( mapN.x * scale ) + B * ( mapN.y * scale ) + N * mapN.z );\n\t}\n#endif",clearcoat_normal_fragment_begin:"#ifdef CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif",clearcoat_normal_fragment_maps:"#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\t#ifdef USE_TANGENT\n\t\tclearcoatNormal = normalize( vTBN * clearcoatMapN );\n\t#else\n\t\tclearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatMapN, faceDirection );\n\t#endif\n#endif",clearcoat_pars_fragment:"#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif",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}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ));\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w);\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\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}",premultiplied_alpha_fragment:"#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif",project_vertex:"vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;",dithering_fragment:"#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif",dithering_pars_fragment:"#ifdef 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",roughnessmap_fragment:"float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif",roughnessmap_pars_fragment:"#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif",shadowmap_pars_fragment:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\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\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\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( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), 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( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), 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 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ), \n\t\t\t\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t\tf.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ), \n\t\t\t\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t\tf.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\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 ) || defined( SHADOWMAP_TYPE_VSM )\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",shadowmap_pars_vertex:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif",shadowmap_vertex:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SPOT_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0\n\t\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\tvec4 shadowWorldPosition;\n\t#endif\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n#endif",shadowmask_pars_fragment:"float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\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 highp 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",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",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\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif",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\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif",tonemapping_pars_fragment:"#ifndef saturate\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\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}\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}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3(\t1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108,\t1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605,\t1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }",transmissionmap_fragment:"#ifdef USE_TRANSMISSIONMAP\n\ttotalTransmission *= texture2D( transmissionMap, vUv ).r;\n#endif",transmissionmap_pars_fragment:"#ifdef USE_TRANSMISSIONMAP\n\tuniform sampler2D transmissionMap;\n#endif",uv_pars_fragment:"#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif",uv_pars_vertex:"#ifdef USE_UV\n\t#ifdef UVS_VERTEX_ONLY\n\t\tvec2 vUv;\n\t#else\n\t\tvarying vec2 vUv;\n\t#endif\n\tuniform mat3 uvTransform;\n#endif",uv_vertex:"#ifdef USE_UV\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\tuniform mat3 uv2Transform;\n#endif",uv2_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n#endif",worldpos_vertex:"#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif",background_frag:"uniform sampler2D t2D;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include \n\t#include \n}",background_vert:"varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}",cube_frag:"#include \nuniform float opacity;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 vReflect = vWorldDirection;\n\t#include \n\tgl_FragColor = envColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}",cube_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\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 \nvarying vec2 vHighPrecisionZW;\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\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}",depth_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\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\tvHighPrecisionZW = gl_Position.zw;\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}",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}",equirect_frag:"uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tvec4 texColor = texture2D( tEquirect, sampleUV );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include \n\t#include \n}",equirect_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \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}",linedashed_vert:"uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \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 \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\n\t\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\t\treflectedLight.indirectDiffuse += lightMapTexelToLinear( lightMapTexel ).rgb * 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\t#include \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}",meshlambert_frag:"uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\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 \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#ifdef DOUBLE_SIDED\n\t\treflectedLight.indirectDiffuse += ( gl_FrontFacing ) ? vIndirectFront : vIndirectBack;\n\t#else\n\t\treflectedLight.indirectDiffuse += vIndirectFront;\n\t#endif\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}",meshlambert_vert:"#define LAMBERT\nvarying vec3 vLightFront;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\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}",meshmatcap_frag:"#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\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\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t\tmatcapColor = matcapTexelToLinear( matcapColor );\n\t#else\n\t\tvec4 matcapColor = vec4( 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshmatcap_vert:"#define MATCAP\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 \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#ifndef FLAT_SHADED\n\t\tvNormal = normalize( transformedNormal );\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\tvViewPosition = - mvPosition.xyz;\n}",meshtoon_frag:"#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\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 \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\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshtoon_vert:"#define TOON\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}",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 \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\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}",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}",meshphysical_frag:"#define STANDARD\n#ifdef PHYSICAL\n\t#define REFLECTIVITY\n\t#define CLEARCOAT\n\t#define TRANSMISSION\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef TRANSMISSION\n\tuniform float transmission;\n#endif\n#ifdef REFLECTIVITY\n\tuniform float reflectivity;\n#endif\n#ifdef CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheen;\n#endif\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\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 \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#ifdef TRANSMISSION\n\t\tfloat totalTransmission = transmission;\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\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#ifdef TRANSMISSION\n\t\tdiffuseColor.a *= mix( saturate( 1. - totalTransmission + linearToRelativeLuminance( reflectedLight.directSpecular + reflectedLight.indirectSpecular ) ), 1.0, metalness );\n\t#endif\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshphysical_vert:"#define STANDARD\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\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\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\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}",normal_frag:"#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\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\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}",normal_vert:"#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\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#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif\n\t#include \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( TANGENTSPACE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}",points_frag:"uniform vec3 diffuse;\nuniform float opacity;\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}",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#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \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\t#include \n\t#include \n}",shadow_vert:"#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}",sprite_frag:"uniform vec3 diffuse;\nuniform float opacity;\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}",sprite_vert:"uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}"},ui={common:{diffuse:{value:new tn(15658734)},opacity:{value:1},map:{value:null},uvTransform:{value:new yt},uv2Transform:{value:new yt},alphaMap:{value:null}},specularmap:{specularMap:{value:null}},envmap:{envMap:{value:null},flipEnvMap:{value:-1},reflectivity:{value:1},refractionRatio:{value:.98},maxMipLevel:{value:0}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1}},emissivemap:{emissiveMap:{value:null}},bumpmap:{bumpMap:{value:null},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalScale:{value:new vt(1,1)}},displacementmap:{displacementMap:{value:null},displacementScale:{value:1},displacementBias:{value:0}},roughnessmap:{roughnessMap:{value:null}},metalnessmap:{metalnessMap:{value:null}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new tn(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{}}},directionalLightShadows:{value:[],properties:{shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},directionalShadowMap:{value:[]},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{}}},spotLightShadows:{value:[],properties:{shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},spotShadowMap:{value:[]},spotShadowMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{}}},pointLightShadows:{value:[],properties:{shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}},pointShadowMap:{value:[]},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}},ltc_1:{value:null},ltc_2:{value:null}},points:{diffuse:{value:new tn(15658734)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},uvTransform:{value:new yt}},sprite:{diffuse:{value:new tn(15658734)},opacity:{value:1},center:{value:new vt(.5,.5)},rotation:{value:0},map:{value:null},alphaMap:{value:null},uvTransform:{value:new yt}}},di={basic:{uniforms:Yn([ui.common,ui.specularmap,ui.envmap,ui.aomap,ui.lightmap,ui.fog]),vertexShader:hi.meshbasic_vert,fragmentShader:hi.meshbasic_frag},lambert:{uniforms:Yn([ui.common,ui.specularmap,ui.envmap,ui.aomap,ui.lightmap,ui.emissivemap,ui.fog,ui.lights,{emissive:{value:new tn(0)}}]),vertexShader:hi.meshlambert_vert,fragmentShader:hi.meshlambert_frag},phong:{uniforms:Yn([ui.common,ui.specularmap,ui.envmap,ui.aomap,ui.lightmap,ui.emissivemap,ui.bumpmap,ui.normalmap,ui.displacementmap,ui.fog,ui.lights,{emissive:{value:new tn(0)},specular:{value:new tn(1118481)},shininess:{value:30}}]),vertexShader:hi.meshphong_vert,fragmentShader:hi.meshphong_frag},standard:{uniforms:Yn([ui.common,ui.envmap,ui.aomap,ui.lightmap,ui.emissivemap,ui.bumpmap,ui.normalmap,ui.displacementmap,ui.roughnessmap,ui.metalnessmap,ui.fog,ui.lights,{emissive:{value:new tn(0)},roughness:{value:1},metalness:{value:0},envMapIntensity:{value:1}}]),vertexShader:hi.meshphysical_vert,fragmentShader:hi.meshphysical_frag},toon:{uniforms:Yn([ui.common,ui.aomap,ui.lightmap,ui.emissivemap,ui.bumpmap,ui.normalmap,ui.displacementmap,ui.gradientmap,ui.fog,ui.lights,{emissive:{value:new tn(0)}}]),vertexShader:hi.meshtoon_vert,fragmentShader:hi.meshtoon_frag},matcap:{uniforms:Yn([ui.common,ui.bumpmap,ui.normalmap,ui.displacementmap,ui.fog,{matcap:{value:null}}]),vertexShader:hi.meshmatcap_vert,fragmentShader:hi.meshmatcap_frag},points:{uniforms:Yn([ui.points,ui.fog]),vertexShader:hi.points_vert,fragmentShader:hi.points_frag},dashed:{uniforms:Yn([ui.common,ui.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:hi.linedashed_vert,fragmentShader:hi.linedashed_frag},depth:{uniforms:Yn([ui.common,ui.displacementmap]),vertexShader:hi.depth_vert,fragmentShader:hi.depth_frag},normal:{uniforms:Yn([ui.common,ui.bumpmap,ui.normalmap,ui.displacementmap,{opacity:{value:1}}]),vertexShader:hi.normal_vert,fragmentShader:hi.normal_frag},sprite:{uniforms:Yn([ui.sprite,ui.fog]),vertexShader:hi.sprite_vert,fragmentShader:hi.sprite_frag},background:{uniforms:{uvTransform:{value:new yt},t2D:{value:null}},vertexShader:hi.background_vert,fragmentShader:hi.background_frag},cube:{uniforms:Yn([ui.envmap,{opacity:{value:1}}]),vertexShader:hi.cube_vert,fragmentShader:hi.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:hi.equirect_vert,fragmentShader:hi.equirect_frag},distanceRGBA:{uniforms:Yn([ui.common,ui.displacementmap,{referencePosition:{value:new Lt},nearDistance:{value:1},farDistance:{value:1e3}}]),vertexShader:hi.distanceRGBA_vert,fragmentShader:hi.distanceRGBA_frag},shadow:{uniforms:Yn([ui.lights,ui.fog,{color:{value:new tn(0)},opacity:{value:1}}]),vertexShader:hi.shadow_vert,fragmentShader:hi.shadow_frag}};function pi(t,e,n,i,r){const s=new tn(0);let a,o,c=0,h=null,u=0,d=null;function p(t,e){n.buffers.color.setClear(t.r,t.g,t.b,e,r)}return{getClearColor:function(){return s},setClearColor:function(t,e=1){s.set(t),c=e,p(s,c)},getClearAlpha:function(){return c},setClearAlpha:function(t){c=t,p(s,c)},render:function(n,r,m,f){let g=!0===r.isScene?r.background:null;g&&g.isTexture&&(g=e.get(g));const v=t.xr,y=v.getSession&&v.getSession();y&&"additive"===y.environmentBlendMode&&(g=null),null===g?p(s,c):g&&g.isColor&&(p(g,1),f=!0),(t.autoClear||f)&&t.clear(t.autoClearColor,t.autoClearDepth,t.autoClearStencil),g&&(g.isCubeTexture||g.mapping===l)?(void 0===o&&(o=new Wn(new qn(1,1,1),new Jn({name:"BackgroundCubeMaterial",uniforms:Xn(di.cube.uniforms),vertexShader:di.cube.vertexShader,fragmentShader:di.cube.fragmentShader,side:1,depthTest:!1,depthWrite:!1,fog:!1})),o.geometry.deleteAttribute("normal"),o.geometry.deleteAttribute("uv"),o.onBeforeRender=function(t,e,n){this.matrixWorld.copyPosition(n.matrixWorld)},Object.defineProperty(o.material,"envMap",{get:function(){return this.uniforms.envMap.value}}),i.update(o)),o.material.uniforms.envMap.value=g,o.material.uniforms.flipEnvMap.value=g.isCubeTexture&&g._needsFlipEnvMap?-1:1,h===g&&u===g.version&&d===t.toneMapping||(o.material.needsUpdate=!0,h=g,u=g.version,d=t.toneMapping),n.unshift(o,o.geometry,o.material,0,0,null)):g&&g.isTexture&&(void 0===a&&(a=new Wn(new ci(2,2),new Jn({name:"BackgroundMaterial",uniforms:Xn(di.background.uniforms),vertexShader:di.background.vertexShader,fragmentShader:di.background.fragmentShader,side:0,depthTest:!1,depthWrite:!1,fog:!1})),a.geometry.deleteAttribute("normal"),Object.defineProperty(a.material,"map",{get:function(){return this.uniforms.t2D.value}}),i.update(a)),a.material.uniforms.t2D.value=g,!0===g.matrixAutoUpdate&&g.updateMatrix(),a.material.uniforms.uvTransform.value.copy(g.matrix),h===g&&u===g.version&&d===t.toneMapping||(a.material.needsUpdate=!0,h=g,u=g.version,d=t.toneMapping),n.unshift(a,a.geometry,a.material,0,0,null))}}}function mi(t,e,n,i){const r=t.getParameter(34921),s=i.isWebGL2?null:e.get("OES_vertex_array_object"),a=i.isWebGL2||null!==s,o={},l=d(null);let c=l;function h(e){return i.isWebGL2?t.bindVertexArray(e):s.bindVertexArrayOES(e)}function u(e){return i.isWebGL2?t.deleteVertexArray(e):s.deleteVertexArrayOES(e)}function d(t){const e=[],n=[],i=[];for(let t=0;t=0){const s=l[e];if(void 0!==s){const e=s.normalized,r=s.itemSize,a=n.get(s);if(void 0===a)continue;const l=a.buffer,c=a.type,h=a.bytesPerElement;if(s.isInterleavedBufferAttribute){const n=s.data,a=n.stride,u=s.offset;n&&n.isInstancedInterleavedBuffer?(f(i,n.meshPerAttribute),void 0===o._maxInstanceCount&&(o._maxInstanceCount=n.meshPerAttribute*n.count)):m(i),t.bindBuffer(34962,l),v(i,r,c,e,a*h,u*h)}else s.isInstancedBufferAttribute?(f(i,s.meshPerAttribute),void 0===o._maxInstanceCount&&(o._maxInstanceCount=s.meshPerAttribute*s.count)):m(i),t.bindBuffer(34962,l),v(i,r,c,e,0,0)}else if("instanceMatrix"===e){const e=n.get(r.instanceMatrix);if(void 0===e)continue;const s=e.buffer,a=e.type;f(i+0,1),f(i+1,1),f(i+2,1),f(i+3,1),t.bindBuffer(34962,s),t.vertexAttribPointer(i+0,4,a,!1,64,0),t.vertexAttribPointer(i+1,4,a,!1,64,16),t.vertexAttribPointer(i+2,4,a,!1,64,32),t.vertexAttribPointer(i+3,4,a,!1,64,48)}else if("instanceColor"===e){const e=n.get(r.instanceColor);if(void 0===e)continue;const s=e.buffer,a=e.type;f(i,1),t.bindBuffer(34962,s),t.vertexAttribPointer(i,3,a,!1,12,0)}else if(void 0!==h){const n=h[e];if(void 0!==n)switch(n.length){case 2:t.vertexAttrib2fv(i,n);break;case 3:t.vertexAttrib3fv(i,n);break;case 4:t.vertexAttrib4fv(i,n);break;default:t.vertexAttrib1fv(i,n)}}}}g()}(r,l,u,y),null!==x&&t.bindBuffer(34963,n.get(x).buffer))},reset:y,resetDefaultState:x,dispose:function(){y();for(const t in o){const e=o[t];for(const t in e){const n=e[t];for(const t in n)u(n[t].object),delete n[t];delete e[t]}delete o[t]}},releaseStatesOfGeometry:function(t){if(void 0===o[t.id])return;const e=o[t.id];for(const t in e){const n=e[t];for(const t in n)u(n[t].object),delete n[t];delete e[t]}delete o[t.id]},releaseStatesOfProgram:function(t){for(const e in o){const n=o[e];if(void 0===n[t.id])continue;const i=n[t.id];for(const t in i)u(i[t].object),delete i[t];delete n[t.id]}},initAttributes:p,enableAttribute:m,disableUnusedAttributes:g}}function fi(t,e,n,i){const r=i.isWebGL2;let s;this.setMode=function(t){s=t},this.render=function(e,i){t.drawArrays(s,e,i),n.update(i,s,1)},this.renderInstances=function(i,a,o){if(0===o)return;let l,c;if(r)l=t,c="drawArraysInstanced";else if(l=e.get("ANGLE_instanced_arrays"),c="drawArraysInstancedANGLE",null===l)return void console.error("THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.");l[c](s,i,a,o),n.update(a,s,o)}}function gi(t,e,n){let i;function r(e){if("highp"===e){if(t.getShaderPrecisionFormat(35633,36338).precision>0&&t.getShaderPrecisionFormat(35632,36338).precision>0)return"highp";e="mediump"}return"mediump"===e&&t.getShaderPrecisionFormat(35633,36337).precision>0&&t.getShaderPrecisionFormat(35632,36337).precision>0?"mediump":"lowp"}const s="undefined"!=typeof WebGL2RenderingContext&&t instanceof WebGL2RenderingContext||"undefined"!=typeof WebGL2ComputeRenderingContext&&t instanceof WebGL2ComputeRenderingContext;let a=void 0!==n.precision?n.precision:"highp";const o=r(a);o!==a&&(console.warn("THREE.WebGLRenderer:",a,"not supported, using",o,"instead."),a=o);const l=!0===n.logarithmicDepthBuffer,c=t.getParameter(34930),h=t.getParameter(35660),u=t.getParameter(3379),d=t.getParameter(34076),p=t.getParameter(34921),m=t.getParameter(36347),f=t.getParameter(36348),g=t.getParameter(36349),v=h>0,y=s||e.has("OES_texture_float");return{isWebGL2:s,getMaxAnisotropy:function(){if(void 0!==i)return i;if(!0===e.has("EXT_texture_filter_anisotropic")){const n=e.get("EXT_texture_filter_anisotropic");i=t.getParameter(n.MAX_TEXTURE_MAX_ANISOTROPY_EXT)}else i=0;return i},getMaxPrecision:r,precision:a,logarithmicDepthBuffer:l,maxTextures:c,maxVertexTextures:h,maxTextureSize:u,maxCubemapSize:d,maxAttributes:p,maxVertexUniforms:m,maxVaryings:f,maxFragmentUniforms:g,vertexTextures:v,floatFragmentTextures:y,floatVertexTextures:v&&y,maxSamples:s?t.getParameter(36183):0}}function vi(t){const e=this;let n=null,i=0,r=!1,s=!1;const a=new Ne,o=new yt,l={value:null,needsUpdate:!1};function c(){l.value!==n&&(l.value=n,l.needsUpdate=i>0),e.numPlanes=i,e.numIntersection=0}function h(t,n,i,r){const s=null!==t?t.length:0;let c=null;if(0!==s){if(c=l.value,!0!==r||null===c){const e=i+4*s,r=n.matrixWorldInverse;o.getNormalMatrix(r),(null===c||c.length0){const a=t.getRenderTarget(),o=new ni(s.height/2);return o.fromEquirectangularTexture(t,r),e.set(r,o),t.setRenderTarget(a),r.addEventListener("dispose",i),n(o.texture,r.mapping)}return null}}}return r},dispose:function(){e=new WeakMap}}}function xi(t){const e={};function n(n){if(void 0!==e[n])return e[n];let i;switch(n){case"WEBGL_depth_texture":i=t.getExtension("WEBGL_depth_texture")||t.getExtension("MOZ_WEBGL_depth_texture")||t.getExtension("WEBKIT_WEBGL_depth_texture");break;case"EXT_texture_filter_anisotropic":i=t.getExtension("EXT_texture_filter_anisotropic")||t.getExtension("MOZ_EXT_texture_filter_anisotropic")||t.getExtension("WEBKIT_EXT_texture_filter_anisotropic");break;case"WEBGL_compressed_texture_s3tc":i=t.getExtension("WEBGL_compressed_texture_s3tc")||t.getExtension("MOZ_WEBGL_compressed_texture_s3tc")||t.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc");break;case"WEBGL_compressed_texture_pvrtc":i=t.getExtension("WEBGL_compressed_texture_pvrtc")||t.getExtension("WEBKIT_WEBGL_compressed_texture_pvrtc");break;default:i=t.getExtension(n)}return e[n]=i,i}return{has:function(t){return null!==n(t)},init:function(t){t.isWebGL2?n("EXT_color_buffer_float"):(n("WEBGL_depth_texture"),n("OES_texture_float"),n("OES_texture_half_float"),n("OES_texture_half_float_linear"),n("OES_standard_derivatives"),n("OES_element_index_uint"),n("OES_vertex_array_object"),n("ANGLE_instanced_arrays")),n("OES_texture_float_linear"),n("EXT_color_buffer_half_float")},get:function(t){const e=n(t);return null===e&&console.warn("THREE.WebGLRenderer: "+t+" extension not supported."),e}}}function _i(t,e,n,i){const r={},s=new WeakMap;function a(t){const o=t.target;null!==o.index&&e.remove(o.index);for(const t in o.attributes)e.remove(o.attributes[t]);o.removeEventListener("dispose",a),delete r[o.id];const l=s.get(o);l&&(e.remove(l),s.delete(o)),i.releaseStatesOfGeometry(o),!0===o.isInstancedBufferGeometry&&delete o._maxInstanceCount,n.memory.geometries--}function o(t){const n=[],i=t.index,r=t.attributes.position;let a=0;if(null!==i){const t=i.array;a=i.version;for(let e=0,i=t.length;e65535?dn:hn)(n,1);o.version=a;const l=s.get(t);l&&e.remove(l),s.set(t,o)}return{get:function(t,e){return!0===r[e.id]||(e.addEventListener("dispose",a),r[e.id]=!0,n.memory.geometries++),e},update:function(t){const n=t.attributes;for(const t in n)e.update(n[t],34962);const i=t.morphAttributes;for(const t in i){const n=i[t];for(let t=0,i=n.length;t0)return t;const r=e*n;let s=Ii[r];if(void 0===s&&(s=new Float32Array(r),Ii[r]=s),0!==e){i.toArray(s,0);for(let i=1,r=0;i!==e;++i)r+=n,t[i].toArray(s,r)}return s}function Hi(t,e){if(t.length!==e.length)return!1;for(let n=0,i=t.length;n/gm;function kr(t){return t.replace(Ur,Vr)}function Vr(t,e){const n=hi[e];if(void 0===n)throw new Error("Can not resolve #include <"+e+">");return kr(n)}const Wr=/#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g,jr=/#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;function qr(t){return t.replace(jr,Yr).replace(Wr,Xr)}function Xr(t,e,n,i){return console.warn("WebGLProgram: #pragma unroll_loop shader syntax is deprecated. Please use #pragma unroll_loop_start syntax instead."),Yr(t,e,n,i)}function Yr(t,e,n,i){let r="";for(let t=parseInt(e);t0?t.gammaFactor:1,v=n.isWebGL2?"":function(t){return[t.extensionDerivatives||t.envMapCubeUV||t.bumpMap||t.tangentSpaceNormalMap||t.clearcoatNormalMap||t.flatShading||"physical"===t.shaderID?"#extension GL_OES_standard_derivatives : enable":"",(t.extensionFragDepth||t.logarithmicDepthBuffer)&&t.rendererExtensionFragDepth?"#extension GL_EXT_frag_depth : enable":"",t.extensionDrawBuffers&&t.rendererExtensionDrawBuffers?"#extension GL_EXT_draw_buffers : require":"",(t.extensionShaderTextureLOD||t.envMap)&&t.rendererExtensionShaderTextureLod?"#extension GL_EXT_shader_texture_lod : enable":""].filter(Or).join("\n")}(n),y=function(t){const e=[];for(const n in t){const i=t[n];!1!==i&&e.push("#define "+n+" "+i)}return e.join("\n")}(o),x=a.createProgram();let _,w,b=n.glslVersion?"#version "+n.glslVersion+"\n":"";n.isRawShaderMaterial?(_=[y].filter(Or).join("\n"),_.length>0&&(_+="\n"),w=[v,y].filter(Or).join("\n"),w.length>0&&(w+="\n")):(_=[Zr(n),"#define SHADER_NAME "+n.shaderName,y,n.instancing?"#define USE_INSTANCING":"",n.instancingColor?"#define USE_INSTANCING_COLOR":"",n.supportsVertexTextures?"#define VERTEX_TEXTURES":"","#define GAMMA_FACTOR "+g,"#define MAX_BONES "+n.maxBones,n.useFog&&n.fog?"#define USE_FOG":"",n.useFog&&n.fogExp2?"#define FOG_EXP2":"",n.map?"#define USE_MAP":"",n.envMap?"#define USE_ENVMAP":"",n.envMap?"#define "+m:"",n.lightMap?"#define USE_LIGHTMAP":"",n.aoMap?"#define USE_AOMAP":"",n.emissiveMap?"#define USE_EMISSIVEMAP":"",n.bumpMap?"#define USE_BUMPMAP":"",n.normalMap?"#define USE_NORMALMAP":"",n.normalMap&&n.objectSpaceNormalMap?"#define OBJECTSPACE_NORMALMAP":"",n.normalMap&&n.tangentSpaceNormalMap?"#define TANGENTSPACE_NORMALMAP":"",n.clearcoatMap?"#define USE_CLEARCOATMAP":"",n.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",n.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",n.displacementMap&&n.supportsVertexTextures?"#define USE_DISPLACEMENTMAP":"",n.specularMap?"#define USE_SPECULARMAP":"",n.roughnessMap?"#define USE_ROUGHNESSMAP":"",n.metalnessMap?"#define USE_METALNESSMAP":"",n.alphaMap?"#define USE_ALPHAMAP":"",n.transmissionMap?"#define USE_TRANSMISSIONMAP":"",n.vertexTangents?"#define USE_TANGENT":"",n.vertexColors?"#define USE_COLOR":"",n.vertexAlphas?"#define USE_COLOR_ALPHA":"",n.vertexUvs?"#define USE_UV":"",n.uvsVertexOnly?"#define UVS_VERTEX_ONLY":"",n.flatShading?"#define FLAT_SHADED":"",n.skinning?"#define USE_SKINNING":"",n.useVertexTexture?"#define BONE_TEXTURE":"",n.morphTargets?"#define USE_MORPHTARGETS":"",n.morphNormals&&!1===n.flatShading?"#define USE_MORPHNORMALS":"",n.doubleSided?"#define DOUBLE_SIDED":"",n.flipSided?"#define FLIP_SIDED":"",n.shadowMapEnabled?"#define USE_SHADOWMAP":"",n.shadowMapEnabled?"#define "+d:"",n.sizeAttenuation?"#define USE_SIZEATTENUATION":"",n.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",n.logarithmicDepthBuffer&&n.rendererExtensionFragDepth?"#define USE_LOGDEPTHBUF_EXT":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;","#ifdef USE_INSTANCING","\tattribute mat4 instanceMatrix;","#endif","#ifdef USE_INSTANCING_COLOR","\tattribute vec3 instanceColor;","#endif","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_TANGENT","\tattribute vec4 tangent;","#endif","#if defined( USE_COLOR_ALPHA )","\tattribute vec4 color;","#elif defined( USE_COLOR )","\tattribute vec3 color;","#endif","#ifdef USE_MORPHTARGETS","\tattribute vec3 morphTarget0;","\tattribute vec3 morphTarget1;","\tattribute vec3 morphTarget2;","\tattribute vec3 morphTarget3;","\t#ifdef USE_MORPHNORMALS","\t\tattribute vec3 morphNormal0;","\t\tattribute vec3 morphNormal1;","\t\tattribute vec3 morphNormal2;","\t\tattribute vec3 morphNormal3;","\t#else","\t\tattribute vec3 morphTarget4;","\t\tattribute vec3 morphTarget5;","\t\tattribute vec3 morphTarget6;","\t\tattribute vec3 morphTarget7;","\t#endif","#endif","#ifdef USE_SKINNING","\tattribute vec4 skinIndex;","\tattribute vec4 skinWeight;","#endif","\n"].filter(Or).join("\n"),w=[v,Zr(n),"#define SHADER_NAME "+n.shaderName,y,n.alphaTest?"#define ALPHATEST "+n.alphaTest+(n.alphaTest%1?"":".0"):"","#define GAMMA_FACTOR "+g,n.useFog&&n.fog?"#define USE_FOG":"",n.useFog&&n.fogExp2?"#define FOG_EXP2":"",n.map?"#define USE_MAP":"",n.matcap?"#define USE_MATCAP":"",n.envMap?"#define USE_ENVMAP":"",n.envMap?"#define "+p:"",n.envMap?"#define "+m:"",n.envMap?"#define "+f:"",n.lightMap?"#define USE_LIGHTMAP":"",n.aoMap?"#define USE_AOMAP":"",n.emissiveMap?"#define USE_EMISSIVEMAP":"",n.bumpMap?"#define USE_BUMPMAP":"",n.normalMap?"#define USE_NORMALMAP":"",n.normalMap&&n.objectSpaceNormalMap?"#define OBJECTSPACE_NORMALMAP":"",n.normalMap&&n.tangentSpaceNormalMap?"#define TANGENTSPACE_NORMALMAP":"",n.clearcoatMap?"#define USE_CLEARCOATMAP":"",n.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",n.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",n.specularMap?"#define USE_SPECULARMAP":"",n.roughnessMap?"#define USE_ROUGHNESSMAP":"",n.metalnessMap?"#define USE_METALNESSMAP":"",n.alphaMap?"#define USE_ALPHAMAP":"",n.sheen?"#define USE_SHEEN":"",n.transmissionMap?"#define USE_TRANSMISSIONMAP":"",n.vertexTangents?"#define USE_TANGENT":"",n.vertexColors||n.instancingColor?"#define USE_COLOR":"",n.vertexAlphas?"#define USE_COLOR_ALPHA":"",n.vertexUvs?"#define USE_UV":"",n.uvsVertexOnly?"#define UVS_VERTEX_ONLY":"",n.gradientMap?"#define USE_GRADIENTMAP":"",n.flatShading?"#define FLAT_SHADED":"",n.doubleSided?"#define DOUBLE_SIDED":"",n.flipSided?"#define FLIP_SIDED":"",n.shadowMapEnabled?"#define USE_SHADOWMAP":"",n.shadowMapEnabled?"#define "+d:"",n.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",n.physicallyCorrectLights?"#define PHYSICALLY_CORRECT_LIGHTS":"",n.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",n.logarithmicDepthBuffer&&n.rendererExtensionFragDepth?"#define USE_LOGDEPTHBUF_EXT":"",(n.extensionShaderTextureLOD||n.envMap)&&n.rendererExtensionShaderTextureLod?"#define TEXTURE_LOD_EXT":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",0!==n.toneMapping?"#define TONE_MAPPING":"",0!==n.toneMapping?hi.tonemapping_pars_fragment:"",0!==n.toneMapping?Fr("toneMapping",n.toneMapping):"",n.dithering?"#define DITHERING":"",hi.encodings_pars_fragment,n.map?Br("mapTexelToLinear",n.mapEncoding):"",n.matcap?Br("matcapTexelToLinear",n.matcapEncoding):"",n.envMap?Br("envMapTexelToLinear",n.envMapEncoding):"",n.emissiveMap?Br("emissiveMapTexelToLinear",n.emissiveMapEncoding):"",n.lightMap?Br("lightMapTexelToLinear",n.lightMapEncoding):"",zr("linearToOutputTexel",n.outputEncoding),n.depthPacking?"#define DEPTH_PACKING "+n.depthPacking:"","\n"].filter(Or).join("\n")),h=kr(h),h=Hr(h,n),h=Gr(h,n),u=kr(u),u=Hr(u,n),u=Gr(u,n),h=qr(h),u=qr(u),n.isWebGL2&&!0!==n.isRawShaderMaterial&&(b="#version 300 es\n",_=["#define attribute in","#define varying out","#define texture2D texture"].join("\n")+"\n"+_,w=["#define varying in",n.glslVersion===it?"":"out highp vec4 pc_fragColor;",n.glslVersion===it?"":"#define gl_FragColor pc_fragColor","#define gl_FragDepthEXT gl_FragDepth","#define texture2D texture","#define textureCube texture","#define texture2DProj textureProj","#define texture2DLodEXT textureLod","#define texture2DProjLodEXT textureProjLod","#define textureCubeLodEXT textureLod","#define texture2DGradEXT textureGrad","#define texture2DProjGradEXT textureProjGrad","#define textureCubeGradEXT textureGrad"].join("\n")+"\n"+w);const M=b+w+u,S=Pr(a,35633,b+_+h),T=Pr(a,35632,M);if(a.attachShader(x,S),a.attachShader(x,T),void 0!==n.index0AttributeName?a.bindAttribLocation(x,0,n.index0AttributeName):!0===n.morphTargets&&a.bindAttribLocation(x,0,"position"),a.linkProgram(x),t.debug.checkShaderErrors){const t=a.getProgramInfoLog(x).trim(),e=a.getShaderInfoLog(S).trim(),n=a.getShaderInfoLog(T).trim();let i=!0,r=!0;if(!1===a.getProgramParameter(x,35714)){i=!1;const e=Nr(a,S,"vertex"),n=Nr(a,T,"fragment");console.error("THREE.WebGLProgram: shader error: ",a.getError(),"35715",a.getProgramParameter(x,35715),"gl.getProgramInfoLog",t,e,n)}else""!==t?console.warn("THREE.WebGLProgram: gl.getProgramInfoLog()",t):""!==e&&""!==n||(r=!1);r&&(this.diagnostics={runnable:i,programLog:t,vertexShader:{log:e,prefix:_},fragmentShader:{log:n,prefix:w}})}let E,A;return a.deleteShader(S),a.deleteShader(T),this.getUniforms=function(){return void 0===E&&(E=new Cr(a,x)),E},this.getAttributes=function(){return void 0===A&&(A=function(t,e){const n={},i=t.getProgramParameter(e,35721);for(let r=0;r0,maxBones:S,useVertexTexture:u,morphTargets:r.morphTargets,morphNormals:r.morphNormals,numDirLights:a.directional.length,numPointLights:a.point.length,numSpotLights:a.spot.length,numRectAreaLights:a.rectArea.length,numHemiLights:a.hemi.length,numDirLightShadows:a.directionalShadowMap.length,numPointLightShadows:a.pointShadowMap.length,numSpotLightShadows:a.spotShadowMap.length,numClippingPlanes:s.numPlanes,numClipIntersection:s.numIntersection,dithering:r.dithering,shadowMapEnabled:t.shadowMap.enabled&&g.length>0,shadowMapType:t.shadowMap.type,toneMapping:r.toneMapped?t.toneMapping:0,physicallyCorrectLights:t.physicallyCorrectLights,premultipliedAlpha:r.premultipliedAlpha,alphaTest:r.alphaTest,doubleSided:2===r.side,flipSided:1===r.side,depthPacking:void 0!==r.depthPacking&&r.depthPacking,index0AttributeName:r.index0AttributeName,extensionDerivatives:r.extensions&&r.extensions.derivatives,extensionFragDepth:r.extensions&&r.extensions.fragDepth,extensionDrawBuffers:r.extensions&&r.extensions.drawBuffers,extensionShaderTextureLOD:r.extensions&&r.extensions.shaderTextureLOD,rendererExtensionFragDepth:o||n.has("EXT_frag_depth"),rendererExtensionDrawBuffers:o||n.has("WEBGL_draw_buffers"),rendererExtensionShaderTextureLod:o||n.has("EXT_shader_texture_lod"),customProgramCacheKey:r.customProgramCacheKey()}},getProgramCacheKey:function(e){const n=[];if(e.shaderID?n.push(e.shaderID):(n.push(e.fragmentShader),n.push(e.vertexShader)),void 0!==e.defines)for(const t in e.defines)n.push(t),n.push(e.defines[t]);if(!1===e.isRawShaderMaterial){for(let t=0;t1&&i.sort(t||$r),r.length>1&&r.sort(e||ts)}}}function ns(t){let e=new WeakMap;return{get:function(n,i){let r;return!1===e.has(n)?(r=new es(t),e.set(n,[r])):i>=e.get(n).length?(r=new es(t),e.get(n).push(r)):r=e.get(n)[i],r},dispose:function(){e=new WeakMap}}}function is(){const t={};return{get:function(e){if(void 0!==t[e.id])return t[e.id];let n;switch(e.type){case"DirectionalLight":n={direction:new Lt,color:new tn};break;case"SpotLight":n={position:new Lt,direction:new Lt,color:new tn,distance:0,coneCos:0,penumbraCos:0,decay:0};break;case"PointLight":n={position:new Lt,color:new tn,distance:0,decay:0};break;case"HemisphereLight":n={direction:new Lt,skyColor:new tn,groundColor:new tn};break;case"RectAreaLight":n={color:new tn,position:new Lt,halfWidth:new Lt,halfHeight:new Lt}}return t[e.id]=n,n}}}let rs=0;function ss(t,e){return(e.castShadow?1:0)-(t.castShadow?1:0)}function as(t,e){const n=new is,i=function(){const t={};return{get:function(e){if(void 0!==t[e.id])return t[e.id];let n;switch(e.type){case"DirectionalLight":case"SpotLight":n={shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new vt};break;case"PointLight":n={shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new vt,shadowCameraNear:1,shadowCameraFar:1e3}}return t[e.id]=n,n}}}(),r={version:0,hash:{directionalLength:-1,pointLength:-1,spotLength:-1,rectAreaLength:-1,hemiLength:-1,numDirectionalShadows:-1,numPointShadows:-1,numSpotShadows:-1},ambient:[0,0,0],probe:[],directional:[],directionalShadow:[],directionalShadowMap:[],directionalShadowMatrix:[],spot:[],spotShadow:[],spotShadowMap:[],spotShadowMatrix:[],rectArea:[],rectAreaLTC1:null,rectAreaLTC2:null,point:[],pointShadow:[],pointShadowMap:[],pointShadowMatrix:[],hemi:[]};for(let t=0;t<9;t++)r.probe.push(new Lt);const s=new Lt,a=new se,o=new se;return{setup:function(s){let a=0,o=0,l=0;for(let t=0;t<9;t++)r.probe[t].set(0,0,0);let c=0,h=0,u=0,d=0,p=0,m=0,f=0,g=0;s.sort(ss);for(let t=0,e=s.length;t0&&(e.isWebGL2||!0===t.has("OES_texture_float_linear")?(r.rectAreaLTC1=ui.LTC_FLOAT_1,r.rectAreaLTC2=ui.LTC_FLOAT_2):!0===t.has("OES_texture_half_float_linear")?(r.rectAreaLTC1=ui.LTC_HALF_1,r.rectAreaLTC2=ui.LTC_HALF_2):console.error("THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.")),r.ambient[0]=a,r.ambient[1]=o,r.ambient[2]=l;const v=r.hash;v.directionalLength===c&&v.pointLength===h&&v.spotLength===u&&v.rectAreaLength===d&&v.hemiLength===p&&v.numDirectionalShadows===m&&v.numPointShadows===f&&v.numSpotShadows===g||(r.directional.length=c,r.spot.length=u,r.rectArea.length=d,r.point.length=h,r.hemi.length=p,r.directionalShadow.length=m,r.directionalShadowMap.length=m,r.pointShadow.length=f,r.pointShadowMap.length=f,r.spotShadow.length=g,r.spotShadowMap.length=g,r.directionalShadowMatrix.length=m,r.pointShadowMatrix.length=f,r.spotShadowMatrix.length=g,v.directionalLength=c,v.pointLength=h,v.spotLength=u,v.rectAreaLength=d,v.hemiLength=p,v.numDirectionalShadows=m,v.numPointShadows=f,v.numSpotShadows=g,r.version=rs++)},setupView:function(t,e){let n=0,i=0,l=0,c=0,h=0;const u=e.matrixWorldInverse;for(let e=0,d=t.length;e=n.get(i).length?(s=new os(t,e),n.get(i).push(s)):s=n.get(i)[r],s},dispose:function(){n=new WeakMap}}}class cs extends Xe{constructor(t){super(),this.type="MeshDepthMaterial",this.depthPacking=3200,this.skinning=!1,this.morphTargets=!1,this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.fog=!1,this.setValues(t)}copy(t){return super.copy(t),this.depthPacking=t.depthPacking,this.skinning=t.skinning,this.morphTargets=t.morphTargets,this.map=t.map,this.alphaMap=t.alphaMap,this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this}}cs.prototype.isMeshDepthMaterial=!0;class hs extends Xe{constructor(t){super(),this.type="MeshDistanceMaterial",this.referencePosition=new Lt,this.nearDistance=1,this.farDistance=1e3,this.skinning=!1,this.morphTargets=!1,this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.fog=!1,this.setValues(t)}copy(t){return super.copy(t),this.referencePosition.copy(t.referencePosition),this.nearDistance=t.nearDistance,this.farDistance=t.farDistance,this.skinning=t.skinning,this.morphTargets=t.morphTargets,this.map=t.map,this.alphaMap=t.alphaMap,this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this}}hs.prototype.isMeshDistanceMaterial=!0;function us(t,e,n){let i=new ai;const r=new vt,s=new vt,a=new St,o=[],l=[],c={},h=n.maxTextureSize,u={0:1,1:0,2:2},d=new Jn({defines:{SAMPLE_RATE:2/8,HALF_SAMPLE_RATE:1/8},uniforms:{shadow_pass:{value:null},resolution:{value:new vt},radius:{value:4}},vertexShader:"void main() {\n\tgl_Position = vec4( position, 1.0 );\n}",fragmentShader:"uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\n#include \nvoid main() {\n\tfloat mean = 0.0;\n\tfloat squared_mean = 0.0;\n\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy ) / resolution ) );\n\tfor ( float i = -1.0; i < 1.0 ; i += SAMPLE_RATE) {\n\t\t#ifdef HORIZONTAL_PASS\n\t\t\tvec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( i, 0.0 ) * radius ) / resolution ) );\n\t\t\tmean += distribution.x;\n\t\t\tsquared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n\t\t#else\n\t\t\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, i ) * radius ) / resolution ) );\n\t\t\tmean += depth;\n\t\t\tsquared_mean += depth * depth;\n\t\t#endif\n\t}\n\tmean = mean * HALF_SAMPLE_RATE;\n\tsquared_mean = squared_mean * HALF_SAMPLE_RATE;\n\tfloat std_dev = sqrt( squared_mean - mean * mean );\n\tgl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}"}),m=d.clone();m.defines.HORIZONTAL_PASS=1;const f=new En;f.setAttribute("position",new sn(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));const v=new Wn(f,d),y=this;function x(n,i){const r=e.update(v);d.uniforms.shadow_pass.value=n.map.texture,d.uniforms.resolution.value=n.mapSize,d.uniforms.radius.value=n.radius,t.setRenderTarget(n.mapPass),t.clear(),t.renderBufferDirect(i,null,r,d,v,null),m.uniforms.shadow_pass.value=n.mapPass.texture,m.uniforms.resolution.value=n.mapSize,m.uniforms.radius.value=n.radius,t.setRenderTarget(n.map),t.clear(),t.renderBufferDirect(i,null,r,m,v,null)}function _(t,e,n){const i=t<<0|e<<1|n<<2;let r=o[i];return void 0===r&&(r=new cs({depthPacking:3201,morphTargets:t,skinning:e}),o[i]=r),r}function w(t,e,n){const i=t<<0|e<<1|n<<2;let r=l[i];return void 0===r&&(r=new hs({morphTargets:t,skinning:e}),l[i]=r),r}function b(e,n,i,r,s,a,o){let l=null,h=_,d=e.customDepthMaterial;if(!0===r.isPointLight&&(h=w,d=e.customDistanceMaterial),void 0===d){let t=!1;!0===i.morphTargets&&(t=n.morphAttributes&&n.morphAttributes.position&&n.morphAttributes.position.length>0);let r=!1;!0===e.isSkinnedMesh&&(!0===i.skinning?r=!0:console.warn("THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:",e));l=h(t,r,!0===e.isInstancedMesh)}else l=d;if(t.localClippingEnabled&&!0===i.clipShadows&&0!==i.clippingPlanes.length){const t=l.uuid,e=i.uuid;let n=c[t];void 0===n&&(n={},c[t]=n);let r=n[e];void 0===r&&(r=l.clone(),n[e]=r),l=r}return l.visible=i.visible,l.wireframe=i.wireframe,l.side=3===o?null!==i.shadowSide?i.shadowSide:i.side:null!==i.shadowSide?i.shadowSide:u[i.side],l.clipShadows=i.clipShadows,l.clippingPlanes=i.clippingPlanes,l.clipIntersection=i.clipIntersection,l.wireframeLinewidth=i.wireframeLinewidth,l.linewidth=i.linewidth,!0===r.isPointLight&&!0===l.isMeshDistanceMaterial&&(l.referencePosition.setFromMatrixPosition(r.matrixWorld),l.nearDistance=s,l.farDistance=a),l}function M(n,r,s,a,o){if(!1===n.visible)return;if(n.layers.test(r.layers)&&(n.isMesh||n.isLine||n.isPoints)&&(n.castShadow||n.receiveShadow&&3===o)&&(!n.frustumCulled||i.intersectsObject(n))){n.modelViewMatrix.multiplyMatrices(s.matrixWorldInverse,n.matrixWorld);const i=e.update(n),r=n.material;if(Array.isArray(r)){const e=i.groups;for(let l=0,c=e.length;lh||r.y>h)&&(r.x>h&&(s.x=Math.floor(h/m.x),r.x=s.x*m.x,u.mapSize.x=s.x),r.y>h&&(s.y=Math.floor(h/m.y),r.y=s.y*m.y,u.mapSize.y=s.y)),null===u.map&&!u.isPointLightShadow&&3===this.type){const t={minFilter:g,magFilter:g,format:E};u.map=new Tt(r.x,r.y,t),u.map.texture.name=c.name+".shadowMap",u.mapPass=new Tt(r.x,r.y,t),u.camera.updateProjectionMatrix()}if(null===u.map){const t={minFilter:p,magFilter:p,format:E};u.map=new Tt(r.x,r.y,t),u.map.texture.name=c.name+".shadowMap",u.camera.updateProjectionMatrix()}t.setRenderTarget(u.map),t.clear();const f=u.getViewportCount();for(let t=0;t=1):-1!==R.indexOf("OpenGL ES")&&(L=parseFloat(/^OpenGL ES (\d)/.exec(R)[1]),A=L>=2);let C=null,P={};const D=new St(0,0,t.canvas.width,t.canvas.height),I=new St(0,0,t.canvas.width,t.canvas.height);function N(e,n,i){const r=new Uint8Array(4),s=t.createTexture();t.bindTexture(e,s),t.texParameteri(e,10241,9728),t.texParameteri(e,10240,9728);for(let e=0;ei||t.height>i)&&(r=i/Math.max(t.width,t.height)),r<1||!0===e){if("undefined"!=typeof HTMLImageElement&&t instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&t instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&t instanceof ImageBitmap){const i=e?ft:Math.floor,s=i(r*t.width),a=i(r*t.height);void 0===P&&(P=I(s,a));const o=n?I(s,a):P;o.width=s,o.height=a;return o.getContext("2d").drawImage(t,0,0,s,a),console.warn("THREE.WebGLRenderer: Texture has been resized from ("+t.width+"x"+t.height+") to ("+s+"x"+a+")."),o}return"data"in t&&console.warn("THREE.WebGLRenderer: Image in DataTexture is too big ("+t.width+"x"+t.height+")."),t}return t}function B(t){return pt(t.width)&&pt(t.height)}function z(t,e){return t.generateMipmaps&&e&&t.minFilter!==p&&t.minFilter!==g}function F(e,n,r,s){t.generateMipmap(e);i.get(n).__maxMipLevel=Math.log2(Math.max(r,s))}function O(n,i,r){if(!1===o)return i;if(null!==n){if(void 0!==t[n])return t[n];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+n+"'")}let s=i;return 6403===i&&(5126===r&&(s=33326),5131===r&&(s=33325),5121===r&&(s=33321)),6407===i&&(5126===r&&(s=34837),5131===r&&(s=34843),5121===r&&(s=32849)),6408===i&&(5126===r&&(s=34836),5131===r&&(s=34842),5121===r&&(s=32856)),33325!==s&&33326!==s&&34842!==s&&34836!==s||e.get("EXT_color_buffer_float"),s}function H(t){return t===p||t===m||t===f?9728:9729}function G(e){const n=e.target;n.removeEventListener("dispose",G),function(e){const n=i.get(e);if(void 0===n.__webglInit)return;t.deleteTexture(n.__webglTexture),i.remove(e)}(n),n.isVideoTexture&&C.delete(n),a.memory.textures--}function U(e){const n=e.target;n.removeEventListener("dispose",U),function(e){const n=e.texture,r=i.get(e),s=i.get(n);if(!e)return;void 0!==s.__webglTexture&&t.deleteTexture(s.__webglTexture);e.depthTexture&&e.depthTexture.dispose();if(e.isWebGLCubeRenderTarget)for(let e=0;e<6;e++)t.deleteFramebuffer(r.__webglFramebuffer[e]),r.__webglDepthbuffer&&t.deleteRenderbuffer(r.__webglDepthbuffer[e]);else t.deleteFramebuffer(r.__webglFramebuffer),r.__webglDepthbuffer&&t.deleteRenderbuffer(r.__webglDepthbuffer),r.__webglMultisampledFramebuffer&&t.deleteFramebuffer(r.__webglMultisampledFramebuffer),r.__webglColorRenderbuffer&&t.deleteRenderbuffer(r.__webglColorRenderbuffer),r.__webglDepthRenderbuffer&&t.deleteRenderbuffer(r.__webglDepthRenderbuffer);i.remove(n),i.remove(e)}(n),a.memory.textures--}let k=0;function V(t,e){const r=i.get(t);if(t.isVideoTexture&&function(t){const e=a.render.frame;C.get(t)!==e&&(C.set(t,e),t.update())}(t),t.version>0&&r.__version!==t.version){const n=t.image;if(void 0===n)console.warn("THREE.WebGLRenderer: Texture marked for update but image is undefined");else{if(!1!==n.complete)return void Z(r,t,e);console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete")}}n.activeTexture(33984+e),n.bindTexture(3553,r.__webglTexture)}function W(e,r){const a=i.get(e);e.version>0&&a.__version!==e.version?function(e,i,r){if(6!==i.image.length)return;Y(e,i),n.activeTexture(33984+r),n.bindTexture(34067,e.__webglTexture),t.pixelStorei(37440,i.flipY),t.pixelStorei(37441,i.premultiplyAlpha),t.pixelStorei(3317,i.unpackAlignment),t.pixelStorei(37443,0);const a=i&&(i.isCompressedTexture||i.image[0].isCompressedTexture),l=i.image[0]&&i.image[0].isDataTexture,h=[];for(let t=0;t<6;t++)h[t]=a||l?l?i.image[t].image:i.image[t]:N(i.image[t],!1,!0,c);const u=h[0],d=B(u)||o,p=s.convert(i.format),m=s.convert(i.type),f=O(i.internalFormat,p,m);let g;if(X(34067,i,d),a){for(let t=0;t<6;t++){g=h[t].mipmaps;for(let e=0;e1||i.get(s).__currentAnisotropy)&&(t.texParameterf(n,a.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(s.anisotropy,r.getMaxAnisotropy())),i.get(s).__currentAnisotropy=s.anisotropy)}}function Y(e,n){void 0===e.__webglInit&&(e.__webglInit=!0,n.addEventListener("dispose",G),e.__webglTexture=t.createTexture(),a.memory.textures++)}function Z(e,i,r){let a=3553;i.isDataTexture2DArray&&(a=35866),i.isDataTexture3D&&(a=32879),Y(e,i),n.activeTexture(33984+r),n.bindTexture(a,e.__webglTexture),t.pixelStorei(37440,i.flipY),t.pixelStorei(37441,i.premultiplyAlpha),t.pixelStorei(3317,i.unpackAlignment),t.pixelStorei(37443,0);const l=function(t){return!o&&(t.wrapS!==u||t.wrapT!==u||t.minFilter!==p&&t.minFilter!==g)}(i)&&!1===B(i.image),c=N(i.image,l,!1,x),h=B(c)||o,d=s.convert(i.format);let m,f=s.convert(i.type),v=O(i.internalFormat,d,f);X(a,i,h);const y=i.mipmaps;if(i.isDepthTexture)v=6402,o?v=i.type===b?36012:i.type===w?33190:i.type===S?35056:33189:i.type===b&&console.error("WebGLRenderer: Floating point depth texture requires WebGL2."),i.format===A&&6402===v&&i.type!==_&&i.type!==w&&(console.warn("THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture."),i.type=_,f=s.convert(i.type)),i.format===L&&6402===v&&(v=34041,i.type!==S&&(console.warn("THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture."),i.type=S,f=s.convert(i.type))),n.texImage2D(3553,0,v,c.width,c.height,0,d,f,null);else if(i.isDataTexture)if(y.length>0&&h){for(let t=0,e=y.length;t0&&h){for(let t=0,e=y.length;t=l&&console.warn("THREE.WebGLTextures: Trying to use "+t+" texture units while this GPU supports only "+l),k+=1,t},this.resetTextureUnits=function(){k=0},this.setTexture2D=V,this.setTexture2DArray=function(t,e){const r=i.get(t);t.version>0&&r.__version!==t.version?Z(r,t,e):(n.activeTexture(33984+e),n.bindTexture(35866,r.__webglTexture))},this.setTexture3D=function(t,e){const r=i.get(t);t.version>0&&r.__version!==t.version?Z(r,t,e):(n.activeTexture(33984+e),n.bindTexture(32879,r.__webglTexture))},this.setTextureCube=W,this.setupRenderTarget=function(e){const r=e.texture,l=i.get(e),c=i.get(r);e.addEventListener("dispose",U),c.__webglTexture=t.createTexture(),c.__version=r.version,a.memory.textures++;const h=!0===e.isWebGLCubeRenderTarget,u=!0===e.isWebGLMultisampleRenderTarget,d=r.isDataTexture3D||r.isDataTexture2DArray,p=B(e)||o;if(!o||r.format!==T||r.type!==b&&r.type!==M||(r.format=E,console.warn("THREE.WebGLRenderer: Rendering to textures with RGB format is not supported. Using RGBA format instead.")),h){l.__webglFramebuffer=[];for(let e=0;e<6;e++)l.__webglFramebuffer[e]=t.createFramebuffer()}else if(l.__webglFramebuffer=t.createFramebuffer(),u)if(o){l.__webglMultisampledFramebuffer=t.createFramebuffer(),l.__webglColorRenderbuffer=t.createRenderbuffer(),t.bindRenderbuffer(36161,l.__webglColorRenderbuffer);const i=s.convert(r.format),a=s.convert(r.type),o=O(r.internalFormat,i,a),c=$(e);t.renderbufferStorageMultisample(36161,c,o,e.width,e.height),n.bindFramebuffer(36160,l.__webglMultisampledFramebuffer),t.framebufferRenderbuffer(36160,36064,36161,l.__webglColorRenderbuffer),t.bindRenderbuffer(36161,null),e.depthBuffer&&(l.__webglDepthRenderbuffer=t.createRenderbuffer(),Q(l.__webglDepthRenderbuffer,e,!0)),n.bindFramebuffer(36160,null)}else console.warn("THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.");if(h){n.bindTexture(34067,c.__webglTexture),X(34067,r,p);for(let t=0;t<6;t++)J(l.__webglFramebuffer[t],e,36064,34069+t);z(r,p)&&F(34067,r,e.width,e.height),n.bindTexture(34067,null)}else{let t=3553;if(d)if(o){t=r.isDataTexture3D?32879:35866}else console.warn("THREE.DataTexture3D and THREE.DataTexture2DArray only supported with WebGL2.");n.bindTexture(t,c.__webglTexture),X(t,r,p),J(l.__webglFramebuffer,e,36064,t),z(r,p)&&F(3553,r,e.width,e.height),n.bindTexture(3553,null)}e.depthBuffer&&K(e)},this.updateRenderTargetMipmap=function(t){const e=t.texture;if(z(e,B(t)||o)){const r=t.isWebGLCubeRenderTarget?34067:3553,s=i.get(e).__webglTexture;n.bindTexture(r,s),F(r,e,t.width,t.height),n.bindTexture(r,null)}},this.updateMultisampleRenderTarget=function(e){if(e.isWebGLMultisampleRenderTarget)if(o){const r=e.width,s=e.height;let a=16384;e.depthBuffer&&(a|=256),e.stencilBuffer&&(a|=1024);const o=i.get(e);n.bindFramebuffer(36008,o.__webglMultisampledFramebuffer),n.bindFramebuffer(36009,o.__webglFramebuffer),t.blitFramebuffer(0,0,r,s,0,0,r,s,a,9728),n.bindFramebuffer(36008,null),n.bindFramebuffer(36009,o.__webglMultisampledFramebuffer)}else console.warn("THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.")},this.safeSetTexture2D=function(t,e){t&&t.isWebGLRenderTarget&&(!1===tt&&(console.warn("THREE.WebGLTextures.safeSetTexture2D: don't use render targets as textures. Use their .texture property instead."),tt=!0),t=t.texture),V(t,e)},this.safeSetTextureCube=function(t,e){t&&t.isWebGLCubeRenderTarget&&(!1===et&&(console.warn("THREE.WebGLTextures.safeSetTextureCube: don't use cube render targets as textures. Use their .texture property instead."),et=!0),t=t.texture),W(t,e)}}function ms(t,e,n){const i=n.isWebGL2;return{convert:function(t){let n;if(t===x)return 5121;if(1017===t)return 32819;if(1018===t)return 32820;if(1019===t)return 33635;if(1010===t)return 5120;if(1011===t)return 5122;if(t===_)return 5123;if(1013===t)return 5124;if(t===w)return 5125;if(t===b)return 5126;if(t===M)return i?5131:(n=e.get("OES_texture_half_float"),null!==n?n.HALF_FLOAT_OES:null);if(1021===t)return 6406;if(t===T)return 6407;if(t===E)return 6408;if(1024===t)return 6409;if(1025===t)return 6410;if(t===A)return 6402;if(t===L)return 34041;if(1028===t)return 6403;if(1029===t)return 36244;if(1030===t)return 33319;if(1031===t)return 33320;if(1032===t)return 36248;if(1033===t)return 36249;if(t===R||t===C||t===P||t===D){if(n=e.get("WEBGL_compressed_texture_s3tc"),null===n)return null;if(t===R)return n.COMPRESSED_RGB_S3TC_DXT1_EXT;if(t===C)return n.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(t===P)return n.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(t===D)return n.COMPRESSED_RGBA_S3TC_DXT5_EXT}if(t===I||t===N||t===B||t===z){if(n=e.get("WEBGL_compressed_texture_pvrtc"),null===n)return null;if(t===I)return n.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(t===N)return n.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(t===B)return n.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(t===z)return n.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}if(36196===t)return n=e.get("WEBGL_compressed_texture_etc1"),null!==n?n.COMPRESSED_RGB_ETC1_WEBGL:null;if((t===F||t===O)&&(n=e.get("WEBGL_compressed_texture_etc"),null!==n)){if(t===F)return n.COMPRESSED_RGB8_ETC2;if(t===O)return n.COMPRESSED_RGBA8_ETC2_EAC}return 37808===t||37809===t||37810===t||37811===t||37812===t||37813===t||37814===t||37815===t||37816===t||37817===t||37818===t||37819===t||37820===t||37821===t||37840===t||37841===t||37842===t||37843===t||37844===t||37845===t||37846===t||37847===t||37848===t||37849===t||37850===t||37851===t||37852===t||37853===t?(n=e.get("WEBGL_compressed_texture_astc"),null!==n?t:null):36492===t?(n=e.get("EXT_texture_compression_bptc"),null!==n?t:null):t===S?i?34042:(n=e.get("WEBGL_depth_texture"),null!==n?n.UNSIGNED_INT_24_8_WEBGL:null):void 0}}}class fs extends Kn{constructor(t=[]){super(),this.cameras=t}}fs.prototype.isArrayCamera=!0;class gs extends Ce{constructor(){super(),this.type="Group"}}gs.prototype.isGroup=!0;const vs={type:"move"};class ys{constructor(){this._targetRay=null,this._grip=null,this._hand=null}getHandSpace(){return null===this._hand&&(this._hand=new gs,this._hand.matrixAutoUpdate=!1,this._hand.visible=!1,this._hand.joints={},this._hand.inputState={pinching:!1}),this._hand}getTargetRaySpace(){return null===this._targetRay&&(this._targetRay=new gs,this._targetRay.matrixAutoUpdate=!1,this._targetRay.visible=!1,this._targetRay.hasLinearVelocity=!1,this._targetRay.linearVelocity=new Lt,this._targetRay.hasAngularVelocity=!1,this._targetRay.angularVelocity=new Lt),this._targetRay}getGripSpace(){return null===this._grip&&(this._grip=new gs,this._grip.matrixAutoUpdate=!1,this._grip.visible=!1,this._grip.hasLinearVelocity=!1,this._grip.linearVelocity=new Lt,this._grip.hasAngularVelocity=!1,this._grip.angularVelocity=new Lt),this._grip}dispatchEvent(t){return null!==this._targetRay&&this._targetRay.dispatchEvent(t),null!==this._grip&&this._grip.dispatchEvent(t),null!==this._hand&&this._hand.dispatchEvent(t),this}disconnect(t){return this.dispatchEvent({type:"disconnected",data:t}),null!==this._targetRay&&(this._targetRay.visible=!1),null!==this._grip&&(this._grip.visible=!1),null!==this._hand&&(this._hand.visible=!1),this}update(t,e,n){let i=null,r=null,s=null;const a=this._targetRay,o=this._grip,l=this._hand;if(t&&"visible-blurred"!==e.session.visibilityState)if(null!==a&&(i=e.getPose(t.targetRaySpace,n),null!==i&&(a.matrix.fromArray(i.transform.matrix),a.matrix.decompose(a.position,a.rotation,a.scale),i.linearVelocity?(a.hasLinearVelocity=!0,a.linearVelocity.copy(i.linearVelocity)):a.hasLinearVelocity=!1,i.angularVelocity?(a.hasAngularVelocity=!0,a.angularVelocity.copy(i.angularVelocity)):a.hasAngularVelocity=!1,this.dispatchEvent(vs))),l&&t.hand){s=!0;for(const i of t.hand.values()){const t=e.getJointPose(i,n);if(void 0===l.joints[i.jointName]){const t=new gs;t.matrixAutoUpdate=!1,t.visible=!1,l.joints[i.jointName]=t,l.add(t)}const r=l.joints[i.jointName];null!==t&&(r.matrix.fromArray(t.transform.matrix),r.matrix.decompose(r.position,r.rotation,r.scale),r.jointRadius=t.radius),r.visible=null!==t}const i=l.joints["index-finger-tip"],r=l.joints["thumb-tip"],a=i.position.distanceTo(r.position),o=.02,c=.005;l.inputState.pinching&&a>o+c?(l.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:t.handedness,target:this})):!l.inputState.pinching&&a<=o-c&&(l.inputState.pinching=!0,this.dispatchEvent({type:"pinchstart",handedness:t.handedness,target:this}))}else null!==o&&t.gripSpace&&(r=e.getPose(t.gripSpace,n),null!==r&&(o.matrix.fromArray(r.transform.matrix),o.matrix.decompose(o.position,o.rotation,o.scale),r.linearVelocity?(o.hasLinearVelocity=!0,o.linearVelocity.copy(r.linearVelocity)):o.hasLinearVelocity=!1,r.angularVelocity?(o.hasAngularVelocity=!0,o.angularVelocity.copy(r.angularVelocity)):o.hasAngularVelocity=!1));return null!==a&&(a.visible=null!==i),null!==o&&(o.visible=null!==r),null!==l&&(l.visible=null!==s),this}}class xs extends rt{constructor(t,e){super();const n=this,i=t.state;let r=null,s=1,a=null,o="local-floor",l=null;const c=[],h=new Map,u=new Kn;u.layers.enable(1),u.viewport=new St;const d=new Kn;d.layers.enable(2),d.viewport=new St;const p=[u,d],m=new fs;m.layers.enable(1),m.layers.enable(2);let f=null,g=null;function v(t){const e=h.get(t.inputSource);e&&e.dispatchEvent({type:t.type,data:t.inputSource})}function y(){h.forEach((function(t,e){t.disconnect(e)})),h.clear(),f=null,g=null,i.bindXRFramebuffer(null),t.setRenderTarget(t.getRenderTarget()),S.stop(),n.isPresenting=!1,n.dispatchEvent({type:"sessionend"})}function x(t){const e=r.inputSources;for(let t=0;t0&&Rt(s,t,e),a.length>0&&Rt(a,t,e),null!==_&&(J.updateRenderTargetMipmap(_),J.updateMultisampleRenderTarget(_)),!0===t.isScene&&t.onAfterRender(f,t,e),q.buffers.depth.setTest(!0),q.buffers.depth.setMask(!0),q.buffers.color.setMask(!0),q.setPolygonOffset(!1),dt.resetDefaultState(),w=-1,S=null,m.pop(),d=m.length>0?m[m.length-1]:null,p.pop(),u=p.length>0?p[p.length-1]:null},this.getActiveCubeFace=function(){return v},this.getActiveMipmapLevel=function(){return y},this.getRenderTarget=function(){return _},this.setRenderTarget=function(t,e=0,n=0){_=t,v=e,y=n,t&&void 0===Z.get(t).__webglFramebuffer&&J.setupRenderTarget(t);let i=null,r=!1,s=!1;if(t){const n=t.texture;(n.isDataTexture3D||n.isDataTexture2DArray)&&(s=!0);const a=Z.get(t).__webglFramebuffer;t.isWebGLCubeRenderTarget?(i=a[e],r=!0):i=t.isWebGLMultisampleRenderTarget?Z.get(t).__webglMultisampledFramebuffer:a,T.copy(t.viewport),A.copy(t.scissor),L=t.scissorTest}else T.copy(N).multiplyScalar(P).floor(),A.copy(B).multiplyScalar(P).floor(),L=z;if(q.bindFramebuffer(36160,i),q.viewport(T),q.scissor(A),q.setScissorTest(L),r){const i=Z.get(t.texture);pt.framebufferTexture2D(36160,36064,34069+e,i.__webglTexture,n)}else if(s){const i=Z.get(t.texture),r=e||0;pt.framebufferTextureLayer(36160,36064,i.__webglTexture,n||0,r)}},this.readRenderTargetPixels=function(t,e,n,i,r,s,a){if(!t||!t.isWebGLRenderTarget)return void console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let o=Z.get(t).__webglFramebuffer;if(t.isWebGLCubeRenderTarget&&void 0!==a&&(o=o[a]),o){q.bindFramebuffer(36160,o);try{const a=t.texture,o=a.format,l=a.type;if(o!==E&&ut.convert(o)!==pt.getParameter(35739))return void console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.");const c=l===M&&(W.has("EXT_color_buffer_half_float")||j.isWebGL2&&W.has("EXT_color_buffer_float"));if(!(l===x||ut.convert(l)===pt.getParameter(35738)||l===b&&(j.isWebGL2||W.has("OES_texture_float")||W.has("WEBGL_color_buffer_float"))||c))return void console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.");36053===pt.checkFramebufferStatus(36160)?e>=0&&e<=t.width-i&&n>=0&&n<=t.height-r&&pt.readPixels(e,n,i,r,ut.convert(o),ut.convert(l),s):console.error("THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.")}finally{const t=null!==_?Z.get(_).__webglFramebuffer:null;q.bindFramebuffer(36160,t)}}},this.copyFramebufferToTexture=function(t,e,n=0){const i=Math.pow(2,-n),r=Math.floor(e.image.width*i),s=Math.floor(e.image.height*i),a=ut.convert(e.format);J.setTexture2D(e,0),pt.copyTexImage2D(3553,n,a,t.x,t.y,r,s,0),q.unbindTexture()},this.copyTextureToTexture=function(t,e,n,i=0){const r=e.image.width,s=e.image.height,a=ut.convert(n.format),o=ut.convert(n.type);J.setTexture2D(n,0),pt.pixelStorei(37440,n.flipY),pt.pixelStorei(37441,n.premultiplyAlpha),pt.pixelStorei(3317,n.unpackAlignment),e.isDataTexture?pt.texSubImage2D(3553,i,t.x,t.y,r,s,a,o,e.image.data):e.isCompressedTexture?pt.compressedTexSubImage2D(3553,i,t.x,t.y,e.mipmaps[0].width,e.mipmaps[0].height,a,e.mipmaps[0].data):pt.texSubImage2D(3553,i,t.x,t.y,a,o,e.image),0===i&&n.generateMipmaps&&pt.generateMipmap(3553),q.unbindTexture()},this.copyTextureToTexture3D=function(t,e,n,i,r=0){if(f.isWebGL1Renderer)return void console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.");const{width:s,height:a,data:o}=n.image,l=ut.convert(i.format),c=ut.convert(i.type);let h;if(i.isDataTexture3D)J.setTexture3D(i,0),h=32879;else{if(!i.isDataTexture2DArray)return void console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.");J.setTexture2DArray(i,0),h=35866}pt.pixelStorei(37440,i.flipY),pt.pixelStorei(37441,i.premultiplyAlpha),pt.pixelStorei(3317,i.unpackAlignment);const u=pt.getParameter(3314),d=pt.getParameter(32878),p=pt.getParameter(3316),m=pt.getParameter(3315),g=pt.getParameter(32877);pt.pixelStorei(3314,s),pt.pixelStorei(32878,a),pt.pixelStorei(3316,t.min.x),pt.pixelStorei(3315,t.min.y),pt.pixelStorei(32877,t.min.z),pt.texSubImage3D(h,r,e.x,e.y,e.z,t.max.x-t.min.x+1,t.max.y-t.min.y+1,t.max.z-t.min.z+1,l,c,o),pt.pixelStorei(3314,u),pt.pixelStorei(32878,d),pt.pixelStorei(3316,p),pt.pixelStorei(3315,m),pt.pixelStorei(32877,g),0===r&&i.generateMipmaps&&pt.generateMipmap(h),q.unbindTexture()},this.initTexture=function(t){J.setTexture2D(t,0),q.unbindTexture()},this.resetState=function(){v=0,y=0,_=null,q.reset(),dt.reset()},"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}class bs extends ws{}bs.prototype.isWebGL1Renderer=!0;class Ms{constructor(t,e=25e-5){this.name="",this.color=new tn(t),this.density=e}clone(){return new Ms(this.color,this.density)}toJSON(){return{type:"FogExp2",color:this.color.getHex(),density:this.density}}}Ms.prototype.isFogExp2=!0;class Ss{constructor(t,e=1,n=1e3){this.name="",this.color=new tn(t),this.near=e,this.far=n}clone(){return new Ss(this.color,this.near,this.far)}toJSON(){return{type:"Fog",color:this.color.getHex(),near:this.near,far:this.far}}}Ss.prototype.isFog=!0;class Ts extends Ce{constructor(){super(),this.type="Scene",this.background=null,this.environment=null,this.fog=null,this.overrideMaterial=null,this.autoUpdate=!0,"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}copy(t,e){return super.copy(t,e),null!==t.background&&(this.background=t.background.clone()),null!==t.environment&&(this.environment=t.environment.clone()),null!==t.fog&&(this.fog=t.fog.clone()),null!==t.overrideMaterial&&(this.overrideMaterial=t.overrideMaterial.clone()),this.autoUpdate=t.autoUpdate,this.matrixAutoUpdate=t.matrixAutoUpdate,this}toJSON(t){const e=super.toJSON(t);return null!==this.background&&(e.object.background=this.background.toJSON(t)),null!==this.environment&&(e.object.environment=this.environment.toJSON(t)),null!==this.fog&&(e.object.fog=this.fog.toJSON()),e}}Ts.prototype.isScene=!0;class Es{constructor(t,e){this.array=t,this.stride=e,this.count=void 0!==t?t.length/e:0,this.usage=et,this.updateRange={offset:0,count:-1},this.version=0,this.uuid=ct(),this.onUploadCallback=function(){}}set needsUpdate(t){!0===t&&this.version++}setUsage(t){return this.usage=t,this}copy(t){return this.array=new t.array.constructor(t.array),this.count=t.count,this.stride=t.stride,this.usage=t.usage,this}copyAt(t,e,n){t*=this.stride,n*=e.stride;for(let i=0,r=this.stride;it.far||e.push({distance:o,point:Ps.clone(),uv:je.getUV(Ps,Fs,Os,Hs,Gs,Us,ks,new vt),face:null,object:this})}copy(t){return super.copy(t),void 0!==t.center&&this.center.copy(t.center),this.material=t.material,this}}function Ws(t,e,n,i,r,s){Ns.subVectors(t,n).addScalar(.5).multiply(i),void 0!==r?(Bs.x=s*Ns.x-r*Ns.y,Bs.y=r*Ns.x+s*Ns.y):Bs.copy(Ns),t.copy(e),t.x+=Bs.x,t.y+=Bs.y,t.applyMatrix4(zs)}Vs.prototype.isSprite=!0;const js=new Lt,qs=new Lt;class Xs extends Ce{constructor(){super(),this._currentLevel=0,this.type="LOD",Object.defineProperties(this,{levels:{enumerable:!0,value:[]},isLOD:{value:!0}}),this.autoUpdate=!0}copy(t){super.copy(t,!1);const e=t.levels;for(let t=0,n=e.length;t0){let n,i;for(n=1,i=e.length;n0){js.setFromMatrixPosition(this.matrixWorld);const n=t.ray.origin.distanceTo(js);this.getObjectForDistance(n).raycast(t,e)}}update(t){const e=this.levels;if(e.length>1){js.setFromMatrixPosition(t.matrixWorld),qs.setFromMatrixPosition(this.matrixWorld);const n=js.distanceTo(qs)/t.zoom;let i,r;for(e[0].object.visible=!0,i=1,r=e.length;i=e[i].distance;i++)e[i-1].object.visible=!1,e[i].object.visible=!0;for(this._currentLevel=i-1;io)continue;u.applyMatrix4(this.matrixWorld);const d=t.ray.origin.distanceTo(u);dt.far||e.push({distance:d,point:h.clone().applyMatrix4(this.matrixWorld),index:n,face:null,faceIndex:null,object:this})}}else{for(let n=Math.max(0,s.start),i=Math.min(r.count,s.start+s.count)-1;no)continue;u.applyMatrix4(this.matrixWorld);const i=t.ray.origin.distanceTo(u);it.far||e.push({distance:i,point:h.clone().applyMatrix4(this.matrixWorld),index:n,face:null,faceIndex:null,object:this})}}}else n.isGeometry&&console.error("THREE.Line.raycast() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.")}updateMorphTargets(){const t=this.geometry;if(t.isBufferGeometry){const e=t.morphAttributes,n=Object.keys(e);if(n.length>0){const t=e[n[0]];if(void 0!==t){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let e=0,n=t.length;e0&&console.error("THREE.Line.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.")}}}fa.prototype.isLine=!0;const ga=new Lt,va=new Lt;class ya extends fa{constructor(t,e){super(t,e),this.type="LineSegments"}computeLineDistances(){const t=this.geometry;if(t.isBufferGeometry)if(null===t.index){const e=t.attributes.position,n=[];for(let t=0,i=e.count;t0){const t=e[n[0]];if(void 0!==t){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let e=0,n=t.length;e0&&console.error("THREE.Points.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.")}}}function Ea(t,e,n,i,r,s,a){const o=ba.distanceSqToPoint(t);if(or.far)return;s.push({distance:l,distanceToRay:Math.sqrt(o),point:n,index:e,face:null,object:a})}}Ta.prototype.isPoints=!0;class Aa extends bt{constructor(t,e,n,i,r,s,a,o,l){super(t,e,n,i,r,s,a,o,l),this.format=void 0!==a?a:T,this.minFilter=void 0!==s?s:g,this.magFilter=void 0!==r?r:g,this.generateMipmaps=!1;const c=this;"requestVideoFrameCallback"in t&&t.requestVideoFrameCallback((function e(){c.needsUpdate=!0,t.requestVideoFrameCallback(e)}))}clone(){return new this.constructor(this.image).copy(this)}update(){const t=this.image;!1==="requestVideoFrameCallback"in t&&t.readyState>=t.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}}Aa.prototype.isVideoTexture=!0;class La extends bt{constructor(t,e,n,i,r,s,a,o,l,c,h,u){super(null,s,a,o,l,c,i,r,h,u),this.image={width:e,height:n},this.mipmaps=t,this.flipY=!1,this.generateMipmaps=!1}}La.prototype.isCompressedTexture=!0;class Ra extends bt{constructor(t,e,n,i,r,s,a,o,l){super(t,e,n,i,r,s,a,o,l),this.needsUpdate=!0}}Ra.prototype.isCanvasTexture=!0;class Ca extends bt{constructor(t,e,n,i,r,s,a,o,l,c){if((c=void 0!==c?c:A)!==A&&c!==L)throw new Error("DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat");void 0===n&&c===A&&(n=_),void 0===n&&c===L&&(n=S),super(null,i,r,s,a,o,c,n,l),this.image={width:t,height:e},this.magFilter=void 0!==a?a:p,this.minFilter=void 0!==o?o:p,this.flipY=!1,this.generateMipmaps=!1}}Ca.prototype.isDepthTexture=!0;class Pa extends En{constructor(t=1,e=8,n=0,i=2*Math.PI){super(),this.type="CircleGeometry",this.parameters={radius:t,segments:e,thetaStart:n,thetaLength:i},e=Math.max(3,e);const r=[],s=[],a=[],o=[],l=new Lt,c=new vt;s.push(0,0,0),a.push(0,0,1),o.push(.5,.5);for(let r=0,h=3;r<=e;r++,h+=3){const u=n+r/e*i;l.x=t*Math.cos(u),l.y=t*Math.sin(u),s.push(l.x,l.y,l.z),a.push(0,0,1),c.x=(s[h]/t+1)/2,c.y=(s[h+1]/t+1)/2,o.push(c.x,c.y)}for(let t=1;t<=e;t++)r.push(t,t+1,0);this.setIndex(r),this.setAttribute("position",new mn(s,3)),this.setAttribute("normal",new mn(a,3)),this.setAttribute("uv",new mn(o,2))}}class Da extends En{constructor(t=1,e=1,n=1,i=8,r=1,s=!1,a=0,o=2*Math.PI){super(),this.type="CylinderGeometry",this.parameters={radiusTop:t,radiusBottom:e,height:n,radialSegments:i,heightSegments:r,openEnded:s,thetaStart:a,thetaLength:o};const l=this;i=Math.floor(i),r=Math.floor(r);const c=[],h=[],u=[],d=[];let p=0;const m=[],f=n/2;let g=0;function v(n){const r=p,s=new vt,m=new Lt;let v=0;const y=!0===n?t:e,x=!0===n?1:-1;for(let t=1;t<=i;t++)h.push(0,f*x,0),u.push(0,x,0),d.push(.5,.5),p++;const _=p;for(let t=0;t<=i;t++){const e=t/i*o+a,n=Math.cos(e),r=Math.sin(e);m.x=y*r,m.y=f*x,m.z=y*n,h.push(m.x,m.y,m.z),u.push(0,x,0),s.x=.5*n+.5,s.y=.5*r*x+.5,d.push(s.x,s.y),p++}for(let t=0;t0&&v(!0),e>0&&v(!1)),this.setIndex(c),this.setAttribute("position",new mn(h,3)),this.setAttribute("normal",new mn(u,3)),this.setAttribute("uv",new mn(d,2))}}class Ia extends Da{constructor(t=1,e=1,n=8,i=1,r=!1,s=0,a=2*Math.PI){super(0,t,e,n,i,r,s,a),this.type="ConeGeometry",this.parameters={radius:t,height:e,radialSegments:n,heightSegments:i,openEnded:r,thetaStart:s,thetaLength:a}}}class Na extends En{constructor(t,e,n=1,i=0){super(),this.type="PolyhedronGeometry",this.parameters={vertices:t,indices:e,radius:n,detail:i};const r=[],s=[];function a(t,e,n,i){const r=i+1,s=[];for(let i=0;i<=r;i++){s[i]=[];const a=t.clone().lerp(n,i/r),o=e.clone().lerp(n,i/r),l=r-i;for(let t=0;t<=l;t++)s[i][t]=0===t&&i===r?a:a.clone().lerp(o,t/l)}for(let t=0;t.9&&a<.1&&(e<.2&&(s[t+0]+=1),n<.2&&(s[t+2]+=1),i<.2&&(s[t+4]+=1))}}()}(),this.setAttribute("position",new mn(r,3)),this.setAttribute("normal",new mn(r.slice(),3)),this.setAttribute("uv",new mn(s,2)),0===i?this.computeVertexNormals():this.normalizeNormals()}}class Ba extends Na{constructor(t=1,e=0){const n=(1+Math.sqrt(5))/2,i=1/n;super([-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,-i,-n,0,-i,n,0,i,-n,0,i,n,-i,-n,0,-i,n,0,i,-n,0,i,n,0,-n,0,-i,n,0,-i,-n,0,i,n,0,i],[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],t,e),this.type="DodecahedronGeometry",this.parameters={radius:t,detail:e}}}const za=new Lt,Fa=new Lt,Oa=new Lt,Ha=new je;class Ga extends En{constructor(t,e){if(super(),this.type="EdgesGeometry",this.parameters={thresholdAngle:e},e=void 0!==e?e:1,!0===t.isGeometry)return void console.error("THREE.EdgesGeometry no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.");const n=Math.pow(10,4),i=Math.cos(ot*e),r=t.getIndex(),s=t.getAttribute("position"),a=r?r.count:s.count,o=[0,0,0],l=["a","b","c"],c=new Array(3),h={},u=[];for(let t=0;t80*n){o=c=t[0],l=h=t[1];for(let e=n;ec&&(c=u),d>h&&(h=d);p=Math.max(c-o,h-l),p=0!==p?1/p:0}return Wa(s,a,n,o,l,p),a};function ka(t,e,n,i,r){let s,a;if(r===function(t,e,n,i){let r=0;for(let s=e,a=n-i;s0)for(s=e;s=e;s-=i)a=co(s,t[s],t[s+1],a);return a&&io(a,a.next)&&(ho(a),a=a.next),a}function Va(t,e){if(!t)return t;e||(e=t);let n,i=t;do{if(n=!1,i.steiner||!io(i,i.next)&&0!==no(i.prev,i,i.next))i=i.next;else{if(ho(i),i=e=i.prev,i===i.next)break;n=!0}}while(n||i!==e);return e}function Wa(t,e,n,i,r,s,a){if(!t)return;!a&&s&&function(t,e,n,i){let r=t;do{null===r.z&&(r.z=Ka(r.x,r.y,e,n,i)),r.prevZ=r.prev,r.nextZ=r.next,r=r.next}while(r!==t);r.prevZ.nextZ=null,r.prevZ=null,function(t){let e,n,i,r,s,a,o,l,c=1;do{for(n=t,t=null,s=null,a=0;n;){for(a++,i=n,o=0,e=0;e0||l>0&&i;)0!==o&&(0===l||!i||n.z<=i.z)?(r=n,n=n.nextZ,o--):(r=i,i=i.nextZ,l--),s?s.nextZ=r:t=r,r.prevZ=s,s=r;n=i}s.nextZ=null,c*=2}while(a>1)}(r)}(t,i,r,s);let o,l,c=t;for(;t.prev!==t.next;)if(o=t.prev,l=t.next,s?qa(t,i,r,s):ja(t))e.push(o.i/n),e.push(t.i/n),e.push(l.i/n),ho(t),t=l.next,c=l.next;else if((t=l)===c){a?1===a?Wa(t=Xa(Va(t),e,n),e,n,i,r,s,2):2===a&&Ya(t,e,n,i,r,s):Wa(Va(t),e,n,i,r,s,1);break}}function ja(t){const e=t.prev,n=t,i=t.next;if(no(e,n,i)>=0)return!1;let r=t.next.next;for(;r!==t.prev;){if(to(e.x,e.y,n.x,n.y,i.x,i.y,r.x,r.y)&&no(r.prev,r,r.next)>=0)return!1;r=r.next}return!0}function qa(t,e,n,i){const r=t.prev,s=t,a=t.next;if(no(r,s,a)>=0)return!1;const o=r.xs.x?r.x>a.x?r.x:a.x:s.x>a.x?s.x:a.x,h=r.y>s.y?r.y>a.y?r.y:a.y:s.y>a.y?s.y:a.y,u=Ka(o,l,e,n,i),d=Ka(c,h,e,n,i);let p=t.prevZ,m=t.nextZ;for(;p&&p.z>=u&&m&&m.z<=d;){if(p!==t.prev&&p!==t.next&&to(r.x,r.y,s.x,s.y,a.x,a.y,p.x,p.y)&&no(p.prev,p,p.next)>=0)return!1;if(p=p.prevZ,m!==t.prev&&m!==t.next&&to(r.x,r.y,s.x,s.y,a.x,a.y,m.x,m.y)&&no(m.prev,m,m.next)>=0)return!1;m=m.nextZ}for(;p&&p.z>=u;){if(p!==t.prev&&p!==t.next&&to(r.x,r.y,s.x,s.y,a.x,a.y,p.x,p.y)&&no(p.prev,p,p.next)>=0)return!1;p=p.prevZ}for(;m&&m.z<=d;){if(m!==t.prev&&m!==t.next&&to(r.x,r.y,s.x,s.y,a.x,a.y,m.x,m.y)&&no(m.prev,m,m.next)>=0)return!1;m=m.nextZ}return!0}function Xa(t,e,n){let i=t;do{const r=i.prev,s=i.next.next;!io(r,s)&&ro(r,i,i.next,s)&&oo(r,s)&&oo(s,r)&&(e.push(r.i/n),e.push(i.i/n),e.push(s.i/n),ho(i),ho(i.next),i=t=s),i=i.next}while(i!==t);return Va(i)}function Ya(t,e,n,i,r,s){let a=t;do{let t=a.next.next;for(;t!==a.prev;){if(a.i!==t.i&&eo(a,t)){let o=lo(a,t);return a=Va(a,a.next),o=Va(o,o.next),Wa(a,e,n,i,r,s),void Wa(o,e,n,i,r,s)}t=t.next}a=a.next}while(a!==t)}function Za(t,e){return t.x-e.x}function Ja(t,e){if(e=function(t,e){let n=e;const i=t.x,r=t.y;let s,a=-1/0;do{if(r<=n.y&&r>=n.next.y&&n.next.y!==n.y){const t=n.x+(r-n.y)*(n.next.x-n.x)/(n.next.y-n.y);if(t<=i&&t>a){if(a=t,t===i){if(r===n.y)return n;if(r===n.next.y)return n.next}s=n.x=n.x&&n.x>=l&&i!==n.x&&to(rs.x||n.x===s.x&&Qa(s,n)))&&(s=n,u=h)),n=n.next}while(n!==o);return s}(t,e)){const n=lo(e,t);Va(e,e.next),Va(n,n.next)}}function Qa(t,e){return no(t.prev,t,e.prev)<0&&no(e.next,t,t.next)<0}function Ka(t,e,n,i,r){return(t=1431655765&((t=858993459&((t=252645135&((t=16711935&((t=32767*(t-n)*r)|t<<8))|t<<4))|t<<2))|t<<1))|(e=1431655765&((e=858993459&((e=252645135&((e=16711935&((e=32767*(e-i)*r)|e<<8))|e<<4))|e<<2))|e<<1))<<1}function $a(t){let e=t,n=t;do{(e.x=0&&(t-a)*(i-o)-(n-a)*(e-o)>=0&&(n-a)*(s-o)-(r-a)*(i-o)>=0}function eo(t,e){return t.next.i!==e.i&&t.prev.i!==e.i&&!function(t,e){let n=t;do{if(n.i!==t.i&&n.next.i!==t.i&&n.i!==e.i&&n.next.i!==e.i&&ro(n,n.next,t,e))return!0;n=n.next}while(n!==t);return!1}(t,e)&&(oo(t,e)&&oo(e,t)&&function(t,e){let n=t,i=!1;const r=(t.x+e.x)/2,s=(t.y+e.y)/2;do{n.y>s!=n.next.y>s&&n.next.y!==n.y&&r<(n.next.x-n.x)*(s-n.y)/(n.next.y-n.y)+n.x&&(i=!i),n=n.next}while(n!==t);return i}(t,e)&&(no(t.prev,t,e.prev)||no(t,e.prev,e))||io(t,e)&&no(t.prev,t,t.next)>0&&no(e.prev,e,e.next)>0)}function no(t,e,n){return(e.y-t.y)*(n.x-e.x)-(e.x-t.x)*(n.y-e.y)}function io(t,e){return t.x===e.x&&t.y===e.y}function ro(t,e,n,i){const r=ao(no(t,e,n)),s=ao(no(t,e,i)),a=ao(no(n,i,t)),o=ao(no(n,i,e));return r!==s&&a!==o||(!(0!==r||!so(t,n,e))||(!(0!==s||!so(t,i,e))||(!(0!==a||!so(n,t,i))||!(0!==o||!so(n,e,i)))))}function so(t,e,n){return e.x<=Math.max(t.x,n.x)&&e.x>=Math.min(t.x,n.x)&&e.y<=Math.max(t.y,n.y)&&e.y>=Math.min(t.y,n.y)}function ao(t){return t>0?1:t<0?-1:0}function oo(t,e){return no(t.prev,t,t.next)<0?no(t,e,t.next)>=0&&no(t,t.prev,e)>=0:no(t,e,t.prev)<0||no(t,t.next,e)<0}function lo(t,e){const n=new uo(t.i,t.x,t.y),i=new uo(e.i,e.x,e.y),r=t.next,s=e.prev;return t.next=e,e.prev=t,n.next=r,r.prev=n,i.next=n,n.prev=i,s.next=i,i.prev=s,i}function co(t,e,n,i){const r=new uo(t,e,n);return i?(r.next=i.next,r.prev=i,i.next.prev=r,i.next=r):(r.prev=r,r.next=r),r}function ho(t){t.next.prev=t.prev,t.prev.next=t.next,t.prevZ&&(t.prevZ.nextZ=t.nextZ),t.nextZ&&(t.nextZ.prevZ=t.prevZ)}function uo(t,e,n){this.i=t,this.x=e,this.y=n,this.prev=null,this.next=null,this.z=null,this.prevZ=null,this.nextZ=null,this.steiner=!1}class po{static area(t){const e=t.length;let n=0;for(let i=e-1,r=0;r2&&t[e-1].equals(t[0])&&t.pop()}function fo(t,e){for(let n=0;nNumber.EPSILON){const u=Math.sqrt(h),d=Math.sqrt(l*l+c*c),p=e.x-o/u,m=e.y+a/u,f=((n.x-c/d-p)*c-(n.y+l/d-m)*l)/(a*c-o*l);i=p+a*f-t.x,r=m+o*f-t.y;const g=i*i+r*r;if(g<=2)return new vt(i,r);s=Math.sqrt(g/2)}else{let t=!1;a>Number.EPSILON?l>Number.EPSILON&&(t=!0):a<-Number.EPSILON?l<-Number.EPSILON&&(t=!0):Math.sign(o)===Math.sign(c)&&(t=!0),t?(i=-o,r=a,s=Math.sqrt(h)):(i=a,r=o,s=Math.sqrt(h/2))}return new vt(i/s,r/s)}const P=[];for(let t=0,e=E.length,n=e-1,i=t+1;t=0;t--){const e=t/p,n=h*Math.cos(e*Math.PI/2),i=u*Math.sin(e*Math.PI/2)+d;for(let t=0,e=E.length;t=0;){const i=n;let r=n-1;r<0&&(r=t.length-1);for(let t=0,n=o+2*p;t=0?(t(i-o,p,h),u.subVectors(c,h)):(t(i+o,p,h),u.subVectors(h,c)),p-o>=0?(t(i,p-o,h),d.subVectors(c,h)):(t(i,p+o,h),d.subVectors(h,c)),l.crossVectors(u,d).normalize(),s.push(l.x,l.y,l.z),a.push(i,p)}}for(let t=0;t0)&&d.push(e,r,l),(t!==n-1||o=i)){l.push(e.times[t]);for(let n=0;ns.tracks[t].times[0]&&(o=s.tracks[t].times[0]);for(let t=0;t=i.times[u]){const t=u*l+o,e=t+l-o;d=Vo.arraySlice(i.values,t,e)}else{const t=i.createInterpolant(),e=o,n=l-o;t.evaluate(s),d=Vo.arraySlice(t.resultBuffer,e,n)}if("quaternion"===r){(new At).fromArray(d).normalize().conjugate().toArray(d)}const p=a.times.length;for(let t=0;t=r)break t;{const a=e[1];t=r)break e}s=n,n=0}}for(;n>>1;te;)--s;if(++s,0!==r||s!==i){r>=s&&(s=Math.max(s,1),r=s-1);const t=this.getValueSize();this.times=Vo.arraySlice(n,r,s),this.values=Vo.arraySlice(this.values,r*t,s*t)}return this}validate(){let t=!0;const e=this.getValueSize();e-Math.floor(e)!=0&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),t=!1);const n=this.times,i=this.values,r=n.length;0===r&&(console.error("THREE.KeyframeTrack: Track is empty.",this),t=!1);let s=null;for(let e=0;e!==r;e++){const i=n[e];if("number"==typeof i&&isNaN(i)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,e,i),t=!1;break}if(null!==s&&s>i){console.error("THREE.KeyframeTrack: Out of order keys.",this,e,i,s),t=!1;break}s=i}if(void 0!==i&&Vo.isTypedArray(i))for(let e=0,n=i.length;e!==n;++e){const n=i[e];if(isNaN(n)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this,e,n),t=!1;break}}return t}optimize(){const t=Vo.arraySlice(this.times),e=Vo.arraySlice(this.values),n=this.getValueSize(),i=this.getInterpolation()===U,r=t.length-1;let s=1;for(let a=1;a0){t[s]=t[r];for(let t=r*n,i=s*n,a=0;a!==n;++a)e[i+a]=e[t+a];++s}return s!==t.length?(this.times=Vo.arraySlice(t,0,s),this.values=Vo.arraySlice(e,0,s*n)):(this.times=t,this.values=e),this}clone(){const t=Vo.arraySlice(this.times,0),e=Vo.arraySlice(this.values,0),n=new(0,this.constructor)(this.name,t,e);return n.createInterpolant=this.createInterpolant,n}}Yo.prototype.TimeBufferType=Float32Array,Yo.prototype.ValueBufferType=Float32Array,Yo.prototype.DefaultInterpolation=G;class Zo extends Yo{}Zo.prototype.ValueTypeName="bool",Zo.prototype.ValueBufferType=Array,Zo.prototype.DefaultInterpolation=H,Zo.prototype.InterpolantFactoryMethodLinear=void 0,Zo.prototype.InterpolantFactoryMethodSmooth=void 0;class Jo extends Yo{}Jo.prototype.ValueTypeName="color";class Qo extends Yo{}Qo.prototype.ValueTypeName="number";class Ko extends Wo{constructor(t,e,n,i){super(t,e,n,i)}interpolate_(t,e,n,i){const r=this.resultBuffer,s=this.sampleValues,a=this.valueSize,o=(n-e)/(i-e);let l=t*a;for(let t=l+a;l!==t;l+=4)At.slerpFlat(r,0,s,l-a,s,l,o);return r}}class $o extends Yo{InterpolantFactoryMethodLinear(t){return new Ko(this.times,this.values,this.getValueSize(),t)}}$o.prototype.ValueTypeName="quaternion",$o.prototype.DefaultInterpolation=G,$o.prototype.InterpolantFactoryMethodSmooth=void 0;class tl extends Yo{}tl.prototype.ValueTypeName="string",tl.prototype.ValueBufferType=Array,tl.prototype.DefaultInterpolation=H,tl.prototype.InterpolantFactoryMethodLinear=void 0,tl.prototype.InterpolantFactoryMethodSmooth=void 0;class el extends Yo{}el.prototype.ValueTypeName="vector";class nl{constructor(t,e=-1,n,i=2500){this.name=t,this.tracks=n,this.duration=e,this.blendMode=i,this.uuid=ct(),this.duration<0&&this.resetDuration()}static parse(t){const e=[],n=t.tracks,i=1/(t.fps||1);for(let t=0,r=n.length;t!==r;++t)e.push(il(n[t]).scale(i));const r=new this(t.name,t.duration,e,t.blendMode);return r.uuid=t.uuid,r}static toJSON(t){const e=[],n=t.tracks,i={name:t.name,duration:t.duration,tracks:e,uuid:t.uuid,blendMode:t.blendMode};for(let t=0,i=n.length;t!==i;++t)e.push(Yo.toJSON(n[t]));return i}static CreateFromMorphTargetSequence(t,e,n,i){const r=e.length,s=[];for(let t=0;t1){const t=s[1];let e=i[t];e||(i[t]=e=[]),e.push(n)}}const s=[];for(const t in i)s.push(this.CreateFromMorphTargetSequence(t,i[t],e,n));return s}static parseAnimation(t,e){if(!t)return console.error("THREE.AnimationClip: No animation in JSONLoader data."),null;const n=function(t,e,n,i,r){if(0!==n.length){const s=[],a=[];Vo.flattenJSON(n,s,a,i),0!==s.length&&r.push(new t(e,s,a))}},i=[],r=t.name||"default",s=t.fps||30,a=t.blendMode;let o=t.length||-1;const l=t.hierarchy||[];for(let t=0;t0||0===t.search(/^data\:image\/jpeg/);r.format=i?T:E,r.needsUpdate=!0,void 0!==e&&e(r)}),n,i),r}}class ml{constructor(){this.type="Curve",this.arcLengthDivisions=200}getPoint(){return console.warn("THREE.Curve: .getPoint() not implemented."),null}getPointAt(t,e){const n=this.getUtoTmapping(t);return this.getPoint(n,e)}getPoints(t=5){const e=[];for(let n=0;n<=t;n++)e.push(this.getPoint(n/t));return e}getSpacedPoints(t=5){const e=[];for(let n=0;n<=t;n++)e.push(this.getPointAt(n/t));return e}getLength(){const t=this.getLengths();return t[t.length-1]}getLengths(t=this.arcLengthDivisions){if(this.cacheArcLengths&&this.cacheArcLengths.length===t+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=!1;const e=[];let n,i=this.getPoint(0),r=0;e.push(0);for(let s=1;s<=t;s++)n=this.getPoint(s/t),r+=n.distanceTo(i),e.push(r),i=n;return this.cacheArcLengths=e,e}updateArcLengths(){this.needsUpdate=!0,this.getLengths()}getUtoTmapping(t,e){const n=this.getLengths();let i=0;const r=n.length;let s;s=e||t*n[r-1];let a,o=0,l=r-1;for(;o<=l;)if(i=Math.floor(o+(l-o)/2),a=n[i]-s,a<0)o=i+1;else{if(!(a>0)){l=i;break}l=i-1}if(i=l,n[i]===s)return i/(r-1);const c=n[i];return(i+(s-c)/(n[i+1]-c))/(r-1)}getTangent(t,e){const n=1e-4;let i=t-n,r=t+n;i<0&&(i=0),r>1&&(r=1);const s=this.getPoint(i),a=this.getPoint(r),o=e||(s.isVector2?new vt:new Lt);return o.copy(a).sub(s).normalize(),o}getTangentAt(t,e){const n=this.getUtoTmapping(t);return this.getTangent(n,e)}computeFrenetFrames(t,e){const n=new Lt,i=[],r=[],s=[],a=new Lt,o=new se;for(let e=0;e<=t;e++){const n=e/t;i[e]=this.getTangentAt(n,new Lt),i[e].normalize()}r[0]=new Lt,s[0]=new Lt;let l=Number.MAX_VALUE;const c=Math.abs(i[0].x),h=Math.abs(i[0].y),u=Math.abs(i[0].z);c<=l&&(l=c,n.set(1,0,0)),h<=l&&(l=h,n.set(0,1,0)),u<=l&&n.set(0,0,1),a.crossVectors(i[0],n).normalize(),r[0].crossVectors(i[0],a),s[0].crossVectors(i[0],r[0]);for(let e=1;e<=t;e++){if(r[e]=r[e-1].clone(),s[e]=s[e-1].clone(),a.crossVectors(i[e-1],i[e]),a.length()>Number.EPSILON){a.normalize();const t=Math.acos(ht(i[e-1].dot(i[e]),-1,1));r[e].applyMatrix4(o.makeRotationAxis(a,t))}s[e].crossVectors(i[e],r[e])}if(!0===e){let e=Math.acos(ht(r[0].dot(r[t]),-1,1));e/=t,i[0].dot(a.crossVectors(r[0],r[t]))>0&&(e=-e);for(let n=1;n<=t;n++)r[n].applyMatrix4(o.makeRotationAxis(i[n],e*n)),s[n].crossVectors(i[n],r[n])}return{tangents:i,normals:r,binormals:s}}clone(){return(new this.constructor).copy(this)}copy(t){return this.arcLengthDivisions=t.arcLengthDivisions,this}toJSON(){const t={metadata:{version:4.5,type:"Curve",generator:"Curve.toJSON"}};return t.arcLengthDivisions=this.arcLengthDivisions,t.type=this.type,t}fromJSON(t){return this.arcLengthDivisions=t.arcLengthDivisions,this}}class fl extends ml{constructor(t=0,e=0,n=1,i=1,r=0,s=2*Math.PI,a=!1,o=0){super(),this.type="EllipseCurve",this.aX=t,this.aY=e,this.xRadius=n,this.yRadius=i,this.aStartAngle=r,this.aEndAngle=s,this.aClockwise=a,this.aRotation=o}getPoint(t,e){const n=e||new vt,i=2*Math.PI;let r=this.aEndAngle-this.aStartAngle;const s=Math.abs(r)i;)r-=i;r0?0:(Math.floor(Math.abs(l)/r)+1)*r:0===c&&l===r-1&&(l=r-2,c=1),this.closed||l>0?a=i[(l-1)%r]:(yl.subVectors(i[0],i[1]).add(i[0]),a=yl);const h=i[l%r],u=i[(l+1)%r];if(this.closed||l+2i.length-2?i.length-1:s+1],h=i[s>i.length-3?i.length-1:s+2];return n.set(Ml(a,o.x,l.x,c.x,h.x),Ml(a,o.y,l.y,c.y,h.y)),n}copy(t){super.copy(t),this.points=[];for(let e=0,n=t.points.length;e=e){const t=n[i]-e,r=this.curves[i],s=r.getLength(),a=0===s?0:1-t/s;return r.getPointAt(a)}i++}return null}getLength(){const t=this.getCurveLengths();return t[t.length-1]}updateArcLengths(){this.needsUpdate=!0,this.cacheLengths=null,this.getCurveLengths()}getCurveLengths(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;const t=[];let e=0;for(let n=0,i=this.curves.length;n1&&!e[e.length-1].equals(e[0])&&e.push(e[0]),e}copy(t){super.copy(t),this.curves=[];for(let e=0,n=t.curves.length;e0){const t=l.getPoint(0);t.equals(this.currentPoint)||this.lineTo(t.x,t.y)}this.curves.push(l);const c=l.getPoint(1);return this.currentPoint.copy(c),this}copy(t){return super.copy(t),this.currentPoint.copy(t.currentPoint),this}toJSON(){const t=super.toJSON();return t.currentPoint=this.currentPoint.toArray(),t}fromJSON(t){return super.fromJSON(t),this.currentPoint.fromArray(t.currentPoint),this}}class zl extends Bl{constructor(t){super(t),this.uuid=ct(),this.type="Shape",this.holes=[]}getPointsHoles(t){const e=[];for(let n=0,i=this.holes.length;n0:i.vertexColors=t.vertexColors),void 0!==t.uniforms)for(const e in t.uniforms){const r=t.uniforms[e];switch(i.uniforms[e]={},r.type){case"t":i.uniforms[e].value=n(r.value);break;case"c":i.uniforms[e].value=(new tn).setHex(r.value);break;case"v2":i.uniforms[e].value=(new vt).fromArray(r.value);break;case"v3":i.uniforms[e].value=(new Lt).fromArray(r.value);break;case"v4":i.uniforms[e].value=(new St).fromArray(r.value);break;case"m3":i.uniforms[e].value=(new yt).fromArray(r.value);break;case"m4":i.uniforms[e].value=(new se).fromArray(r.value);break;default:i.uniforms[e].value=r.value}}if(void 0!==t.defines&&(i.defines=t.defines),void 0!==t.vertexShader&&(i.vertexShader=t.vertexShader),void 0!==t.fragmentShader&&(i.fragmentShader=t.fragmentShader),void 0!==t.extensions)for(const e in t.extensions)i.extensions[e]=t.extensions[e];if(void 0!==t.shading&&(i.flatShading=1===t.shading),void 0!==t.size&&(i.size=t.size),void 0!==t.sizeAttenuation&&(i.sizeAttenuation=t.sizeAttenuation),void 0!==t.map&&(i.map=n(t.map)),void 0!==t.matcap&&(i.matcap=n(t.matcap)),void 0!==t.alphaMap&&(i.alphaMap=n(t.alphaMap)),void 0!==t.bumpMap&&(i.bumpMap=n(t.bumpMap)),void 0!==t.bumpScale&&(i.bumpScale=t.bumpScale),void 0!==t.normalMap&&(i.normalMap=n(t.normalMap)),void 0!==t.normalMapType&&(i.normalMapType=t.normalMapType),void 0!==t.normalScale){let e=t.normalScale;!1===Array.isArray(e)&&(e=[e,e]),i.normalScale=(new vt).fromArray(e)}return void 0!==t.displacementMap&&(i.displacementMap=n(t.displacementMap)),void 0!==t.displacementScale&&(i.displacementScale=t.displacementScale),void 0!==t.displacementBias&&(i.displacementBias=t.displacementBias),void 0!==t.roughnessMap&&(i.roughnessMap=n(t.roughnessMap)),void 0!==t.metalnessMap&&(i.metalnessMap=n(t.metalnessMap)),void 0!==t.emissiveMap&&(i.emissiveMap=n(t.emissiveMap)),void 0!==t.emissiveIntensity&&(i.emissiveIntensity=t.emissiveIntensity),void 0!==t.specularMap&&(i.specularMap=n(t.specularMap)),void 0!==t.envMap&&(i.envMap=n(t.envMap)),void 0!==t.envMapIntensity&&(i.envMapIntensity=t.envMapIntensity),void 0!==t.reflectivity&&(i.reflectivity=t.reflectivity),void 0!==t.refractionRatio&&(i.refractionRatio=t.refractionRatio),void 0!==t.lightMap&&(i.lightMap=n(t.lightMap)),void 0!==t.lightMapIntensity&&(i.lightMapIntensity=t.lightMapIntensity),void 0!==t.aoMap&&(i.aoMap=n(t.aoMap)),void 0!==t.aoMapIntensity&&(i.aoMapIntensity=t.aoMapIntensity),void 0!==t.gradientMap&&(i.gradientMap=n(t.gradientMap)),void 0!==t.clearcoatMap&&(i.clearcoatMap=n(t.clearcoatMap)),void 0!==t.clearcoatRoughnessMap&&(i.clearcoatRoughnessMap=n(t.clearcoatRoughnessMap)),void 0!==t.clearcoatNormalMap&&(i.clearcoatNormalMap=n(t.clearcoatNormalMap)),void 0!==t.clearcoatNormalScale&&(i.clearcoatNormalScale=(new vt).fromArray(t.clearcoatNormalScale)),void 0!==t.transmission&&(i.transmission=t.transmission),void 0!==t.transmissionMap&&(i.transmissionMap=n(t.transmissionMap)),i}setTextures(t){return this.textures=t,this}}class rc{static decodeText(t){if("undefined"!=typeof TextDecoder)return(new TextDecoder).decode(t);let e="";for(let n=0,i=t.length;nNumber.EPSILON){if(l<0&&(n=e[s],o=-o,a=e[r],l=-l),t.ya.y)continue;if(t.y===n.y){if(t.x===n.x)return!0}else{const e=l*(t.x-n.x)-o*(t.y-n.y);if(0===e)return!0;if(e<0)continue;i=!i}}else{if(t.y!==n.y)continue;if(a.x<=t.x&&t.x<=n.x||n.x<=t.x&&t.x<=a.x)return!0}}return i}const r=po.isClockWise,s=this.subPaths;if(0===s.length)return[];if(!0===e)return n(s);let a,o,l;const c=[];if(1===s.length)return o=s[0],l=new zl,l.curves=o.curves,c.push(l),c;let h=!r(s[0].getPoints());h=t?!h:h;const u=[],d=[];let p,m,f=[],g=0;d[g]=void 0,f[g]=[];for(let e=0,n=s.length;e1){let t=!1;const e=[];for(let t=0,e=d.length;t0&&(t||(f=u))}for(let t=0,e=d.length;t0){this.source.connect(this.filters[0]);for(let t=1,e=this.filters.length;t0){this.source.disconnect(this.filters[0]);for(let t=1,e=this.filters.length;t0&&this._mixBufferRegionAdditive(n,i,this._addIndex*e,1,e);for(let t=e,r=e+e;t!==r;++t)if(n[t]!==n[t+e]){a.setValue(n,i);break}}saveOriginalState(){const t=this.binding,e=this.buffer,n=this.valueSize,i=n*this._origIndex;t.getValue(e,i);for(let t=n,r=i;t!==r;++t)e[t]=e[i+t%n];this._setIdentity(),this.cumulativeWeight=0,this.cumulativeWeightAdditive=0}restoreOriginalState(){const t=3*this.valueSize;this.binding.setValue(this.buffer,t)}_setAdditiveIdentityNumeric(){const t=this._addIndex*this.valueSize,e=t+this.valueSize;for(let n=t;n=.5)for(let i=0;i!==r;++i)t[e+i]=t[n+i]}_slerp(t,e,n,i){At.slerpFlat(t,e,t,e,t,n,i)}_slerpAdditive(t,e,n,i,r){const s=this._workIndex*r;At.multiplyQuaternionsFlat(t,s,t,e,t,n),At.slerpFlat(t,e,t,e,t,s,i)}_lerp(t,e,n,i,r){const s=1-i;for(let a=0;a!==r;++a){const r=e+a;t[r]=t[r]*s+t[n+a]*i}}_lerpAdditive(t,e,n,i,r){for(let s=0;s!==r;++s){const r=e+s;t[r]=t[r]+t[n+s]*i}}}const Bc="\\[\\]\\.:\\/",zc=new RegExp("[\\[\\]\\.:\\/]","g"),Fc="[^\\[\\]\\.:\\/]",Oc="[^"+Bc.replace("\\.","")+"]",Hc=/((?:WC+[\/:])*)/.source.replace("WC",Fc),Gc=/(WCOD+)?/.source.replace("WCOD",Oc),Uc=/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC",Fc),kc=/\.(WC+)(?:\[(.+)\])?/.source.replace("WC",Fc),Vc=new RegExp("^"+Hc+Gc+Uc+kc+"$"),Wc=["material","materials","bones"];class jc{constructor(t,e,n){this.path=e,this.parsedPath=n||jc.parseTrackName(e),this.node=jc.findNode(t,this.parsedPath.nodeName)||t,this.rootNode=t,this.getValue=this._getValue_unbound,this.setValue=this._setValue_unbound}static create(t,e,n){return t&&t.isAnimationObjectGroup?new jc.Composite(t,e,n):new jc(t,e,n)}static sanitizeNodeName(t){return t.replace(/\s/g,"_").replace(zc,"")}static parseTrackName(t){const e=Vc.exec(t);if(!e)throw new Error("PropertyBinding: Cannot parse trackName: "+t);const n={nodeName:e[2],objectName:e[3],objectIndex:e[4],propertyName:e[5],propertyIndex:e[6]},i=n.nodeName&&n.nodeName.lastIndexOf(".");if(void 0!==i&&-1!==i){const t=n.nodeName.substring(i+1);-1!==Wc.indexOf(t)&&(n.nodeName=n.nodeName.substring(0,i),n.objectName=t)}if(null===n.propertyName||0===n.propertyName.length)throw new Error("PropertyBinding: can not parse propertyName from trackName: "+t);return n}static findNode(t,e){if(!e||""===e||"."===e||-1===e||e===t.name||e===t.uuid)return t;if(t.skeleton){const n=t.skeleton.getBoneByName(e);if(void 0!==n)return n}if(t.children){const n=function(t){for(let i=0;i=r){const s=r++,c=t[s];e[c.uuid]=l,t[l]=c,e[o]=s,t[s]=a;for(let t=0,e=i;t!==e;++t){const e=n[t],i=e[s],r=e[l];e[l]=i,e[s]=r}}}this.nCachedObjects_=r}uncache(){const t=this._objects,e=this._indicesByUUID,n=this._bindings,i=n.length;let r=this.nCachedObjects_,s=t.length;for(let a=0,o=arguments.length;a!==o;++a){const o=arguments[a].uuid,l=e[o];if(void 0!==l)if(delete e[o],l0&&(e[a.uuid]=l),t[l]=a,t.pop();for(let t=0,e=i;t!==e;++t){const e=n[t];e[l]=e[r],e.pop()}}}this.nCachedObjects_=r}subscribe_(t,e){const n=this._bindingsIndicesByPath;let i=n[t];const r=this._bindings;if(void 0!==i)return r[i];const s=this._paths,a=this._parsedPaths,o=this._objects,l=o.length,c=this.nCachedObjects_,h=new Array(l);i=r.length,n[t]=i,s.push(t),a.push(e),r.push(h);for(let n=c,i=o.length;n!==i;++n){const i=o[n];h[n]=new jc(i,t,e)}return h}unsubscribe_(t){const e=this._bindingsIndicesByPath,n=e[t];if(void 0!==n){const i=this._paths,r=this._parsedPaths,s=this._bindings,a=s.length-1,o=s[a];e[t[a]]=n,s[n]=o,s.pop(),r[n]=r[a],r.pop(),i[n]=i[a],i.pop()}}}qc.prototype.isAnimationObjectGroup=!0;class Xc{constructor(t,e,n=null,i=e.blendMode){this._mixer=t,this._clip=e,this._localRoot=n,this.blendMode=i;const r=e.tracks,s=r.length,a=new Array(s),o={endingStart:k,endingEnd:k};for(let t=0;t!==s;++t){const e=r[t].createInterpolant(null);a[t]=e,e.settings=o}this._interpolantSettings=o,this._interpolants=a,this._propertyBindings=new Array(s),this._cacheIndex=null,this._byClipCacheIndex=null,this._timeScaleInterpolant=null,this._weightInterpolant=null,this.loop=2201,this._loopCount=-1,this._startTime=null,this.time=0,this.timeScale=1,this._effectiveTimeScale=1,this.weight=1,this._effectiveWeight=1,this.repetitions=1/0,this.paused=!1,this.enabled=!0,this.clampWhenFinished=!1,this.zeroSlopeAtStart=!0,this.zeroSlopeAtEnd=!0}play(){return this._mixer._activateAction(this),this}stop(){return this._mixer._deactivateAction(this),this.reset()}reset(){return this.paused=!1,this.enabled=!0,this.time=0,this._loopCount=-1,this._startTime=null,this.stopFading().stopWarping()}isRunning(){return this.enabled&&!this.paused&&0!==this.timeScale&&null===this._startTime&&this._mixer._isActiveAction(this)}isScheduled(){return this._mixer._isActiveAction(this)}startAt(t){return this._startTime=t,this}setLoop(t,e){return this.loop=t,this.repetitions=e,this}setEffectiveWeight(t){return this.weight=t,this._effectiveWeight=this.enabled?t:0,this.stopFading()}getEffectiveWeight(){return this._effectiveWeight}fadeIn(t){return this._scheduleFading(t,0,1)}fadeOut(t){return this._scheduleFading(t,1,0)}crossFadeFrom(t,e,n){if(t.fadeOut(e),this.fadeIn(e),n){const n=this._clip.duration,i=t._clip.duration,r=i/n,s=n/i;t.warp(1,r,e),this.warp(s,1,e)}return this}crossFadeTo(t,e,n){return t.crossFadeFrom(this,e,n)}stopFading(){const t=this._weightInterpolant;return null!==t&&(this._weightInterpolant=null,this._mixer._takeBackControlInterpolant(t)),this}setEffectiveTimeScale(t){return this.timeScale=t,this._effectiveTimeScale=this.paused?0:t,this.stopWarping()}getEffectiveTimeScale(){return this._effectiveTimeScale}setDuration(t){return this.timeScale=this._clip.duration/t,this.stopWarping()}syncWith(t){return this.time=t.time,this.timeScale=t.timeScale,this.stopWarping()}halt(t){return this.warp(this._effectiveTimeScale,0,t)}warp(t,e,n){const i=this._mixer,r=i.time,s=this.timeScale;let a=this._timeScaleInterpolant;null===a&&(a=i._lendControlInterpolant(),this._timeScaleInterpolant=a);const o=a.parameterPositions,l=a.sampleValues;return o[0]=r,o[1]=r+n,l[0]=t/s,l[1]=e/s,this}stopWarping(){const t=this._timeScaleInterpolant;return null!==t&&(this._timeScaleInterpolant=null,this._mixer._takeBackControlInterpolant(t)),this}getMixer(){return this._mixer}getClip(){return this._clip}getRoot(){return this._localRoot||this._mixer._root}_update(t,e,n,i){if(!this.enabled)return void this._updateWeight(t);const r=this._startTime;if(null!==r){const i=(t-r)*n;if(i<0||0===n)return;this._startTime=null,e=n*i}e*=this._updateTimeScale(t);const s=this._updateTime(e),a=this._updateWeight(t);if(a>0){const t=this._interpolants,e=this._propertyBindings;switch(this.blendMode){case q:for(let n=0,i=t.length;n!==i;++n)t[n].evaluate(s),e[n].accumulateAdditive(a);break;case j:default:for(let n=0,r=t.length;n!==r;++n)t[n].evaluate(s),e[n].accumulate(i,a)}}}_updateWeight(t){let e=0;if(this.enabled){e=this.weight;const n=this._weightInterpolant;if(null!==n){const i=n.evaluate(t)[0];e*=i,t>n.parameterPositions[1]&&(this.stopFading(),0===i&&(this.enabled=!1))}}return this._effectiveWeight=e,e}_updateTimeScale(t){let e=0;if(!this.paused){e=this.timeScale;const n=this._timeScaleInterpolant;if(null!==n){e*=n.evaluate(t)[0],t>n.parameterPositions[1]&&(this.stopWarping(),0===e?this.paused=!0:this.timeScale=e)}}return this._effectiveTimeScale=e,e}_updateTime(t){const e=this._clip.duration,n=this.loop;let i=this.time+t,r=this._loopCount;const s=2202===n;if(0===t)return-1===r?i:s&&1==(1&r)?e-i:i;if(2200===n){-1===r&&(this._loopCount=0,this._setEndings(!0,!0,!1));t:{if(i>=e)i=e;else{if(!(i<0)){this.time=i;break t}i=0}this.clampWhenFinished?this.paused=!0:this.enabled=!1,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:t<0?-1:1})}}else{if(-1===r&&(t>=0?(r=0,this._setEndings(!0,0===this.repetitions,s)):this._setEndings(0===this.repetitions,!0,s)),i>=e||i<0){const n=Math.floor(i/e);i-=e*n,r+=Math.abs(n);const a=this.repetitions-r;if(a<=0)this.clampWhenFinished?this.paused=!0:this.enabled=!1,i=t>0?e:0,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:t>0?1:-1});else{if(1===a){const e=t<0;this._setEndings(e,!e,s)}else this._setEndings(!1,!1,s);this._loopCount=r,this.time=i,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:n})}}else this.time=i;if(s&&1==(1&r))return e-i}return i}_setEndings(t,e,n){const i=this._interpolantSettings;n?(i.endingStart=V,i.endingEnd=V):(i.endingStart=t?this.zeroSlopeAtStart?V:k:W,i.endingEnd=e?this.zeroSlopeAtEnd?V:k:W)}_scheduleFading(t,e,n){const i=this._mixer,r=i.time;let s=this._weightInterpolant;null===s&&(s=i._lendControlInterpolant(),this._weightInterpolant=s);const a=s.parameterPositions,o=s.sampleValues;return a[0]=r,o[0]=e,a[1]=r+t,o[1]=n,this}}class Yc extends rt{constructor(t){super(),this._root=t,this._initMemoryManager(),this._accuIndex=0,this.time=0,this.timeScale=1}_bindAction(t,e){const n=t._localRoot||this._root,i=t._clip.tracks,r=i.length,s=t._propertyBindings,a=t._interpolants,o=n.uuid,l=this._bindingsByRootAndName;let c=l[o];void 0===c&&(c={},l[o]=c);for(let t=0;t!==r;++t){const r=i[t],l=r.name;let h=c[l];if(void 0!==h)s[t]=h;else{if(h=s[t],void 0!==h){null===h._cacheIndex&&(++h.referenceCount,this._addInactiveBinding(h,o,l));continue}const i=e&&e._propertyBindings[t].binding.parsedPath;h=new Nc(jc.create(n,l,i),r.ValueTypeName,r.getValueSize()),++h.referenceCount,this._addInactiveBinding(h,o,l),s[t]=h}a[t].resultBuffer=h.buffer}}_activateAction(t){if(!this._isActiveAction(t)){if(null===t._cacheIndex){const e=(t._localRoot||this._root).uuid,n=t._clip.uuid,i=this._actionsByClip[n];this._bindAction(t,i&&i.knownActions[0]),this._addInactiveAction(t,n,e)}const e=t._propertyBindings;for(let t=0,n=e.length;t!==n;++t){const n=e[t];0==n.useCount++&&(this._lendBinding(n),n.saveOriginalState())}this._lendAction(t)}}_deactivateAction(t){if(this._isActiveAction(t)){const e=t._propertyBindings;for(let t=0,n=e.length;t!==n;++t){const n=e[t];0==--n.useCount&&(n.restoreOriginalState(),this._takeBackBinding(n))}this._takeBackAction(t)}}_initMemoryManager(){this._actions=[],this._nActiveActions=0,this._actionsByClip={},this._bindings=[],this._nActiveBindings=0,this._bindingsByRootAndName={},this._controlInterpolants=[],this._nActiveControlInterpolants=0;const t=this;this.stats={actions:{get total(){return t._actions.length},get inUse(){return t._nActiveActions}},bindings:{get total(){return t._bindings.length},get inUse(){return t._nActiveBindings}},controlInterpolants:{get total(){return t._controlInterpolants.length},get inUse(){return t._nActiveControlInterpolants}}}}_isActiveAction(t){const e=t._cacheIndex;return null!==e&&e=0;--e)t[e].stop();return this}update(t){t*=this.timeScale;const e=this._actions,n=this._nActiveActions,i=this.time+=t,r=Math.sign(t),s=this._accuIndex^=1;for(let a=0;a!==n;++a){e[a]._update(i,t,r,s)}const a=this._bindings,o=this._nActiveBindings;for(let t=0;t!==o;++t)a[t].apply(s);return this}setTime(t){this.time=0;for(let t=0;tthis.max.x||t.ythis.max.y)}containsBox(t){return this.min.x<=t.min.x&&t.max.x<=this.max.x&&this.min.y<=t.min.y&&t.max.y<=this.max.y}getParameter(t,e){return void 0===e&&(console.warn("THREE.Box2: .getParameter() target is now required"),e=new vt),e.set((t.x-this.min.x)/(this.max.x-this.min.x),(t.y-this.min.y)/(this.max.y-this.min.y))}intersectsBox(t){return!(t.max.xthis.max.x||t.max.ythis.max.y)}clampPoint(t,e){return void 0===e&&(console.warn("THREE.Box2: .clampPoint() target is now required"),e=new vt),e.copy(t).clamp(this.min,this.max)}distanceToPoint(t){return th.copy(t).clamp(this.min,this.max).sub(t).length()}intersect(t){return this.min.max(t.min),this.max.min(t.max),this}union(t){return this.min.min(t.min),this.max.max(t.max),this}translate(t){return this.min.add(t),this.max.add(t),this}equals(t){return t.min.equals(this.min)&&t.max.equals(this.max)}}eh.prototype.isBox2=!0;const nh=new Lt,ih=new Lt;class rh{constructor(t=new Lt,e=new Lt){this.start=t,this.end=e}set(t,e){return this.start.copy(t),this.end.copy(e),this}copy(t){return this.start.copy(t.start),this.end.copy(t.end),this}getCenter(t){return void 0===t&&(console.warn("THREE.Line3: .getCenter() target is now required"),t=new Lt),t.addVectors(this.start,this.end).multiplyScalar(.5)}delta(t){return void 0===t&&(console.warn("THREE.Line3: .delta() target is now required"),t=new Lt),t.subVectors(this.end,this.start)}distanceSq(){return this.start.distanceToSquared(this.end)}distance(){return this.start.distanceTo(this.end)}at(t,e){return void 0===e&&(console.warn("THREE.Line3: .at() target is now required"),e=new Lt),this.delta(e).multiplyScalar(t).add(this.start)}closestPointToPointParameter(t,e){nh.subVectors(t,this.start),ih.subVectors(this.end,this.start);const n=ih.dot(ih);let i=ih.dot(nh)/n;return e&&(i=ht(i,0,1)),i}closestPointToPoint(t,e,n){const i=this.closestPointToPointParameter(t,e);return void 0===n&&(console.warn("THREE.Line3: .closestPointToPoint() target is now required"),n=new Lt),this.delta(n).multiplyScalar(i).add(this.start)}applyMatrix4(t){return this.start.applyMatrix4(t),this.end.applyMatrix4(t),this}equals(t){return t.start.equals(this.start)&&t.end.equals(this.end)}clone(){return(new this.constructor).copy(this)}}class sh extends Ce{constructor(t){super(),this.material=t,this.render=function(){},this.hasPositions=!1,this.hasNormals=!1,this.hasColors=!1,this.hasUvs=!1,this.positionArray=null,this.normalArray=null,this.colorArray=null,this.uvArray=null,this.count=0}}sh.prototype.isImmediateRenderObject=!0;const ah=new Lt;const oh=new Lt,lh=new se,ch=new se;class hh extends ya{constructor(t){const e=uh(t),n=new En,i=[],r=[],s=new tn(0,0,1),a=new tn(0,1,0);for(let t=0;t4?a=Ph[r-8+4-1]:0==r&&(a=0),n.push(a);const o=1/(s-1),l=-o/2,c=1+o/2,h=[l,l,c,l,c,c,l,l,c,c,l,c],u=6,d=6,p=3,m=2,f=1,g=new Float32Array(p*d*u),v=new Float32Array(m*d*u),y=new Float32Array(f*d*u);for(let t=0;t2?0:-1,i=[e,n,0,e+2/3,n,0,e+2/3,n+1,0,e,n,0,e+2/3,n+1,0,e,n+1,0];g.set(i,p*d*t),v.set(h,m*d*t);const r=[t,t,t,t,t,t];y.set(r,f*d*t)}const x=new En;x.setAttribute("position",new sn(g,p)),x.setAttribute("uv",new sn(v,m)),x.setAttribute("faceIndex",new sn(y,f)),t.push(x),i>4&&i--}return{_lodPlanes:t,_sizeLods:e,_sigmas:n}}function Zh(t){const e=new Tt(3*Ch,3*Ch,t);return e.texture.mapping=l,e.texture.name="PMREM.cubeUv",e.scissorTest=!0,e}function Jh(t,e,n,i,r){t.viewport.set(e,n,i,r),t.scissor.set(e,n,i,r)}function Qh(){const t=new vt(1,1);return new Io({name:"EquirectangularToCubeUV",uniforms:{envMap:{value:null},texelSize:{value:t},inputEncoding:{value:Nh[3e3]},outputEncoding:{value:Nh[3e3]}},vertexShader:$h(),fragmentShader:`\n\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tvarying vec3 vOutputDirection;\n\n\t\t\tuniform sampler2D envMap;\n\t\t\tuniform vec2 texelSize;\n\n\t\t\t${tu()}\n\n\t\t\t#include \n\n\t\t\tvoid main() {\n\n\t\t\t\tgl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\n\t\t\t\tvec3 outputDirection = normalize( vOutputDirection );\n\t\t\t\tvec2 uv = equirectUv( outputDirection );\n\n\t\t\t\tvec2 f = fract( uv / texelSize - 0.5 );\n\t\t\t\tuv -= f * texelSize;\n\t\t\t\tvec3 tl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;\n\t\t\t\tuv.x += texelSize.x;\n\t\t\t\tvec3 tr = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;\n\t\t\t\tuv.y += texelSize.y;\n\t\t\t\tvec3 br = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;\n\t\t\t\tuv.x -= texelSize.x;\n\t\t\t\tvec3 bl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;\n\n\t\t\t\tvec3 tm = mix( tl, tr, f.x );\n\t\t\t\tvec3 bm = mix( bl, br, f.x );\n\t\t\t\tgl_FragColor.rgb = mix( tm, bm, f.y );\n\n\t\t\t\tgl_FragColor = linearToOutputTexel( gl_FragColor );\n\n\t\t\t}\n\t\t`,blending:0,depthTest:!1,depthWrite:!1})}function Kh(){return new Io({name:"CubemapToCubeUV",uniforms:{envMap:{value:null},inputEncoding:{value:Nh[3e3]},outputEncoding:{value:Nh[3e3]}},vertexShader:$h(),fragmentShader:`\n\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tvarying vec3 vOutputDirection;\n\n\t\t\tuniform samplerCube envMap;\n\n\t\t\t${tu()}\n\n\t\t\tvoid main() {\n\n\t\t\t\tgl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t\t\t\tgl_FragColor.rgb = envMapTexelToLinear( textureCube( envMap, vec3( - vOutputDirection.x, vOutputDirection.yz ) ) ).rgb;\n\t\t\t\tgl_FragColor = linearToOutputTexel( gl_FragColor );\n\n\t\t\t}\n\t\t`,blending:0,depthTest:!1,depthWrite:!1})}function $h(){return"\n\n\t\tprecision mediump float;\n\t\tprecision mediump int;\n\n\t\tattribute vec3 position;\n\t\tattribute vec2 uv;\n\t\tattribute float faceIndex;\n\n\t\tvarying vec3 vOutputDirection;\n\n\t\t// RH coordinate system; PMREM face-indexing convention\n\t\tvec3 getDirection( vec2 uv, float face ) {\n\n\t\t\tuv = 2.0 * uv - 1.0;\n\n\t\t\tvec3 direction = vec3( uv, 1.0 );\n\n\t\t\tif ( face == 0.0 ) {\n\n\t\t\t\tdirection = direction.zyx; // ( 1, v, u ) pos x\n\n\t\t\t} else if ( face == 1.0 ) {\n\n\t\t\t\tdirection = direction.xzy;\n\t\t\t\tdirection.xz *= -1.0; // ( -u, 1, -v ) pos y\n\n\t\t\t} else if ( face == 2.0 ) {\n\n\t\t\t\tdirection.x *= -1.0; // ( -u, v, 1 ) pos z\n\n\t\t\t} else if ( face == 3.0 ) {\n\n\t\t\t\tdirection = direction.zyx;\n\t\t\t\tdirection.xz *= -1.0; // ( -1, v, -u ) neg x\n\n\t\t\t} else if ( face == 4.0 ) {\n\n\t\t\t\tdirection = direction.xzy;\n\t\t\t\tdirection.xy *= -1.0; // ( -u, -1, v ) neg y\n\n\t\t\t} else if ( face == 5.0 ) {\n\n\t\t\t\tdirection.z *= -1.0; // ( u, v, -1 ) neg z\n\n\t\t\t}\n\n\t\t\treturn direction;\n\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\tvOutputDirection = getDirection( uv, faceIndex );\n\t\t\tgl_Position = vec4( position, 1.0 );\n\n\t\t}\n\t"}function tu(){return"\n\n\t\tuniform int inputEncoding;\n\t\tuniform int outputEncoding;\n\n\t\t#include \n\n\t\tvec4 inputTexelToLinear( vec4 value ) {\n\n\t\t\tif ( inputEncoding == 0 ) {\n\n\t\t\t\treturn value;\n\n\t\t\t} else if ( inputEncoding == 1 ) {\n\n\t\t\t\treturn sRGBToLinear( value );\n\n\t\t\t} else if ( inputEncoding == 2 ) {\n\n\t\t\t\treturn RGBEToLinear( value );\n\n\t\t\t} else if ( inputEncoding == 3 ) {\n\n\t\t\t\treturn RGBMToLinear( value, 7.0 );\n\n\t\t\t} else if ( inputEncoding == 4 ) {\n\n\t\t\t\treturn RGBMToLinear( value, 16.0 );\n\n\t\t\t} else if ( inputEncoding == 5 ) {\n\n\t\t\t\treturn RGBDToLinear( value, 256.0 );\n\n\t\t\t} else {\n\n\t\t\t\treturn GammaToLinear( value, 2.2 );\n\n\t\t\t}\n\n\t\t}\n\n\t\tvec4 linearToOutputTexel( vec4 value ) {\n\n\t\t\tif ( outputEncoding == 0 ) {\n\n\t\t\t\treturn value;\n\n\t\t\t} else if ( outputEncoding == 1 ) {\n\n\t\t\t\treturn LinearTosRGB( value );\n\n\t\t\t} else if ( outputEncoding == 2 ) {\n\n\t\t\t\treturn LinearToRGBE( value );\n\n\t\t\t} else if ( outputEncoding == 3 ) {\n\n\t\t\t\treturn LinearToRGBM( value, 7.0 );\n\n\t\t\t} else if ( outputEncoding == 4 ) {\n\n\t\t\t\treturn LinearToRGBM( value, 16.0 );\n\n\t\t\t} else if ( outputEncoding == 5 ) {\n\n\t\t\t\treturn LinearToRGBD( value, 256.0 );\n\n\t\t\t} else {\n\n\t\t\t\treturn LinearToGamma( value, 2.2 );\n\n\t\t\t}\n\n\t\t}\n\n\t\tvec4 envMapTexelToLinear( vec4 color ) {\n\n\t\t\treturn inputTexelToLinear( color );\n\n\t\t}\n\t"}ml.create=function(t,e){return console.log("THREE.Curve.create() has been deprecated"),t.prototype=Object.create(ml.prototype),t.prototype.constructor=t,t.prototype.getPoint=e,t},Bl.prototype.fromPoints=function(t){return console.warn("THREE.Path: .fromPoints() has been renamed to .setFromPoints()."),this.setFromPoints(t)},fh.prototype.setColors=function(){console.error("THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.")},hh.prototype.update=function(){console.error("THREE.SkeletonHelper: update() no longer needs to be called.")},ol.prototype.extractUrlBase=function(t){return console.warn("THREE.Loader: .extractUrlBase() has been deprecated. Use THREE.LoaderUtils.extractUrlBase() instead."),rc.extractUrlBase(t)},ol.Handlers={add:function(){console.error("THREE.Loader: Handlers.add() has been removed. Use LoadingManager.addHandler() instead.")},get:function(){console.error("THREE.Loader: Handlers.get() has been removed. Use LoadingManager.getHandler() instead.")}},eh.prototype.center=function(t){return console.warn("THREE.Box2: .center() has been renamed to .getCenter()."),this.getCenter(t)},eh.prototype.empty=function(){return console.warn("THREE.Box2: .empty() has been renamed to .isEmpty()."),this.isEmpty()},eh.prototype.isIntersectionBox=function(t){return console.warn("THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox()."),this.intersectsBox(t)},eh.prototype.size=function(t){return console.warn("THREE.Box2: .size() has been renamed to .getSize()."),this.getSize(t)},Pt.prototype.center=function(t){return console.warn("THREE.Box3: .center() has been renamed to .getCenter()."),this.getCenter(t)},Pt.prototype.empty=function(){return console.warn("THREE.Box3: .empty() has been renamed to .isEmpty()."),this.isEmpty()},Pt.prototype.isIntersectionBox=function(t){return console.warn("THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox()."),this.intersectsBox(t)},Pt.prototype.isIntersectionSphere=function(t){return console.warn("THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere()."),this.intersectsSphere(t)},Pt.prototype.size=function(t){return console.warn("THREE.Box3: .size() has been renamed to .getSize()."),this.getSize(t)},Jt.prototype.empty=function(){return console.warn("THREE.Sphere: .empty() has been renamed to .isEmpty()."),this.isEmpty()},ai.prototype.setFromMatrix=function(t){return console.warn("THREE.Frustum: .setFromMatrix() has been renamed to .setFromProjectionMatrix()."),this.setFromProjectionMatrix(t)},rh.prototype.center=function(t){return console.warn("THREE.Line3: .center() has been renamed to .getCenter()."),this.getCenter(t)},yt.prototype.flattenToArrayOffset=function(t,e){return console.warn("THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead."),this.toArray(t,e)},yt.prototype.multiplyVector3=function(t){return console.warn("THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead."),t.applyMatrix3(this)},yt.prototype.multiplyVector3Array=function(){console.error("THREE.Matrix3: .multiplyVector3Array() has been removed.")},yt.prototype.applyToBufferAttribute=function(t){return console.warn("THREE.Matrix3: .applyToBufferAttribute() has been removed. Use attribute.applyMatrix3( matrix ) instead."),t.applyMatrix3(this)},yt.prototype.applyToVector3Array=function(){console.error("THREE.Matrix3: .applyToVector3Array() has been removed.")},yt.prototype.getInverse=function(t){return console.warn("THREE.Matrix3: .getInverse() has been removed. Use matrixInv.copy( matrix ).invert(); instead."),this.copy(t).invert()},se.prototype.extractPosition=function(t){return console.warn("THREE.Matrix4: .extractPosition() has been renamed to .copyPosition()."),this.copyPosition(t)},se.prototype.flattenToArrayOffset=function(t,e){return console.warn("THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead."),this.toArray(t,e)},se.prototype.getPosition=function(){return console.warn("THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead."),(new Lt).setFromMatrixColumn(this,3)},se.prototype.setRotationFromQuaternion=function(t){return console.warn("THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion()."),this.makeRotationFromQuaternion(t)},se.prototype.multiplyToArray=function(){console.warn("THREE.Matrix4: .multiplyToArray() has been removed.")},se.prototype.multiplyVector3=function(t){return console.warn("THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead."),t.applyMatrix4(this)},se.prototype.multiplyVector4=function(t){return console.warn("THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead."),t.applyMatrix4(this)},se.prototype.multiplyVector3Array=function(){console.error("THREE.Matrix4: .multiplyVector3Array() has been removed.")},se.prototype.rotateAxis=function(t){console.warn("THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead."),t.transformDirection(this)},se.prototype.crossVector=function(t){return console.warn("THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead."),t.applyMatrix4(this)},se.prototype.translate=function(){console.error("THREE.Matrix4: .translate() has been removed.")},se.prototype.rotateX=function(){console.error("THREE.Matrix4: .rotateX() has been removed.")},se.prototype.rotateY=function(){console.error("THREE.Matrix4: .rotateY() has been removed.")},se.prototype.rotateZ=function(){console.error("THREE.Matrix4: .rotateZ() has been removed.")},se.prototype.rotateByAxis=function(){console.error("THREE.Matrix4: .rotateByAxis() has been removed.")},se.prototype.applyToBufferAttribute=function(t){return console.warn("THREE.Matrix4: .applyToBufferAttribute() has been removed. Use attribute.applyMatrix4( matrix ) instead."),t.applyMatrix4(this)},se.prototype.applyToVector3Array=function(){console.error("THREE.Matrix4: .applyToVector3Array() has been removed.")},se.prototype.makeFrustum=function(t,e,n,i,r,s){return console.warn("THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead."),this.makePerspective(t,e,i,n,r,s)},se.prototype.getInverse=function(t){return console.warn("THREE.Matrix4: .getInverse() has been removed. Use matrixInv.copy( matrix ).invert(); instead."),this.copy(t).invert()},Ne.prototype.isIntersectionLine=function(t){return console.warn("THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine()."),this.intersectsLine(t)},At.prototype.multiplyVector3=function(t){return console.warn("THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead."),t.applyQuaternion(this)},At.prototype.inverse=function(){return console.warn("THREE.Quaternion: .inverse() has been renamed to invert()."),this.invert()},re.prototype.isIntersectionBox=function(t){return console.warn("THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox()."),this.intersectsBox(t)},re.prototype.isIntersectionPlane=function(t){return console.warn("THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane()."),this.intersectsPlane(t)},re.prototype.isIntersectionSphere=function(t){return console.warn("THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere()."),this.intersectsSphere(t)},je.prototype.area=function(){return console.warn("THREE.Triangle: .area() has been renamed to .getArea()."),this.getArea()},je.prototype.barycoordFromPoint=function(t,e){return console.warn("THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord()."),this.getBarycoord(t,e)},je.prototype.midpoint=function(t){return console.warn("THREE.Triangle: .midpoint() has been renamed to .getMidpoint()."),this.getMidpoint(t)},je.prototypenormal=function(t){return console.warn("THREE.Triangle: .normal() has been renamed to .getNormal()."),this.getNormal(t)},je.prototype.plane=function(t){return console.warn("THREE.Triangle: .plane() has been renamed to .getPlane()."),this.getPlane(t)},je.barycoordFromPoint=function(t,e,n,i,r){return console.warn("THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord()."),je.getBarycoord(t,e,n,i,r)},je.normal=function(t,e,n,i){return console.warn("THREE.Triangle: .normal() has been renamed to .getNormal()."),je.getNormal(t,e,n,i)},zl.prototype.extractAllPoints=function(t){return console.warn("THREE.Shape: .extractAllPoints() has been removed. Use .extractPoints() instead."),this.extractPoints(t)},zl.prototype.extrude=function(t){return console.warn("THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead."),new go(this,t)},zl.prototype.makeGeometry=function(t){return console.warn("THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead."),new Mo(this,t)},vt.prototype.fromAttribute=function(t,e,n){return console.warn("THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute()."),this.fromBufferAttribute(t,e,n)},vt.prototype.distanceToManhattan=function(t){return console.warn("THREE.Vector2: .distanceToManhattan() has been renamed to .manhattanDistanceTo()."),this.manhattanDistanceTo(t)},vt.prototype.lengthManhattan=function(){return console.warn("THREE.Vector2: .lengthManhattan() has been renamed to .manhattanLength()."),this.manhattanLength()},Lt.prototype.setEulerFromRotationMatrix=function(){console.error("THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.")},Lt.prototype.setEulerFromQuaternion=function(){console.error("THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.")},Lt.prototype.getPositionFromMatrix=function(t){return console.warn("THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition()."),this.setFromMatrixPosition(t)},Lt.prototype.getScaleFromMatrix=function(t){return console.warn("THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale()."),this.setFromMatrixScale(t)},Lt.prototype.getColumnFromMatrix=function(t,e){return console.warn("THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn()."),this.setFromMatrixColumn(e,t)},Lt.prototype.applyProjection=function(t){return console.warn("THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead."),this.applyMatrix4(t)},Lt.prototype.fromAttribute=function(t,e,n){return console.warn("THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute()."),this.fromBufferAttribute(t,e,n)},Lt.prototype.distanceToManhattan=function(t){return console.warn("THREE.Vector3: .distanceToManhattan() has been renamed to .manhattanDistanceTo()."),this.manhattanDistanceTo(t)},Lt.prototype.lengthManhattan=function(){return console.warn("THREE.Vector3: .lengthManhattan() has been renamed to .manhattanLength()."),this.manhattanLength()},St.prototype.fromAttribute=function(t,e,n){return console.warn("THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute()."),this.fromBufferAttribute(t,e,n)},St.prototype.lengthManhattan=function(){return console.warn("THREE.Vector4: .lengthManhattan() has been renamed to .manhattanLength()."),this.manhattanLength()},Ce.prototype.getChildByName=function(t){return console.warn("THREE.Object3D: .getChildByName() has been renamed to .getObjectByName()."),this.getObjectByName(t)},Ce.prototype.renderDepth=function(){console.warn("THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.")},Ce.prototype.translate=function(t,e){return console.warn("THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead."),this.translateOnAxis(e,t)},Ce.prototype.getWorldRotation=function(){console.error("THREE.Object3D: .getWorldRotation() has been removed. Use THREE.Object3D.getWorldQuaternion( target ) instead.")},Ce.prototype.applyMatrix=function(t){return console.warn("THREE.Object3D: .applyMatrix() has been renamed to .applyMatrix4()."),this.applyMatrix4(t)},Object.defineProperties(Ce.prototype,{eulerOrder:{get:function(){return console.warn("THREE.Object3D: .eulerOrder is now .rotation.order."),this.rotation.order},set:function(t){console.warn("THREE.Object3D: .eulerOrder is now .rotation.order."),this.rotation.order=t}},useQuaternion:{get:function(){console.warn("THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.")},set:function(){console.warn("THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.")}}}),Wn.prototype.setDrawMode=function(){console.error("THREE.Mesh: .setDrawMode() has been removed. The renderer now always assumes THREE.TrianglesDrawMode. Transform your geometry via BufferGeometryUtils.toTrianglesDrawMode() if necessary.")},Object.defineProperties(Wn.prototype,{drawMode:{get:function(){return console.error("THREE.Mesh: .drawMode has been removed. The renderer now always assumes THREE.TrianglesDrawMode."),0},set:function(){console.error("THREE.Mesh: .drawMode has been removed. The renderer now always assumes THREE.TrianglesDrawMode. Transform your geometry via BufferGeometryUtils.toTrianglesDrawMode() if necessary.")}}}),$s.prototype.initBones=function(){console.error("THREE.SkinnedMesh: initBones() has been removed.")},Kn.prototype.setLens=function(t,e){console.warn("THREE.PerspectiveCamera.setLens is deprecated. Use .setFocalLength and .filmGauge for a photographic setup."),void 0!==e&&(this.filmGauge=e),this.setFocalLength(t)},Object.defineProperties(Fl.prototype,{onlyShadow:{set:function(){console.warn("THREE.Light: .onlyShadow has been removed.")}},shadowCameraFov:{set:function(t){console.warn("THREE.Light: .shadowCameraFov is now .shadow.camera.fov."),this.shadow.camera.fov=t}},shadowCameraLeft:{set:function(t){console.warn("THREE.Light: .shadowCameraLeft is now .shadow.camera.left."),this.shadow.camera.left=t}},shadowCameraRight:{set:function(t){console.warn("THREE.Light: .shadowCameraRight is now .shadow.camera.right."),this.shadow.camera.right=t}},shadowCameraTop:{set:function(t){console.warn("THREE.Light: .shadowCameraTop is now .shadow.camera.top."),this.shadow.camera.top=t}},shadowCameraBottom:{set:function(t){console.warn("THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom."),this.shadow.camera.bottom=t}},shadowCameraNear:{set:function(t){console.warn("THREE.Light: .shadowCameraNear is now .shadow.camera.near."),this.shadow.camera.near=t}},shadowCameraFar:{set:function(t){console.warn("THREE.Light: .shadowCameraFar is now .shadow.camera.far."),this.shadow.camera.far=t}},shadowCameraVisible:{set:function(){console.warn("THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.")}},shadowBias:{set:function(t){console.warn("THREE.Light: .shadowBias is now .shadow.bias."),this.shadow.bias=t}},shadowDarkness:{set:function(){console.warn("THREE.Light: .shadowDarkness has been removed.")}},shadowMapWidth:{set:function(t){console.warn("THREE.Light: .shadowMapWidth is now .shadow.mapSize.width."),this.shadow.mapSize.width=t}},shadowMapHeight:{set:function(t){console.warn("THREE.Light: .shadowMapHeight is now .shadow.mapSize.height."),this.shadow.mapSize.height=t}}}),Object.defineProperties(sn.prototype,{length:{get:function(){return console.warn("THREE.BufferAttribute: .length has been deprecated. Use .count instead."),this.array.length}},dynamic:{get:function(){return console.warn("THREE.BufferAttribute: .dynamic has been deprecated. Use .usage instead."),this.usage===nt},set:function(){console.warn("THREE.BufferAttribute: .dynamic has been deprecated. Use .usage instead."),this.setUsage(nt)}}}),sn.prototype.setDynamic=function(t){return console.warn("THREE.BufferAttribute: .setDynamic() has been deprecated. Use .setUsage() instead."),this.setUsage(!0===t?nt:et),this},sn.prototype.copyIndicesArray=function(){console.error("THREE.BufferAttribute: .copyIndicesArray() has been removed.")},sn.prototype.setArray=function(){console.error("THREE.BufferAttribute: .setArray has been removed. Use BufferGeometry .setAttribute to replace/resize attribute buffers")},En.prototype.addIndex=function(t){console.warn("THREE.BufferGeometry: .addIndex() has been renamed to .setIndex()."),this.setIndex(t)},En.prototype.addAttribute=function(t,e){return console.warn("THREE.BufferGeometry: .addAttribute() has been renamed to .setAttribute()."),e&&e.isBufferAttribute||e&&e.isInterleavedBufferAttribute?"index"===t?(console.warn("THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute."),this.setIndex(e),this):this.setAttribute(t,e):(console.warn("THREE.BufferGeometry: .addAttribute() now expects ( name, attribute )."),this.setAttribute(t,new sn(arguments[1],arguments[2])))},En.prototype.addDrawCall=function(t,e,n){void 0!==n&&console.warn("THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset."),console.warn("THREE.BufferGeometry: .addDrawCall() is now .addGroup()."),this.addGroup(t,e)},En.prototype.clearDrawCalls=function(){console.warn("THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups()."),this.clearGroups()},En.prototype.computeOffsets=function(){console.warn("THREE.BufferGeometry: .computeOffsets() has been removed.")},En.prototype.removeAttribute=function(t){return console.warn("THREE.BufferGeometry: .removeAttribute() has been renamed to .deleteAttribute()."),this.deleteAttribute(t)},En.prototype.applyMatrix=function(t){return console.warn("THREE.BufferGeometry: .applyMatrix() has been renamed to .applyMatrix4()."),this.applyMatrix4(t)},Object.defineProperties(En.prototype,{drawcalls:{get:function(){return console.error("THREE.BufferGeometry: .drawcalls has been renamed to .groups."),this.groups}},offsets:{get:function(){return console.warn("THREE.BufferGeometry: .offsets has been renamed to .groups."),this.groups}}}),Es.prototype.setDynamic=function(t){return console.warn("THREE.InterleavedBuffer: .setDynamic() has been deprecated. Use .setUsage() instead."),this.setUsage(!0===t?nt:et),this},Es.prototype.setArray=function(){console.error("THREE.InterleavedBuffer: .setArray has been removed. Use BufferGeometry .setAttribute to replace/resize attribute buffers")},go.prototype.getArrays=function(){console.error("THREE.ExtrudeGeometry: .getArrays() has been removed.")},go.prototype.addShapeList=function(){console.error("THREE.ExtrudeGeometry: .addShapeList() has been removed.")},go.prototype.addShape=function(){console.error("THREE.ExtrudeGeometry: .addShape() has been removed.")},Ts.prototype.dispose=function(){console.error("THREE.Scene: .dispose() has been removed.")},Zc.prototype.onUpdate=function(){return console.warn("THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead."),this},Object.defineProperties(Xe.prototype,{wrapAround:{get:function(){console.warn("THREE.Material: .wrapAround has been removed.")},set:function(){console.warn("THREE.Material: .wrapAround has been removed.")}},overdraw:{get:function(){console.warn("THREE.Material: .overdraw has been removed.")},set:function(){console.warn("THREE.Material: .overdraw has been removed.")}},wrapRGB:{get:function(){return console.warn("THREE.Material: .wrapRGB has been removed."),new tn}},shading:{get:function(){console.error("THREE."+this.type+": .shading has been removed. Use the boolean .flatShading instead.")},set:function(t){console.warn("THREE."+this.type+": .shading has been removed. Use the boolean .flatShading instead."),this.flatShading=1===t}},stencilMask:{get:function(){return console.warn("THREE."+this.type+": .stencilMask has been removed. Use .stencilFuncMask instead."),this.stencilFuncMask},set:function(t){console.warn("THREE."+this.type+": .stencilMask has been removed. Use .stencilFuncMask instead."),this.stencilFuncMask=t}}}),Object.defineProperties(Jn.prototype,{derivatives:{get:function(){return console.warn("THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives."),this.extensions.derivatives},set:function(t){console.warn("THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives."),this.extensions.derivatives=t}}}),ws.prototype.clearTarget=function(t,e,n,i){console.warn("THREE.WebGLRenderer: .clearTarget() has been deprecated. Use .setRenderTarget() and .clear() instead."),this.setRenderTarget(t),this.clear(e,n,i)},ws.prototype.animate=function(t){console.warn("THREE.WebGLRenderer: .animate() is now .setAnimationLoop()."),this.setAnimationLoop(t)},ws.prototype.getCurrentRenderTarget=function(){return console.warn("THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget()."),this.getRenderTarget()},ws.prototype.getMaxAnisotropy=function(){return console.warn("THREE.WebGLRenderer: .getMaxAnisotropy() is now .capabilities.getMaxAnisotropy()."),this.capabilities.getMaxAnisotropy()},ws.prototype.getPrecision=function(){return console.warn("THREE.WebGLRenderer: .getPrecision() is now .capabilities.precision."),this.capabilities.precision},ws.prototype.resetGLState=function(){return console.warn("THREE.WebGLRenderer: .resetGLState() is now .state.reset()."),this.state.reset()},ws.prototype.supportsFloatTextures=function(){return console.warn("THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( 'OES_texture_float' )."),this.extensions.get("OES_texture_float")},ws.prototype.supportsHalfFloatTextures=function(){return console.warn("THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( 'OES_texture_half_float' )."),this.extensions.get("OES_texture_half_float")},ws.prototype.supportsStandardDerivatives=function(){return console.warn("THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( 'OES_standard_derivatives' )."),this.extensions.get("OES_standard_derivatives")},ws.prototype.supportsCompressedTextureS3TC=function(){return console.warn("THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( 'WEBGL_compressed_texture_s3tc' )."),this.extensions.get("WEBGL_compressed_texture_s3tc")},ws.prototype.supportsCompressedTexturePVRTC=function(){return console.warn("THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( 'WEBGL_compressed_texture_pvrtc' )."),this.extensions.get("WEBGL_compressed_texture_pvrtc")},ws.prototype.supportsBlendMinMax=function(){return console.warn("THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( 'EXT_blend_minmax' )."),this.extensions.get("EXT_blend_minmax")},ws.prototype.supportsVertexTextures=function(){return console.warn("THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures."),this.capabilities.vertexTextures},ws.prototype.supportsInstancedArrays=function(){return console.warn("THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( 'ANGLE_instanced_arrays' )."),this.extensions.get("ANGLE_instanced_arrays")},ws.prototype.enableScissorTest=function(t){console.warn("THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest()."),this.setScissorTest(t)},ws.prototype.initMaterial=function(){console.warn("THREE.WebGLRenderer: .initMaterial() has been removed.")},ws.prototype.addPrePlugin=function(){console.warn("THREE.WebGLRenderer: .addPrePlugin() has been removed.")},ws.prototype.addPostPlugin=function(){console.warn("THREE.WebGLRenderer: .addPostPlugin() has been removed.")},ws.prototype.updateShadowMap=function(){console.warn("THREE.WebGLRenderer: .updateShadowMap() has been removed.")},ws.prototype.setFaceCulling=function(){console.warn("THREE.WebGLRenderer: .setFaceCulling() has been removed.")},ws.prototype.allocTextureUnit=function(){console.warn("THREE.WebGLRenderer: .allocTextureUnit() has been removed.")},ws.prototype.setTexture=function(){console.warn("THREE.WebGLRenderer: .setTexture() has been removed.")},ws.prototype.setTexture2D=function(){console.warn("THREE.WebGLRenderer: .setTexture2D() has been removed.")},ws.prototype.setTextureCube=function(){console.warn("THREE.WebGLRenderer: .setTextureCube() has been removed.")},ws.prototype.getActiveMipMapLevel=function(){return console.warn("THREE.WebGLRenderer: .getActiveMipMapLevel() is now .getActiveMipmapLevel()."),this.getActiveMipmapLevel()},Object.defineProperties(ws.prototype,{shadowMapEnabled:{get:function(){return this.shadowMap.enabled},set:function(t){console.warn("THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled."),this.shadowMap.enabled=t}},shadowMapType:{get:function(){return this.shadowMap.type},set:function(t){console.warn("THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type."),this.shadowMap.type=t}},shadowMapCullFace:{get:function(){console.warn("THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.")},set:function(){console.warn("THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.")}},context:{get:function(){return console.warn("THREE.WebGLRenderer: .context has been removed. Use .getContext() instead."),this.getContext()}},vr:{get:function(){return console.warn("THREE.WebGLRenderer: .vr has been renamed to .xr"),this.xr}},gammaInput:{get:function(){return console.warn("THREE.WebGLRenderer: .gammaInput has been removed. Set the encoding for textures via Texture.encoding instead."),!1},set:function(){console.warn("THREE.WebGLRenderer: .gammaInput has been removed. Set the encoding for textures via Texture.encoding instead.")}},gammaOutput:{get:function(){return console.warn("THREE.WebGLRenderer: .gammaOutput has been removed. Set WebGLRenderer.outputEncoding instead."),!1},set:function(t){console.warn("THREE.WebGLRenderer: .gammaOutput has been removed. Set WebGLRenderer.outputEncoding instead."),this.outputEncoding=!0===t?Y:X}},toneMappingWhitePoint:{get:function(){return console.warn("THREE.WebGLRenderer: .toneMappingWhitePoint has been removed."),1},set:function(){console.warn("THREE.WebGLRenderer: .toneMappingWhitePoint has been removed.")}}}),Object.defineProperties(us.prototype,{cullFace:{get:function(){console.warn("THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.")},set:function(){console.warn("THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.")}},renderReverseSided:{get:function(){console.warn("THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.")},set:function(){console.warn("THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.")}},renderSingleSided:{get:function(){console.warn("THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.")},set:function(){console.warn("THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.")}}}),Object.defineProperties(Tt.prototype,{wrapS:{get:function(){return console.warn("THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS."),this.texture.wrapS},set:function(t){console.warn("THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS."),this.texture.wrapS=t}},wrapT:{get:function(){return console.warn("THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT."),this.texture.wrapT},set:function(t){console.warn("THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT."),this.texture.wrapT=t}},magFilter:{get:function(){return console.warn("THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter."),this.texture.magFilter},set:function(t){console.warn("THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter."),this.texture.magFilter=t}},minFilter:{get:function(){return console.warn("THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter."),this.texture.minFilter},set:function(t){console.warn("THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter."),this.texture.minFilter=t}},anisotropy:{get:function(){return console.warn("THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy."),this.texture.anisotropy},set:function(t){console.warn("THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy."),this.texture.anisotropy=t}},offset:{get:function(){return console.warn("THREE.WebGLRenderTarget: .offset is now .texture.offset."),this.texture.offset},set:function(t){console.warn("THREE.WebGLRenderTarget: .offset is now .texture.offset."),this.texture.offset=t}},repeat:{get:function(){return console.warn("THREE.WebGLRenderTarget: .repeat is now .texture.repeat."),this.texture.repeat},set:function(t){console.warn("THREE.WebGLRenderTarget: .repeat is now .texture.repeat."),this.texture.repeat=t}},format:{get:function(){return console.warn("THREE.WebGLRenderTarget: .format is now .texture.format."),this.texture.format},set:function(t){console.warn("THREE.WebGLRenderTarget: .format is now .texture.format."),this.texture.format=t}},type:{get:function(){return console.warn("THREE.WebGLRenderTarget: .type is now .texture.type."),this.texture.type},set:function(t){console.warn("THREE.WebGLRenderTarget: .type is now .texture.type."),this.texture.type=t}},generateMipmaps:{get:function(){return console.warn("THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps."),this.texture.generateMipmaps},set:function(t){console.warn("THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps."),this.texture.generateMipmaps=t}}}),Lc.prototype.load=function(t){console.warn("THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.");const e=this;return(new vc).load(t,(function(t){e.setBuffer(t)})),this},Ic.prototype.getData=function(){return console.warn("THREE.AudioAnalyser: .getData() is now .getFrequencyData()."),this.getFrequencyData()},ti.prototype.updateCubeMap=function(t,e){return console.warn("THREE.CubeCamera: .updateCubeMap() is now .update()."),this.update(t,e)},ti.prototype.clear=function(t,e,n,i){return console.warn("THREE.CubeCamera: .clear() is now .renderTarget.clear()."),this.renderTarget.clear(t,e,n,i)},_t.crossOrigin=void 0,_t.loadTexture=function(t,e,n,i){console.warn("THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.");const r=new pl;r.setCrossOrigin(this.crossOrigin);const s=r.load(t,n,void 0,i);return e&&(s.mapping=e),s},_t.loadTextureCube=function(t,e,n,i){console.warn("THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.");const r=new ul;r.setCrossOrigin(this.crossOrigin);const s=r.load(t,n,void 0,i);return e&&(s.mapping=e),s},_t.loadCompressedTexture=function(){console.error("THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.")},_t.loadCompressedTextureCube=function(){console.error("THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.")};const eu={createMultiMaterialObject:function(){console.error("THREE.SceneUtils has been moved to /examples/jsm/utils/SceneUtils.js")},detach:function(){console.error("THREE.SceneUtils has been moved to /examples/jsm/utils/SceneUtils.js")},attach:function(){console.error("THREE.SceneUtils has been moved to /examples/jsm/utils/SceneUtils.js")}};"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("register",{detail:{revision:e}})),"undefined"!=typeof window&&(window.__THREE__?console.warn("WARNING: Multiple instances of Three.js being imported."):window.__THREE__=e),t.ACESFilmicToneMapping=4,t.AddEquation=n,t.AddOperation=2,t.AdditiveAnimationBlendMode=q,t.AdditiveBlending=2,t.AlphaFormat=1021,t.AlwaysDepth=1,t.AlwaysStencilFunc=519,t.AmbientLight=$l,t.AmbientLightProbe=xc,t.AnimationClip=nl,t.AnimationLoader=class extends ol{constructor(t){super(t)}load(t,e,n,i){const r=this,s=new cl(this.manager);s.setPath(this.path),s.setRequestHeader(this.requestHeader),s.setWithCredentials(this.withCredentials),s.load(t,(function(n){try{e(r.parse(JSON.parse(n)))}catch(e){i?i(e):console.error(e),r.manager.itemError(t)}}),n,i)}parse(t){const e=[];for(let n=0;n.99999)this.quaternion.set(0,0,0,1);else if(t.y<-.99999)this.quaternion.set(1,0,0,0);else{Sh.set(t.z,0,-t.x).normalize();const e=Math.acos(t.y);this.quaternion.setFromAxisAngle(Sh,e)}}setLength(t,e=.2*t,n=.2*e){this.line.scale.set(1,Math.max(1e-4,t-e),1),this.line.updateMatrix(),this.cone.scale.set(n,e,n),this.cone.position.y=t,this.cone.updateMatrix()}setColor(t){this.line.material.color.set(t),this.cone.material.color.set(t)}copy(t){return super.copy(t,!1),this.line.copy(t.line),this.cone.copy(t.cone),this}},t.Audio=Lc,t.AudioAnalyser=Ic,t.AudioContext=gc,t.AudioListener=class extends Ce{constructor(){super(),this.type="AudioListener",this.context=gc.getContext(),this.gain=this.context.createGain(),this.gain.connect(this.context.destination),this.filter=null,this.timeDelta=0,this._clock=new bc}getInput(){return this.gain}removeFilter(){return null!==this.filter&&(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination),this.gain.connect(this.context.destination),this.filter=null),this}getFilter(){return this.filter}setFilter(t){return null!==this.filter?(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination)):this.gain.disconnect(this.context.destination),this.filter=t,this.gain.connect(this.filter),this.filter.connect(this.context.destination),this}getMasterVolume(){return this.gain.gain.value}setMasterVolume(t){return this.gain.gain.setTargetAtTime(t,this.context.currentTime,.01),this}updateMatrixWorld(t){super.updateMatrixWorld(t);const e=this.context.listener,n=this.up;if(this.timeDelta=this._clock.getDelta(),this.matrixWorld.decompose(Sc,Tc,Ec),Ac.set(0,0,-1).applyQuaternion(Tc),e.positionX){const t=this.context.currentTime+this.timeDelta;e.positionX.linearRampToValueAtTime(Sc.x,t),e.positionY.linearRampToValueAtTime(Sc.y,t),e.positionZ.linearRampToValueAtTime(Sc.z,t),e.forwardX.linearRampToValueAtTime(Ac.x,t),e.forwardY.linearRampToValueAtTime(Ac.y,t),e.forwardZ.linearRampToValueAtTime(Ac.z,t),e.upX.linearRampToValueAtTime(n.x,t),e.upY.linearRampToValueAtTime(n.y,t),e.upZ.linearRampToValueAtTime(n.z,t)}else e.setPosition(Sc.x,Sc.y,Sc.z),e.setOrientation(Ac.x,Ac.y,Ac.z,n.x,n.y,n.z)}},t.AudioLoader=vc,t.AxesHelper=Ah,t.AxisHelper=function(t){return console.warn("THREE.AxisHelper has been renamed to THREE.AxesHelper."),new Ah(t)},t.BackSide=1,t.BasicDepthPacking=3200,t.BasicShadowMap=0,t.BinaryTextureLoader=function(t){return console.warn("THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader."),new dl(t)},t.Bone=ta,t.BooleanKeyframeTrack=Zo,t.BoundingBoxHelper=function(t,e){return console.warn("THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead."),new Mh(t,e)},t.Box2=eh,t.Box3=Pt,t.Box3Helper=class extends ya{constructor(t,e=16776960){const n=new Uint16Array([0,1,1,2,2,3,3,0,4,5,5,6,6,7,7,4,0,4,1,5,2,6,3,7]),i=new En;i.setIndex(new sn(n,1)),i.setAttribute("position",new mn([1,1,1,-1,1,1,-1,-1,1,1,-1,1,1,1,-1,-1,1,-1,-1,-1,-1,1,-1,-1],3)),super(i,new ca({color:e,toneMapped:!1})),this.box=t,this.type="Box3Helper",this.geometry.computeBoundingSphere()}updateMatrixWorld(t){const e=this.box;e.isEmpty()||(e.getCenter(this.position),e.getSize(this.scale),this.scale.multiplyScalar(.5),super.updateMatrixWorld(t))}},t.BoxBufferGeometry=qn,t.BoxGeometry=qn,t.BoxHelper=Mh,t.BufferAttribute=sn,t.BufferGeometry=En,t.BufferGeometryLoader=oc,t.ByteType=1010,t.Cache=rl,t.Camera=Qn,t.CameraHelper=class extends ya{constructor(t){const e=new En,n=new ca({color:16777215,vertexColors:!0,toneMapped:!1}),i=[],r=[],s={},a=new tn(16755200),o=new tn(16711680),l=new tn(43775),c=new tn(16777215),h=new tn(3355443);function u(t,e,n){d(t,n),d(e,n)}function d(t,e){i.push(0,0,0),r.push(e.r,e.g,e.b),void 0===s[t]&&(s[t]=[]),s[t].push(i.length/3-1)}u("n1","n2",a),u("n2","n4",a),u("n4","n3",a),u("n3","n1",a),u("f1","f2",a),u("f2","f4",a),u("f4","f3",a),u("f3","f1",a),u("n1","f1",a),u("n2","f2",a),u("n3","f3",a),u("n4","f4",a),u("p","n1",o),u("p","n2",o),u("p","n3",o),u("p","n4",o),u("u1","u2",l),u("u2","u3",l),u("u3","u1",l),u("c","t",c),u("p","c",h),u("cn1","cn2",h),u("cn3","cn4",h),u("cf1","cf2",h),u("cf3","cf4",h),e.setAttribute("position",new mn(i,3)),e.setAttribute("color",new mn(r,3)),super(e,n),this.type="CameraHelper",this.camera=t,this.camera.updateProjectionMatrix&&this.camera.updateProjectionMatrix(),this.matrix=t.matrixWorld,this.matrixAutoUpdate=!1,this.pointMap=s,this.update()}update(){const t=this.geometry,e=this.pointMap;_h.projectionMatrixInverse.copy(this.camera.projectionMatrixInverse),wh("c",e,t,_h,0,0,-1),wh("t",e,t,_h,0,0,1),wh("n1",e,t,_h,-1,-1,-1),wh("n2",e,t,_h,1,-1,-1),wh("n3",e,t,_h,-1,1,-1),wh("n4",e,t,_h,1,1,-1),wh("f1",e,t,_h,-1,-1,1),wh("f2",e,t,_h,1,-1,1),wh("f3",e,t,_h,-1,1,1),wh("f4",e,t,_h,1,1,1),wh("u1",e,t,_h,.7,1.1,-1),wh("u2",e,t,_h,-.7,1.1,-1),wh("u3",e,t,_h,0,2,-1),wh("cf1",e,t,_h,-1,0,1),wh("cf2",e,t,_h,1,0,1),wh("cf3",e,t,_h,0,-1,1),wh("cf4",e,t,_h,0,1,1),wh("cn1",e,t,_h,-1,0,-1),wh("cn2",e,t,_h,1,0,-1),wh("cn3",e,t,_h,0,-1,-1),wh("cn4",e,t,_h,0,1,-1),t.getAttribute("position").needsUpdate=!0}dispose(){this.geometry.dispose(),this.material.dispose()}},t.CanvasRenderer=function(){console.error("THREE.CanvasRenderer has been removed")},t.CanvasTexture=Ra,t.CatmullRomCurve3=bl,t.CineonToneMapping=3,t.CircleBufferGeometry=Pa,t.CircleGeometry=Pa,t.ClampToEdgeWrapping=u,t.Clock=bc,t.Color=tn,t.ColorKeyframeTrack=Jo,t.CompressedTexture=La,t.CompressedTextureLoader=class extends ol{constructor(t){super(t)}load(t,e,n,i){const r=this,s=[],a=new La,o=new cl(this.manager);o.setPath(this.path),o.setResponseType("arraybuffer"),o.setRequestHeader(this.requestHeader),o.setWithCredentials(r.withCredentials);let l=0;function c(c){o.load(t[c],(function(t){const n=r.parse(t,!0);s[c]={width:n.width,height:n.height,format:n.format,mipmaps:n.mipmaps},l+=1,6===l&&(1===n.mipmapCount&&(a.minFilter=g),a.image=s,a.format=n.format,a.needsUpdate=!0,e&&e(a))}),n,i)}if(Array.isArray(t))for(let e=0,n=t.length;e>16&32768,i=e>>12&2047;const r=e>>23&255;return r<103?n:r>142?(n|=31744,n|=(255==r?0:1)&&8388607&e,n):r<113?(i|=2048,n|=(i>>114-r)+(i>>113-r&1),n):(n|=r-112<<10|i>>1,n+=1&i,n)}},t.DecrementStencilOp=7683,t.DecrementWrapStencilOp=34056,t.DefaultLoadingManager=al,t.DepthFormat=A,t.DepthStencilFormat=L,t.DepthTexture=Ca,t.DirectionalLight=Kl,t.DirectionalLightHelper=class extends Ce{constructor(t,e,n){super(),this.light=t,this.light.updateMatrixWorld(),this.matrix=t.matrixWorld,this.matrixAutoUpdate=!1,this.color=n,void 0===e&&(e=1);let i=new En;i.setAttribute("position",new mn([-e,e,0,e,e,0,e,-e,0,-e,-e,0,-e,e,0],3));const r=new ca({fog:!1,toneMapped:!1});this.lightPlane=new fa(i,r),this.add(this.lightPlane),i=new En,i.setAttribute("position",new mn([0,0,0,0,0,1],3)),this.targetLine=new fa(i,r),this.add(this.targetLine),this.update()}dispose(){this.lightPlane.geometry.dispose(),this.lightPlane.material.dispose(),this.targetLine.geometry.dispose(),this.targetLine.material.dispose()}update(){gh.setFromMatrixPosition(this.light.matrixWorld),vh.setFromMatrixPosition(this.light.target.matrixWorld),yh.subVectors(vh,gh),this.lightPlane.lookAt(vh),void 0!==this.color?(this.lightPlane.material.color.set(this.color),this.targetLine.material.color.set(this.color)):(this.lightPlane.material.color.copy(this.light.color),this.targetLine.material.color.copy(this.light.color)),this.targetLine.lookAt(vh),this.targetLine.scale.z=yh.length()}},t.DiscreteInterpolant=Xo,t.DodecahedronBufferGeometry=Ba,t.DodecahedronGeometry=Ba,t.DoubleSide=2,t.DstAlphaFactor=206,t.DstColorFactor=208,t.DynamicBufferAttribute=function(t,e){return console.warn("THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setUsage( THREE.DynamicDrawUsage ) instead."),new sn(t,e).setUsage(nt)},t.DynamicCopyUsage=35050,t.DynamicDrawUsage=nt,t.DynamicReadUsage=35049,t.EdgesGeometry=Ga,t.EdgesHelper=function(t,e){return console.warn("THREE.EdgesHelper has been removed. Use THREE.EdgesGeometry instead."),new ya(new Ga(t.geometry),new ca({color:void 0!==e?e:16777215}))},t.EllipseCurve=fl,t.EqualDepth=4,t.EqualStencilFunc=514,t.EquirectangularReflectionMapping=a,t.EquirectangularRefractionMapping=o,t.Euler=fe,t.EventDispatcher=rt,t.ExtrudeBufferGeometry=go,t.ExtrudeGeometry=go,t.FaceColors=1,t.FileLoader=cl,t.FlatShading=1,t.Float16BufferAttribute=pn,t.Float32Attribute=function(t,e){return console.warn("THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead."),new mn(t,e)},t.Float32BufferAttribute=mn,t.Float64Attribute=function(t,e){return console.warn("THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead."),new fn(t,e)},t.Float64BufferAttribute=fn,t.FloatType=b,t.Fog=Ss,t.FogExp2=Ms,t.Font=pc,t.FontLoader=class extends ol{constructor(t){super(t)}load(t,e,n,i){const r=this,s=new cl(this.manager);s.setPath(this.path),s.setRequestHeader(this.requestHeader),s.setWithCredentials(r.withCredentials),s.load(t,(function(t){let n;try{n=JSON.parse(t)}catch(e){console.warn("THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead."),n=JSON.parse(t.substring(65,t.length-2))}const i=r.parse(n);e&&e(i)}),n,i)}parse(t){return new pc(t)}},t.FrontSide=0,t.Frustum=ai,t.GLBufferAttribute=Qc,t.GLSL1="100",t.GLSL3=it,t.GammaEncoding=Z,t.GreaterDepth=6,t.GreaterEqualDepth=5,t.GreaterEqualStencilFunc=518,t.GreaterStencilFunc=516,t.GridHelper=fh,t.Group=gs,t.HalfFloatType=M,t.HemisphereLight=Ol,t.HemisphereLightHelper=class extends Ce{constructor(t,e,n){super(),this.light=t,this.light.updateMatrixWorld(),this.matrix=t.matrixWorld,this.matrixAutoUpdate=!1,this.color=n;const i=new _o(e);i.rotateY(.5*Math.PI),this.material=new en({wireframe:!0,fog:!1,toneMapped:!1}),void 0===this.color&&(this.material.vertexColors=!0);const r=i.getAttribute("position"),s=new Float32Array(3*r.count);i.setAttribute("color",new sn(s,3)),this.add(new Wn(i,this.material)),this.update()}dispose(){this.children[0].geometry.dispose(),this.children[0].material.dispose()}update(){const t=this.children[0];if(void 0!==this.color)this.material.color.set(this.color);else{const e=t.geometry.getAttribute("color");ph.copy(this.light.color),mh.copy(this.light.groundColor);for(let t=0,n=e.count;t0){const n=new sl(e);r=new hl(n),r.setCrossOrigin(this.crossOrigin);for(let e=0,n=t.length;e\n\n\t\t\tvec3 getSample( float theta, vec3 axis ) {\n\n\t\t\t\tfloat cosTheta = cos( theta );\n\t\t\t\t// Rodrigues' axis-angle rotation\n\t\t\t\tvec3 sampleDirection = vOutputDirection * cosTheta\n\t\t\t\t\t+ cross( axis, vOutputDirection ) * sin( theta )\n\t\t\t\t\t+ axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta );\n\n\t\t\t\treturn bilinearCubeUV( envMap, sampleDirection, mipInt );\n\n\t\t\t}\n\n\t\t\tvoid main() {\n\n\t\t\t\tvec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection );\n\n\t\t\t\tif ( all( equal( axis, vec3( 0.0 ) ) ) ) {\n\n\t\t\t\t\taxis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x );\n\n\t\t\t\t}\n\n\t\t\t\taxis = normalize( axis );\n\n\t\t\t\tgl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t\t\t\tgl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis );\n\n\t\t\t\tfor ( int i = 1; i < n; i++ ) {\n\n\t\t\t\t\tif ( i >= samples ) {\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfloat theta = dTheta * float( i );\n\t\t\t\t\tgl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis );\n\t\t\t\t\tgl_FragColor.rgb += weights[ i ] * getSample( theta, axis );\n\n\t\t\t\t}\n\n\t\t\t\tgl_FragColor = linearToOutputTexel( gl_FragColor );\n\n\t\t\t}\n\t\t`,blending:0,depthTest:!1,depthWrite:!1})}(Ih),this._equirectShader=null,this._cubemapShader=null,this._compileMaterial(this._blurMaterial)}fromScene(t,e=0,n=.1,i=100){kh=this._renderer.getRenderTarget();const r=this._allocateTargets();return this._sceneToCubeUV(t,n,i,r),e>0&&this._blur(r,0,0,e),this._applyPMREM(r),this._cleanup(r),r}fromEquirectangular(t){return this._fromTexture(t)}fromCubemap(t){return this._fromTexture(t)}compileCubemapShader(){null===this._cubemapShader&&(this._cubemapShader=Kh(),this._compileMaterial(this._cubemapShader))}compileEquirectangularShader(){null===this._equirectShader&&(this._equirectShader=Qh(),this._compileMaterial(this._equirectShader))}dispose(){this._blurMaterial.dispose(),null!==this._cubemapShader&&this._cubemapShader.dispose(),null!==this._equirectShader&&this._equirectShader.dispose();for(let t=0;t2?Ch:0,Ch,Ch),o.setRenderTarget(i),u&&o.render(zh,r),o.render(t,r)}o.toneMapping=h,o.outputEncoding=c,o.autoClear=l}_textureToCubeUV(t,e){const n=this._renderer;t.isCubeTexture?null==this._cubemapShader&&(this._cubemapShader=Kh()):null==this._equirectShader&&(this._equirectShader=Qh());const i=t.isCubeTexture?this._cubemapShader:this._equirectShader,r=new Wn(Oh[0],i),s=i.uniforms;s.envMap.value=t,t.isCubeTexture||s.texelSize.value.set(1/t.image.width,1/t.image.height),s.inputEncoding.value=Nh[t.encoding],s.outputEncoding.value=Nh[e.texture.encoding],Jh(e,0,0,3*Ch,2*Ch),n.setRenderTarget(e),n.render(r,Fh)}_applyPMREM(t){const e=this._renderer,n=e.autoClear;e.autoClear=!1;for(let e=1;eIh&&console.warn(`sigmaRadians, ${r}, is too large and will clip, as it requested ${m} samples when the maximum is set to 20`);const f=[];let g=0;for(let t=0;t4?i-8+4:0),3*v,2*v),o.setRenderTarget(e),o.render(c,Fh)}},t.ParametricBufferGeometry=wo,t.ParametricGeometry=wo,t.Particle=function(t){return console.warn("THREE.Particle has been renamed to THREE.Sprite."),new Vs(t)},t.ParticleBasicMaterial=function(t){return console.warn("THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial."),new _a(t)},t.ParticleSystem=function(t,e){return console.warn("THREE.ParticleSystem has been renamed to THREE.Points."),new Ta(t,e)},t.ParticleSystemMaterial=function(t){return console.warn("THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial."),new _a(t)},t.Path=Bl,t.PerspectiveCamera=Kn,t.Plane=Ne,t.PlaneBufferGeometry=ci,t.PlaneGeometry=ci,t.PlaneHelper=class extends fa{constructor(t,e=1,n=16776960){const i=n,r=new En;r.setAttribute("position",new mn([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,0,1,0,0,0],3)),r.computeBoundingSphere(),super(r,new ca({color:i,toneMapped:!1})),this.type="PlaneHelper",this.plane=t,this.size=e;const s=new En;s.setAttribute("position",new mn([1,1,1,-1,1,1,-1,-1,1,1,1,1,-1,-1,1,1,-1,1],3)),s.computeBoundingSphere(),this.add(new Wn(s,new en({color:i,opacity:.2,transparent:!0,depthWrite:!1,toneMapped:!1})))}updateMatrixWorld(t){let e=-this.plane.constant;Math.abs(e)<1e-8&&(e=1e-8),this.scale.set(.5*this.size,.5*this.size,e),this.children[0].material.side=e<0?1:0,this.lookAt(this.plane.normal),super.updateMatrixWorld(t)}},t.PointCloud=function(t,e){return console.warn("THREE.PointCloud has been renamed to THREE.Points."),new Ta(t,e)},t.PointCloudMaterial=function(t){return console.warn("THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial."),new _a(t)},t.PointLight=Zl,t.PointLightHelper=class extends Wn{constructor(t,e,n){super(new So(e,4,2),new en({wireframe:!0,fog:!1,toneMapped:!1})),this.light=t,this.light.updateMatrixWorld(),this.color=n,this.type="PointLightHelper",this.matrix=this.light.matrixWorld,this.matrixAutoUpdate=!1,this.update()}dispose(){this.geometry.dispose(),this.material.dispose()}update(){void 0!==this.color?this.material.color.set(this.color):this.material.color.copy(this.light.color)}},t.Points=Ta,t.PointsMaterial=_a,t.PolarGridHelper=class extends ya{constructor(t=10,e=16,n=8,i=64,r=4473924,s=8947848){r=new tn(r),s=new tn(s);const a=[],o=[];for(let n=0;n<=e;n++){const i=n/e*(2*Math.PI),l=Math.sin(i)*t,c=Math.cos(i)*t;a.push(0,0,0),a.push(l,0,c);const h=1&n?r:s;o.push(h.r,h.g,h.b),o.push(h.r,h.g,h.b)}for(let e=0;e<=n;e++){const l=1&e?r:s,c=t-t/n*e;for(let t=0;t=22.12.0" + } + }, + "node_modules/@github/copilot-win32-arm64": { + "version": "1.0.75", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.75.tgz", + "integrity": "sha512-wlLDuor+Qm1H43VwZNi03QI4H9FSyZoQzE/YHpGhUay7sKA+4cDJF8ZZNGrtYkyPskfH5HCdNygUn7EEt6lRyQ==", + "cpu": [ + "arm64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "win32" + ], + "bin": { + "copilot-win32-arm64": "copilot.exe" + } + }, + "node_modules/@github/copilot-win32-x64": { + "version": "1.0.75", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.75.tgz", + "integrity": "sha512-TKISaaILkgcOi7ThaTnln1XoasbUIx+HKSb+pf678RvGucIfLohQyLceuq+rTykoynX54KQ0pf9TEUbMVkUNAA==", + "cpu": [ + "x64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "win32" + ], + "bin": { + "copilot-win32-x64": "copilot.exe" + } + }, + "node_modules/@koromix/koffi-darwin-arm64": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@koromix/koffi-darwin-arm64/-/koffi-darwin-arm64-3.1.2.tgz", + "integrity": "sha512-32pU4pNZABIz+l9DNJl51Y+jur4vv+SF4Ip2CSF4OUg1xUyefoLpX0NttDmzGITIrneUEVSEN+dT22524ESKBw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-darwin-x64": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@koromix/koffi-darwin-x64/-/koffi-darwin-x64-3.1.2.tgz", + "integrity": "sha512-S+H6LQgUoMj77BqDegwlRaxwLXDfwvSJGuceOqtH0I5V8rzKLmu/hC7NBlxOoAlvKlcV63FtdNiE2E9YSltffg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-freebsd-arm64": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@koromix/koffi-freebsd-arm64/-/koffi-freebsd-arm64-3.1.2.tgz", + "integrity": "sha512-fD0ow2PBE60nw7K6xcbala6qwXxfcYeU62tduNeIPvx0KoWhU2rMKZiDNe+iI5TQb3rxYYjjP+aF2Sdm9y6EXQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-freebsd-ia32": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@koromix/koffi-freebsd-ia32/-/koffi-freebsd-ia32-3.1.2.tgz", + "integrity": "sha512-t8OmL+hoJGDLZDnuLjgLemSYrXX99M7Md+zJX8bMHOtiNbFtkGXn/mV21Pb1ik9JhBXjwK1r4hvBPNlqTMGrHg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-freebsd-x64": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@koromix/koffi-freebsd-x64/-/koffi-freebsd-x64-3.1.2.tgz", + "integrity": "sha512-axbLgiM4Y2vyDOTqlXCI8vkg9wqjwSRsmoWXSKreA5YFJwnYA6Sc4aHMz+qZgUSfFei52Qrv1RGhDyo4kHvqhA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-arm64": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@koromix/koffi-linux-arm64/-/koffi-linux-arm64-3.1.2.tgz", + "integrity": "sha512-f0hqAIlFcL9wlRGJ/uCfyfspqnGaASk2gLx1UAP3RBgMQl68D1e+fiHNdXa7g9d76ttmpA8/PGNAqc1X4Byy1Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-ia32": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@koromix/koffi-linux-ia32/-/koffi-linux-ia32-3.1.2.tgz", + "integrity": "sha512-UGLPuqeOV/UArsK6oeB5yI/XjSWkFqFlBTC9rUbezBuHJhSibk1EMv7QC0cvtDMu18bo+ucqXWPzh42oT5yYlw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-loong64": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@koromix/koffi-linux-loong64/-/koffi-linux-loong64-3.1.2.tgz", + "integrity": "sha512-jI0+gM2oDsJ7reOt3XPyO7lyQtZ1CT6NR2uqGQcQVM43cyXBAVYYCUxEH3LHCbgumFaZ+LueIUgbMSwb9pHBxQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-riscv64": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@koromix/koffi-linux-riscv64/-/koffi-linux-riscv64-3.1.2.tgz", + "integrity": "sha512-yB99adXBRd5T+xXG+f6nnUkC3jCI0iXvPU6RqD9Kx7aZP4Y4NNUWJ5Q4FaP9jb1XmZLY4pGBUiHt8u03Yl7NyA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-x64": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@koromix/koffi-linux-x64/-/koffi-linux-x64-3.1.2.tgz", + "integrity": "sha512-Oxvo6F3Edzy/Jm2EtbHWkJ2xRB0mXDAe63k5+USL5uiGE5xZjwEUDOBKIhv2BpCZSOAJrfoojFFogj6+ICKQhw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-openbsd-ia32": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@koromix/koffi-openbsd-ia32/-/koffi-openbsd-ia32-3.1.2.tgz", + "integrity": "sha512-SSWzUhL8Ex84JTsO67+MdWZrdwgOzoOrQ0+ZbB+UsivHoAxmWLHKWZaSafNqyBZtxGY1EgtR8AIPouWE9U+Zfw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-openbsd-x64": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@koromix/koffi-openbsd-x64/-/koffi-openbsd-x64-3.1.2.tgz", + "integrity": "sha512-0ZuI4St7chq3M0d3VivvKIqacZ7RhgohdR476V3HpJkaNdfIywsJIw+GBvqkQahu+4A2Rpu6yQJpWSrfk/Z+Jw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-win32-arm64": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@koromix/koffi-win32-arm64/-/koffi-win32-arm64-3.1.2.tgz", + "integrity": "sha512-8Wn6phw7y53uI52+aBPAqEfZ5pj/HCjg/YtdthqSWYHy+d0MhyASKlcmuP0B5raxQnnA1Bm9LC8UO3M3RojeBw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-win32-ia32": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@koromix/koffi-win32-ia32/-/koffi-win32-ia32-3.1.2.tgz", + "integrity": "sha512-FkKaPBMawgHMNnp1FwLldXMNvEa139GXkxPi9JD9xU71Kh/ZmuEYHGSD6JwZDmDr4jekVrBrr+eGZ+j6C2mkXg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-win32-x64": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@koromix/koffi-win32-x64/-/koffi-win32-x64-3.1.2.tgz", + "integrity": "sha512-FeFC59UU1XX4J3ZaqKrsrEzczzB5qksMJo7/R45vIg8mGNVSLMVE85JRiZpjcp9i5Lbav5Vw47QvwFzBgIfvlw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "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==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/koffi": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/koffi/-/koffi-3.1.2.tgz", + "integrity": "sha512-wVwuE21TBl8/si6E0hPorKR2PJ2q33mEWVETANrtSp3kFM8fi2FcD/J5wmxu0T4TBcqmMQ4xKuF1X1ayFmphzw==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "url": "https://liberapay.com/Koromix" + }, + "optionalDependencies": { + "@koromix/koffi-darwin-arm64": "3.1.2", + "@koromix/koffi-darwin-x64": "3.1.2", + "@koromix/koffi-freebsd-arm64": "3.1.2", + "@koromix/koffi-freebsd-ia32": "3.1.2", + "@koromix/koffi-freebsd-x64": "3.1.2", + "@koromix/koffi-linux-arm64": "3.1.2", + "@koromix/koffi-linux-ia32": "3.1.2", + "@koromix/koffi-linux-loong64": "3.1.2", + "@koromix/koffi-linux-riscv64": "3.1.2", + "@koromix/koffi-linux-x64": "3.1.2", + "@koromix/koffi-openbsd-ia32": "3.1.2", + "@koromix/koffi-openbsd-x64": "3.1.2", + "@koromix/koffi-win32-arm64": "3.1.2", + "@koromix/koffi-win32-ia32": "3.1.2", + "@koromix/koffi-win32-x64": "3.1.2" + } + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/extensions/flight-map-canvas/package.json b/extensions/flight-map-canvas/package.json new file mode 100644 index 00000000..8f637900 --- /dev/null +++ b/extensions/flight-map-canvas/package.json @@ -0,0 +1,21 @@ +{ + "name": "flight-map-canvas", + "version": "1.0.0", + "main": "extension.mjs", + "author": "John Haugabook", + "license": "MIT", + "type": "module", + "dependencies": { + "@github/copilot-sdk": "latest" + }, + "description": "A GitHub Copilot canvas that generates a view where Google Maps can be explored using 3D controls, as if a flight simulator. Agents can send the flight anywhere and report what they are working on.", + "keywords": [ + "copilot-canvas", + "flight-simulator", + "geography", + "google-maps", + "interactive-canvas", + "session-breaks", + "threejs" + ] +} diff --git a/extensions/flight-map-canvas/renderMap.json b/extensions/flight-map-canvas/renderMap.json new file mode 100644 index 00000000..4a67e867 --- /dev/null +++ b/extensions/flight-map-canvas/renderMap.json @@ -0,0 +1,37 @@ +{ + "map": { + "width": 2210, + "height": 1290, + "tileZoom": 15, + "tileSize": 100, + "loadRadius": 25, + "unloadRadius": 9, + "startAltitude": 200, + "fogDensity": 0.00092, + "radiusFeather": 28.5, + "maxTiles": 600 + }, + "filler": { + "sampleInterval": 55, + "updateIntervalSec": 15, + "perimeter": { + "patchCount": 15, + "patchSize": 15 + }, + "center": { + "patchCount": 4, + "patchSize": 7 + }, + "padding": { + "patchCount": 6, + "patchSize": 9 + } + }, + "cloud": { + "enabled": true, + "opacity": 0.35, + "speed": 0.0004, + "coverage": 0.5, + "scale": 0.008 + } +}