├── .gitignore ├── .nvmrc ├── .postcssrc.json ├── .yarn └── releases │ └── yarn-3.1.0.cjs ├── .yarnrc.yml ├── LICENSE.md ├── demo ├── index.css ├── index.html ├── index.js ├── sample.mp4 ├── spread.frag.glsl └── view.frag.glsl ├── docs ├── index.3749c18b.js ├── index.3749c18b.js.map ├── index.dbe5a2ab.css ├── index.dbe5a2ab.css.map ├── index.f295124b.js ├── index.f295124b.js.map ├── index.html └── sample.6124211c.mp4 ├── index.frag.glsl ├── index.frag.js ├── index.glsl ├── index.js ├── package.json ├── readme.md ├── snap ├── demo.mp4 └── demo.png └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See "Custom Overrides" below the following generated rules. 2 | 3 | # Created by https://www.toptal.com/developers/gitignore/api/node,yarn,osx 4 | # Edit at https://www.toptal.com/developers/gitignore?templates=node,yarn,osx 5 | 6 | ### Node ### 7 | # Logs 8 | logs 9 | *.log 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | lerna-debug.log* 14 | .pnpm-debug.log* 15 | 16 | # Diagnostic reports (https://nodejs.org/api/report.html) 17 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 18 | 19 | # Runtime data 20 | pids 21 | *.pid 22 | *.seed 23 | *.pid.lock 24 | 25 | # Directory for instrumented libs generated by jscoverage/JSCover 26 | lib-cov 27 | 28 | # Coverage directory used by tools like istanbul 29 | coverage 30 | *.lcov 31 | 32 | # nyc test coverage 33 | .nyc_output 34 | 35 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 36 | .grunt 37 | 38 | # Bower dependency directory (https://bower.io/) 39 | bower_components 40 | 41 | # node-waf configuration 42 | .lock-wscript 43 | 44 | # Compiled binary addons (https://nodejs.org/api/addons.html) 45 | build/Release 46 | 47 | # Dependency directories 48 | node_modules/ 49 | jspm_packages/ 50 | 51 | # Snowpack dependency directory (https://snowpack.dev/) 52 | web_modules/ 53 | 54 | # TypeScript cache 55 | *.tsbuildinfo 56 | 57 | # Optional npm cache directory 58 | .npm 59 | 60 | # Optional eslint cache 61 | .eslintcache 62 | 63 | # Microbundle cache 64 | .rpt2_cache/ 65 | .rts2_cache_cjs/ 66 | .rts2_cache_es/ 67 | .rts2_cache_umd/ 68 | 69 | # Optional REPL history 70 | .node_repl_history 71 | 72 | # Output of 'npm pack' 73 | *.tgz 74 | 75 | # Yarn Integrity file 76 | .yarn-integrity 77 | 78 | # dotenv environment variables file 79 | .env 80 | .env.test 81 | .env.production 82 | 83 | # parcel-bundler cache (https://parceljs.org/) 84 | .cache 85 | .parcel-cache 86 | 87 | # Next.js build output 88 | .next 89 | out 90 | 91 | # Nuxt.js build / generate output 92 | .nuxt 93 | dist 94 | 95 | # Gatsby files 96 | .cache/ 97 | # Comment in the public line in if your project uses Gatsby and not Next.js 98 | # https://nextjs.org/blog/next-9-1#public-directory-support 99 | # public 100 | 101 | # vuepress build output 102 | .vuepress/dist 103 | 104 | # Serverless directories 105 | .serverless/ 106 | 107 | # FuseBox cache 108 | .fusebox/ 109 | 110 | # DynamoDB Local files 111 | .dynamodb/ 112 | 113 | # TernJS port file 114 | .tern-port 115 | 116 | # Stores VSCode versions used for testing VSCode extensions 117 | .vscode-test 118 | 119 | # yarn v2 120 | .yarn/cache 121 | .yarn/unplugged 122 | .yarn/build-state.yml 123 | .yarn/install-state.gz 124 | .pnp.* 125 | 126 | ### Node Patch ### 127 | # Serverless Webpack directories 128 | .webpack/ 129 | 130 | ### OSX ### 131 | # General 132 | .DS_Store 133 | .AppleDouble 134 | .LSOverride 135 | 136 | # Icon must end with two \r 137 | Icon 138 | 139 | 140 | # Thumbnails 141 | ._* 142 | 143 | # Files that might appear in the root of a volume 144 | .DocumentRevisions-V100 145 | .fseventsd 146 | .Spotlight-V100 147 | .TemporaryItems 148 | .Trashes 149 | .VolumeIcon.icns 150 | .com.apple.timemachine.donotpresent 151 | 152 | # Directories potentially created on remote AFP share 153 | .AppleDB 154 | .AppleDesktop 155 | Network Trash Folder 156 | Temporary Items 157 | .apdisk 158 | 159 | ### yarn ### 160 | # https://yarnpkg.com/advanced/qa#which-files-should-be-gitignored 161 | 162 | .yarn/* 163 | !.yarn/releases 164 | !.yarn/plugins 165 | !.yarn/sdks 166 | !.yarn/versions 167 | 168 | # if you are NOT using Zero-installs, then: 169 | # comment the following lines 170 | # !.yarn/cache 171 | 172 | # and uncomment the following lines 173 | # .pnp.* 174 | 175 | # End of https://www.toptal.com/developers/gitignore/api/node,yarn,osx 176 | 177 | # Custom Overrides 178 | 179 | /dist 180 | 181 | # Ignore files/folders marked with `.gitignore`, but not `.gitignore` itself. 182 | *.gitignore 183 | !.gitignore 184 | *.gitignore.* 185 | *.gitignore/ 186 | 187 | *.lfs 188 | *.lfs.* 189 | *.lfs/ 190 | 191 | # Re-enable Yarn zero-installs and PnP config. 192 | # !.pnp.* 193 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v16.13.0 2 | -------------------------------------------------------------------------------- /.postcssrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": { 3 | "postcss-nesting": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | yarnPath: .yarn/releases/yarn-3.1.0.cjs 2 | nodeLinker: node-modules 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Eoghan O'Keeffe 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /demo/index.css: -------------------------------------------------------------------------------- 1 | *, 2 | *:before, 3 | *:after { box-sizing: inherit; } 4 | 5 | html { 6 | box-sizing: border-box; 7 | background: #000; 8 | } 9 | 10 | body, 11 | .demo { 12 | display: flex; 13 | flex-flow: row wrap; 14 | justify-content: center; 15 | align-items: center; 16 | } 17 | 18 | body { 19 | margin: 0; 20 | gap: 4em; 21 | } 22 | 23 | video, 24 | canvas, 25 | img { 26 | max-width: 100%; 27 | max-height: 100%; 28 | } 29 | 30 | .webcam, 31 | .output { 32 | max-width: 100vw; 33 | max-height: 100vh; 34 | } 35 | 36 | .webcam { display: none; } 37 | 38 | .output { z-index: 1; } 39 | 40 | .demo { 41 | position: relative; 42 | cursor: copy; 43 | 44 | &.mirror { 45 | .webcam, 46 | .output { transform: scaleX(-1); } 47 | } 48 | 49 | &.overlay { 50 | cursor: alias; 51 | 52 | .webcam { display: block; } 53 | 54 | .output { 55 | position: absolute; 56 | top: 50%; 57 | left: 50%; 58 | transform: translate(-50%, -50%); 59 | } 60 | 61 | &.mirror .output { transform: translate(-50%, -50%) scaleX(-1); } 62 | } 63 | } 64 | 65 | .fallback { 66 | display: none; 67 | 68 | &[src] { 69 | display: block; 70 | position: relative; 71 | width: 100%; 72 | height: 720px; 73 | margin: auto; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 |
10 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /demo/index.js: -------------------------------------------------------------------------------- 1 | /** Any rendering library, but made with `regl` in mind. */ 2 | import getRegl from 'regl'; 3 | import getUserMedia from 'getusermedia'; 4 | import { positions, count } from '@epok.tech/gl-screen-triangle'; 5 | import range from '@epok.tech/fn-lists/range'; 6 | import map from '@epok.tech/fn-lists/map'; 7 | import each from '@epok.tech/fn-lists/each'; 8 | import { wrapIndex, wrapGet } from '@epok.tech/fn-lists/wrap-index'; 9 | 10 | import vert from '@epok.tech/gl-screen-triangle/uv-texture.vert.glsl'; 11 | import flowFrag from '../index.frag.glsl'; 12 | import spreadFrag from './spread.frag.glsl'; 13 | import viewFrag from './view.frag.glsl'; 14 | 15 | const $demo = document.querySelector('.demo'); 16 | const $video = $demo.querySelector('.webcam'); 17 | const $canvas = $demo.querySelector('.output'); 18 | const $fallback = document.querySelector('.fallback'); 19 | 20 | // Handle query parameters. 21 | const query = new URLSearchParams(location.search); 22 | 23 | const regl = getRegl({ 24 | canvas: $canvas, 25 | optionalExtensions: [ 26 | 'oes_texture_half_float', 'oes_texture_float', 'oes_texture_float_linear' 27 | ] 28 | }); 29 | 30 | const float = (regl.hasExtension('oes_texture_float_linear') && 31 | ((regl.hasExtension('oes_texture_float'))? 'float' 32 | : regl.hasExtension('oes_texture_half_float') && 'half float')); 33 | 34 | // Whether to remap values between `float`/`int` in textures. 35 | const remap = !float; 36 | 37 | const mapProps = { type: float || 'uint8', min: 'linear', mag: 'linear' }; 38 | const frameProps = { width: 0, height: 0, depth: false, stencil: false }; 39 | 40 | const getMap = () => regl.texture(mapProps); 41 | 42 | const getFrame = (color = getMap()) => 43 | regl.framebuffer({ color, ...frameProps }); 44 | 45 | // Each blur axis of spread. 46 | const spreadMaps = map(getMap, range(2), 0); 47 | const spreadFrames = map(getFrame, spreadMaps); 48 | 49 | // Past and next video frames for optical-flow. 50 | const flowFrames = map(() => getFrame(), range(2), 0); 51 | const flowTo = getFrame(); 52 | 53 | // Past and next optical-flow frames to blend. 54 | const blendFrames = map(() => getFrame(), range(2), 0); 55 | 56 | const resizers = [...spreadFrames, ...flowFrames, flowTo, ...blendFrames]; 57 | 58 | const inRange = [-1, -1, 1, 1]; 59 | const toRange = [0, 0, 1, 1]; 60 | 61 | const props = self.opticalFlow = { 62 | videoFrame: { data: $video, flipY: true }, 63 | spreadVideo: { 64 | /** 65 | * Blur the video. 66 | * 67 | * @see drawSpreadVideoProps 68 | */ 69 | frag: '#define opticalFlowSpreadBlur\n'+spreadFrag, 70 | 71 | /** 72 | * The `passes` props array spreads blur one axis after the other. 73 | * Blurs the first axis of the first frame into the next frame, then 74 | * the last axis of that frame into the first frame. 75 | * 76 | * @see drawSpreadProps 77 | */ 78 | passes: map((a, p) => ({ axis: a, pass: p }), [[1.4, 0], [0, 1.4]], 0) 79 | }, 80 | flow: { 81 | frag: ((remap)? '#define opticalFlowMap\n' : '')+flowFrag, 82 | // Pixels units; will divide `offset` by the video resolution later. 83 | offset: 3, lambda: 1e-3, speed: range(2, 1), alpha: 100, 84 | inRange, toRange, 85 | to: flowTo 86 | }, 87 | spreadFlow: { 88 | /** 89 | * Blur the past flow frames along each `axis`, shift/advect along 90 | * the `flow` by `speed`, `tint` to weaken the past flow, `blend` in 91 | * the next optical-flow frame. 92 | * 93 | * @see drawSpreadFlowProps 94 | */ 95 | frag: '#define opticalFlowSpreadBlur\n'+ 96 | '#define opticalFlowSpreadTint\n'+ 97 | '#define opticalFlowSpreadShift opticalFlowSpreadShift_flow\n'+ 98 | ((remap)? '#define opticalFlowSpreadMap\n' : '')+ 99 | '#define opticalFlowSpreadBlend\n'+ 100 | spreadFrag, 101 | 102 | other: flowTo, blend: 1, 103 | inRange, toRange, 104 | 105 | /** 106 | * Bear in mind each of the `passes` per-`axis` also apply the other 107 | * `spread` inputs; some may be better to control per-`pass`, others 108 | * across both. 109 | * 110 | * @see props.spreadVideo.passes 111 | */ 112 | passes: map((o, p) => { 113 | o.pass = p; 114 | 115 | return o; 116 | }, 117 | [ 118 | { axis: [3, 0], tint: range(4, 1), speed: range(2, 0) }, 119 | { axis: [0, 3], tint: range(4, 0.99), speed: range(2, 1) } 120 | ], 121 | 0) 122 | }, 123 | view: { 124 | frag: ((remap)? '#define opticalFlowViewMap\n' : '')+viewFrag, 125 | inRange, toRange 126 | } 127 | }; 128 | 129 | const clearView = { color: [0, 0, 0, 1], depth: 1, stencil: 0 }; 130 | const clearFlow = { ...clearView, framebuffer: flowTo }; 131 | 132 | const clearFlows = map((f) => ({ ...clearView, framebuffer: f }), flowFrames); 133 | 134 | const clearSpreads = map((f) => ({ ...clearView, framebuffer: f }), 135 | spreadFrames); 136 | 137 | const clearBlends = map((f) => ({ ...clearView, framebuffer: f }), blendFrames); 138 | 139 | const drawScreen = regl({ 140 | vert, attributes: { position: positions }, count, depth: { enable: false } 141 | }); 142 | 143 | // Spread a frame `pass`; blur along an `axis`, shift by a `flow`, `blend` 144 | // with an `other` map; if given. 145 | const drawSpread = regl({ 146 | frag: (_, p) => p.frag ?? spreadFrag, 147 | uniforms: { 148 | // Swap by `pass`; allow `frame` to override if given. 149 | frame: (_, { pass: p = 0, frame: f }) => f ?? wrapGet(p+1, spreadFrames), 150 | axis: regl.prop('axis'), 151 | tint: regl.prop('tint'), 152 | speed: regl.prop('speed'), 153 | flow: regl.prop('flow'), 154 | inRange: regl.prop('inRange'), 155 | toRange: regl.prop('toRange'), 156 | other: regl.prop('other'), 157 | blend: regl.prop('blend'), 158 | width: regl.context('drawingBufferWidth'), 159 | height: regl.context('drawingBufferHeight') 160 | }, 161 | // Swap by `pass`; allow `to` to override `framebuffer` if given. 162 | framebuffer: (_, { pass: p = 0, to }) => to ?? wrapGet(p, spreadFrames) 163 | }); 164 | 165 | // Draws the 2 spread blur `passes` across both axes one after the other. 166 | const drawSpreadProps = (props) => 167 | // Merge any common `props` into each of `props.passes`. 168 | drawSpread(map((pass) => Object.assign(pass, props, pass), props.passes, 0)); 169 | 170 | // Blur the input video's current frame, into the next flow input frame. 171 | function drawSpreadVideoProps(tick) { 172 | const { videoFrame, spreadVideo } = props; 173 | const f = wrapIndex(tick, flowFrames.length); 174 | 175 | each(regl.clear, clearSpreads); 176 | spreadMaps[1](videoFrame); 177 | 178 | regl.clear(clearFlows[f]); 179 | spreadVideo.passes[1].to = flowFrames[f]; 180 | 181 | return drawSpreadProps(spreadVideo); 182 | } 183 | 184 | // The main function of concern - optical flow of the last 2 video frames. 185 | const drawFlow = regl({ 186 | frag: (_, { frag: f = flowFrag }) => f, 187 | uniforms: { 188 | next: (c) => wrapGet(c.tick, flowFrames), 189 | past: (c) => wrapGet(c.tick+1, flowFrames), 190 | offset: regl.prop('offset'), 191 | lambda: regl.prop('lambda'), 192 | speed: regl.prop('speed'), 193 | alpha: regl.prop('alpha'), 194 | inRange: regl.prop('inRange'), 195 | toRange: regl.prop('toRange') 196 | }, 197 | framebuffer: (_, p) => p.to ?? flowTo 198 | }); 199 | 200 | function drawFlowProps() { 201 | regl.clear(clearFlow); 202 | 203 | return drawFlow(props.flow); 204 | } 205 | 206 | /** 207 | * Blur the past flow frames along each `axis`, shift/advect along the 208 | * `flow` by `speed`, `tint` to weaken the past flow, `blend` in the next 209 | * optical-flow frame. 210 | * 211 | * @see props.spreadFlow 212 | */ 213 | function drawSpreadFlowProps(tick) { 214 | const { spreadFlow } = props; 215 | const { passes } = spreadFlow; 216 | 217 | each(regl.clear, clearSpreads); 218 | spreadFlow.flow = passes[0].frame = wrapGet(tick+1, blendFrames); 219 | 220 | const b = wrapIndex(tick, blendFrames.length); 221 | 222 | regl.clear(clearBlends[b]); 223 | passes[1].to = blendFrames[b]; 224 | 225 | return drawSpreadProps(spreadFlow); 226 | } 227 | 228 | // Draw to the screen. 229 | const drawView = regl({ 230 | frag: (_, p) => p.frag ?? viewFrag, 231 | uniforms: { 232 | frame: (c) => wrapGet(c.tick, blendFrames), 233 | inRange: regl.prop('inRange'), 234 | toRange: regl.prop('toRange') 235 | }, 236 | framebuffer: (_, p) => p.to 237 | }); 238 | 239 | function drawViewProps() { 240 | regl.clear(clearView); 241 | 242 | return drawView(props.view); 243 | } 244 | 245 | // All together now. 246 | function draw({ tick: t }) { 247 | // Blur the input video's current frame. 248 | drawSpreadVideoProps(t); 249 | // Get the optical flow from the last 2 `video` frames. 250 | drawFlowProps(); 251 | // Spread the past flow frame and blend with the next one. 252 | drawSpreadFlowProps(t); 253 | // Draw to the screen. 254 | drawViewProps(); 255 | } 256 | 257 | function setup() { 258 | const { videoWidth: w, videoHeight: h } = $video; 259 | 260 | $video.width = $canvas.width = w; 261 | $video.height = $canvas.height = h; 262 | each((r) => r.resize(w, h), resizers); 263 | // Pixels units; divide `offset` by the video resolution. 264 | props.flow.offset /= Math.max(w, h, 1e3); 265 | $video.play(); 266 | 267 | // Fill the flow frames with the first frame. 268 | drawScreen(() => { 269 | drawSpreadVideoProps(0); 270 | drawSpreadVideoProps(1); 271 | }); 272 | 273 | // Start the main loop. 274 | regl.frame(() => drawScreen(draw)); 275 | 276 | $video.removeEventListener('canplay', setup); 277 | } 278 | 279 | $video.addEventListener('canplay', setup); 280 | 281 | const sampleURL = new URL('sample.mp4', import.meta.url); 282 | 283 | ((query.get('camera') === 'false')? $video.src = sampleURL 284 | : getUserMedia({ video: true }, (e, stream) => { 285 | if(e) { 286 | return console.warn(e, 'Error getting webcam stream, using sample video', 287 | $video.src = sampleURL); 288 | } 289 | 290 | (('srcObject' in $video)? $video.srcObject = stream 291 | : $video.src = URL.createObjectURL(stream)); 292 | 293 | $demo.classList.add('mirror'); 294 | })); 295 | 296 | $demo.addEventListener('click', () => { 297 | const c = $demo.classList; 298 | 299 | c[(c.contains('overlay'))? 'remove' : 'add']('overlay'); 300 | }); 301 | 302 | $fallback && (query.get('fallback') !== 'false') && 303 | ($fallback.src = $fallback.dataset.src); 304 | -------------------------------------------------------------------------------- /demo/sample.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keeffEoghan/glsl-optical-flow/336ddaee613a8cf616af01253cd143faf1c5cb89/demo/sample.mp4 -------------------------------------------------------------------------------- /demo/spread.frag.glsl: -------------------------------------------------------------------------------- 1 | // Perform a `blur`. 2 | // #define opticalFlowSpreadBlur 3 | 4 | // Scale values output by a `tint`. 5 | // #define opticalFlowSpreadTint 6 | 7 | // Shift the sample lookup by a `flow` lookup. 8 | #define opticalFlowSpreadShift_none 0 9 | #define opticalFlowSpreadShift_frame 1 10 | #define opticalFlowSpreadShift_flow 2 11 | #ifndef opticalFlowSpreadShift 12 | #define opticalFlowSpreadShift opticalFlowSpreadShift_none 13 | #endif 14 | 15 | // Map any flow values. 16 | // #define opticalFlowSpreadMap 17 | 18 | // Blend with past frame. 19 | // #define opticalFlowSpreadBlend 20 | 21 | precision highp float; 22 | 23 | uniform sampler2D frame; 24 | 25 | // Perform a `blur`. 26 | #ifdef opticalFlowSpreadBlur 27 | uniform vec2 axis; 28 | uniform float width; 29 | uniform float height; 30 | #endif 31 | 32 | // Alter the values output, scaling by a `tint`. 33 | #ifdef opticalFlowSpreadTint 34 | uniform vec4 tint; 35 | #endif 36 | 37 | #if opticalFlowSpreadShift != opticalFlowSpreadShift_none 38 | // Shift the sample lookup by a `flow` lookup. 39 | uniform vec2 speed; 40 | 41 | // Use a separate `flow` input. 42 | #if opticalFlowSpreadShift == opticalFlowSpreadShift_flow 43 | uniform sampler2D flow; 44 | #endif 45 | 46 | // Map any flow values. 47 | #ifdef opticalFlowSpreadMap 48 | uniform vec4 inRange; 49 | uniform vec4 toRange; 50 | 51 | #pragma glslify: map = require(glsl-map) 52 | #endif 53 | #endif 54 | 55 | #ifdef opticalFlowSpreadBlend 56 | uniform sampler2D other; 57 | uniform float blend; 58 | #endif 59 | 60 | varying vec2 uv; 61 | 62 | #pragma glslify: blur = require(glsl-fast-gaussian-blur/5) 63 | 64 | #if opticalFlowSpreadShift != opticalFlowSpreadShift_none 65 | vec2 shift(vec2 uv, sampler2D flow) { 66 | vec2 f = texture2D(flow, uv).xy; 67 | 68 | // Reverse any mapping of the flow values. 69 | #ifdef opticalFlowSpreadMap 70 | f = map(f, toRange.xy, toRange.zw, inRange.xy, inRange.zw); 71 | #endif 72 | 73 | return uv+(f*speed); 74 | } 75 | #endif 76 | 77 | void main() { 78 | vec2 st = uv; 79 | 80 | // Shift the sample lookup by a `flow` lookup. 81 | #if opticalFlowSpreadShift == opticalFlowSpreadShift_flow 82 | // Use the given `flow` input. 83 | st = shift(st, flow); 84 | #elif opticalFlowSpreadShift == opticalFlowSpreadShift_frame 85 | // Use the `frame` itself as `flow` input. 86 | st = shift(st, frame); 87 | #endif 88 | 89 | // Perform a `blur`. 90 | #ifdef opticalFlowSpreadBlur 91 | vec4 c = blur(frame, st, vec2(width, height), axis); 92 | #else 93 | vec4 c = texture2D(frame, st); 94 | #endif 95 | 96 | // Map back to any given range. 97 | #ifdef opticalFlowSpreadMap 98 | c.xy = map(c.xy, toRange.xy, toRange.zw, inRange.xy, inRange.zw); 99 | #endif 100 | 101 | // Scale values output by `tint`. 102 | #ifdef opticalFlowSpreadTint 103 | c *= tint; 104 | #endif 105 | 106 | // Reverse any mapping. 107 | #ifdef opticalFlowSpreadMap 108 | c.xy = map(c.xy, inRange.xy, inRange.zw, toRange.xy, toRange.zw); 109 | #endif 110 | 111 | #ifdef opticalFlowSpreadBlend 112 | vec4 o = texture2D(other, uv); 113 | 114 | c = mix(c, o, mix(1.0-c.a, o.a, blend)); 115 | #endif 116 | 117 | gl_FragColor = c; 118 | } 119 | -------------------------------------------------------------------------------- /demo/view.frag.glsl: -------------------------------------------------------------------------------- 1 | // Map any flow values. 2 | // #define opticalFlowViewMap 3 | 4 | precision highp float; 5 | 6 | uniform sampler2D frame; 7 | 8 | // Map any flow values. 9 | #ifdef opticalFlowViewMap 10 | uniform vec4 inRange; 11 | uniform vec4 toRange; 12 | 13 | #pragma glslify: map = require(glsl-map) 14 | #endif 15 | 16 | varying vec2 uv; 17 | 18 | #pragma glslify: tau = require(glsl-constants/TWO_PI) 19 | #pragma glslify: hslToRGB = require(glsl-hsl2rgb) 20 | 21 | void main() { 22 | vec4 data = texture2D(frame, uv); 23 | float a = clamp(data.a, 0.0, 1.0); 24 | vec2 flow = data.xy; 25 | 26 | // Map any flow values. 27 | #ifdef opticalFlowViewMap 28 | flow = map(flow, toRange.xy, toRange.zw, inRange.xy, inRange.zw); 29 | #endif 30 | 31 | // Angle to hue - red right, green up, cyan left, magenta down. 32 | vec3 color = hslToRGB(atan(flow.y, flow.x)/tau, 0.9*a, 0.6*a); 33 | 34 | gl_FragColor = vec4(color, a); 35 | } 36 | -------------------------------------------------------------------------------- /docs/index.dbe5a2ab.css: -------------------------------------------------------------------------------- 1 | *,:after,:before{box-sizing:inherit}html{background:#000;box-sizing:border-box}.demo,body{align-items:center;display:flex;flex-flow:row wrap;justify-content:center}body{gap:4em;margin:0}canvas,img,video{max-height:100%;max-width:100%}.output,.webcam{max-height:100vh;max-width:100vw}.webcam{display:none}.output{z-index:1}.demo{cursor:copy;position:relative}.demo.mirror .output,.demo.mirror .webcam{transform:scaleX(-1)}.demo.overlay{cursor:alias}.demo.overlay .webcam{display:block}.demo.overlay .output{left:50%;position:absolute;top:50%;transform:translate(-50%,-50%)}.demo.overlay.mirror .output{transform:translate(-50%,-50%) scaleX(-1)}.fallback{display:none}.fallback[src]{display:block;height:720px;margin:auto;position:relative;width:100%} 2 | /*# sourceMappingURL=index.dbe5a2ab.css.map */ 3 | -------------------------------------------------------------------------------- /docs/index.dbe5a2ab.css.map: -------------------------------------------------------------------------------- 1 | {"mappings":"AAAA,iBAEU,kBAAqB,CAE/B,KAEE,eAAgB,CADhB,qBAEF,CAEA,WAKE,kBAAmB,CAHnB,YAAa,CACb,kBAAmB,CACnB,sBAEF,CAEA,KAEE,OAAQ,CADR,QAEF,CAEA,iBAIE,eAAgB,CADhB,cAEF,CAEA,gBAGE,gBAAiB,CADjB,eAEF,CAEA,QAAU,YAAe,CAEzB,QAAU,SAAY,CAEtB,MAEE,WAAY,CADZ,iBAsBF,CAlBI,0CACU,oBAAuB,CAGnC,cACE,YAYF,CAVE,sBAAU,aAAgB,CAE1B,sBAGE,QAAS,CAFT,iBAAkB,CAClB,OAAQ,CAER,8BACF,CAEA,6BAAmB,yCAA6C,CAIpE,UACE,YASF,CAPE,eACE,aAAc,CAGd,YAAa,CACb,WAAY,CAHZ,iBAAkB,CAClB,UAGF","sources":["demo/index.css"],"sourcesContent":["*,\n*:before,\n*:after { box-sizing: inherit; }\n\nhtml {\n box-sizing: border-box;\n background: #000;\n}\n\nbody,\n.demo {\n display: flex;\n flex-flow: row wrap;\n justify-content: center;\n align-items: center;\n}\n\nbody {\n margin: 0;\n gap: 4em;\n}\n\nvideo,\ncanvas,\nimg {\n max-width: 100%;\n max-height: 100%;\n}\n\n.webcam,\n.output {\n max-width: 100vw;\n max-height: 100vh;\n}\n\n.webcam { display: none; }\n\n.output { z-index: 1; }\n\n.demo {\n position: relative;\n cursor: copy;\n\n &.mirror {\n .webcam,\n .output { transform: scaleX(-1); }\n }\n\n &.overlay {\n cursor: alias;\n\n .webcam { display: block; }\n\n .output {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n }\n\n &.mirror .output { transform: translate(-50%, -50%) scaleX(-1); }\n }\n}\n\n.fallback {\n display: none;\n\n &[src] {\n display: block;\n position: relative;\n width: 100%;\n height: 720px;\n margin: auto;\n }\n}\n"],"names":[],"version":3,"file":"index.dbe5a2ab.css.map"} -------------------------------------------------------------------------------- /docs/index.f295124b.js: -------------------------------------------------------------------------------- 1 | function e(e,t,n,r){Object.defineProperty(e,t,{get:n,set:r,enumerable:!0,configurable:!0})}function t(e){return e&&e.__esModule?e.default:e}var n="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},r={},a={},i=n.parcelRequireda05;null==i&&((i=function(e){if(e in r)return r[e].exports;if(e in a){var t=a[e];delete a[e];var n={id:e,exports:{}};return r[e]=n,t.call(n.exports,n,n.exports),n.exports}var i=new Error("Cannot find module '"+e+"'");throw i.code="MODULE_NOT_FOUND",i}).register=function(e,t){a[e]=t},n.parcelRequireda05=i),i.register("g8vZD",(function(t,n){var r,a;e(t.exports,"register",(function(){return r}),(function(e){return r=e})),e(t.exports,"resolve",(function(){return a}),(function(e){return a=e}));var i={};r=function(e){for(var t=Object.keys(e),n=0;n=0&&(0|e)===e||r("invalid parameter type, ("+e+")"+i(t)+". must be a nonnegative integer")},oneOf:s,shaderError:function(e,t,r,i,o){if(!e.getShaderParameter(t,e.COMPILE_STATUS)){var s=e.getShaderInfoLog(t),f=i===e.FRAGMENT_SHADER?"fragment":"vertex";b(r,"string",f+" shader source must be a string",o);var u=h(r,o),l=function(e){var t=[];return e.split("\n").forEach((function(e){if(!(e.length<5)){var n=/^ERROR:\s+(\d+):(\d+):\s*(.*)$/.exec(e);n?t.push(new d(0|n[1],0|n[2],n[3].trim())):e.length>0&&t.push(new d("unknown",0,e))}})),t}(s);!function(e,t){t.forEach((function(t){var n=e[t.file];if(n){var r=n.index[t.line];if(r)return r.errors.push(t),void(n.hasErrors=!0)}e.unknown.hasErrors=!0,e.unknown.lines[0].errors.push(t)}))}(u,l),Object.keys(u).forEach((function(e){var t=u[e];if(t.hasErrors){var r=[""],a=[""];i("file number "+e+": "+t.name+"\n","color:red;text-decoration:underline;font-weight:bold"),t.lines.forEach((function(e){if(e.errors.length>0){i(c(e.number,4)+"| ","background-color:yellow; font-weight:bold"),i(e.line+n,"color:red; background-color:yellow; font-weight:bold");var t=0;e.errors.forEach((function(r){var a=r.message,o=/^\s*'(.*)'\s*:\s*(.*)$/.exec(a);if(o){var s=o[1];if(a=o[2],"assign"===s)s="=";t=Math.max(e.line.indexOf(s,t),0)}else t=0;i(c("| ",6)),i(c("^^^",t+3)+n,"font-weight:bold"),i(c("| ",6)),i(a+n,"font-weight:bold")})),i(c("| ",6)+n)}else i(c(e.number,4)+"| "),i(e.line+n,"color:red")})),"undefined"==typeof document||window.chrome?console.log(r.join("")):(a[0]=r.join("%c"),console.log.apply(console,a))}function i(e,t){r.push(e),a.push(t||"")}})),a.raise("Error compiling "+f+" shader, "+u[0].name)}},linkError:function(e,t,r,i,o){if(!e.getProgramParameter(t,e.LINK_STATUS)){var s=e.getProgramInfoLog(t),f=h(r,o),c='Error linking program with vertex shader, "'+h(i,o)[0].name+'", and fragment shader "'+f[0].name+'"';"undefined"!=typeof document?console.log("%c"+c+"\n%c"+s,"color:red;text-decoration:underline;font-weight:bold","color:red"):console.log(c+n+s),a.raise(c)}},callSite:m,saveCommandRef:v,saveDrawInfo:function(e,t,n,r){function a(e){return e?r.id(e):0}function i(e,t){Object.keys(t).forEach((function(t){e[r.id(t)]=!0}))}v(e),e._fragId=a(e.static.frag),e._vertId=a(e.static.vert);var o=e._uniformSet={};i(o,t.static),i(o,t.dynamic);var s=e._attributeSet={};i(s,n.static),i(s,n.dynamic),e._hasCount="count"in e.static||"count"in e.dynamic||"elements"in e.static||"elements"in e.dynamic},framebufferFormat:function(e,t,n){e.texture?s(e.texture._texture.internalformat,t,"unsupported texture format for attachment"):s(e.renderbuffer._renderbuffer.format,n,"unsupported renderbuffer format for attachment")},guessCommand:p,texture2D:function(e,t,n){var r,i=t.width,o=t.height,s=t.channels;a(i>0&&i<=n.maxTextureSize&&o>0&&o<=n.maxTextureSize,"invalid texture shape"),e.wrapS===y&&e.wrapT===y||a(S(i)&&S(o),"incompatible wrap mode for texture, both width and height must be power of 2"),1===t.mipmask?1!==i&&1!==o&&a(9984!==e.minFilter&&9986!==e.minFilter&&9985!==e.minFilter&&9987!==e.minFilter,"min filter requires mipmap"):(a(S(i)&&S(o),"texture must be a square power of 2 to support mipmapping"),a(t.mipmask===(i<<1)-1,"missing or incomplete mipmap data")),5126===t.type&&(n.extensions.indexOf("oes_texture_float_linear")<0&&a(9728===e.minFilter&&9728===e.magFilter,"filter not supported, must enable oes_texture_float_linear"),a(!e.genMipmaps,"mipmap generation not supported with float textures"));var f=t.images;for(r=0;r<16;++r)if(f[r]){var c=i>>r,u=o>>r;a(t.mipmask&1<0&&i<=r.maxTextureSize&&o>0&&o<=r.maxTextureSize,"invalid texture shape"),a(i===o,"cube map must be square"),a(t.wrapS===y&&t.wrapT===y,"wrap mode not supported by cube map");for(var f=0;f>l,m=o>>l;a(c.mipmask&1<1&&t===n&&('"'===t||"'"===t))return['"'+C(e.substr(1,e.length-2))+'"'];var r=/\[(false|true|null|\d+|'[^']*'|"[^"]*")\]/.exec(e);if(r)return E(e.substr(0,r.index)).concat(E(r[1])).concat(E(e.substr(r.index+r[0].length)));var a=e.split(".");if(1===a.length)return['"'+C(e)+'"'];for(var i=[],o=0;o0,"invalid pixel ratio"))):a=(i=s).canvas:k.raise("invalid arguments to regl"),n&&("canvas"===n.nodeName.toLowerCase()?a=n:r=n),!i){if(!a){k("undefined"!=typeof document,"must manually specify webgl context outside of DOM environments");var h=function(e,n,r){var a,i=document.createElement("canvas");function o(){var t=window.innerWidth,n=window.innerHeight;if(e!==document.body){var a=i.getBoundingClientRect();t=a.right-a.left,n=a.bottom-a.top}i.width=r*t,i.height=r*n}return t(i.style,{border:0,margin:0,padding:0,top:0,left:0,width:"100%",height:"100%"}),e.appendChild(i),e===document.body&&(i.style.position="absolute",t(e.style,{margin:0,padding:0})),e!==document.body&&"function"==typeof ResizeObserver?(a=new ResizeObserver((function(){setTimeout(o)}))).observe(e):window.addEventListener("resize",o,!1),o(),{canvas:i,onDestroy:function(){a?a.disconnect():window.removeEventListener("resize",o),e.removeChild(i)}}}(r||document.body,0,l);if(!h)return null;a=h.canvas,m=h.onDestroy}void 0===f.premultipliedAlpha&&(f.premultipliedAlpha=!0),i=function(e,t){function n(n){try{return e.getContext(n,t)}catch(e){return null}}return n("webgl")||n("experimental-webgl")||n("webgl-experimental")}(a,f)}return i?{gl:i,canvas:a,container:r,extensions:c,optionalExtensions:u,pixelRatio:l,profile:d,onDone:p,onDestroy:m}:(m(),p("webgl not supported, try upgrading your browser or graphics drivers http://get.webgl.org"),null)}function F(e,t){for(var n=Array(e),r=0;r65535)<<4,t|=n=((e>>>=t)>255)<<3,t|=n=((e>>>=n)>15)<<2,(t|=n=((e>>>=n)>3)<<1)|(e>>>=n)>>1}function I(){var e=F(8,(function(){return[]}));function t(t){var n=function(e){for(var t=16;t<=268435456;t*=16)if(e<=t)return t;return 0}(t),r=e[L(n)>>2];return r.length>0?r.pop():new ArrayBuffer(n)}function n(t){e[L(t.byteLength)>>2].push(t)}return{alloc:t,free:n,allocType:function(e,n){var r=null;switch(e){case 5120:r=new Int8Array(t(n),0,n);break;case 5121:r=new Uint8Array(t(n),0,n);break;case 5122:r=new Int16Array(t(2*n),0,n);break;case 5123:r=new Uint16Array(t(2*n),0,n);break;case 5124:r=new Int32Array(t(4*n),0,n);break;case 5125:r=new Uint32Array(t(4*n),0,n);break;case 5126:r=new Float32Array(t(4*n),0,n);break;default:return null}return r.length!==n?r.subarray(0,n):r},freeType:function(e){n(e.buffer)}}}var z=I();z.zero=I();var B=3553,V=6408,U=5126,G=36160;function N(t){return!!t&&"object"==typeof t&&Array.isArray(t.shape)&&Array.isArray(t.stride)&&"number"==typeof t.offset&&t.shape.length===t.stride.length&&(Array.isArray(t.data)||e(t.data))}var H=function(e){return Object.keys(e).map((function(t){return e[t]}))},q={shape:function(e){for(var t=[],n=e;n.length;n=n[0])t.push(n.length);return t},flatten:function(e,t,n,r){var a=1;if(t.length)for(var i=0;i>>31<<15,i=(r<<1>>>24)-127,o=r>>13&1023;if(i<-24)t[n]=a;else if(i<-14){var s=-14-i;t[n]=a+(o+1024>>s)}else t[n]=i>15?a+31744:a+(i+15<<10)+o}return t}function pe(t){return Array.isArray(t)||e(t)}var me=function(e){return!(e&e-1||!e)},he=3553,ve=34067,ge=34069,be=6408,ye=6406,we=6407,xe=6409,Se=6410,ke=32855,Te=6402,Ae=34041,Ce=35904,Ee=35906,_e=36193,Oe=33776,De=33777,Me=33778,Pe=33779,Re=5121,je=5123,Fe=5125,Le=5126,Ie=33071,ze=9728,Be=9984,Ve=9987,Ue=4352,Ge=33984,Ne=[Be,9986,9985,Ve],He=[0,xe,Se,we,be],qe={};function We(e){return"[object "+e+"]"}qe[6409]=qe[6406]=qe[6402]=1,qe[34041]=qe[6410]=2,qe[6407]=qe[35904]=3,qe[6408]=qe[35906]=4;var Qe=We("HTMLCanvasElement"),Ye=We("OffscreenCanvas"),Je=We("CanvasRenderingContext2D"),Xe=We("ImageBitmap"),$e=We("HTMLImageElement"),Ke=We("HTMLVideoElement"),Ze=Object.keys(Y).concat([Qe,Ye,Je,Xe,$e,Ke]),et=[];et[5121]=1,et[5126]=4,et[36193]=2,et[5123]=2,et[5125]=4;var tt=[];function nt(e){return Array.isArray(e)&&(0===e.length||"number"==typeof e[0])}function rt(e){return!!Array.isArray(e)&&!(0===e.length||!pe(e[0]))}function at(e){return Object.prototype.toString.call(e)}function it(e){return at(e)===Qe}function ot(e){return at(e)===Ye}function st(e){if(!e)return!1;var t=at(e);return Ze.indexOf(t)>=0||(nt(e)||rt(e)||N(e))}function ft(e){return 0|Y[Object.prototype.toString.call(e)]}function ct(e,t){return z.allocType(e.type===_e?Le:e.type,t)}function ut(e,t){e.type===_e?(e.data=de(t),z.freeType(t)):e.data=t}function lt(e,t,n,r,a,i){var o;if(o=void 0!==tt[e]?tt[e]:qe[e]*et[t],i&&(o*=6),a){for(var s=0,f=n;f>=1;)s+=o*f*f,f/=2;return s}return o*n*r}function dt(n,r,a,i,o,s,f){var c={"don't care":Ue,"dont care":Ue,nice:4354,fast:4353},u={repeat:10497,clamp:Ie,mirror:33648},l={nearest:ze,linear:9729},d=t({mipmap:Ve,"nearest mipmap nearest":Be,"linear mipmap nearest":9985,"nearest mipmap linear":9986,"linear mipmap linear":Ve},l),p={none:0,browser:37444},m={uint8:Re,rgba4:32819,rgb565:33635,"rgb5 a1":32820},h={alpha:ye,luminance:xe,"luminance alpha":Se,rgb:we,rgba:be,rgba4:32854,"rgb5 a1":ke,rgb565:36194},v={};r.ext_srgb&&(h.srgb=Ce,h.srgba=Ee),r.oes_texture_float&&(m.float32=m.float=Le),r.oes_texture_half_float&&(m.float16=m["half float"]=_e),r.webgl_depth_texture&&(t(h,{depth:Te,"depth stencil":Ae}),t(m,{uint16:je,uint32:Fe,"depth stencil":34042})),r.webgl_compressed_texture_s3tc&&t(v,{"rgb s3tc dxt1":Oe,"rgba s3tc dxt1":De,"rgba s3tc dxt3":Me,"rgba s3tc dxt5":Pe}),r.webgl_compressed_texture_atc&&t(v,{"rgb atc":35986,"rgba atc explicit alpha":35987,"rgba atc interpolated alpha":34798}),r.webgl_compressed_texture_pvrtc&&t(v,{"rgb pvrtc 4bppv1":35840,"rgb pvrtc 2bppv1":35841,"rgba pvrtc 4bppv1":35842,"rgba pvrtc 2bppv1":35843}),r.webgl_compressed_texture_etc1&&(v["rgb etc1"]=36196);var g=Array.prototype.slice.call(n.getParameter(34467));Object.keys(v).forEach((function(e){var t=v[e];g.indexOf(t)>=0&&(h[e]=t)}));var b=Object.keys(h);a.textureFormats=b;var y=[];Object.keys(h).forEach((function(e){var t=h[e];y[t]=e}));var w=[];Object.keys(m).forEach((function(e){var t=m[e];w[t]=e}));var x=[];Object.keys(l).forEach((function(e){x[l[e]]=e}));var S=[];Object.keys(d).forEach((function(e){var t=d[e];S[t]=e}));var T=[];Object.keys(u).forEach((function(e){T[u[e]]=e}));var A=b.reduce((function(e,t){var n=h[t];return n===xe||n===ye||n===xe||n===Se||n===Te||n===Ae||r.ext_srgb&&(n===Ce||n===Ee)?e[n]=n:n===ke||t.indexOf("rgba")>=0?e[n]=be:e[n]=we,e}),{});function C(){this.internalformat=be,this.format=be,this.type=Re,this.compressed=!1,this.premultiplyAlpha=!1,this.flipY=!1,this.unpackAlignment=1,this.colorSpace=37444,this.width=0,this.height=0,this.channels=0}function E(e,t){e.internalformat=t.internalformat,e.format=t.format,e.type=t.type,e.compressed=t.compressed,e.premultiplyAlpha=t.premultiplyAlpha,e.flipY=t.flipY,e.unpackAlignment=t.unpackAlignment,e.colorSpace=t.colorSpace,e.width=t.width,e.height=t.height,e.channels=t.channels}function _(e,t){if("object"==typeof t&&t){if("premultiplyAlpha"in t&&(k.type(t.premultiplyAlpha,"boolean","invalid premultiplyAlpha"),e.premultiplyAlpha=t.premultiplyAlpha),"flipY"in t&&(k.type(t.flipY,"boolean","invalid texture flip"),e.flipY=t.flipY),"alignment"in t&&(k.oneOf(t.alignment,[1,2,4,8],"invalid texture unpack alignment"),e.unpackAlignment=t.alignment),"colorSpace"in t&&(k.parameter(t.colorSpace,p,"invalid colorSpace"),e.colorSpace=p[t.colorSpace]),"type"in t){var n=t.type;k(r.oes_texture_float||!("float"===n||"float32"===n),"you must enable the OES_texture_float extension in order to use floating point textures."),k(r.oes_texture_half_float||!("half float"===n||"float16"===n),"you must enable the OES_texture_half_float extension in order to use 16-bit floating point textures."),k(r.webgl_depth_texture||!("uint16"===n||"uint32"===n||"depth stencil"===n),"you must enable the WEBGL_depth_texture extension in order to use depth/stencil textures."),k.parameter(n,m,"invalid texture type"),e.type=m[n]}var i=e.width,o=e.height,s=e.channels,f=!1;"shape"in t?(k(Array.isArray(t.shape)&&t.shape.length>=2,"shape must be an array"),i=t.shape[0],o=t.shape[1],3===t.shape.length&&(s=t.shape[2],k(s>0&&s<=4,"invalid number of channels"),f=!0),k(i>=0&&i<=a.maxTextureSize,"invalid width"),k(o>=0&&o<=a.maxTextureSize,"invalid height")):("radius"in t&&(i=o=t.radius,k(i>=0&&i<=a.maxTextureSize,"invalid radius")),"width"in t&&(i=t.width,k(i>=0&&i<=a.maxTextureSize,"invalid width")),"height"in t&&(o=t.height,k(o>=0&&o<=a.maxTextureSize,"invalid height")),"channels"in t&&(s=t.channels,k(s>0&&s<=4,"invalid number of channels"),f=!0)),e.width=0|i,e.height=0|o,e.channels=0|s;var c=!1;if("format"in t){var u=t.format;k(r.webgl_depth_texture||!("depth"===u||"depth stencil"===u),"you must enable the WEBGL_depth_texture extension in order to use depth/stencil textures."),k.parameter(u,h,"invalid texture format");var l=e.internalformat=h[u];e.format=A[l],u in m&&("type"in t||(e.type=m[u])),u in v&&(e.compressed=!0),c=!0}!f&&c?e.channels=qe[e.format]:f&&!c?e.channels!==He[e.format]&&(e.format=e.internalformat=He[e.channels]):c&&f&&k(e.channels===qe[e.format],"number of channels inconsistent with specified format")}}function O(e){n.pixelStorei(37440,e.flipY),n.pixelStorei(37441,e.premultiplyAlpha),n.pixelStorei(37443,e.colorSpace),n.pixelStorei(3317,e.unpackAlignment)}function D(){C.call(this),this.xOffset=0,this.yOffset=0,this.data=null,this.needsFree=!1,this.element=null,this.needsCopy=!1}function M(t,n){var r=null;if(st(n)?r=n:n&&(k.type(n,"object","invalid pixel data type"),_(t,n),"x"in n&&(t.xOffset=0|n.x),"y"in n&&(t.yOffset=0|n.y),st(n.data)&&(r=n.data)),k(!t.compressed||r instanceof Uint8Array,"compressed texture data must be stored in a uint8array"),n.copy){k(!r,"can not specify copy and data field for the same texture");var i=o.viewportWidth,s=o.viewportHeight;t.width=t.width||i-t.xOffset,t.height=t.height||s-t.yOffset,t.needsCopy=!0,k(t.xOffset>=0&&t.xOffset=0&&t.yOffset0&&t.width<=i&&t.height>0&&t.height<=s,"copy texture read out of bounds")}else if(r){if(e(r))t.channels=t.channels||4,t.data=r,"type"in n||t.type!==Re||(t.type=ft(r));else if(nt(r))t.channels=t.channels||4,function(e,t){var n=t.length;switch(e.type){case Re:case je:case Fe:case Le:var r=z.allocType(e.type,n);r.set(t),e.data=r;break;case _e:e.data=de(t);break;default:k.raise("unsupported texture type, must specify a typed array")}}(t,r),t.alignment=1,t.needsFree=!0;else if(N(r)){var f=r.data;Array.isArray(f)||t.type!==Re||(t.type=ft(f));var c,u,l,d,p,m,h=r.shape,v=r.stride;3===h.length?(l=h[2],m=v[2]):(k(2===h.length,"invalid ndarray pixel data, must be 2 or 3D"),l=1,m=1),c=h[0],u=h[1],d=v[0],p=v[1],t.alignment=1,t.width=c,t.height=u,t.channels=l,t.format=t.internalformat=He[l],t.needsFree=!0,function(e,t,n,r,a,i){for(var o=e.width,s=e.height,f=e.channels,c=ct(e,o*s*f),u=0,l=0;l=0,"oes_texture_float extension not enabled"):t.type===_e&&k(a.extensions.indexOf("oes_texture_half_float")>=0,"oes_texture_half_float extension not enabled")}function P(e,t,r){var a=e.element,o=e.data,s=e.internalformat,f=e.format,c=e.type,u=e.width,l=e.height;O(e),a?n.texImage2D(t,r,f,f,c,a):e.compressed?n.compressedTexImage2D(t,r,s,u,l,0,o):e.needsCopy?(i(),n.copyTexImage2D(t,r,f,e.xOffset,e.yOffset,u,l,0)):n.texImage2D(t,r,f,u,l,0,f,c,o||null)}function R(e,t,r,a,o){var s=e.element,f=e.data,c=e.internalformat,u=e.format,l=e.type,d=e.width,p=e.height;O(e),s?n.texSubImage2D(t,o,r,a,u,l,s):e.compressed?n.compressedTexSubImage2D(t,o,r,a,c,d,p,f):e.needsCopy?(i(),n.copyTexSubImage2D(t,o,r,a,e.xOffset,e.yOffset,d,p)):n.texSubImage2D(t,o,r,a,d,p,u,l,f)}var j=[];function F(){return j.pop()||new D}function L(e){e.needsFree&&z.freeType(e.data),D.call(e),j.push(e)}function I(){C.call(this),this.genMipmaps=!1,this.mipmapHint=Ue,this.mipmask=0,this.images=Array(16)}function B(e,t,n){var r=e.images[0]=F();e.mipmask=1,r.width=e.width=t,r.height=e.height=n,r.channels=e.channels=4}function V(e,t){var n=null;if(st(t))E(n=e.images[0]=F(),e),M(n,t),e.mipmask=1;else if(_(e,t),Array.isArray(t.mipmap))for(var r=t.mipmap,a=0;a>=a,n.height>>=a,M(n,r[a]),e.mipmask|=1<=0&&!("faces"in t)&&(e.genMipmaps=!0)}if("mag"in t){var r=t.mag;k.parameter(r,l),e.magFilter=l[r]}var i=e.wrapS,o=e.wrapT;if("wrap"in t){var s=t.wrap;"string"==typeof s?(k.parameter(s,u),i=o=u[s]):Array.isArray(s)&&(k.parameter(s[0],u),k.parameter(s[1],u),i=u[s[0]],o=u[s[1]])}else{if("wrapS"in t){var f=t.wrapS;k.parameter(f,u),i=u[f]}if("wrapT"in t){var p=t.wrapT;k.parameter(p,u),o=u[p]}}if(e.wrapS=i,e.wrapT=o,"anisotropic"in t){var m=t.anisotropic;k("number"==typeof m&&m>=1&&m<=a.maxAnisotropic,"aniso samples must be between 1 and "),e.anisotropic=t.anisotropic}if("mipmap"in t){var h=!1;switch(typeof t.mipmap){case"string":k.parameter(t.mipmap,c,"invalid mipmap hint"),e.mipmapHint=c[t.mipmap],e.genMipmaps=!0,h=!0;break;case"boolean":h=e.genMipmaps=t.mipmap;break;case"object":k(Array.isArray(t.mipmap),"invalid mipmap type"),e.genMipmaps=!1,h=!0;break;default:k.raise("invalid mipmap type")}h&&!("min"in t)&&(e.minFilter=Be)}}function X(e,t){n.texParameteri(t,10241,e.minFilter),n.texParameteri(t,10240,e.magFilter),n.texParameteri(t,10242,e.wrapS),n.texParameteri(t,10243,e.wrapT),r.ext_texture_filter_anisotropic&&n.texParameteri(t,34046,e.anisotropic),e.genMipmaps&&(n.hint(33170,e.mipmapHint),n.generateMipmap(t))}var $=0,K={},Z=a.maxTextureUnits,ee=Array(Z).map((function(){return null}));function te(e){C.call(this),this.mipmask=0,this.internalformat=be,this.id=$++,this.refCount=1,this.target=e,this.texture=n.createTexture(),this.unit=-1,this.bindCount=0,this.texInfo=new Y,f.profile&&(this.stats={size:0})}function ne(e){n.activeTexture(Ge),n.bindTexture(e.target,e.texture)}function re(){var e=ee[0];e?n.bindTexture(e.target,e.texture):n.bindTexture(he,null)}function ae(e){var t=e.texture;k(t,"must not double destroy texture");var r=e.unit,a=e.target;r>=0&&(n.activeTexture(Ge+r),n.bindTexture(a,null),ee[r]=null),n.deleteTexture(t),e.texture=null,e.params=null,e.pixels=null,e.refCount=0,delete K[e.id],s.textureCount--}return t(te.prototype,{bind:function(){var e=this;e.bindCount+=1;var t=e.unit;if(t<0){for(var r=0;r0)continue;a.unit=-1}ee[r]=e,t=r;break}t>=Z&&k.raise("insufficient number of texture units"),f.profile&&s.maxTextureUnits>f)-o,c.height=c.height||(r.height>>f)-s,k(r.type===c.type&&r.format===c.format&&r.internalformat===c.internalformat,"incompatible format for texture.subimage"),k(o>=0&&s>=0&&o+c.width<=r.width&&s+c.height<=r.height,"texture.subimage write out of bounds"),k(r.mipmask&1<>s;++s){var c=a>>s,u=o>>s;if(!c||!u)break;n.texImage2D(he,s,r.format,c,u,0,r.format,r.type,null)}return re(),f.profile&&(r.stats.size=lt(r.internalformat,r.type,a,o,!1,!1)),i},i._reglType="texture2d",i._texture=r,f.profile&&(i.stats=r.stats),i.destroy=function(){r.decRef()},i},createCube:function(e,t,r,i,o,c){var u=new te(ve);K[u.id]=u,s.cubeCount++;var l=new Array(6);function d(e,t,n,r,i,o){var s,c=u.texInfo;for(Y.call(c),s=0;s<6;++s)l[s]=W();if("number"!=typeof e&&e)if("object"==typeof e)if(t)V(l[0],e),V(l[1],t),V(l[2],n),V(l[3],r),V(l[4],i),V(l[5],o);else if(J(c,e),_(u,e),"faces"in e){var p=e.faces;for(k(Array.isArray(p)&&6===p.length,"cube faces must be a length 6 array"),s=0;s<6;++s)k("object"==typeof p[s]&&!!p[s],"invalid input for cube map face"),E(l[s],u),V(l[s],p[s])}else for(s=0;s<6;++s)V(l[s],e);else k.raise("invalid arguments to cube map");else{var m=0|e||1;for(s=0;s<6;++s)B(l[s],m,m)}for(E(u,l[0]),k.optional((function(){a.npotTextureCube||k(me(u.width)&&me(u.height),"your browser does not support non power or two texture dimensions")})),c.genMipmaps?u.mipmask=(l[0].width<<1)-1:u.mipmask=l[0].mipmask,k.textureCube(u,c,l,a),u.internalformat=l[0].internalformat,d.width=l[0].width,d.height=l[0].height,ne(u),s=0;s<6;++s)U(l[s],ge+s);for(X(c,ve),re(),f.profile&&(u.stats.size=lt(u.internalformat,u.type,d.width,d.height,c.genMipmaps,!0)),d.format=y[u.internalformat],d.type=w[u.type],d.mag=x[c.magFilter],d.min=S[c.minFilter],d.wrapS=T[c.wrapS],d.wrapT=T[c.wrapT],s=0;s<6;++s)Q(l[s]);return d}return d(e,t,r,i,o,c),d.subimage=function(e,t,n,r,a){k(!!t,"must specify image data"),k("number"==typeof e&&e===(0|e)&&e>=0&&e<6,"invalid face");var i=0|n,o=0|r,s=0|a,f=F();return E(f,u),f.width=0,f.height=0,M(f,t),f.width=f.width||(u.width>>s)-i,f.height=f.height||(u.height>>s)-o,k(u.type===f.type&&u.format===f.format&&u.internalformat===f.internalformat,"incompatible format for texture.subimage"),k(i>=0&&o>=0&&i+f.width<=u.width&&o+f.height<=u.height,"texture.subimage write out of bounds"),k(u.mipmask&1<>a;++a)n.texImage2D(ge+r,a,u.format,t>>a,t>>a,0,u.format,u.type,null);return re(),f.profile&&(u.stats.size=lt(u.internalformat,u.type,d.width,d.height,!1,!0)),d}},d._reglType="textureCube",d._texture=u,f.profile&&(d.stats=u.stats),d.destroy=function(){u.decRef()},d},clear:function(){for(var e=0;e>t,e.height>>t,0,e.internalformat,e.type,null);else for(var r=0;r<6;++r)n.texImage2D(ge+r,t,e.internalformat,e.width>>t,e.height>>t,0,e.internalformat,e.type,null);X(e.texInfo,e.target)}))},refresh:function(){for(var e=0;e=0&&u=0&&l0&&d+u<=a.framebufferWidth,"invalid width for read pixels"),k(p>0&&p+l<=a.framebufferHeight,"invalid height for read pixels"),r();var h=d*p*4;return m||(c===Ot?m=new Uint8Array(h):c===Dt&&(m=m||new Float32Array(h))),k.isTypedArray(m,"data buffer for regl.read() must be a typedarray"),k(m.byteLength>=h,"data buffer for regl.read() too small"),t.pixelStorei(3333,4),t.readPixels(u,l,d,p,6408,c,m),m}return function(e){return e&&"framebuffer"in e?function(e){var t;return n.setFBO({framebuffer:e.framebuffer},(function(){t=f(e)})),t}(e):f(e)}}function Pt(e){return Array.prototype.slice.call(e)}function Rt(e){return Pt(e).join("")}var jt="xyzw".split(""),Ft="dither",Lt="blend.enable",It="blend.color",zt="blend.equation",Bt="blend.func",Vt="depth.enable",Ut="depth.func",Gt="depth.range",Nt="depth.mask",Ht="colorMask",qt="cull.enable",Wt="cull.face",Qt="frontFace",Yt="lineWidth",Jt="polygonOffset.enable",Xt="polygonOffset.offset",$t="sample.alpha",Kt="sample.enable",Zt="sample.coverage",en="stencil.enable",tn="stencil.mask",nn="stencil.func",rn="stencil.opFront",an="stencil.opBack",on="scissor.enable",sn="scissor.box",fn="viewport",cn="profile",un="framebuffer",ln="vert",dn="frag",pn="elements",mn="primitive",hn="count",vn="offset",gn="instances",bn="vao",yn="Width",wn="Height",xn=un+yn,Sn=un+wn,kn="drawingBufferWidth",Tn="drawingBufferHeight",An=[Bt,zt,nn,rn,an,Zt,fn,sn,Xt],Cn=34962,En=34963,_n=5126,On=35664,Dn=35665,Mn=35666,Pn=5124,Rn=35667,jn=35668,Fn=35669,Ln=35670,In=35671,zn=35672,Bn=35673,Vn=35674,Un=35675,Gn=35676,Nn=35678,Hn=35680,qn=1028,Wn=1029,Qn=2305,Yn=7680,Jn={0:0,1:1,zero:0,one:1,"src color":768,"one minus src color":769,"src alpha":770,"one minus src alpha":771,"dst color":774,"one minus dst color":775,"dst alpha":772,"one minus dst alpha":773,"constant color":32769,"one minus constant color":32770,"constant alpha":32771,"one minus constant alpha":32772,"src alpha saturate":776},Xn=["constant color, constant alpha","one minus constant color, constant alpha","constant color, one minus constant alpha","one minus constant color, one minus constant alpha","constant alpha, constant color","constant alpha, one minus constant color","one minus constant alpha, constant color","one minus constant alpha, one minus constant color"],$n={never:512,less:513,"<":513,equal:514,"=":514,"==":514,"===":514,lequal:515,"<=":515,greater:516,">":516,notequal:517,"!=":517,"!==":517,gequal:518,">=":518,always:519},Kn={0:0,zero:0,keep:7680,replace:7681,increment:7682,decrement:7683,"increment wrap":34055,"decrement wrap":34056,invert:5386},Zn={frag:35632,vert:35633},er={cw:2304,ccw:Qn};function tr(t){return Array.isArray(t)||e(t)||N(t)}function nr(e){return e.sort((function(e,t){return e===fn?-1:t===fn?1:e=1,r>=2,t)}if(4===n){var a=e.data;return new rr(a.thisDep,a.contextDep,a.propDep,t)}if(5===n)return new rr(!1,!1,!1,t);if(6===n){for(var i=!1,o=!1,s=!1,f=0;f=1&&(o=!0),u>=2&&(s=!0)}else 4===c.type&&(i=i||c.data.thisDep,o=o||c.data.contextDep,s=s||c.data.propDep)}return new rr(i,o,s,t)}return new rr(3===n,2===n,1===n,t)}var sr=new rr(!1,!1,!1,(function(){}));function fr(e,n,r,a,i,o,s,f,c,u,l,d,p,m,h){var v=u.Record,g={add:32774,subtract:32778,"reverse subtract":32779};r.ext_blend_minmax&&(g.min=32775,g.max=32776);var b=r.angle_instanced_arrays,y=r.webgl_draw_buffers,w=r.oes_vertex_array_object,x={dirty:!0,profile:h.profile},S={},T=[],A={},C={};function E(e){return e.replace(".","_")}function _(e,t,n){var r=E(e);T.push(e),S[r]=x[r]=!!n,A[r]=t}function D(e,t,n){var r=E(e);T.push(e),Array.isArray(n)?(x[r]=n.slice(),S[r]=n.slice()):x[r]=S[r]=n,C[r]=t}_(Ft,3024),_(Lt,3042),D(It,"blendColor",[0,0,0,0]),D(zt,"blendEquationSeparate",[32774,32774]),D(Bt,"blendFuncSeparate",[1,0,1,0]),_(Vt,2929,!0),D(Ut,"depthFunc",513),D(Gt,"depthRange",[0,1]),D(Nt,"depthMask",!0),D(Ht,Ht,[!0,!0,!0,!0]),_(qt,2884),D(Wt,"cullFace",Wn),D(Qt,Qt,Qn),D(Yt,Yt,1),_(Jt,32823),D(Xt,"polygonOffset",[0,0]),_($t,32926),_(Kt,32928),D(Zt,"sampleCoverage",[1,!1]),_(en,2960),D(tn,"stencilMask",-1),D(nn,"stencilFunc",[519,0,-1]),D(rn,"stencilOpSeparate",[qn,Yn,Yn,Yn]),D(an,"stencilOpSeparate",[Wn,Yn,Yn,Yn]),_(on,3089),D(sn,"scissor",[0,0,e.drawingBufferWidth,e.drawingBufferHeight]),D(fn,fn,[0,0,e.drawingBufferWidth,e.drawingBufferHeight]);var M={gl:e,context:p,strings:n,next:S,current:x,draw:d,elements:o,buffer:i,shader:l,attributes:u.state,vao:u,uniforms:c,framebuffer:f,extensions:r,timer:m,isBufferArgs:tr},P={primTypes:ie,compareFuncs:$n,blendFuncs:Jn,blendEquations:g,stencilOps:Kn,glTypes:J,orientationType:er};k.optional((function(){M.isArrayLike=pe})),y&&(P.backBuffer=[Wn],P.drawBuffer=F(a.maxDrawbuffers,(function(e){return 0===e?[0]:F(e,(function(e){return 36064+e}))})));var R=0;function j(){var e=function(){var e=0,n=[],r=[];function a(){var n=[],r=[];return t((function(){n.push.apply(n,Pt(arguments))}),{def:function(){var t="v"+e++;return r.push(t),arguments.length>0&&(n.push(t,"="),n.push.apply(n,Pt(arguments)),n.push(";")),t},toString:function(){return Rt([r.length>0?"var "+r.join(",")+";":"",Rt(n)])}})}function i(){var e=a(),n=a(),r=e.toString,i=n.toString;function o(t,r){n(t,r,"=",e.def(t,r),";")}return t((function(){e.apply(e,Pt(arguments))}),{def:e.def,entry:e,exit:n,save:o,set:function(t,n,r){o(t,n),e(t,n,"=",r,";")},toString:function(){return r()+i()}})}var o=a(),s={};return{global:o,link:function(t){for(var a=0;a=0,'unknown parameter "'+t+'"',d.commandStr)}))}t(p),t(m)}));var h=function(e,t){var n=e.static;if("string"==typeof n[dn]&&"string"==typeof n[ln]){if(Object.keys(t.dynamic).length>0)return null;var r=t.static,a=Object.keys(r);if(a.length>0&&"number"==typeof r[a[0]]){for(var i=[],o=0;o=0,"invalid "+e,n.commandStr)):f=!1,"height"in i?(s=0|i.height,k.command(s>=0,"invalid "+e,n.commandStr)):f=!1,new rr(!f&&t&&t.thisDep,!f&&t&&t.contextDep,!f&&t&&t.propDep,(function(e,t){var n=e.shared.context,r=o;"width"in i||(r=t.def(n,".",xn,"-",c));var a=s;return"height"in i||(a=t.def(n,".",Sn,"-",u)),[c,u,r,a]}))}if(e in a){var l=a[e],d=or(l,(function(t,n){var r=t.invoke(n,l);k.optional((function(){t.assert(n,r+"&&typeof "+r+'==="object"',"invalid "+e)}));var a=t.shared.context,i=n.def(r,".x|0"),o=n.def(r,".y|0"),s=n.def('"width" in ',r,"?",r,".width|0:","(",a,".",xn,"-",i,")"),f=n.def('"height" in ',r,"?",r,".height|0:","(",a,".",Sn,"-",o,")");return k.optional((function(){t.assert(n,s+">=0&&"+f+">=0","invalid "+e)})),[i,o,s,f]}));return t&&(d.thisDep=d.thisDep||t.thisDep,d.contextDep=d.contextDep||t.contextDep,d.propDep=d.propDep||t.propDep),d}return t?new rr(t.thisDep,t.contextDep,t.propDep,(function(e,t){var n=e.shared.context;return[0,0,t.def(n,".",xn),t.def(n,".",Sn)]})):null}var o=i(fn);if(o){var s=o;o=new rr(o.thisDep,o.contextDep,o.propDep,(function(e,t){var n=s.append(e,t),r=e.shared.context;return t.set(r,".viewportWidth",n[2]),t.set(r,".viewportHeight",n[3]),n}))}return{viewport:o,scissor_box:i(sn)}}(e,y,d),x=function(e,t){var n=e.static,r=e.dynamic,a={},i=!1,s=function(){if(bn in n){var e=n[bn];return null!==e&&null===u.getVAO(e)&&(e=u.createVAO(e)),i=!0,a.vao=e,ir((function(t){var n=u.getVAO(e);return n?t.link(n):"null"}))}if(bn in r){i=!0;var t=r[bn];return or(t,(function(e,n){var r=e.invoke(n,t);return n.def(e.shared.vao+".getVAO("+r+")")}))}return null}(),f=!1,c=function(){if(pn in n){var e=n[pn];if(a.elements=e,tr(e)){var c=a.elements=o.create(e,!0);e=o.getElements(c),f=!0}else e&&(e=o.getElements(e),f=!0,k.command(e,"invalid elements",t.commandStr));var u=ir((function(t,n){if(e){var r=t.link(e);return t.ELEMENTS=r,r}return t.ELEMENTS=null,null}));return u.value=e,u}if(pn in r){f=!0;var l=r[pn];return or(l,(function(e,t){var n=e.shared,r=n.isBufferArgs,a=n.elements,i=e.invoke(t,l),o=t.def("null"),s=t.def(r,"(",i,")"),f=e.cond(s).then(o,"=",a,".createStream(",i,");").else(o,"=",a,".getElements(",i,");");return k.optional((function(){e.assert(f.else,"!"+i+"||"+o,"invalid elements")})),t.entry(f),t.exit(e.cond(s).then(a,".destroyStream(",o,");")),e.ELEMENTS=o,o}))}return i?new rr(s.thisDep,s.contextDep,s.propDep,(function(e,t){return t.def(e.shared.vao+".currentVAO?"+e.shared.elements+".getElements("+e.shared.vao+".currentVAO.elements):null")})):null}();function l(e,o){if(e in n){var c=0|n[e];return o?a.offset=c:a.instances=c,k.command(!o||c>=0,"invalid "+e,t.commandStr),ir((function(e,t){return o&&(e.OFFSET=c),c}))}if(e in r){var u=r[e];return or(u,(function(t,n){var r=t.invoke(n,u);return o&&(t.OFFSET=r,k.optional((function(){t.assert(n,r+">=0","invalid "+e)}))),r}))}if(o){if(f)return ir((function(e,t){return e.OFFSET=0,0}));if(i)return new rr(s.thisDep,s.contextDep,s.propDep,(function(e,t){return t.def(e.shared.vao+".currentVAO?"+e.shared.vao+".currentVAO.offset:0")}))}else if(i)return new rr(s.thisDep,s.contextDep,s.propDep,(function(e,t){return t.def(e.shared.vao+".currentVAO?"+e.shared.vao+".currentVAO.instances:-1")}));return null}var d=l(vn,!0),p=function(){if(mn in n){var e=n[mn];return a.primitive=e,k.commandParameter(e,ie,"invalid primitve",t.commandStr),ir((function(t,n){return ie[e]}))}if(mn in r){var o=r[mn];return or(o,(function(e,t){var n=e.constants.primTypes,r=e.invoke(t,o);return k.optional((function(){e.assert(t,r+" in "+n,"invalid primitive, must be one of "+Object.keys(ie))})),t.def(n,"[",r,"]")}))}return f?ar(c)?c.value?ir((function(e,t){return t.def(e.ELEMENTS,".primType")})):ir((function(){return 4})):new rr(c.thisDep,c.contextDep,c.propDep,(function(e,t){var n=e.ELEMENTS;return t.def(n,"?",n,".primType:",4)})):i?new rr(s.thisDep,s.contextDep,s.propDep,(function(e,t){return t.def(e.shared.vao+".currentVAO?"+e.shared.vao+".currentVAO.primitive:4")})):null}(),m=function(){if(hn in n){var e=0|n[hn];return a.count=e,k.command("number"==typeof e&&e>=0,"invalid vertex count",t.commandStr),ir((function(){return e}))}if(hn in r){var o=r[hn];return or(o,(function(e,t){var n=e.invoke(t,o);return k.optional((function(){e.assert(t,"typeof "+n+'==="number"&&'+n+">=0&&"+n+"===("+n+"|0)","invalid vertex count")})),n}))}if(f){if(ar(c)){if(c)return d?new rr(d.thisDep,d.contextDep,d.propDep,(function(e,t){var n=t.def(e.ELEMENTS,".vertCount-",e.OFFSET);return k.optional((function(){e.assert(t,n+">=0","invalid vertex offset/element buffer too small")})),n})):ir((function(e,t){return t.def(e.ELEMENTS,".vertCount")}));var u=ir((function(){return-1}));return k.optional((function(){u.MISSING=!0})),u}var l=new rr(c.thisDep||d.thisDep,c.contextDep||d.contextDep,c.propDep||d.propDep,(function(e,t){var n=e.ELEMENTS;return e.OFFSET?t.def(n,"?",n,".vertCount-",e.OFFSET,":-1"):t.def(n,"?",n,".vertCount:-1")}));return k.optional((function(){l.DYNAMIC=!0})),l}return i?new rr(s.thisDep,s.contextDep,s.propDep,(function(e,t){return t.def(e.shared.vao,".currentVAO?",e.shared.vao,".currentVAO.count:-1")})):null}(),h=l(gn,!1);return{elements:c,primitive:p,count:m,instances:h,offset:d,vao:s,vaoActive:i,elementsActive:f,static:a}}(e,d),S=function(e,t){var n=e.static,r=e.dynamic,i={};return T.forEach((function(e){var o=E(e);function s(t,a){if(e in n){var s=t(n[e]);i[o]=ir((function(){return s}))}else if(e in r){var f=r[e];i[o]=or(f,(function(e,t){return a(e,t,e.invoke(t,f))}))}}switch(e){case qt:case Lt:case Ft:case en:case Vt:case on:case Jt:case $t:case Kt:case Nt:return s((function(n){return k.commandType(n,"boolean",e,t.commandStr),n}),(function(t,n,r){return k.optional((function(){t.assert(n,"typeof "+r+'==="boolean"',"invalid flag "+e,t.commandStr)})),r}));case Ut:return s((function(n){return k.commandParameter(n,$n,"invalid "+e,t.commandStr),$n[n]}),(function(t,n,r){var a=t.constants.compareFuncs;return k.optional((function(){t.assert(n,r+" in "+a,"invalid "+e+", must be one of "+Object.keys($n))})),n.def(a,"[",r,"]")}));case Gt:return s((function(e){return k.command(pe(e)&&2===e.length&&"number"==typeof e[0]&&"number"==typeof e[1]&&e[0]<=e[1],"depth range is 2d array",t.commandStr),e}),(function(e,t,n){return k.optional((function(){e.assert(t,e.shared.isArrayLike+"("+n+")&&"+n+".length===2&&typeof "+n+'[0]==="number"&&typeof '+n+'[1]==="number"&&'+n+"[0]<="+n+"[1]","depth range must be a 2d array")})),[t.def("+",n,"[0]"),t.def("+",n,"[1]")]}));case Bt:return s((function(e){k.commandType(e,"object","blend.func",t.commandStr);var n="srcRGB"in e?e.srcRGB:e.src,r="srcAlpha"in e?e.srcAlpha:e.src,a="dstRGB"in e?e.dstRGB:e.dst,i="dstAlpha"in e?e.dstAlpha:e.dst;return k.commandParameter(n,Jn,o+".srcRGB",t.commandStr),k.commandParameter(r,Jn,o+".srcAlpha",t.commandStr),k.commandParameter(a,Jn,o+".dstRGB",t.commandStr),k.commandParameter(i,Jn,o+".dstAlpha",t.commandStr),k.command(-1===Xn.indexOf(n+", "+a),"unallowed blending combination (srcRGB, dstRGB) = ("+n+", "+a+")",t.commandStr),[Jn[n],Jn[a],Jn[r],Jn[i]]}),(function(t,n,r){var a=t.constants.blendFuncs;function i(i,o){var s=n.def('"',i,o,'" in ',r,"?",r,".",i,o,":",r,".",i);return k.optional((function(){t.assert(n,s+" in "+a,"invalid "+e+"."+i+o+", must be one of "+Object.keys(Jn))})),s}k.optional((function(){t.assert(n,r+"&&typeof "+r+'==="object"',"invalid blend func, must be an object")}));var o=i("src","RGB"),s=i("dst","RGB");k.optional((function(){var e=t.constants.invalidBlendCombinations;t.assert(n,e+".indexOf("+o+'+", "+'+s+") === -1 ","unallowed blending combination for (srcRGB, dstRGB)")}));var f=n.def(a,"[",o,"]"),c=n.def(a,"[",i("src","Alpha"),"]");return[f,n.def(a,"[",s,"]"),c,n.def(a,"[",i("dst","Alpha"),"]")]}));case zt:return s((function(n){return"string"==typeof n?(k.commandParameter(n,g,"invalid "+e,t.commandStr),[g[n],g[n]]):"object"==typeof n?(k.commandParameter(n.rgb,g,e+".rgb",t.commandStr),k.commandParameter(n.alpha,g,e+".alpha",t.commandStr),[g[n.rgb],g[n.alpha]]):void k.commandRaise("invalid blend.equation",t.commandStr)}),(function(t,n,r){var a=t.constants.blendEquations,i=n.def(),o=n.def(),s=t.cond("typeof ",r,'==="string"');return k.optional((function(){function n(e,n,r){t.assert(e,r+" in "+a,"invalid "+n+", must be one of "+Object.keys(g))}n(s.then,e,r),t.assert(s.else,r+"&&typeof "+r+'==="object"',"invalid "+e),n(s.else,e+".rgb",r+".rgb"),n(s.else,e+".alpha",r+".alpha")})),s.then(i,"=",o,"=",a,"[",r,"];"),s.else(i,"=",a,"[",r,".rgb];",o,"=",a,"[",r,".alpha];"),n(s),[i,o]}));case It:return s((function(e){return k.command(pe(e)&&4===e.length,"blend.color must be a 4d array",t.commandStr),F(4,(function(t){return+e[t]}))}),(function(e,t,n){return k.optional((function(){e.assert(t,e.shared.isArrayLike+"("+n+")&&"+n+".length===4","blend.color must be a 4d array")})),F(4,(function(e){return t.def("+",n,"[",e,"]")}))}));case tn:return s((function(e){return k.commandType(e,"number",o,t.commandStr),0|e}),(function(e,t,n){return k.optional((function(){e.assert(t,"typeof "+n+'==="number"',"invalid stencil.mask")})),t.def(n,"|0")}));case nn:return s((function(n){k.commandType(n,"object",o,t.commandStr);var r=n.cmp||"keep",a=n.ref||0,i="mask"in n?n.mask:-1;return k.commandParameter(r,$n,e+".cmp",t.commandStr),k.commandType(a,"number",e+".ref",t.commandStr),k.commandType(i,"number",e+".mask",t.commandStr),[$n[r],a,i]}),(function(e,t,n){var r=e.constants.compareFuncs;return k.optional((function(){function a(){e.assert(t,Array.prototype.join.call(arguments,""),"invalid stencil.func")}a(n+"&&typeof ",n,'==="object"'),a('!("cmp" in ',n,")||(",n,".cmp in ",r,")")})),[t.def('"cmp" in ',n,"?",r,"[",n,".cmp]",":",Yn),t.def(n,".ref|0"),t.def('"mask" in ',n,"?",n,".mask|0:-1")]}));case rn:case an:return s((function(n){k.commandType(n,"object",o,t.commandStr);var r=n.fail||"keep",a=n.zfail||"keep",i=n.zpass||"keep";return k.commandParameter(r,Kn,e+".fail",t.commandStr),k.commandParameter(a,Kn,e+".zfail",t.commandStr),k.commandParameter(i,Kn,e+".zpass",t.commandStr),[e===an?Wn:qn,Kn[r],Kn[a],Kn[i]]}),(function(t,n,r){var a=t.constants.stencilOps;function i(i){return k.optional((function(){t.assert(n,'!("'+i+'" in '+r+")||("+r+"."+i+" in "+a+")","invalid "+e+"."+i+", must be one of "+Object.keys(Kn))})),n.def('"',i,'" in ',r,"?",a,"[",r,".",i,"]:",Yn)}return k.optional((function(){t.assert(n,r+"&&typeof "+r+'==="object"',"invalid "+e)})),[e===an?Wn:qn,i("fail"),i("zfail"),i("zpass")]}));case Xt:return s((function(e){k.commandType(e,"object",o,t.commandStr);var n=0|e.factor,r=0|e.units;return k.commandType(n,"number",o+".factor",t.commandStr),k.commandType(r,"number",o+".units",t.commandStr),[n,r]}),(function(t,n,r){return k.optional((function(){t.assert(n,r+"&&typeof "+r+'==="object"',"invalid "+e)})),[n.def(r,".factor|0"),n.def(r,".units|0")]}));case Wt:return s((function(e){var n=0;return"front"===e?n=qn:"back"===e&&(n=Wn),k.command(!!n,o,t.commandStr),n}),(function(e,t,n){return k.optional((function(){e.assert(t,n+'==="front"||'+n+'==="back"',"invalid cull.face")})),t.def(n,'==="front"?',qn,":",Wn)}));case Yt:return s((function(e){return k.command("number"==typeof e&&e>=a.lineWidthDims[0]&&e<=a.lineWidthDims[1],"invalid line width, must be a positive number between "+a.lineWidthDims[0]+" and "+a.lineWidthDims[1],t.commandStr),e}),(function(e,t,n){return k.optional((function(){e.assert(t,"typeof "+n+'==="number"&&'+n+">="+a.lineWidthDims[0]+"&&"+n+"<="+a.lineWidthDims[1],"invalid line width")})),n}));case Qt:return s((function(e){return k.commandParameter(e,er,o,t.commandStr),er[e]}),(function(e,t,n){return k.optional((function(){e.assert(t,n+'==="cw"||'+n+'==="ccw"',"invalid frontFace, must be one of cw,ccw")})),t.def(n+'==="cw"?2304:'+Qn)}));case Ht:return s((function(e){return k.command(pe(e)&&4===e.length,"color.mask must be length 4 array",t.commandStr),e.map((function(e){return!!e}))}),(function(e,t,n){return k.optional((function(){e.assert(t,e.shared.isArrayLike+"("+n+")&&"+n+".length===4","invalid color.mask")})),F(4,(function(e){return"!!"+n+"["+e+"]"}))}));case Zt:return s((function(e){k.command("object"==typeof e&&e,o,t.commandStr);var n="value"in e?e.value:1,r=!!e.invert;return k.command("number"==typeof n&&n>=0&&n<=1,"sample.coverage.value must be a number between 0 and 1",t.commandStr),[n,r]}),(function(e,t,n){return k.optional((function(){e.assert(t,n+"&&typeof "+n+'==="object"',"invalid sample.coverage")})),[t.def('"value" in ',n,"?+",n,".value:1"),t.def("!!",n,".invert")]}))}})),i}(e,d),A=function(e,t,r){var a=e.static,i=e.dynamic;function o(e){if(e in a){var t=n.id(a[e]);k.optional((function(){l.shader(Zn[e],t,k.guessCommand())}));var r=ir((function(){return t}));return r.id=t,r}if(e in i){var o=i[e];return or(o,(function(t,n){var r=t.invoke(n,o),a=n.def(t.shared.strings,".id(",r,")");return k.optional((function(){n(t.shared.shader,".shader(",Zn[e],",",a,",",t.command,");")})),a}))}return null}var s,f=o(dn),c=o(ln),u=null;return ar(f)&&ar(c)?(u=l.program(c.id,f.id,null,r),s=ir((function(e,t){return e.link(u)}))):s=new rr(f&&f.thisDep||c&&c.thisDep,f&&f.contextDep||c&&c.contextDep,f&&f.propDep||c&&c.propDep,(function(e,t){var n,r=e.shared.shader;n=f?f.append(e,t):t.def(r,".",dn);var a=r+".program("+(c?c.append(e,t):t.def(r,".",ln))+","+n;return k.optional((function(){a+=","+e.command})),t.def(a+")")})),{frag:f,vert:c,progVar:s,program:u}}(e,0,h);function C(e){var t=w[e];t&&(S[e]=t)}C(fn),C(E(sn));var _=Object.keys(S).length>0,O={framebuffer:y,draw:x,shader:A,state:S,dirty:_,scopeVAO:null,drawVAO:null,useVAO:!1,attributes:{}};if(O.profile=function(e){var t,n=e.static,r=e.dynamic;if(cn in n){var a=!!n[cn];(t=ir((function(e,t){return a}))).enable=a}else if(cn in r){var i=r[cn];t=or(i,(function(e,t){return e.invoke(t,i)}))}return t}(e),O.uniforms=function(e,t){var n=e.static,r=e.dynamic,a={};return Object.keys(n).forEach((function(e){var r,i=n[e];if("number"==typeof i||"boolean"==typeof i)r=ir((function(){return i}));else if("function"==typeof i){var o=i._reglType;"texture2d"===o||"textureCube"===o?r=ir((function(e){return e.link(i)})):"framebuffer"===o||"framebufferCube"===o?(k.command(i.color.length>0,'missing color attachment for framebuffer sent to uniform "'+e+'"',t.commandStr),r=ir((function(e){return e.link(i.color[0])}))):k.commandRaise('invalid data for uniform "'+e+'"',t.commandStr)}else pe(i)?r=ir((function(t){return t.global.def("[",F(i.length,(function(n){return k.command("number"==typeof i[n]||"boolean"==typeof i[n],"invalid uniform "+e,t.commandStr),i[n]})),"]")})):k.commandRaise('invalid or missing data for uniform "'+e+'"',t.commandStr);r.value=i,a[e]=r})),Object.keys(r).forEach((function(e){var t=r[e];a[e]=or(t,(function(e,n){return e.invoke(n,t)}))})),a}(s,d),O.drawVAO=O.scopeVAO=x.vao,!O.drawVAO&&A.program&&!h&&r.angle_instanced_arrays&&x.static.elements){var D=!0,M=A.program.attributes.map((function(e){var n=t.static[e];return D=D&&!!n,n}));if(D&&M.length>0){var P=u.getVAO(u.createVAO({attributes:M,elements:x.static.elements}));O.drawVAO=new rr(null,null,null,(function(e,t){return e.link(P)})),O.useVAO=!0}}return h?O.useVAO=!0:O.attributes=function(e,t){var r=e.static,a=e.dynamic,o={};return Object.keys(r).forEach((function(e){var a=r[e],s=n.id(e),f=new v;if(tr(a))f.state=1,f.buffer=i.getBuffer(i.create(a,Cn,!1,!0)),f.type=0;else{var c=i.getBuffer(a);if(c)f.state=1,f.buffer=c,f.type=0;else if(k.command("object"==typeof a&&a,"invalid data for attribute "+e,t.commandStr),"constant"in a){var u=a.constant;f.buffer="null",f.state=2,"number"==typeof u?f.x=u:(k.command(pe(u)&&u.length>0&&u.length<=4,"invalid constant for attribute "+e,t.commandStr),jt.forEach((function(e,t){t=0,'invalid offset for attribute "'+e+'"',t.commandStr);var d=0|a.stride;k.command(d>=0&&d<256,'invalid stride for attribute "'+e+'", must be integer betweeen [0, 255]',t.commandStr);var p=0|a.size;k.command(!("size"in a)||p>0&&p<=4,'invalid size for attribute "'+e+'", must be 1,2,3,4',t.commandStr);var m=!!a.normalized,h=0;"type"in a&&(k.commandParameter(a.type,J,"invalid type for attribute "+e,t.commandStr),h=J[a.type]);var g=0|a.divisor;k.optional((function(){"divisor"in a&&(k.command(0===g||b,'cannot specify divisor for attribute "'+e+'", instancing not supported',t.commandStr),k.command(g>=0,'invalid divisor for attribute "'+e+'"',t.commandStr));var n=t.commandStr,r=["buffer","offset","divisor","normalized","type","size","stride"];Object.keys(a).forEach((function(t){k.command(r.indexOf(t)>=0,'unknown parameter "'+t+'" for attribute pointer "'+e+'" (valid parameters are '+r+")",n)}))})),f.buffer=c,f.state=1,f.size=p,f.normalized=m,f.type=h||c.dtype,f.offset=l,f.stride=d,f.divisor=g}}o[e]=ir((function(e,t){var n=e.attribCache;if(s in n)return n[s];var r={isStream:!1};return Object.keys(f).forEach((function(e){r[e]=f[e]})),f.buffer&&(r.buffer=e.link(f.buffer),r.type=r.type||r.buffer+".dtype"),n[s]=r,r}))})),Object.keys(a).forEach((function(e){var t=a[e];o[e]=or(t,(function(n,r){var a=n.invoke(r,t),i=n.shared,o=n.constants,s=i.isBufferArgs,f=i.buffer;k.optional((function(){n.assert(r,a+"&&(typeof "+a+'==="object"||typeof '+a+'==="function")&&('+s+"("+a+")||"+f+".getBuffer("+a+")||"+f+".getBuffer("+a+".buffer)||"+s+"("+a+'.buffer)||("constant" in '+a+"&&(typeof "+a+'.constant==="number"||'+i.isArrayLike+"("+a+".constant))))",'invalid dynamic attribute "'+e+'"')}));var c={isStream:r.def(!1)},u=new v;u.state=1,Object.keys(u).forEach((function(e){c[e]=r.def(""+u[e])}));var l=c.buffer,d=c.type;function p(e){r(c[e],"=",a,".",e,"|0;")}return r("if(",s,"(",a,")){",c.isStream,"=true;",l,"=",f,".createStream(",Cn,",",a,");",d,"=",l,".dtype;","}else{",l,"=",f,".getBuffer(",a,");","if(",l,"){",d,"=",l,".dtype;",'}else if("constant" in ',a,"){",c.state,"=",2,";","if(typeof "+a+'.constant === "number"){',c[jt[0]],"=",a,".constant;",jt.slice(1).map((function(e){return c[e]})).join("="),"=0;","}else{",jt.map((function(e,t){return c[e]+"="+a+".constant.length>"+t+"?"+a+".constant["+t+"]:0;"})).join(""),"}}else{","if(",s,"(",a,".buffer)){",l,"=",f,".createStream(",Cn,",",a,".buffer);","}else{",l,"=",f,".getBuffer(",a,".buffer);","}",d,'="type" in ',a,"?",o.glTypes,"[",a,".type]:",l,".dtype;",c.normalized,"=!!",a,".normalized;"),p("size"),p("offset"),p("stride"),p("divisor"),r("}}"),r.exit("if(",c.isStream,"){",f,".destroyStream(",l,");","}"),c}))})),o}(t,d),O.context=function(e){var t=e.static,n=e.dynamic,r={};return Object.keys(t).forEach((function(e){var n=t[e];r[e]=ir((function(e,t){return"number"==typeof n||"boolean"==typeof n?""+n:e.link(n)}))})),Object.keys(n).forEach((function(e){var t=n[e];r[e]=or(t,(function(e,n){return e.invoke(n,t)}))})),r}(c),O}function I(e,t,n){var r=e.shared.context,a=e.scope();Object.keys(n).forEach((function(i){t.save(r,"."+i);var o=n[i].append(e,t);Array.isArray(o)?a(r,".",i,"=[",o.join(),"];"):a(r,".",i,"=",o,";")})),t(a)}function z(e,t,n,r){var a,i=e.shared,o=i.gl,s=i.framebuffer;y&&(a=t.def(i.extensions,".webgl_draw_buffers"));var f,c=e.constants,u=c.drawBuffer,l=c.backBuffer;f=n?n.append(e,t):t.def(s,".next"),r||t("if(",f,"!==",s,".cur){"),t("if(",f,"){",o,".bindFramebuffer(",36160,",",f,".framebuffer);"),y&&t(a,".drawBuffersWEBGL(",u,"[",f,".colorAttachments.length]);"),t("}else{",o,".bindFramebuffer(",36160,",null);"),y&&t(a,".drawBuffersWEBGL(",l,");"),t("}",s,".cur=",f,";"),r||t("}")}function B(e,t,n){var r=e.shared,a=r.gl,i=e.current,o=e.next,s=r.current,f=r.next,c=e.cond(s,".dirty");T.forEach((function(t){var r,u,l=E(t);if(!(l in n.state))if(l in o){r=o[l],u=i[l];var d=F(x[l].length,(function(e){return c.def(r,"[",e,"]")}));c(e.cond(d.map((function(e,t){return e+"!=="+u+"["+t+"]"})).join("||")).then(a,".",C[l],"(",d,");",d.map((function(e,t){return u+"["+t+"]="+e})).join(";"),";"))}else{r=c.def(f,".",l);var p=e.cond(r,"!==",s,".",l);c(p),l in A?p(e.cond(r).then(a,".enable(",A[l],");").else(a,".disable(",A[l],");"),s,".",l,"=",r,";"):p(a,".",C[l],"(",r,");",s,".",l,"=",r,";")}})),0===Object.keys(n.state).length&&c(s,".dirty=false;"),t(c)}function V(e,t,n,r){var a=e.shared,i=e.current,o=a.current,s=a.gl;nr(Object.keys(n)).forEach((function(a){var f=n[a];if(!r||r(f)){var c=f.append(e,t);if(A[a]){var u=A[a];ar(f)?t(s,c?".enable(":".disable(",u,");"):t(e.cond(c).then(s,".enable(",u,");").else(s,".disable(",u,");")),t(o,".",a,"=",c,";")}else if(pe(c)){var l=i[a];t(s,".",C[a],"(",c,");",c.map((function(e,t){return l+"["+t+"]="+e})).join(";"),";")}else t(s,".",C[a],"(",c,");",o,".",a,"=",c,";")}}))}function U(e,t){b&&(e.instancing=t.def(e.shared.extensions,".angle_instanced_arrays"))}function G(e,t,n,r,a){var i,o,s,f=e.shared,c=e.stats,u=f.current,l=f.timer,d=n.profile;function p(){return"undefined"==typeof performance?"Date.now()":"performance.now()"}function h(e){e(i=t.def(),"=",p(),";"),"string"==typeof a?e(c,".count+=",a,";"):e(c,".count++;"),m&&(r?e(o=t.def(),"=",l,".getNumPendingQueries();"):e(l,".beginQuery(",c,");"))}function v(e){e(c,".cpuTime+=",p(),"-",i,";"),m&&(r?e(l,".pushScopeStats(",o,",",l,".getNumPendingQueries(),",c,");"):e(l,".endQuery();"))}function g(e){var n=t.def(u,".profile");t(u,".profile=",e,";"),t.exit(u,".profile=",n,";")}if(d){if(ar(d))return void(d.enable?(h(t),v(t.exit),g("true")):g("false"));g(s=d.append(e,t))}else s=t.def(u,".profile");var b=e.block();h(b),t("if(",s,"){",b,"}");var y=e.block();v(y),t.exit("if(",s,"){",y,"}")}function N(e,t,n,r,a){var i=e.shared;r.forEach((function(r){var o,s=r.name,f=n.attributes[s];if(f){if(!a(f))return;o=f.append(e,t)}else{if(!a(sr))return;var c=e.scopeAttrib(s);k.optional((function(){e.assert(t,c+".state","missing attribute "+s)})),o={},Object.keys(new v).forEach((function(e){o[e]=t.def(c,".",e)}))}!function(n,r,a){var o=i.gl,s=t.def(n,".location"),f=t.def(i.attributes,"[",s,"]"),c=a.state,u=a.buffer,l=[a.x,a.y,a.z,a.w],d=["buffer","normalized","offset","stride"];function p(){t("if(!",f,".buffer){",o,".enableVertexAttribArray(",s,");}");var n,i=a.type;if(n=a.size?t.def(a.size,"||",r):r,t("if(",f,".type!==",i,"||",f,".size!==",n,"||",d.map((function(e){return f+"."+e+"!=="+a[e]})).join("||"),"){",o,".bindBuffer(",Cn,",",u,".buffer);",o,".vertexAttribPointer(",[s,n,i,a.normalized,a.stride,a.offset],");",f,".type=",i,";",f,".size=",n,";",d.map((function(e){return f+"."+e+"="+a[e]+";"})).join(""),"}"),b){var c=a.divisor;t("if(",f,".divisor!==",c,"){",e.instancing,".vertexAttribDivisorANGLE(",[s,c],");",f,".divisor=",c,";}")}}function m(){t("if(",f,".buffer){",o,".disableVertexAttribArray(",s,");",f,".buffer=null;","}if(",jt.map((function(e,t){return f+"."+e+"!=="+l[t]})).join("||"),"){",o,".vertexAttrib4f(",s,",",l,");",jt.map((function(e,t){return f+"."+e+"="+l[t]+";"})).join(""),"}")}1===c?p():2===c?m():(t("if(",c,"===",1,"){"),p(),t("}else{"),m(),t("}"))}(e.link(r),function(e){switch(e){case On:case Rn:case In:return 2;case Dn:case jn:case zn:return 3;case Mn:case Fn:case Bn:return 4;default:return 1}}(r.info.type),o)}))}function H(e,t,r,a,i,o){for(var s,f=e.shared,c=f.gl,u={},l=0;l1){if(!v)continue;var g=p.replace("[0]","");if(u[g])continue;u[g]=1}var b,y=e.link(d)+".location";if(v){if(!i(v))continue;if(ar(v)){var w=v.value;if(k.command(null!=w,'missing uniform "'+p+'"',e.commandStr),m===Nn||m===Hn){k.command("function"==typeof w&&(m===Nn&&("texture2d"===w._reglType||"framebuffer"===w._reglType)||m===Hn&&("textureCube"===w._reglType||"framebufferCube"===w._reglType)),"invalid texture for uniform "+p,e.commandStr);var x=e.link(w._texture||w.color[0]._texture);t(c,".uniform1i(",y,",",x+".bind());"),t.exit(x,".unbind();")}else if(m===Vn||m===Un||m===Gn){k.optional((function(){k.command(pe(w),"invalid matrix for uniform "+p,e.commandStr),k.command(m===Vn&&4===w.length||m===Un&&9===w.length||m===Gn&&16===w.length,"invalid length for matrix uniform "+p,e.commandStr)}));var S=e.global.def("new Float32Array(["+Array.prototype.slice.call(w)+"])"),T=2;m===Un?T=3:m===Gn&&(T=4),t(c,".uniformMatrix",T,"fv(",y,",false,",S,");")}else{switch(m){case _n:1===h?k.commandType(w,"number","uniform "+p,e.commandStr):k.command(pe(w)&&w.length===h,"uniform "+p,e.commandStr),s="1f";break;case On:k.command(pe(w)&&w.length&&w.length%2==0&&w.length<=2*h,"uniform "+p,e.commandStr),s="2f";break;case Dn:k.command(pe(w)&&w.length&&w.length%3==0&&w.length<=3*h,"uniform "+p,e.commandStr),s="3f";break;case Mn:k.command(pe(w)&&w.length&&w.length%4==0&&w.length<=4*h,"uniform "+p,e.commandStr),s="4f";break;case Ln:1===h?k.commandType(w,"boolean","uniform "+p,e.commandStr):k.command(pe(w)&&w.length===h,"uniform "+p,e.commandStr),s="1i";break;case Pn:1===h?k.commandType(w,"number","uniform "+p,e.commandStr):k.command(pe(w)&&w.length===h,"uniform "+p,e.commandStr),s="1i";break;case In:case Rn:k.command(pe(w)&&w.length&&w.length%2==0&&w.length<=2*h,"uniform "+p,e.commandStr),s="2i";break;case zn:case jn:k.command(pe(w)&&w.length&&w.length%3==0&&w.length<=3*h,"uniform "+p,e.commandStr),s="3i";break;case Bn:case Fn:k.command(pe(w)&&w.length&&w.length%4==0&&w.length<=4*h,"uniform "+p,e.commandStr),s="4i"}h>1?(s+="v",w=e.global.def("["+Array.prototype.slice.call(w)+"]")):w=pe(w)?Array.prototype.slice.call(w):w,t(c,".uniform",s,"(",y,",",w,");")}continue}b=v.append(e,t)}else{if(!i(sr))continue;b=t.def(f.uniforms,"[",n.id(p),"]")}m===Nn?(k(!Array.isArray(b),"must specify a scalar prop for textures"),t("if(",b,"&&",b,'._reglType==="framebuffer"){',b,"=",b,".color[0];","}")):m===Hn&&(k(!Array.isArray(b),"must specify a scalar prop for cube maps"),t("if(",b,"&&",b,'._reglType==="framebufferCube"){',b,"=",b,".color[0];","}")),k.optional((function(){function n(n,r){e.assert(t,n,'bad data or missing for uniform "'+p+'". '+r)}function r(e,t){1===t&&k(!Array.isArray(b),"must not specify an array type for uniform"),n("Array.isArray("+b+") && typeof "+b+'[0]===" '+e+'" || typeof '+b+'==="'+e+'"',"invalid type, expected "+e)}function a(t,r,a){Array.isArray(b)?k(b.length&&b.length%t==0&&b.length<=t*a,"must have length of "+(1===a?"":"n * ")+t):n(f.isArrayLike+"("+b+")&&"+b+".length && "+b+".length % "+t+" === 0 && "+b+".length<="+t*a,"invalid vector, should have length of "+(1===a?"":"n * ")+t,e.commandStr)}function i(t){k(!Array.isArray(b),"must not specify a value type"),n("typeof "+b+'==="function"&&'+b+'._reglType==="texture'+(3553===t?"2d":"Cube")+'"',"invalid texture type",e.commandStr)}switch(m){case Pn:case _n:r("number",h);break;case Rn:case On:case In:a(2,0,h);break;case jn:case Dn:case zn:a(3,0,h);break;case Fn:case Mn:case Bn:case Vn:a(4,0,h);break;case Ln:r("boolean",h);break;case Un:a(9,0,h);break;case Gn:a(16,0,h);break;case Nn:i(3553);break;case Hn:i(34067)}}));var A=1;switch(m){case Nn:case Hn:var C=t.def(b,"._texture");t(c,".uniform1i(",y,",",C,".bind());"),t.exit(C,".unbind();");continue;case Pn:case Ln:s="1i";break;case Rn:case In:s="2i",A=2;break;case jn:case zn:s="3i",A=3;break;case Fn:case Bn:s="4i",A=4;break;case _n:s="1f";break;case On:s="2f",A=2;break;case Dn:s="3f",A=3;break;case Mn:s="4f",A=4;break;case Vn:s="Matrix2fv";break;case Un:s="Matrix3fv";break;case Gn:s="Matrix4fv"}if(-1===s.indexOf("Matrix")&&h>1&&(s+="v",A=1),"M"===s.charAt(0)){t(c,".uniform",s,"(",y,",");var E=Math.pow(m-Vn+2,2),_=e.global.def("new Float32Array(",E,")");Array.isArray(b)?t("false,(",F(E,(function(e){return _+"["+e+"]="+b[e]})),",",_,")"):t("false,(Array.isArray(",b,")||",b," instanceof Float32Array)?",b,":(",F(E,(function(e){return _+"["+e+"]="+b+"["+e+"]"})),",",_,")"),t(");")}else if(A>1){for(var O=[],D=[],M=0;M=0","missing vertex count")}))):(a=f.def(o,".",hn),k.optional((function(){e.assert(f,a+">=0","missing vertex count")}))),a}();if("number"==typeof g){if(0===g)return}else n("if(",g,"){"),n.exit("}");b&&(p=d(gn),m=e.instancing);var y=l+".type",x=s.elements&&ar(s.elements)&&!s.vaoActive;function S(){function e(){n(m,".drawElementsInstancedANGLE(",[h,g,y,v+"<<(("+y+"-5121)>>1)",p],");")}function t(){n(m,".drawArraysInstancedANGLE(",[h,v,g,p],");")}l&&"null"!==l?x?e():(n("if(",l,"){"),e(),n("}else{"),t(),n("}")):t()}function T(){function e(){n(i+".drawElements("+[h,g,y,v+"<<(("+y+"-5121)>>1)"]+");")}function t(){n(i+".drawArrays("+[h,v,g]+");")}l&&"null"!==l?x?e():(n("if(",l,"){"),e(),n("}else{"),t(),n("}")):t()}b&&("number"!=typeof p||p>=0)?"string"==typeof p?(n("if(",p,">0){"),S(),n("}else if(",p,"<0){"),T(),n("}")):S():T()}function W(e,t,n,r,a){var i=j(),o=i.proc("body",a);return k.optional((function(){i.commandStr=t.commandStr,i.command=i.link(t.commandStr)})),b&&(i.instancing=o.def(i.shared.extensions,".angle_instanced_arrays")),e(i,o,n,r),i.compile().body}function Q(e,t,n,r){U(e,t),n.useVAO?n.drawVAO?t(e.shared.vao,".setVAO(",n.drawVAO.append(e,t),");"):t(e.shared.vao,".setVAO(",e.shared.vao,".targetVAO);"):(t(e.shared.vao,".setVAO(null);"),N(e,t,n,r.attributes,(function(){return!0}))),H(e,t,n,r.uniforms,(function(){return!0}),!1),q(e,t,t,n)}function Y(e,t,n,r){function a(){return!0}e.batchId="a1",U(e,t),N(e,t,n,r.attributes,a),H(e,t,n,r.uniforms,a,!1),q(e,t,t,n)}function X(e,t,n,r){U(e,t);var a=n.contextDep,i=t.def(),o=t.def();e.shared.props=o,e.batchId=i;var s=e.scope(),f=e.scope();function c(e){return e.contextDep&&a||e.propDep}function u(e){return!c(e)}if(t(s.entry,"for(",i,"=0;",i,"<","a1",";++",i,"){",o,"=","a0","[",i,"];",f,"}",s.exit),n.needsContext&&I(e,f,n.context),n.needsFramebuffer&&z(e,f,n.framebuffer),V(e,f,n.state,c),n.profile&&c(n.profile)&&G(e,f,n,!1,!0),r)n.useVAO?n.drawVAO?c(n.drawVAO)?f(e.shared.vao,".setVAO(",n.drawVAO.append(e,f),");"):s(e.shared.vao,".setVAO(",n.drawVAO.append(e,s),");"):s(e.shared.vao,".setVAO(",e.shared.vao,".targetVAO);"):(s(e.shared.vao,".setVAO(null);"),N(e,s,n,r.attributes,u),N(e,f,n,r.attributes,c)),H(e,s,n,r.uniforms,u,!1),H(e,f,n,r.uniforms,c,!0),q(e,s,f,n);else{var l=e.global.def("{}"),d=n.shader.progVar.append(e,f),p=f.def(d,".id"),m=f.def(l,"[",p,"]");f(e.shared.gl,".useProgram(",d,".program);","if(!",m,"){",m,"=",l,"[",p,"]=",e.link((function(t){return W(Y,e,n,t,2)})),"(",d,");}",m,".call(this,a0[",i,"],",i,");")}}function $(e,t,n){var r=t.static[n];if(r&&function(e){if("object"==typeof e&&!pe(e)){for(var t=Object.keys(e),n=0;n0&&n(e.shared.current,".dirty=true;"),e.shared.vao&&n(e.shared.vao,".setVAO(null);")}(s,f),function(e,t){var r=e.proc("scope",3);e.batchId="a2";var a=e.shared,i=a.current;function o(n){var i=t.shader[n];i&&r.set(a.shader,"."+n,i.append(e,r))}I(e,r,t.context),t.framebuffer&&t.framebuffer.append(e,r),nr(Object.keys(t.state)).forEach((function(n){var i=t.state[n].append(e,r);pe(i)?i.forEach((function(t,a){r.set(e.next[n],"["+a+"]",t)})):r.set(a.next,"."+n,i)})),G(e,r,t,!0,!0),[pn,vn,hn,gn,mn].forEach((function(n){var i=t.draw[n];i&&r.set(a.draw,"."+n,""+i.append(e,r))})),Object.keys(t.uniforms).forEach((function(i){var o=t.uniforms[i].append(e,r);Array.isArray(o)&&(o="["+o.join()+"]"),r.set(a.uniforms,"["+n.id(i)+"]",o)})),Object.keys(t.attributes).forEach((function(n){var a=t.attributes[n].append(e,r),i=e.scopeAttrib(n);Object.keys(new v).forEach((function(e){r.set(i,"."+e,a[e])}))})),t.scopeVAO&&r.set(a.vao,".targetVAO",t.scopeVAO.append(e,r)),o(ln),o(dn),Object.keys(t.state).length>0&&(r(i,".dirty=true;"),r.exit(i,".dirty=true;")),r("a1(",e.shared.context,",a0,",e.batchId,");")}(s,f),function(e,t){var n=e.proc("batch",2);e.batchId="0",U(e,n);var r=!1,a=!0;Object.keys(t.context).forEach((function(e){r=r||t.context[e].propDep})),r||(I(e,n,t.context),a=!1);var i=t.framebuffer,o=!1;function s(e){return e.contextDep&&r||e.propDep}i?(i.propDep?r=o=!0:i.contextDep&&r&&(o=!0),o||z(e,n,i)):z(e,n,null),t.state.viewport&&t.state.viewport.propDep&&(r=!0),B(e,n,t),V(e,n,t.state,(function(e){return!s(e)})),t.profile&&s(t.profile)||G(e,n,t,!1,"a1"),t.contextDep=r,t.needsContext=a,t.needsFramebuffer=o;var f=t.shader.progVar;if(f.contextDep&&r||f.propDep)X(e,n,t,null);else{var c=f.append(e,n);if(n(e.shared.gl,".useProgram(",c,".program);"),t.shader.program)X(e,n,t,t.shader.program);else{n(e.shared.vao,".setVAO(null);");var u=e.global.def("{}"),l=n.def(c,".id"),d=n.def(u,"[",l,"]");n(e.cond(d).then(d,".call(this,a0,a1);").else(d,"=",u,"[",l,"]=",e.link((function(n){return W(X,e,t,n,2)})),"(",c,");",d,".call(this,a0,a1);"))}}Object.keys(t.state).length>0&&n(e.shared.current,".dirty=true;"),e.shared.vao&&n(e.shared.vao,".setVAO(null);")}(s,f),t(s.compile(),{destroy:function(){f.shader.program.destroy()}})}}}var cr=function(e,t){if(!t.ext_disjoint_timer_query)return null;var n=[];function r(e){n.push(e)}var a=[];function i(){this.startQueryIndex=-1,this.endQueryIndex=-1,this.sum=0,this.stats=null}var o=[];var s=[];function f(e,t,n){var r=o.pop()||new i;r.startQueryIndex=e,r.endQueryIndex=t,r.sum=0,r.stats=n,s.push(r)}var c=[],u=[];return{beginQuery:function(e){var r=n.pop()||t.ext_disjoint_timer_query.createQueryEXT();t.ext_disjoint_timer_query.beginQueryEXT(35007,r),a.push(r),f(a.length-1,a.length,e)},endQuery:function(){t.ext_disjoint_timer_query.endQueryEXT(35007)},pushScopeStats:f,update:function(){var e,n,i=a.length;if(0!==i){u.length=Math.max(u.length,i+1),c.length=Math.max(c.length,i+1),c[0]=0,u[0]=0;var f,l=0;for(e=0,n=0;n0)if(Array.isArray(n[0])){s=K(n);for(var u=1,l=1;l0)if("number"==typeof t[0]){var i=z.allocType(d.dtype,t.length);re(i,t),m(i,a),z.freeType(i)}else if(Array.isArray(t[0])||e(t[0])){r=K(t);var o=$(t,r,d.dtype);m(o,a),z.freeType(o)}else k.raise("invalid buffer data")}else if(N(t)){r=t.shape;var s=t.stride,f=0,c=0,u=0,l=0;1===r.length?(f=r[0],c=1,u=s[0],l=0):2===r.length?(f=r[0],c=r[1],u=s[0],l=s[1]):k.raise("invalid shape");var h=Array.isArray(t.data)?d.dtype:ne(t.data),v=z.allocType(h,f*c);ae(v,t.data,f,c,u,l,t.offset),m(v,a),z.freeType(v)}else k.raise("invalid data for buffer subdata");return p},r.profile&&(p.stats=d.stats),p.destroy=function(){l(d)},p},createStream:function(e,t){var n=f.pop();return n||(n=new s(e)),n.bind(),u(n,t,35040,0,1,!1),n},destroyStream:function(e){f.push(e)},clear:function(){H(o).forEach(l),f.forEach(l)},getBuffer:function(e){return e&&e._buffer instanceof s?e._buffer:null},restore:function(){H(o).forEach((function(e){e.buffer=t.createBuffer(),t.bindBuffer(e.type,e.buffer),t.bufferData(e.type,e.persistentData||e.byteLength,e.usage)}))},_initBuffer:u}}(a,l,r,(function(e){return S.destroyBuffer(e)})),x=function(t,n,r,a){var i={},o=0,s={uint8:oe,uint16:se};function f(e){this.id=o++,i[this.id]=this,this.buffer=e,this.primType=4,this.vertCount=0,this.type=0}n.oes_element_index_uint&&(s.uint32=fe),f.prototype.bind=function(){this.buffer.bind()};var c=[];function u(a,i,o,s,f,c,u){var l;if(a.buffer.bind(),i){var d=u;u||e(i)&&(!N(i)||e(i.data))||(d=n.oes_element_index_uint?fe:se),r._initBuffer(a.buffer,i,o,d,3)}else t.bufferData(ce,c,o),a.buffer.dtype=l||oe,a.buffer.usage=o,a.buffer.dimension=3,a.buffer.byteLength=c;if(l=u,!u){switch(a.buffer.dtype){case oe:case 5120:l=oe;break;case se:case 5122:l=se;break;case fe:case 5124:l=fe;break;default:k.raise("unsupported type for element array")}a.buffer.dtype=l}a.type=l,k(l!==fe||!!n.oes_element_index_uint,"32 bit element buffers not supported, enable oes_element_index_uint first");var p=f;p<0&&(p=a.buffer.byteLength,l===se?p>>=1:l===fe&&(p>>=2)),a.vertCount=p;var m=s;if(s<0){m=4;var h=a.buffer.dimension;1===h&&(m=0),2===h&&(m=1),3===h&&(m=4)}a.primType=m}function l(e){a.elementsCount--,k(null!==e.buffer,"must not double destroy elements"),delete i[e.id],e.buffer.destroy(),e.buffer=null}return{create:function(t,n){var i=r.create(null,ce,!0),o=new f(i._buffer);function c(t){if(t)if("number"==typeof t)i(t),o.primType=4,o.vertCount=0|t,o.type=oe;else{var n=null,r=35044,a=-1,f=-1,l=0,d=0;Array.isArray(t)||e(t)||N(t)?n=t:(k.type(t,"object","invalid arguments for elements"),"data"in t&&(n=t.data,k(Array.isArray(n)||e(n)||N(n),"invalid data for element buffer")),"usage"in t&&(k.parameter(t.usage,X,"invalid element buffer usage"),r=X[t.usage]),"primitive"in t&&(k.parameter(t.primitive,ie,"invalid element buffer primitive"),a=ie[t.primitive]),"count"in t&&(k("number"==typeof t.count&&t.count>=0,"invalid vertex count for elements"),f=0|t.count),"type"in t&&(k.parameter(t.type,s,"invalid buffer type"),d=s[t.type]),"length"in t?l=0|t.length:(l=f,d===se||5122===d?l*=2:d!==fe&&5124!==d||(l*=4))),u(o,n,r,a,f,l,d)}else i(),o.primType=4,o.vertCount=0,o.type=oe;return c}return a.elementsCount++,c(t),c._reglType="elements",c._elements=o,c.subdata=function(e,t){return i.subdata(e,t),c},c.destroy=function(){l(o)},c},createStream:function(e){var t=c.pop();return t||(t=new f(r.create(null,ce,!0,!1)._buffer)),u(t,e,35040,-1,-1,0,0),t},destroyStream:function(e){c.push(e)},getElements:function(e){return"function"==typeof e&&e._elements instanceof f?e._elements:null},clear:function(){H(i).forEach(l)}}}(a,d,w,l),S=function(t,n,r,a,i,o,s){for(var f=r.maxAttributes,c=new Array(f),u=0;u{for(var e=Object.keys(t),n=0;n=0,'invalid option for vao: "'+e[n]+'" valid options are '+Et)})),k(Array.isArray(a),"attributes must be an array")}k(a.length0,"must specify at least one attribute");var u={},l=r.attributes;l.length=a.length;for(var d=0;d=v.byteLength?p.subdata(v):(p.destroy(),r.buffers[d]=null)),r.buffers[d]||(p=r.buffers[d]=i.create(m,34962,!1,!0)),h.buffer=i.getBuffer(p),h.size=0|h.buffer.dimension,h.normalized=!1,h.type=h.buffer.dtype,h.offset=0,h.stride=0,h.divisor=0,h.state=1,u[d]=1):i.getBuffer(m)?(h.buffer=i.getBuffer(m),h.size=0|h.buffer.dimension,h.normalized=!1,h.type=h.buffer.dtype,h.offset=0,h.stride=0,h.divisor=0,h.state=1):i.getBuffer(m.buffer)?(h.buffer=i.getBuffer(m.buffer),h.size=0|(+m.size||h.buffer.dimension),h.normalized=!!m.normalized||!1,"type"in m?(k.parameter(m.type,J,"invalid buffer type"),h.type=J[m.type]):h.type=h.buffer.dtype,h.offset=0|(m.offset||0),h.stride=0|(m.stride||0),h.divisor=0|(m.divisor||0),h.state=1,k(h.size>=1&&h.size<=4,"size must be between 1 and 4"),k(h.offset>=0,"invalid offset"),k(h.stride>=0&&h.stride<=255,"stride must be between 0 and 255"),k(h.divisor>=0,"divisor must be positive"),k(!h.divisor||!!n.angle_instanced_arrays,"ANGLE_instanced_arrays must be enabled to use divisor")):"x"in m?(k(d>0,"first attribute must not be a constant"),h.x=+m.x||0,h.y=+m.y||0,h.z=+m.z||0,h.w=+m.w||0,h.state=2):k(!1,"invalid attribute spec for location "+d)}for(var g=0;g1)for(var g=0;g1&&(y=y.replace("[0]","")),f(v,new s(y,n.id(y),e.getUniformLocation(p,y),u))}var w=e.getProgramParameter(p,35721);a.profile&&(t.stats.attributesCount=w);var x=t.attributes;for(o=0;oe&&(e=t.stats.uniformsCount)})),e},r.getMaxAttributesCount=function(){var e=0;return l.forEach((function(t){t.stats.attributesCount>e&&(e=t.stats.attributesCount)})),e}),{clear:function(){var t=e.deleteShader.bind(e);H(i).forEach(t),i={},H(o).forEach(t),o={},l.forEach((function(t){e.deleteProgram(t.program)})),l.length=0,u={},r.shaderCount=0},program:function(n,a,s,f){k.command(n>=0,"missing vertex shader",s),k.command(a>=0,"missing fragment shader",s);var c=u[a];c||(c=u[a]={});var d=c[n];if(d&&(d.refCount++,!f))return d;var h=new p(a,n);return r.shaderCount++,m(h,s,f),d||(c[n]=h),l.push(h),t(h,{destroy:function(){if(h.refCount--,h.refCount<=0){e.deleteProgram(h.program);var t=l.indexOf(h);l.splice(t,1),r.shaderCount--}c[h.vertId].refCount<=0&&(e.deleteShader(o[h.vertId]),delete o[h.vertId],delete u[h.fragId][h.vertId]),Object.keys(u[h.fragId]).length||(e.deleteShader(i[h.fragId]),delete i[h.fragId],delete u[h.fragId])}})},restore:function(){i={},o={};for(var e=0;e=2,"invalid renderbuffer shape"),s=0|p[0],f=0|p[1]}else"radius"in d&&(s=f=0|d.radius),"width"in d&&(s=0|d.width),"height"in d&&(f=0|d.height);"format"in d&&(k.parameter(d.format,i,"invalid renderbuffer format"),c=i[d.format])}else"number"==typeof t?(s=0|t,f="number"==typeof r?0|r:s):t?k.raise("invalid arguments to renderbuffer constructor"):s=f=1;if(k(s>0&&f>0&&s<=n.maxRenderbufferSize&&f<=n.maxRenderbufferSize,"invalid renderbuffer size"),s!==u.width||f!==u.height||c!==u.format)return l.width=u.width=s,l.height=u.height=f,u.format=c,e.bindRenderbuffer(pt,u.renderbuffer),e.renderbufferStorage(pt,c,s,f),k(0===e.getError(),"invalid render buffer format"),a.profile&&(u.stats.size=vt(u.format,u.width,u.height)),l.format=o[u.format],l}return f[u.id]=u,r.renderbufferCount++,l(t,s),l.resize=function(t,r){var i=0|t,o=0|r||i;return i===u.width&&o===u.height||(k(i>0&&o>0&&i<=n.maxRenderbufferSize&&o<=n.maxRenderbufferSize,"invalid renderbuffer size"),l.width=u.width=i,l.height=u.height=o,e.bindRenderbuffer(pt,u.renderbuffer),e.renderbufferStorage(pt,u.format,i,o),k(0===e.getError(),"invalid render buffer format"),a.profile&&(u.stats.size=vt(u.format,u.width,u.height))),l},l._reglType="renderbuffer",l._renderbuffer=u,a.profile&&(l.stats=u.stats),l.destroy=function(){u.decRef()},l},clear:function(){H(f).forEach(u)},restore:function(){H(f).forEach((function(t){t.renderbuffer=e.createRenderbuffer(),e.bindRenderbuffer(pt,t.renderbuffer),e.renderbufferStorage(pt,t.format,t.width,t.height)})),e.bindRenderbuffer(pt,null)}}}(a,d,y,l,r),E=function(e,n,r,a,i,o){var s={cur:null,next:null,dirty:!1,setFBO:null},f=["rgba"],c=["rgba4","rgb565","rgb5 a1"];n.ext_srgb&&c.push("srgba"),n.ext_color_buffer_half_float&&c.push("rgba16f","rgb16f"),n.webgl_color_buffer_float&&c.push("rgba32f");var u=["uint8"];function l(e,t,n){this.target=e,this.texture=t,this.renderbuffer=n;var r=0,a=0;t?(r=t.width,a=t.height):n&&(r=n.width,a=n.height),this.width=r,this.height=a}function d(e){e&&(e.texture&&e.texture._texture.decRef(),e.renderbuffer&&e.renderbuffer._renderbuffer.decRef())}function p(e,t,n){if(e)if(e.texture){var r=e.texture._texture,a=Math.max(1,r.width),i=Math.max(1,r.height);k(a===t&&i===n,"inconsistent width/height for supplied texture"),r.refCount+=1}else{var o=e.renderbuffer._renderbuffer;k(o.width===t&&o.height===n,"inconsistent width/height for renderbuffer"),o.refCount+=1}}function m(t,n){n&&(n.texture?e.framebufferTexture2D(gt,t,n.target,n.texture._texture.texture,0):e.framebufferRenderbuffer(gt,t,bt,n.renderbuffer._renderbuffer.renderbuffer))}function h(e){var t=yt,n=null,r=null,a=e;"object"==typeof e&&(a=e.data,"target"in e&&(t=0|e.target)),k.type(a,"function","invalid attachment data");var i=a._reglType;return"texture2d"===i?(n=a,k(t===yt)):"textureCube"===i?(n=a,k(t>=wt&&t<34075,"invalid cube map target")):"renderbuffer"===i?(r=a,t=bt):k.raise("invalid regl object for attachment"),new l(t,n,r)}function v(e,t,n,r,o){if(n){var s=a.create2D({width:e,height:t,format:r,type:o});return s._texture.refCount=0,new l(yt,s,null)}var f=i.create({width:e,height:t,format:r});return f._renderbuffer.refCount=0,new l(bt,null,f)}function g(e){return e&&(e.texture||e.renderbuffer)}function b(e,t,n){e&&(e.texture?e.texture.resize(t,n):e.renderbuffer&&e.renderbuffer.resize(t,n),e.width=t,e.height=n)}n.oes_texture_half_float&&u.push("half float","float16"),n.oes_texture_float&&u.push("float","float32");var y=0,w={};function x(){this.id=y++,w[this.id]=this,this.framebuffer=e.createFramebuffer(),this.width=0,this.height=0,this.colorAttachments=[],this.depthAttachment=null,this.stencilAttachment=null,this.depthStencilAttachment=null}function S(e){e.colorAttachments.forEach(d),d(e.depthAttachment),d(e.stencilAttachment),d(e.depthStencilAttachment)}function T(t){var n=t.framebuffer;k(n,"must not double destroy framebuffer"),e.deleteFramebuffer(n),t.framebuffer=null,o.framebufferCount--,delete w[t.id]}function A(t){var n;e.bindFramebuffer(gt,t.framebuffer);var a=t.colorAttachments;for(n=0;n=2,"invalid shape for framebuffer"),o=P[0],d=P[1]}else"radius"in M&&(o=d=M.radius),"width"in M&&(o=M.width),"height"in M&&(d=M.height);("color"in M||"colors"in M)&&(y=M.color||M.colors,Array.isArray(y)&&k(1===y.length||n.webgl_draw_buffers,"multiple render targets not supported")),y||("colorCount"in M&&(C=0|M.colorCount,k(C>0,"invalid color buffer count")),"colorTexture"in M&&(w=!!M.colorTexture,x="rgba4"),"colorType"in M&&(T=M.colorType,w?(k(n.oes_texture_float||!("float"===T||"float32"===T),"you must enable OES_texture_float in order to use floating point framebuffer objects"),k(n.oes_texture_half_float||!("half float"===T||"float16"===T),"you must enable OES_texture_half_float in order to use 16-bit floating point framebuffer objects")):"half float"===T||"float16"===T?(k(n.ext_color_buffer_half_float,"you must enable EXT_color_buffer_half_float to use 16-bit render buffers"),x="rgba16f"):"float"!==T&&"float32"!==T||(k(n.webgl_color_buffer_float,"you must enable WEBGL_color_buffer_float in order to use 32-bit floating point renderbuffers"),x="rgba32f"),k.oneOf(T,u,"invalid color type")),"colorFormat"in M&&(x=M.colorFormat,f.indexOf(x)>=0?w=!0:c.indexOf(x)>=0?w=!1:k.optional((function(){w?k.oneOf(M.colorFormat,f,"invalid color format for texture"):k.oneOf(M.colorFormat,c,"invalid color format for renderbuffer")})))),("depthTexture"in M||"depthStencilTexture"in M)&&(D=!(!M.depthTexture&&!M.depthStencilTexture),k(!D||n.webgl_depth_texture,"webgl_depth_texture extension not supported")),"depth"in M&&("boolean"==typeof M.depth?m=M.depth:(E=M.depth,b=!1)),"stencil"in M&&("boolean"==typeof M.stencil?b=M.stencil:(_=M.stencil,m=!1)),"depthStencil"in M&&("boolean"==typeof M.depthStencil?m=b=M.depthStencil:(O=M.depthStencil,m=!1,b=!1))}else o=d=1;var R=null,j=null,F=null,L=null;if(Array.isArray(y))R=y.map(h);else if(y)R=[h(y)];else for(R=new Array(C),a=0;a=0||R[a].renderbuffer&&Tt.indexOf(R[a].renderbuffer._renderbuffer.format)>=0,"framebuffer color attachment "+a+" is invalid"),R[a]&&R[a].texture){var z=St[R[a].texture._texture.format]*kt[R[a].texture._texture.type];null===I?I=z:k(I===z,"all color attachments much have the same number of bits per pixel.")}return p(j,o,d),k(!j||j.texture&&6402===j.texture._texture.format||j.renderbuffer&&33189===j.renderbuffer._renderbuffer.format,"invalid depth attachment for framebuffer object"),p(F,o,d),k(!F||F.renderbuffer&&36168===F.renderbuffer._renderbuffer.format,"invalid stencil attachment for framebuffer object"),p(L,o,d),k(!L||L.texture&&34041===L.texture._texture.format||L.renderbuffer&&34041===L.renderbuffer._renderbuffer.format,"invalid depth-stencil attachment for framebuffer object"),S(i),i.width=o,i.height=d,i.colorAttachments=R,i.depthAttachment=j,i.stencilAttachment=F,i.depthStencilAttachment=L,l.color=R.map(g),l.depth=g(j),l.stencil=g(F),l.depthStencil=g(L),l.width=i.width,l.height=i.height,A(i),l}return o.framebufferCount++,l(e,a),t(l,{resize:function(e,t){k(s.next!==i,"can not resize a framebuffer which is currently in use");var n=Math.max(0|e,1),r=Math.max(0|t||n,1);if(n===i.width&&r===i.height)return l;for(var a=i.colorAttachments,o=0;o=2,"invalid shape for framebuffer"),k(b[0]===b[1],"cube framebuffer must be square"),d=b[0]}else"radius"in g&&(d=0|g.radius),"width"in g?(d=0|g.width,"height"in g&&k(g.height===d,"must be square")):"height"in g&&(d=0|g.height);("color"in g||"colors"in g)&&(p=g.color||g.colors,Array.isArray(p)&&k(1===p.length||n.webgl_draw_buffers,"multiple render targets not supported")),p||("colorCount"in g&&(v=0|g.colorCount,k(v>0,"invalid color buffer count")),"colorType"in g&&(k.oneOf(g.colorType,u,"invalid color type"),h=g.colorType),"colorFormat"in g&&(m=g.colorFormat,k.oneOf(g.colorFormat,f,"invalid color format for texture"))),"depth"in g&&(l.depth=g.depth),"stencil"in g&&(l.stencil=g.stencil),"depthStencil"in g&&(l.depthStencil=g.depthStencil)}else d=1;if(p)if(Array.isArray(p))for(c=[],r=0;r0&&(l.depth=i[0].depth,l.stencil=i[0].stencil,l.depthStencil=i[0].depthStencil),i[r]?i[r](l):i[r]=C(l)}return t(o,{width:d,height:d,color:c})}return o(e),t(o,{faces:i,resize:function(e){var t,n=0|e;if(k(n>0&&n<=r.maxCubeMapSize,"invalid radius for cube fbo"),n===o.width)return o;var a=o.color;for(t=0;t=0;--e){var t=L[e];t&&t(g,null,0)}a.flush(),p&&p.update()}function ue(){!Q&&L.length>0&&(Q=D.next(Y))}function le(){Q&&(D.cancel(Y),Q=null)}function de(e){e.preventDefault(),o=!0,le(),I.forEach((function(e){e()}))}function pe(e){a.getError(),o=!1,s.restore(),T.restore(),w.restore(),A.restore(),C.restore(),E.restore(),S.restore(),p&&p.restore(),_.procs.refresh(),ue(),q.forEach((function(e){e()}))}function me(e){function n(e,t){var n={},r={};return Object.keys(e).forEach((function(a){var i=e[a];if(O.isDynamic(i))r[a]=O.unbox(i,a);else{if(t&&Array.isArray(i))for(var o=0;o0)return l.call(this,function(e){for(;p.length=0,"cannot cancel a frame twice"),L[t]=function e(){var t=dr(L,e);L[t]=L[L.length-1],L.length-=1,L.length<=0&&le()}}}}function be(){var e=R.viewport,t=R.scissor_box;e[0]=e[1]=t[0]=t[1]=0,g.viewportWidth=g.framebufferWidth=g.drawingBufferWidth=e[2]=t[2]=a.drawingBufferWidth,g.viewportHeight=g.framebufferHeight=g.drawingBufferHeight=e[3]=t[3]=a.drawingBufferHeight}function ye(){g.tick+=1,g.time=xe(),be(),_.procs.poll()}function we(){A.refresh(),be(),_.procs.refresh(),p&&p.update()}function xe(){return(M()-m)/1e3}we();var Se=t(me,{clear:function(e){if(k("object"==typeof e&&e,"regl.clear() takes an object as input"),"framebuffer"in e)if(e.framebuffer&&"framebufferCube"===e.framebuffer_reglType)for(var n=0;n<6;++n)he(t({framebuffer:e.framebuffer.faces[n]},e),ve);else he(e,ve);else ve(0,e)},prop:O.define.bind(null,1),context:O.define.bind(null,2),this:O.define.bind(null,3),draw:me({}),buffer:function(e){return w.create(e,34962,!1,!1)},elements:function(e){return x.create(e,!1)},texture:A.create2D,cube:A.createCube,renderbuffer:C.create,framebuffer:E.create,framebufferCube:E.createCube,vao:S.createVAO,attributes:i,frame:ge,on:function(e,t){var n;switch(k.type(t,"function","listener callback must be a function"),e){case"frame":return ge(t);case"lost":n=I;break;case"restore":n=q;break;case"destroy":n=W;break;default:k.raise("invalid event, must be one of frame,lost,restore,destroy")}return n.push(t),{cancel:function(){for(var e=0;e=0},read:P,destroy:function(){L.length=0,le(),F&&(F.removeEventListener(ur,de),F.removeEventListener(lr,pe)),T.clear(),E.clear(),C.clear(),S.clear(),A.clear(),x.clear(),w.clear(),p&&p.clear(),W.forEach((function(e){e()}))},_gl:a,_refresh:we,poll:function(){ye(),p&&p.update()},now:xe,stats:l});return r.onDone(null,Se),Se}}));var s;i.register("utuk7",(function(e,t){var n=!0,r={disableLog:function(e){return"boolean"!=typeof e?new Error("Argument type: "+typeof e+". Please use a boolean."):(n=e,e?"adapter.js logging disabled":"adapter.js logging enabled")},log:function(){if("object"==typeof window){if(n)return;"undefined"!=typeof console&&"function"==typeof console.log&&console.log.apply(console,arguments)}},extractVersion:function(e,t,n){var r=e.match(t);return r&&r.length>=n&&parseInt(r[n],10)},detectBrowser:function(){var e={browser:null,version:null};if("undefined"==typeof window||!window.navigator)return e.browser="Not a browser.",e;if(navigator.mozGetUserMedia)e.browser="firefox",e.version=this.extractVersion(navigator.userAgent,/Firefox\/([0-9]+)\./,1);else if(navigator.webkitGetUserMedia)if(window.webkitRTCPeerConnection)e.browser="chrome",e.version=this.extractVersion(navigator.userAgent,/Chrom(e|ium)\/([0-9]+)\./,2);else{if(!navigator.userAgent.match(/Version\/(\d+).(\d+)/))return e.browser="Unsupported webkit-based browser with GUM support but no WebRTC support.",e;e.browser="safari",e.version=this.extractVersion(navigator.userAgent,/AppleWebKit\/([0-9]+)\./,1)}else{if(!navigator.mediaDevices||!navigator.userAgent.match(/Edge\/(\d+).(\d+)$/))return e.browser="Not a supported browser.",e;e.browser="edge",e.version=this.extractVersion(navigator.userAgent,/Edge\/(\d+).(\d+)$/,2)}return e}};e.exports={log:r.log,disableLog:r.disableLog,browserDetails:r.detectBrowser(),extractVersion:r.extractVersion}})),i.register("9VqdB",(function(e,t){var n=i("utuk7").log,r=i("utuk7").browserDetails,a={shimMediaStream:function(){window.MediaStream=window.MediaStream||window.webkitMediaStream},shimOnTrack:function(){"object"==typeof window&&window.RTCPeerConnection&&!("ontrack"in window.RTCPeerConnection.prototype)&&Object.defineProperty(window.RTCPeerConnection.prototype,"ontrack",{get:function(){return this._ontrack},set:function(e){var t=this;this._ontrack&&(this.removeEventListener("track",this._ontrack),this.removeEventListener("addstream",this._ontrackpoly)),this.addEventListener("track",this._ontrack=e),this.addEventListener("addstream",this._ontrackpoly=function(e){e.stream.addEventListener("addtrack",(function(n){var r=new Event("track");r.track=n.track,r.receiver={track:n.track},r.streams=[e.stream],t.dispatchEvent(r)})),e.stream.getTracks().forEach(function(t){var n=new Event("track");n.track=t,n.receiver={track:t},n.streams=[e.stream],this.dispatchEvent(n)}.bind(this))}.bind(this))}})},shimSourceObject:function(){"object"==typeof window&&window.HTMLMediaElement&&!("srcObject"in window.HTMLMediaElement.prototype)&&Object.defineProperty(window.HTMLMediaElement.prototype,"srcObject",{get:function(){return this._srcObject},set:function(e){var t=this;this._srcObject=e,this.src&&URL.revokeObjectURL(this.src),e?(this.src=URL.createObjectURL(e),e.addEventListener("addtrack",(function(){t.src&&URL.revokeObjectURL(t.src),t.src=URL.createObjectURL(e)})),e.addEventListener("removetrack",(function(){t.src&&URL.revokeObjectURL(t.src),t.src=URL.createObjectURL(e)}))):this.src=""}})},shimPeerConnection:function(){window.RTCPeerConnection=function(e,t){n("PeerConnection"),e&&e.iceTransportPolicy&&(e.iceTransports=e.iceTransportPolicy);var r=new webkitRTCPeerConnection(e,t),a=r.getStats.bind(r);return r.getStats=function(e,t,n){var r=this,i=arguments;if(arguments.length>0&&"function"==typeof e)return a(e,t);var o=function(e){var t={};return e.result().forEach((function(e){var n={id:e.id,timestamp:e.timestamp,type:e.type};e.names().forEach((function(t){n[t]=e.stat(t)})),t[n.id]=n})),t},s=function(e,t){var n=new Map(Object.keys(e).map((function(t){return[t,e[t]]})));return t=t||e,Object.keys(t).forEach((function(e){n[e]=t[e]})),n};if(arguments.length>=2){var f=function(e){i[1](s(o(e)))};return a.apply(this,[f,arguments[0]])}return new Promise((function(t,n){1===i.length&&"object"==typeof e?a.apply(r,[function(e){t(s(o(e)))},n]):a.apply(r,[function(e){t(s(o(e),e.result()))},n])})).then(t,n)},r},window.RTCPeerConnection.prototype=webkitRTCPeerConnection.prototype,webkitRTCPeerConnection.generateCertificate&&Object.defineProperty(window.RTCPeerConnection,"generateCertificate",{get:function(){return webkitRTCPeerConnection.generateCertificate}}),["createOffer","createAnswer"].forEach((function(e){var t=webkitRTCPeerConnection.prototype[e];webkitRTCPeerConnection.prototype[e]=function(){var e=this;if(arguments.length<1||1===arguments.length&&"object"==typeof arguments[0]){var n=1===arguments.length?arguments[0]:void 0;return new Promise((function(r,a){t.apply(e,[r,a,n])}))}return t.apply(this,arguments)}})),r.version<51&&["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach((function(e){var t=webkitRTCPeerConnection.prototype[e];webkitRTCPeerConnection.prototype[e]=function(){var e=arguments,n=this,r=new Promise((function(r,a){t.apply(n,[e[0],r,a])}));return e.length<2?r:r.then((function(){e[1].apply(null,[])}),(function(t){e.length>=3&&e[2].apply(null,[t])}))}})),["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach((function(e){var t=webkitRTCPeerConnection.prototype[e];webkitRTCPeerConnection.prototype[e]=function(){return arguments[0]=new("addIceCandidate"===e?RTCIceCandidate:RTCSessionDescription)(arguments[0]),t.apply(this,arguments)}}));var e=RTCPeerConnection.prototype.addIceCandidate;RTCPeerConnection.prototype.addIceCandidate=function(){return arguments[0]?e.apply(this,arguments):(arguments[1]&&arguments[1].apply(null),Promise.resolve())}}};e.exports={shimMediaStream:a.shimMediaStream,shimOnTrack:a.shimOnTrack,shimSourceObject:a.shimSourceObject,shimPeerConnection:a.shimPeerConnection,shimGetUserMedia:i("bXw2P")}})),i.register("bXw2P",(function(e,t){var n=i("utuk7").log;e.exports=function(){var e=function(e){if("object"!=typeof e||e.mandatory||e.optional)return e;var t={};return Object.keys(e).forEach((function(n){if("require"!==n&&"advanced"!==n&&"mediaSource"!==n){var r="object"==typeof e[n]?e[n]:{ideal:e[n]};void 0!==r.exact&&"number"==typeof r.exact&&(r.min=r.max=r.exact);var a=function(e,t){return e?e+t.charAt(0).toUpperCase()+t.slice(1):"deviceId"===t?"sourceId":t};if(void 0!==r.ideal){t.optional=t.optional||[];var i={};"number"==typeof r.ideal?(i[a("min",n)]=r.ideal,t.optional.push(i),(i={})[a("max",n)]=r.ideal,t.optional.push(i)):(i[a("",n)]=r.ideal,t.optional.push(i))}void 0!==r.exact&&"number"!=typeof r.exact?(t.mandatory=t.mandatory||{},t.mandatory[a("",n)]=r.exact):["min","max"].forEach((function(e){void 0!==r[e]&&(t.mandatory=t.mandatory||{},t.mandatory[a(e,n)]=r[e])}))}})),e.advanced&&(t.optional=(t.optional||[]).concat(e.advanced)),t},t=function(t,r){if((t=JSON.parse(JSON.stringify(t)))&&t.audio&&(t.audio=e(t.audio)),t&&"object"==typeof t.video){var a=t.video.facingMode;if((a=a&&("object"==typeof a?a:{ideal:a}))&&("user"===a.exact||"environment"===a.exact||"user"===a.ideal||"environment"===a.ideal)&&(!navigator.mediaDevices.getSupportedConstraints||!navigator.mediaDevices.getSupportedConstraints().facingMode)&&(delete t.video.facingMode,"environment"===a.exact||"environment"===a.ideal))return navigator.mediaDevices.enumerateDevices().then((function(i){var o=(i=i.filter((function(e){return"videoinput"===e.kind}))).find((function(e){return-1!==e.label.toLowerCase().indexOf("back")}))||i.length&&i[i.length-1];return o&&(t.video.deviceId=a.exact?{exact:o.deviceId}:{ideal:o.deviceId}),t.video=e(t.video),n("chrome: "+JSON.stringify(t)),r(t)}));t.video=e(t.video)}return n("chrome: "+JSON.stringify(t)),r(t)},r=function(e){return{name:{PermissionDeniedError:"NotAllowedError",ConstraintNotSatisfiedError:"OverconstrainedError"}[e.name]||e.name,message:e.message,constraint:e.constraintName,toString:function(){return this.name+(this.message&&": ")+this.message}}};navigator.getUserMedia=function(e,n,a){t(e,(function(e){navigator.webkitGetUserMedia(e,n,(function(e){a(r(e))}))}))};var a=function(e){return new Promise((function(t,n){navigator.getUserMedia(e,t,n)}))};if(navigator.mediaDevices||(navigator.mediaDevices={getUserMedia:a,enumerateDevices:function(){return new Promise((function(e){var t={audio:"audioinput",video:"videoinput"};return MediaStreamTrack.getSources((function(n){e(n.map((function(e){return{label:e.label,kind:t[e.kind],deviceId:e.id,groupId:""}})))}))}))}}),navigator.mediaDevices.getUserMedia){var i=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(e){return t(e,(function(e){return i(e).then((function(t){if(e.audio&&!t.getAudioTracks().length||e.video&&!t.getVideoTracks().length)throw t.getTracks().forEach((function(e){e.stop()})),new DOMException("","NotFoundError");return t}),(function(e){return Promise.reject(r(e))}))}))}}else navigator.mediaDevices.getUserMedia=function(e){return a(e)};void 0===navigator.mediaDevices.addEventListener&&(navigator.mediaDevices.addEventListener=function(){n("Dummy mediaDevices.addEventListener called.")}),void 0===navigator.mediaDevices.removeEventListener&&(navigator.mediaDevices.removeEventListener=function(){n("Dummy mediaDevices.removeEventListener called.")})}})),i.register("h6FP9",(function(e,t){var n=i("eljpv"),r=i("utuk7").browserDetails,a={shimPeerConnection:function(){if(window.RTCIceGatherer){window.RTCIceCandidate||(window.RTCIceCandidate=function(e){return e}),window.RTCSessionDescription||(window.RTCSessionDescription=function(e){return e});var e=Object.getOwnPropertyDescriptor(MediaStreamTrack.prototype,"enabled");Object.defineProperty(MediaStreamTrack.prototype,"enabled",{set:function(t){e.set.call(this,t);var n=new Event("enabled");n.enabled=t,this.dispatchEvent(n)}})}window.RTCPeerConnection=function(e){var t=this,n=document.createDocumentFragment();if(["addEventListener","removeEventListener","dispatchEvent"].forEach((function(e){t[e]=n[e].bind(n)})),this.onicecandidate=null,this.onaddstream=null,this.ontrack=null,this.onremovestream=null,this.onsignalingstatechange=null,this.oniceconnectionstatechange=null,this.onnegotiationneeded=null,this.ondatachannel=null,this.localStreams=[],this.remoteStreams=[],this.getLocalStreams=function(){return t.localStreams},this.getRemoteStreams=function(){return t.remoteStreams},this.localDescription=new RTCSessionDescription({type:"",sdp:""}),this.remoteDescription=new RTCSessionDescription({type:"",sdp:""}),this.signalingState="stable",this.iceConnectionState="new",this.iceGatheringState="new",this.iceOptions={gatherPolicy:"all",iceServers:[]},e&&e.iceTransportPolicy)switch(e.iceTransportPolicy){case"all":case"relay":this.iceOptions.gatherPolicy=e.iceTransportPolicy;break;case"none":throw new TypeError('iceTransportPolicy "none" not supported')}if(this.usingBundle=e&&"max-bundle"===e.bundlePolicy,e&&e.iceServers){var a=JSON.parse(JSON.stringify(e.iceServers));this.iceOptions.iceServers=a.filter((function(e){if(e&&e.urls){var t=e.urls;return"string"==typeof t&&(t=[t]),!!(t=t.filter((function(e){return 0===e.indexOf("turn:")&&-1!==e.indexOf("transport=udp")&&-1===e.indexOf("turn:[")||0===e.indexOf("stun:")&&r.version>=14393}))[0])}return!1}))}this._config=e,this.transceivers=[],this._localIceCandidatesBuffer=[]},window.RTCPeerConnection.prototype._emitBufferedCandidates=function(){var e=this,t=n.splitSections(e.localDescription.sdp);this._localIceCandidatesBuffer.forEach((function(n){if(!n.candidate||0===Object.keys(n.candidate).length)for(var r=1;r-1&&(this.localStreams.splice(t,1),this._maybeFireNegotiationNeeded())},window.RTCPeerConnection.prototype.getSenders=function(){return this.transceivers.filter((function(e){return!!e.rtpSender})).map((function(e){return e.rtpSender}))},window.RTCPeerConnection.prototype.getReceivers=function(){return this.transceivers.filter((function(e){return!!e.rtpReceiver})).map((function(e){return e.rtpReceiver}))},window.RTCPeerConnection.prototype._getCommonCapabilities=function(e,t){var n={codecs:[],headerExtensions:[],fecMechanisms:[]};return e.codecs.forEach((function(e){for(var r=0;r0;t.forEach((function(e,t){var o=a.transceivers[t],s=o.iceGatherer,f=o.iceTransport,c=o.dtlsTransport,u=o.localCapabilities,l=o.remoteCapabilities;if(!("0"===e.split("\n",1)[0].split(" ",2)[1])&&!o.isDatachannel){var d=n.getIceParameters(e,r);if(i){var p=n.matchPrefix(e,"a=candidate:").map((function(e){return n.parseCandidate(e)})).filter((function(e){return"1"===e.component}));p.length&&f.setRemoteCandidates(p)}var m=n.getDtlsParameters(e,r);i&&(m.role="server"),a.usingBundle&&0!==t||(f.start(s,d,i?"controlling":"controlled"),c.start(m));var h=a._getCommonCapabilities(u,l);a._transceive(o,h.codecs.length>0,!1)}}))}switch(this.localDescription={type:e.type,sdp:e.sdp},e.type){case"offer":this._updateSignalingState("have-local-offer");break;case"answer":this._updateSignalingState("stable");break;default:throw new TypeError('unsupported type "'+e.type+'"')}var o=arguments.length>1&&"function"==typeof arguments[1];if(o){var s=arguments[1];window.setTimeout((function(){s(),"new"===a.iceGatheringState&&(a.iceGatheringState="gathering"),a._emitBufferedCandidates()}),0)}var f=Promise.resolve();return f.then((function(){o||("new"===a.iceGatheringState&&(a.iceGatheringState="gathering"),window.setTimeout(a._emitBufferedCandidates.bind(a),500))})),f},window.RTCPeerConnection.prototype.setRemoteDescription=function(e){var t=this,r=new MediaStream,a=[],i=n.splitSections(e.sdp),o=i.shift(),s=n.matchPrefix(o,"a=ice-lite").length>0;switch(this.usingBundle=n.matchPrefix(o,"a=group:BUNDLE ").length>0,i.forEach((function(i,f){var c=n.splitLines(i)[0].substr(2).split(" "),u=c[0],l="0"===c[1],d=n.getDirection(i,o),p=n.matchPrefix(i,"a=mid:");if(p=p.length?p[0].substr(6):n.generateIdentifier(),"application"!==u||"DTLS/SCTP"!==c[2]){var m,h,v,g,b,y,w,x,S,k,T,A,C,E=n.parseRtpParameters(i);l||(T=n.getIceParameters(i,o),(A=n.getDtlsParameters(i,o)).role="client"),x=n.parseRtpEncodingParameters(i);var _=n.matchPrefix(i,"a=ssrc:").map((function(e){return n.parseSsrcMedia(e)})).filter((function(e){return"cname"===e.attribute}))[0];_&&(C=_.value);var O=n.matchPrefix(i,"a=end-of-candidates",o).length>0,D=n.matchPrefix(i,"a=candidate:").map((function(e){return n.parseCandidate(e)})).filter((function(e){return"1"===e.component}));if("offer"!==e.type||l)"answer"!==e.type||l||(h=(m=t.transceivers[f]).iceGatherer,v=m.iceTransport,g=m.dtlsTransport,b=m.rtpSender,y=m.rtpReceiver,w=m.sendEncodingParameters,S=m.localCapabilities,t.transceivers[f].recvEncodingParameters=x,t.transceivers[f].remoteCapabilities=E,t.transceivers[f].cname=C,(s||O)&&D.length&&v.setRemoteCandidates(D),t.usingBundle&&0!==f||(v.start(h,T,"controlling"),g.start(A)),t._transceive(m,"sendrecv"===d||"recvonly"===d,"sendrecv"===d||"sendonly"===d),!y||"sendrecv"!==d&&"sendonly"!==d?delete m.rtpReceiver:(k=y.track,a.push([k,y]),r.addTrack(k)));else{var M,P=t.usingBundle&&f>0?{iceGatherer:t.transceivers[0].iceGatherer,iceTransport:t.transceivers[0].iceTransport,dtlsTransport:t.transceivers[0].dtlsTransport}:t._createIceAndDtlsTransports(p,f);if(O&&P.iceTransport.setRemoteCandidates(D),(S=RTCRtpReceiver.getCapabilities(u)).codecs=S.codecs.filter((function(e){return"rtx"!==e.name})),w=[{ssrc:1001*(2*f+2)}],k=(y=new RTCRtpReceiver(P.dtlsTransport,u)).track,a.push([k,y]),r.addTrack(k),t.localStreams.length>0&&t.localStreams[0].getTracks().length>=f)"audio"===u?M=t.localStreams[0].getAudioTracks()[0]:"video"===u&&(M=t.localStreams[0].getVideoTracks()[0]),M&&(b=new RTCRtpSender(M,P.dtlsTransport));t.transceivers[f]={iceGatherer:P.iceGatherer,iceTransport:P.iceTransport,dtlsTransport:P.dtlsTransport,localCapabilities:S,remoteCapabilities:E,rtpSender:b,rtpReceiver:y,kind:u,mid:p,cname:C,sendEncodingParameters:w,recvEncodingParameters:x},t._transceive(t.transceivers[f],!1,"sendrecv"===d||"sendonly"===d)}}else t.transceivers[f]={mid:p,isDatachannel:!0}})),this.remoteDescription={type:e.type,sdp:e.sdp},e.type){case"offer":this._updateSignalingState("have-remote-offer");break;case"answer":this._updateSignalingState("stable");break;default:throw new TypeError('unsupported type "'+e.type+'"')}return r.getTracks().length&&(t.remoteStreams.push(r),window.setTimeout((function(){var e=new Event("addstream");e.stream=r,t.dispatchEvent(e),null!==t.onaddstream&&window.setTimeout((function(){t.onaddstream(e)}),0),a.forEach((function(n){var a=n[0],i=n[1],o=new Event("track");o.track=a,o.receiver=i,o.streams=[r],t.dispatchEvent(e),null!==t.ontrack&&window.setTimeout((function(){t.ontrack(o)}),0)}))}),0)),arguments.length>1&&"function"==typeof arguments[1]&&window.setTimeout(arguments[1],0),Promise.resolve()},window.RTCPeerConnection.prototype.close=function(){this.transceivers.forEach((function(e){e.iceTransport&&e.iceTransport.stop(),e.dtlsTransport&&e.dtlsTransport.stop(),e.rtpSender&&e.rtpSender.stop(),e.rtpReceiver&&e.rtpReceiver.stop()})),this._updateSignalingState("closed")},window.RTCPeerConnection.prototype._updateSignalingState=function(e){this.signalingState=e;var t=new Event("signalingstatechange");this.dispatchEvent(t),null!==this.onsignalingstatechange&&this.onsignalingstatechange(t)},window.RTCPeerConnection.prototype._maybeFireNegotiationNeeded=function(){var e=new Event("negotiationneeded");this.dispatchEvent(e),null!==this.onnegotiationneeded&&this.onnegotiationneeded(e)},window.RTCPeerConnection.prototype._updateConnectionState=function(){var e,t={new:0,closed:0,connecting:0,checking:0,connected:0,completed:0,failed:0};if(this.transceivers.forEach((function(e){t[e.iceTransport.state]++,t[e.dtlsTransport.state]++})),t.connected+=t.completed,e="new",t.failed>0?e="failed":t.connecting>0||t.checking>0?e="connecting":t.disconnected>0?e="disconnected":t.new>0?e="new":(t.connected>0||t.completed>0)&&(e="connected"),e!==this.iceConnectionState){this.iceConnectionState=e;var n=new Event("iceconnectionstatechange");this.dispatchEvent(n),null!==this.oniceconnectionstatechange&&this.oniceconnectionstatechange(n)}},window.RTCPeerConnection.prototype.createOffer=function(){var e,t=this;if(this._pendingOffer)throw new Error("createOffer called while there is a pending offer.");1===arguments.length&&"function"!=typeof arguments[0]?e=arguments[0]:3===arguments.length&&(e=arguments[2]);var r=[],a=0,i=0;if(this.localStreams.length&&(a=this.localStreams[0].getAudioTracks().length,i=this.localStreams[0].getVideoTracks().length),e){if(e.mandatory||e.optional)throw new TypeError("Legacy mandatory/optional constraints not supported.");void 0!==e.offerToReceiveAudio&&(a=e.offerToReceiveAudio),void 0!==e.offerToReceiveVideo&&(i=e.offerToReceiveVideo)}for(this.localStreams.length&&this.localStreams[0].getTracks().forEach((function(e){r.push({kind:e.kind,track:e,wantReceive:"audio"===e.kind?a>0:i>0}),"audio"===e.kind?a--:"video"===e.kind&&i--}));a>0||i>0;)a>0&&(r.push({kind:"audio",wantReceive:!0}),a--),i>0&&(r.push({kind:"video",wantReceive:!0}),i--);var o=n.writeSessionBoilerplate(),s=[];r.forEach((function(e,r){var a,i,o=e.track,f=e.kind,c=n.generateIdentifier(),u=t.usingBundle&&r>0?{iceGatherer:s[0].iceGatherer,iceTransport:s[0].iceTransport,dtlsTransport:s[0].dtlsTransport}:t._createIceAndDtlsTransports(c,r),l=RTCRtpSender.getCapabilities(f);l.codecs=l.codecs.filter((function(e){return"rtx"!==e.name})),l.codecs.forEach((function(e){"H264"===e.name&&void 0===e.parameters["level-asymmetry-allowed"]&&(e.parameters["level-asymmetry-allowed"]="1")}));var d=[{ssrc:1001*(2*r+1)}];o&&(a=new RTCRtpSender(o,u.dtlsTransport)),e.wantReceive&&(i=new RTCRtpReceiver(u.dtlsTransport,f)),s[r]={iceGatherer:u.iceGatherer,iceTransport:u.iceTransport,dtlsTransport:u.dtlsTransport,localCapabilities:l,remoteCapabilities:null,rtpSender:a,rtpReceiver:i,kind:f,mid:c,sendEncodingParameters:d,recvEncodingParameters:null}})),this.usingBundle&&(o+="a=group:BUNDLE "+s.map((function(e){return e.mid})).join(" ")+"\r\n"),r.forEach((function(e,r){var a=s[r];o+=n.writeMediaSection(a,a.localCapabilities,"offer",t.localStreams[0])})),this._pendingOffer=s;var f=new RTCSessionDescription({type:"offer",sdp:o});return arguments.length&&"function"==typeof arguments[0]&&window.setTimeout(arguments[0],0,f),Promise.resolve(f)},window.RTCPeerConnection.prototype.createAnswer=function(){var e=this,t=n.writeSessionBoilerplate();this.usingBundle&&(t+="a=group:BUNDLE "+this.transceivers.map((function(e){return e.mid})).join(" ")+"\r\n"),this.transceivers.forEach((function(r){if(r.isDatachannel)t+="m=application 0 DTLS/SCTP 5000\r\nc=IN IP4 0.0.0.0\r\na=mid:"+r.mid+"\r\n";else{var a=e._getCommonCapabilities(r.localCapabilities,r.remoteCapabilities);t+=n.writeMediaSection(r,a,"answer",e.localStreams[0])}}));var r=new RTCSessionDescription({type:"answer",sdp:t});return arguments.length&&"function"==typeof arguments[0]&&window.setTimeout(arguments[0],0,r),Promise.resolve(r)},window.RTCPeerConnection.prototype.addIceCandidate=function(e){if(e){var t=e.sdpMLineIndex;if(e.sdpMid)for(var r=0;r0?n.parseCandidate(e.candidate):{};if("tcp"===i.protocol&&(0===i.port||9===i.port))return;if("1"!==i.component)return;"endOfCandidates"===i.type&&(i={}),a.iceTransport.addRemoteCandidate(i);var o=n.splitSections(this.remoteDescription.sdp);o[t+1]+=(i.type?e.candidate.trim():"a=end-of-candidates")+"\r\n",this.remoteDescription.sdp=o.join("")}}else this.transceivers.forEach((function(e){e.iceTransport.addRemoteCandidate({})}));return arguments.length>1&&"function"==typeof arguments[1]&&window.setTimeout(arguments[1],0),Promise.resolve()},window.RTCPeerConnection.prototype.getStats=function(){var e=[];this.transceivers.forEach((function(t){["rtpSender","rtpReceiver","iceGatherer","iceTransport","dtlsTransport"].forEach((function(n){t[n]&&e.push(t[n].getStats())}))}));var t=arguments.length>1&&"function"==typeof arguments[1]&&arguments[1];return new Promise((function(n){var r=new Map;Promise.all(e).then((function(e){e.forEach((function(e){Object.keys(e).forEach((function(t){r.set(t,e[t]),r[t]=e[t]}))})),t&&window.setTimeout(t,0,r),n(r)}))}))}}};e.exports={shimPeerConnection:a.shimPeerConnection,shimGetUserMedia:i("1vuwg")}})),i.register("eljpv",(function(e,t){var n={generateIdentifier:function(){return Math.random().toString(36).substr(2,10)}};n.localCName=n.generateIdentifier(),n.splitLines=function(e){return e.trim().split("\n").map((function(e){return e.trim()}))},n.splitSections=function(e){return e.split("\nm=").map((function(e,t){return(t>0?"m="+e:e).trim()+"\r\n"}))},n.matchPrefix=function(e,t){return n.splitLines(e).filter((function(e){return 0===e.indexOf(t)}))},n.parseCandidate=function(e){for(var t,n={foundation:(t=0===e.indexOf("a=candidate:")?e.substring(12).split(" "):e.substring(10).split(" "))[0],component:t[1],protocol:t[2].toLowerCase(),priority:parseInt(t[3],10),ip:t[4],port:parseInt(t[5],10),type:t[7]},r=8;r0?t[0].split("/")[1]:"sendrecv",uri:t[1]}},n.writeExtmap=function(e){return"a=extmap:"+(e.id||e.preferredId)+(e.direction&&"sendrecv"!==e.direction?"/"+e.direction:"")+" "+e.uri+"\r\n"},n.parseFmtp=function(e){for(var t,n={},r=e.substr(e.indexOf(" ")+1).split(";"),a=0;a-1?(n.attribute=e.substr(t+1,r-t-1),n.value=e.substr(r+1)):n.attribute=e.substr(t+1),n},n.getMid=function(e){var t=n.matchPrefix(e,"a=mid:")[0];if(t)return t.substr(6)},n.parseFingerprint=function(e){var t=e.substr(14).split(" ");return{algorithm:t[0].toLowerCase(),value:t[1]}},n.getDtlsParameters=function(e,t){return{role:"auto",fingerprints:n.matchPrefix(e+t,"a=fingerprint:").map(n.parseFingerprint)}},n.writeDtlsParameters=function(e,t){var n="a=setup:"+t+"\r\n";return e.fingerprints.forEach((function(e){n+="a=fingerprint:"+e.algorithm+" "+e.value+"\r\n"})),n},n.getIceParameters=function(e,t){var r=n.splitLines(e);return{usernameFragment:(r=r.concat(n.splitLines(t))).filter((function(e){return 0===e.indexOf("a=ice-ufrag:")}))[0].substr(12),password:r.filter((function(e){return 0===e.indexOf("a=ice-pwd:")}))[0].substr(10)}},n.writeIceParameters=function(e){return"a=ice-ufrag:"+e.usernameFragment+"\r\na=ice-pwd:"+e.password+"\r\n"},n.parseRtpParameters=function(e){for(var t={codecs:[],headerExtensions:[],fecMechanisms:[],rtcp:[]},r=n.splitLines(e)[0].split(" "),a=3;a0?"9":"0",r+=" UDP/TLS/RTP/SAVPF ",r+=t.codecs.map((function(e){return void 0!==e.preferredPayloadType?e.preferredPayloadType:e.payloadType})).join(" ")+"\r\n",r+="c=IN IP4 0.0.0.0\r\n",r+="a=rtcp:9 IN IP4 0.0.0.0\r\n",t.codecs.forEach((function(e){r+=n.writeRtpMap(e),r+=n.writeFmtp(e),r+=n.writeRtcpFb(e)}));var a=0;return t.codecs.forEach((function(e){e.maxptime>a&&(a=e.maxptime)})),a>0&&(r+="a=maxptime:"+a+"\r\n"),r+="a=rtcp-mux\r\n",t.headerExtensions.forEach((function(e){r+=n.writeExtmap(e)})),r},n.parseRtpEncodingParameters=function(e){var t,r=[],a=n.parseRtpParameters(e),i=-1!==a.fecMechanisms.indexOf("RED"),o=-1!==a.fecMechanisms.indexOf("ULPFEC"),s=n.matchPrefix(e,"a=ssrc:").map((function(e){return n.parseSsrcMedia(e)})).filter((function(e){return"cname"===e.attribute})),f=s.length>0&&s[0].ssrc,c=n.matchPrefix(e,"a=ssrc-group:FID").map((function(e){var t=e.split(" ");return t.shift(),t.map((function(e){return parseInt(e,10)}))}));c.length>0&&c[0].length>1&&c[0][0]===f&&(t=c[0][1]),a.codecs.forEach((function(e){if("RTX"===e.name.toUpperCase()&&e.parameters.apt){var n={ssrc:f,codecPayloadType:parseInt(e.parameters.apt,10),rtx:{ssrc:t}};r.push(n),i&&((n=JSON.parse(JSON.stringify(n))).fec={ssrc:t,mechanism:o?"red+ulpfec":"red"},r.push(n))}})),0===r.length&&f&&r.push({ssrc:f});var u=n.matchPrefix(e,"b=");return u.length&&(0===u[0].indexOf("b=TIAS:")?u=parseInt(u[0].substr(7),10):0===u[0].indexOf("b=AS:")&&(u=parseInt(u[0].substr(5),10)),r.forEach((function(e){e.maxBitrate=u}))),r},n.parseRtcpParameters=function(e){var t={},r=n.matchPrefix(e,"a=ssrc:").map((function(e){return n.parseSsrcMedia(e)})).filter((function(e){return"cname"===e.attribute}))[0];r&&(t.cname=r.value,t.ssrc=r.ssrc);var a=n.matchPrefix(e,"a=rtcp-rsize");t.reducedSize=a.length>0,t.compound=0===a.length;var i=n.matchPrefix(e,"a=rtcp-mux");return t.mux=i.length>0,t},n.parseMsid=function(e){var t,r=n.matchPrefix(e,"a=msid:");if(1===r.length)return{stream:(t=r[0].substr(7).split(" "))[0],track:t[1]};var a=n.matchPrefix(e,"a=ssrc:").map((function(e){return n.parseSsrcMedia(e)})).filter((function(e){return"msid"===e.attribute}));return a.length>0?{stream:(t=a[0].value.split(" "))[0],track:t[1]}:void 0},n.writeSessionBoilerplate=function(){return"v=0\r\no=thisisadapterortc 8169639915646943137 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n"},n.writeMediaSection=function(e,t,r,a){var i=n.writeRtpDescription(e.kind,t);if(i+=n.writeIceParameters(e.iceGatherer.getLocalParameters()),i+=n.writeDtlsParameters(e.dtlsTransport.getLocalParameters(),"offer"===r?"actpass":"active"),i+="a=mid:"+e.mid+"\r\n",e.direction?i+="a="+e.direction+"\r\n":e.rtpSender&&e.rtpReceiver?i+="a=sendrecv\r\n":e.rtpSender?i+="a=sendonly\r\n":e.rtpReceiver?i+="a=recvonly\r\n":i+="a=inactive\r\n",e.rtpSender){var o="msid:"+a.id+" "+e.rtpSender.track.id+"\r\n";i+="a="+o,i+="a=ssrc:"+e.sendEncodingParameters[0].ssrc+" "+o,e.sendEncodingParameters[0].rtx&&(i+="a=ssrc:"+e.sendEncodingParameters[0].rtx.ssrc+" "+o,i+="a=ssrc-group:FID "+e.sendEncodingParameters[0].ssrc+" "+e.sendEncodingParameters[0].rtx.ssrc+"\r\n")}return i+="a=ssrc:"+e.sendEncodingParameters[0].ssrc+" cname:"+n.localCName+"\r\n",e.rtpSender&&e.sendEncodingParameters[0].rtx&&(i+="a=ssrc:"+e.sendEncodingParameters[0].rtx.ssrc+" cname:"+n.localCName+"\r\n"),i},n.getDirection=function(e,t){for(var r=n.splitLines(e),a=0;aArray(e).fill(t,n,r);const d=Array.prototype.reduce,p=(e,t,n)=>void 0===n?d.call(t,e):d.call(t,e,n);var m=(e,t,n=[])=>p(((n,r,a)=>(n[a]=e(r,a,t,n),n)),t,n||t);const h=Array.prototype.forEach;var v=(e,t)=>(h.call(t,e),t);const g=(e,t)=>(e%t+t)%t,b=(e,t)=>t[g(e,t.length)];var y;y="/**\n * Optical flow fragment shader, for convenience.\n *\n * @see ./index.frag\n */\n\n// #define opticalFlowMap\n\nprecision highp float;\n#define GLSLIFY 1\n\nuniform sampler2D next;\nuniform sampler2D past;\nuniform float offset;\nuniform float lambda;\nuniform float alpha;\nuniform vec2 speed;\n\n// Optionally map the flow ([-1, 1]) to a different range (e.g: [0, 1]).\n#ifdef opticalFlowMap\n uniform vec4 inRange;\n uniform vec4 outRange;\n\n float map(float value, float inMin, float inMax, float outMin, float outMax) {\n return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);\n}\n\nvec2 map(vec2 value, vec2 inMin, vec2 inMax, vec2 outMin, vec2 outMax) {\n return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);\n}\n\nvec3 map(vec3 value, vec3 inMin, vec3 inMax, vec3 outMin, vec3 outMax) {\n return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);\n}\n\nvec4 map(vec4 value, vec4 inMin, vec4 inMax, vec4 outMin, vec4 outMax) {\n return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);\n}\n\n#endif\n\nvarying vec2 uv;\n\n/**\n * Optical flow GLSL module.\n * May work best if the views are pre-processed (e.g: blur).\n *\n * @see https://forum.openframeworks.cc/t/ofxflowtools-optical-flow-fluid-dynamics-and-particles-in-glsl/15470\n * @see https://github.com/moostrik/ofxFlowTools\n * @see https://github.com/diwi/PixelFlow\n * @see http://thomasdiewald.com/blog/?p=2766\n * @see https://adamferriss.com/gush/\n * @see https://github.com/princemio/ofxMIOFlowGLSL/blob/master/src/FlowShader.cpp\n */\n\n#define opticalFlowPixel_extern 0\n#define opticalFlowPixel_normal 1\n#define opticalFlowPixel_luma 2\n#ifndef opticalFlowPixel\n #define opticalFlowPixel opticalFlowPixel_luma\n#endif\n\n#if opticalFlowPixel == opticalFlowPixel_luma\n float luma(vec3 color) {\n return dot(color, vec3(0.299, 0.587, 0.114));\n}\n\nfloat luma(vec4 color) {\n return dot(color.rgb, vec3(0.299, 0.587, 0.114));\n}\n\n vec4 pixel(sampler2D texture, vec2 uv) {\n vec4 color = texture2D(texture, uv);\n\n return vec4(vec3(luma(color)), color.a);\n }\n#elif opticalFlowPixel == opticalFlowPixel_normal\n vec4 pixel(sampler2D texture, vec2 uv) { return texture2D(texture, uv); }\n#else\n // To provide external `pixel` lookup function.\n vec4 pixel(sampler2D texture, vec2 uv);\n#endif\n\n// @todo Sample mimaps at different LODs/scales to capture wider features.\nvec2 opticalFlow(in vec2 uv, in sampler2D next, in sampler2D past,\n in float offset, in float lambda) {\n vec2 off = vec2(offset, 0.0);\n\n vec4 gradX = (pixel(next, uv+off.xy)-pixel(next, uv-off.xy))+\n (pixel(past, uv+off.xy)-pixel(past, uv-off.xy));\n\n vec4 gradY = (pixel(next, uv+off.yx)-pixel(next, uv-off.yx))+\n (pixel(past, uv+off.yx)-pixel(past, uv-off.yx));\n\n vec4 gradMag = sqrt((gradX*gradX)+(gradY*gradY)+vec4(lambda));\n\n vec4 diff = pixel(next, uv)-pixel(past, uv);\n\n return vec2((diff*(gradX/gradMag)).x, (diff*(gradY/gradMag)).x);\n}\n\nvec2 opticalFlow(in vec2 uv, in sampler2D views[2], in float offset,\n in float lambda) {\n return opticalFlow(uv, views[0], views[1], offset, lambda);\n}\n\nvoid main() {\n vec2 flow = opticalFlow(uv, next, past, offset, lambda);\n float power = dot(flow, flow);\n\n flow *= speed;\n\n // Optionally map the flow ([-1, 1]) to a different range (e.g: [0, 1]).\n #ifdef opticalFlowMap\n flow = map(flow, inRange.xy, inRange.zw, outRange.xy, outRange.zw);\n #endif\n\n gl_FragColor = vec4(flow, power, clamp(power*alpha, 0.0, 1.0));\n}\n";var w;w="// Perform a `blur`.\n// #define opticalFlowSpreadBlur\n\n// Scale values output by a `tint`.\n// #define opticalFlowSpreadTint\n\n// Shift the sample lookup by a `flow` lookup.\n#define opticalFlowSpreadShift_none 0\n#define opticalFlowSpreadShift_frame 1\n#define opticalFlowSpreadShift_flow 2\n#ifndef opticalFlowSpreadShift\n #define opticalFlowSpreadShift opticalFlowSpreadShift_none\n#endif\n\n// Map any flow values.\n// #define opticalFlowSpreadMap\n\n// Blend with past frame.\n// #define opticalFlowSpreadBlend\n\nprecision highp float;\n#define GLSLIFY 1\n\nuniform sampler2D frame;\n\n// Perform a `blur`.\n#ifdef opticalFlowSpreadBlur\n uniform vec2 axis;\n uniform float width;\n uniform float height;\n#endif\n\n// Alter the values output, scaling by a `tint`.\n#ifdef opticalFlowSpreadTint\n uniform vec4 tint;\n#endif\n\n#if opticalFlowSpreadShift != opticalFlowSpreadShift_none\n // Shift the sample lookup by a `flow` lookup.\n uniform vec2 speed;\n\n // Use a separate `flow` input.\n #if opticalFlowSpreadShift == opticalFlowSpreadShift_flow\n uniform sampler2D flow;\n #endif\n\n // Map any flow values.\n #ifdef opticalFlowSpreadMap\n uniform vec4 inRange;\n uniform vec4 toRange;\n\n float map(float value, float inMin, float inMax, float outMin, float outMax) {\n return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);\n}\n\nvec2 map(vec2 value, vec2 inMin, vec2 inMax, vec2 outMin, vec2 outMax) {\n return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);\n}\n\nvec3 map(vec3 value, vec3 inMin, vec3 inMax, vec3 outMin, vec3 outMax) {\n return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);\n}\n\nvec4 map(vec4 value, vec4 inMin, vec4 inMax, vec4 outMin, vec4 outMax) {\n return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);\n}\n\n #endif\n#endif\n\n#ifdef opticalFlowSpreadBlend\n uniform sampler2D other;\n uniform float blend;\n#endif\n\nvarying vec2 uv;\n\nvec4 blur5(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) {\n vec4 color = vec4(0.0);\n vec2 off1 = vec2(1.3333333333333333) * direction;\n color += texture2D(image, uv) * 0.29411764705882354;\n color += texture2D(image, uv + (off1 / resolution)) * 0.35294117647058826;\n color += texture2D(image, uv - (off1 / resolution)) * 0.35294117647058826;\n return color; \n}\n\n#if opticalFlowSpreadShift != opticalFlowSpreadShift_none\n vec2 shift(vec2 uv, sampler2D flow) {\n vec2 f = texture2D(flow, uv).xy;\n\n // Reverse any mapping of the flow values.\n #ifdef opticalFlowSpreadMap\n f = map(f, toRange.xy, toRange.zw, inRange.xy, inRange.zw);\n #endif\n\n return uv+(f*speed);\n }\n#endif\n\nvoid main() {\n vec2 st = uv;\n\n // Shift the sample lookup by a `flow` lookup.\n #if opticalFlowSpreadShift == opticalFlowSpreadShift_flow\n // Use the given `flow` input.\n st = shift(st, flow);\n #elif opticalFlowSpreadShift == opticalFlowSpreadShift_frame\n // Use the `frame` itself as `flow` input.\n st = shift(st, frame);\n #endif\n\n // Perform a `blur`.\n #ifdef opticalFlowSpreadBlur\n vec4 c = blur5(frame, st, vec2(width, height), axis);\n #else\n vec4 c = texture2D(frame, st);\n #endif\n\n // Map back to any given range.\n #ifdef opticalFlowSpreadMap\n c.xy = map(c.xy, toRange.xy, toRange.zw, inRange.xy, inRange.zw);\n #endif\n\n // Scale values output by `tint`.\n #ifdef opticalFlowSpreadTint\n c *= tint;\n #endif\n\n // Reverse any mapping.\n #ifdef opticalFlowSpreadMap\n c.xy = map(c.xy, inRange.xy, inRange.zw, toRange.xy, toRange.zw);\n #endif\n\n #ifdef opticalFlowSpreadBlend\n vec4 o = texture2D(other, uv);\n\n c = mix(c, o, mix(1.0-c.a, o.a, blend));\n #endif\n\n gl_FragColor = c;\n}\n";var x;x="// Map any flow values.\n// #define opticalFlowViewMap\n\nprecision highp float;\n#define GLSLIFY 1\n\nuniform sampler2D frame;\n\n// Map any flow values.\n#ifdef opticalFlowViewMap\n uniform vec4 inRange;\n uniform vec4 toRange;\n\n float map(float value, float inMin, float inMax, float outMin, float outMax) {\n return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);\n}\n\nvec2 map(vec2 value, vec2 inMin, vec2 inMax, vec2 outMin, vec2 outMax) {\n return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);\n}\n\nvec3 map(vec3 value, vec3 inMin, vec3 inMax, vec3 outMin, vec3 outMax) {\n return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);\n}\n\nvec4 map(vec4 value, vec4 inMin, vec4 inMax, vec4 outMin, vec4 outMax) {\n return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);\n}\n\n#endif\n\nvarying vec2 uv;\n\nconst float TWO_PI_1540259130 = 6.28318530718;\n\nfloat hue2rgb(float f1, float f2, float hue) {\n if (hue < 0.0)\n hue += 1.0;\n else if (hue > 1.0)\n hue -= 1.0;\n float res;\n if ((6.0 * hue) < 1.0)\n res = f1 + (f2 - f1) * 6.0 * hue;\n else if ((2.0 * hue) < 1.0)\n res = f2;\n else if ((3.0 * hue) < 2.0)\n res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;\n else\n res = f1;\n return res;\n}\n\nvec3 hsl2rgb(vec3 hsl) {\n vec3 rgb;\n \n if (hsl.y == 0.0) {\n rgb = vec3(hsl.z); // Luminance\n } else {\n float f2;\n \n if (hsl.z < 0.5)\n f2 = hsl.z * (1.0 + hsl.y);\n else\n f2 = hsl.z + hsl.y - hsl.y * hsl.z;\n \n float f1 = 2.0 * hsl.z - f2;\n \n rgb.r = hue2rgb(f1, f2, hsl.x + (1.0/3.0));\n rgb.g = hue2rgb(f1, f2, hsl.x);\n rgb.b = hue2rgb(f1, f2, hsl.x - (1.0/3.0));\n } \n return rgb;\n}\n\nvec3 hsl2rgb(float h, float s, float l) {\n return hsl2rgb(vec3(h, s, l));\n}\n\nvoid main() {\n vec4 data = texture2D(frame, uv);\n float a = clamp(data.a, 0.0, 1.0);\n vec2 flow = data.xy;\n\n // Map any flow values.\n #ifdef opticalFlowViewMap\n flow = map(flow, toRange.xy, toRange.zw, inRange.xy, inRange.zw);\n #endif\n\n // Angle to hue - red right, green up, cyan left, magenta down.\n vec3 color = hsl2rgb(atan(flow.y, flow.x)/TWO_PI_1540259130, 0.9*a, 0.6*a);\n\n gl_FragColor = vec4(color, a);\n}\n";const S=document.querySelector(".demo"),k=S.querySelector(".webcam"),T=S.querySelector(".output"),A=document.querySelector(".fallback"),C=new URLSearchParams(location.search),E=t(o)({canvas:T,optionalExtensions:["oes_texture_half_float","oes_texture_float","oes_texture_float_linear"]}),_=E.hasExtension("oes_texture_float_linear")&&(E.hasExtension("oes_texture_float")?"float":E.hasExtension("oes_texture_half_float")&&"half float"),O=!_,D={type:_||"uint8",min:"linear",mag:"linear"},M={width:0,height:0,depth:!1,stencil:!1},P=()=>E.texture(D),R=(e=P())=>E.framebuffer({color:e,...M}),j=m(P,l(2),0),F=m(R,j),L=m((()=>R()),l(2),0),I=R(),z=m((()=>R()),l(2),0),B=[...F,...L,I,...z],V=[-1,-1,1,1],U=[0,0,1,1],G=self.opticalFlow={videoFrame:{data:k,flipY:!0},spreadVideo:{frag:"#define opticalFlowSpreadBlur\n"+t(w),passes:m(((e,t)=>({axis:e,pass:t})),[[1.4,0],[0,1.4]],0)},flow:{frag:(O?"#define opticalFlowMap\n":"")+t(y),offset:3,lambda:.001,speed:l(2,1),alpha:100,inRange:V,toRange:U,to:I},spreadFlow:{frag:"#define opticalFlowSpreadBlur\n#define opticalFlowSpreadTint\n#define opticalFlowSpreadShift opticalFlowSpreadShift_flow\n"+(O?"#define opticalFlowSpreadMap\n":"")+"#define opticalFlowSpreadBlend\n"+t(w),other:I,blend:1,inRange:V,toRange:U,passes:m(((e,t)=>(e.pass=t,e)),[{axis:[3,0],tint:l(4,1),speed:l(2,0)},{axis:[0,3],tint:l(4,.99),speed:l(2,1)}],0)},view:{frag:(O?"#define opticalFlowViewMap\n":"")+t(x),inRange:V,toRange:U}},N={color:[0,0,0,1],depth:1,stencil:0},H={...N,framebuffer:I},q=m((e=>({...N,framebuffer:e})),L),W=m((e=>({...N,framebuffer:e})),F),Q=m((e=>({...N,framebuffer:e})),z),Y=E({vert:t("precision highp float;\n#define GLSLIFY 1\n\nattribute vec2 position;\n\nvarying vec2 uv;\n\n// Translation for UV NDC to texture coordinates.\nconst vec2 offset = vec2(0.5);\n\nvoid main() {\n uv = (position*0.5)+offset;\n gl_Position = vec4(position, 0, 1);\n}\n"),attributes:{position:u},count:c,depth:{enable:!1}});var J;const X=E({frag:(e,n)=>null!==(J=n.frag)&&void 0!==J?J:t(w),uniforms:{frame:(e,{pass:t=0,frame:n})=>null!=n?n:b(t+1,F),axis:E.prop("axis"),tint:E.prop("tint"),speed:E.prop("speed"),flow:E.prop("flow"),inRange:E.prop("inRange"),toRange:E.prop("toRange"),other:E.prop("other"),blend:E.prop("blend"),width:E.context("drawingBufferWidth"),height:E.context("drawingBufferHeight")},framebuffer:(e,{pass:t=0,to:n})=>null!=n?n:b(t,F)}),$=e=>X(m((t=>Object.assign(t,e,t)),e.passes,0));function K(e){const{videoFrame:t,spreadVideo:n}=G,r=g(e,L.length);return v(E.clear,W),j[1](t),E.clear(q[r]),n.passes[1].to=L[r],$(n)}var Z;const ee=E({frag:(e,{frag:n=t(y)})=>n,uniforms:{next:e=>b(e.tick,L),past:e=>b(e.tick+1,L),offset:E.prop("offset"),lambda:E.prop("lambda"),speed:E.prop("speed"),alpha:E.prop("alpha"),inRange:E.prop("inRange"),toRange:E.prop("toRange")},framebuffer:(e,t)=>null!==(Z=t.to)&&void 0!==Z?Z:I});var te;const ne=E({frag:(e,n)=>null!==(te=n.frag)&&void 0!==te?te:t(x),uniforms:{frame:e=>b(e.tick,z),inRange:E.prop("inRange"),toRange:E.prop("toRange")},framebuffer:(e,t)=>t.to});function re({tick:e}){K(e),E.clear(H),ee(G.flow),function(e){const{spreadFlow:t}=G,{passes:n}=t;v(E.clear,W),t.flow=n[0].frame=b(e+1,z);const r=g(e,z.length);E.clear(Q[r]),n[1].to=z[r],$(t)}(e),E.clear(N),ne(G.view)}k.addEventListener("canplay",(function e(){const{videoWidth:t,videoHeight:n}=k;k.width=T.width=t,k.height=T.height=n,v((e=>e.resize(t,n)),B),G.flow.offset/=Math.max(t,n,1e3),k.play(),Y((()=>{K(0),K(1)})),E.frame((()=>Y(re))),k.removeEventListener("canplay",e)}));var ae;ae=new URL(i("g8vZD").resolve("a690T"),import.meta.url).toString();const ie=new URL(ae);"false"===C.get("camera")?k.src=ie:t(s)({video:!0},((e,t)=>{if(e)return console.warn(e,"Error getting webcam stream, using sample video",k.src=ie);"srcObject"in k?k.srcObject=t:k.src=URL.createObjectURL(t),S.classList.add("mirror")})),S.addEventListener("click",(()=>{const e=S.classList;e[e.contains("overlay")?"remove":"add"]("overlay")})),A&&"false"!==C.get("fallback")&&(A.src=A.dataset.src); 2 | //# sourceMappingURL=index.f295124b.js.map 3 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /docs/sample.6124211c.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keeffEoghan/glsl-optical-flow/336ddaee613a8cf616af01253cd143faf1c5cb89/docs/sample.6124211c.mp4 -------------------------------------------------------------------------------- /index.frag.glsl: -------------------------------------------------------------------------------- 1 | /** 2 | * Optical flow fragment shader, for convenience. 3 | * 4 | * @see ./index.frag 5 | */ 6 | 7 | // #define opticalFlowMap 8 | 9 | precision highp float; 10 | 11 | uniform sampler2D next; 12 | uniform sampler2D past; 13 | uniform float offset; 14 | uniform float lambda; 15 | uniform float alpha; 16 | uniform vec2 speed; 17 | 18 | // Optionally map the flow ([-1, 1]) to a different range (e.g: [0, 1]). 19 | #ifdef opticalFlowMap 20 | uniform vec4 inRange; 21 | uniform vec4 outRange; 22 | 23 | #pragma glslify: map = require(glsl-map) 24 | #endif 25 | 26 | varying vec2 uv; 27 | 28 | #pragma glslify: opticalFlow = require(./index) 29 | 30 | void main() { 31 | vec2 flow = opticalFlow(uv, next, past, offset, lambda); 32 | float power = dot(flow, flow); 33 | 34 | flow *= speed; 35 | 36 | // Optionally map the flow ([-1, 1]) to a different range (e.g: [0, 1]). 37 | #ifdef opticalFlowMap 38 | flow = map(flow, inRange.xy, inRange.zw, outRange.xy, outRange.zw); 39 | #endif 40 | 41 | gl_FragColor = vec4(flow, power, clamp(power*alpha, 0.0, 1.0)); 42 | } 43 | -------------------------------------------------------------------------------- /index.frag.js: -------------------------------------------------------------------------------- 1 | export * as default from './index.frag.glsl'; 2 | -------------------------------------------------------------------------------- /index.glsl: -------------------------------------------------------------------------------- 1 | /** 2 | * Optical flow GLSL module. 3 | * May work best if the views are pre-processed (e.g: blur). 4 | * 5 | * @see https://forum.openframeworks.cc/t/ofxflowtools-optical-flow-fluid-dynamics-and-particles-in-glsl/15470 6 | * @see https://github.com/moostrik/ofxFlowTools 7 | * @see https://github.com/diwi/PixelFlow 8 | * @see http://thomasdiewald.com/blog/?p=2766 9 | * @see https://adamferriss.com/gush/ 10 | * @see https://github.com/princemio/ofxMIOFlowGLSL/blob/master/src/FlowShader.cpp 11 | */ 12 | 13 | #define opticalFlowPixel_extern 0 14 | #define opticalFlowPixel_normal 1 15 | #define opticalFlowPixel_luma 2 16 | #ifndef opticalFlowPixel 17 | #define opticalFlowPixel opticalFlowPixel_luma 18 | #endif 19 | 20 | #if opticalFlowPixel == opticalFlowPixel_luma 21 | #pragma glslify: luma = require(glsl-luma) 22 | 23 | vec4 pixel(sampler2D texture, vec2 uv) { 24 | vec4 color = texture2D(texture, uv); 25 | 26 | return vec4(vec3(luma(color)), color.a); 27 | } 28 | #elif opticalFlowPixel == opticalFlowPixel_normal 29 | vec4 pixel(sampler2D texture, vec2 uv) { return texture2D(texture, uv); } 30 | #else 31 | // To provide external `pixel` lookup function. 32 | vec4 pixel(sampler2D texture, vec2 uv); 33 | #endif 34 | 35 | // @todo Sample mimaps at different LODs/scales to capture wider features. 36 | vec2 opticalFlow(in vec2 uv, in sampler2D next, in sampler2D past, 37 | in float offset, in float lambda) { 38 | vec2 off = vec2(offset, 0.0); 39 | 40 | vec4 gradX = (pixel(next, uv+off.xy)-pixel(next, uv-off.xy))+ 41 | (pixel(past, uv+off.xy)-pixel(past, uv-off.xy)); 42 | 43 | vec4 gradY = (pixel(next, uv+off.yx)-pixel(next, uv-off.yx))+ 44 | (pixel(past, uv+off.yx)-pixel(past, uv-off.yx)); 45 | 46 | vec4 gradMag = sqrt((gradX*gradX)+(gradY*gradY)+vec4(lambda)); 47 | 48 | vec4 diff = pixel(next, uv)-pixel(past, uv); 49 | 50 | return vec2((diff*(gradX/gradMag)).x, (diff*(gradY/gradMag)).x); 51 | } 52 | 53 | vec2 opticalFlow(in vec2 uv, in sampler2D views[2], in float offset, 54 | in float lambda) { 55 | return opticalFlow(uv, views[0], views[1], offset, lambda); 56 | } 57 | 58 | #pragma glslify: export(opticalFlow); 59 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | export * as default from './index.glsl'; 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@epok.tech/glsl-optical-flow", 3 | "version": "1.6.3", 4 | "description": "Optical flow for WebGL - BYORenderer.", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/keeffEoghan/glsl-optical-flow.git" 8 | }, 9 | "author": "Eoghan O'Keeffe (https://epok.tech/)", 10 | "license": "MIT", 11 | "engines": { 12 | "node": "v16.13.0 || *", 13 | "yarn": "3.1.0 || *" 14 | }, 15 | "packageManager": "yarn@3.1.0", 16 | "scripts": { 17 | "start": "yarn docs", 18 | "dev": "parcel --log-level verbose demo/index.html", 19 | "dist": "yarn build:fresh & yarn docs:fresh & wait", 20 | "build": "rm -rf ./dist/ && parcel build --target esm --target cjs", 21 | "docs": "rm -rf ./docs/ && parcel build --target docs", 22 | "dev:fresh": "yarn dev --no-cache", 23 | "dist:fresh": "yarn build:fresh & yarn docs:fresh & wait", 24 | "build:fresh": "yarn build --no-cache", 25 | "docs:fresh": "yarn docs --no-cache" 26 | }, 27 | "dependencies": { 28 | "glsl-luma": "^1.0.1", 29 | "glsl-map": "^1.0.1" 30 | }, 31 | "devDependencies": { 32 | "@epok.tech/fn-lists": "^0.1.1", 33 | "@epok.tech/gl-screen-triangle": "^1.1.3", 34 | "@parcel/transformer-glsl": "^2.0.1", 35 | "getusermedia": "^2.0.1", 36 | "glsl-constants": "^1.0.0", 37 | "glsl-fast-gaussian-blur": "^1.0.2", 38 | "glsl-hsl2rgb": "^1.1.0", 39 | "parcel": "v2.0.1", 40 | "postcss": "^8.4", 41 | "postcss-nesting": "^13.0.1", 42 | "regl": "^2.1.0" 43 | }, 44 | "main": "dist/cjs/index.js", 45 | "module": "dist/esm/index.js", 46 | "source": [ 47 | "index.js", 48 | "index.frag.js" 49 | ], 50 | "files": [ 51 | "*.{js,glsl}", 52 | "dist/**/*", 53 | "demo/**/*", 54 | "snap/demo.png" 55 | ], 56 | "targets": { 57 | "cjs": { 58 | "outputFormat": "commonjs", 59 | "isLibrary": true, 60 | "engines": { 61 | "browsers": "last 2 versions, > 0.5%, not dead" 62 | }, 63 | "distDir": "dist/cjs/", 64 | "publicUrl": "dist/cjs/" 65 | }, 66 | "esm": { 67 | "outputFormat": "esmodule", 68 | "isLibrary": true, 69 | "engines": { 70 | "browsers": "last 2 versions, > 0.5%, not dead" 71 | }, 72 | "distDir": "dist/esm/", 73 | "publicUrl": "dist/esm/" 74 | }, 75 | "docs": { 76 | "isLibrary": false, 77 | "engines": { 78 | "browsers": "last 2 versions, > 0.5%, not dead" 79 | }, 80 | "source": "demo/index.html", 81 | "distDir": "docs/", 82 | "publicUrl": "./" 83 | } 84 | }, 85 | "keywords": [ 86 | "glsl", 87 | "webgl", 88 | "shader", 89 | "optical", 90 | "flow", 91 | "regl" 92 | ], 93 | "bugs": { 94 | "url": "https://github.com/keeffEoghan/glsl-optical-flow/issues" 95 | }, 96 | "homepage": "https://github.com/keeffEoghan/glsl-optical-flow#readme" 97 | } 98 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # `glsl-optical-flow` 2 | 3 | [![Optical flow advection demo](./snap/demo.png)](https://epok.tech/glsl-optical-flow "Optical flow advection demo") 4 | 5 | Optical flow shader for WebGL - BYORenderer. 6 | 7 | No drawing dependencies - for easier compatibility with any renderer which may rely on tracking the WebGL state (e.g: [`regl`](https://github.com/regl-project/regl/)). 8 | 9 | [Check out the demo](http://epok.tech/glsl-optical-flow/). 10 | 11 | ## Installation 12 | 13 | Install from [`npm`](https://www.npmjs.com/package/@epok.tech/glsl-optical-flow) using: 14 | ```bash 15 | npm install @epok.tech/glsl-optical-flow 16 | ``` 17 | or: 18 | ```bash 19 | yarn add @epok.tech/glsl-optical-flow 20 | ``` 21 | 22 | ## Usage 23 | 24 | [Check out the demo](http://epok.tech/glsl-optical-flow/), and its [source code](https://github.com/keeffEoghan/glsl-optical-flow/blob/master/demo/), a comprehensive example of blurring input, blending across frames, and advecting by the flow to get smooth optical-flow over time: 25 | 26 | You may also use this in your shader... 27 | ```glsl 28 | precision highp float; 29 | 30 | uniform sampler2D next; 31 | uniform sampler2D past; 32 | uniform float offset; 33 | uniform float lambda; 34 | 35 | varying vec2 uv; 36 | 37 | #pragma glslify: opticalFlow = require(@epok.tech/glsl-optical-flow) 38 | 39 | void main() { 40 | gl_FragColor = vec4(opticalFlow(uv, next, past, offset, lambda), 0.0, 1.0); 41 | } 42 | ``` 43 | 44 | ... or [the provided fragment shader](https://github.com/keeffEoghan/glsl-optical-flow/blob/master/index.frag.glsl), for example, or for direct usage (with `glslify`). 45 | 46 | ## See Also 47 | 48 | ### Examples in the wild 49 | - [@tomorrowevening](https://github.com/tomorrowevening/) has [developed](https://github.com/tomorrowevening/webgl-optical-flow) a cool [demo](https://webgl-optical-flow.vercel.app/) that explores the method and ways to use it. 50 | 51 | ### Based on 52 | - Original use in [`tendrils`](https://github.com/keeffEoghan/tendrils). 53 | - `ofxFlowTools` [article](https://forum.openframeworks.cc/t/ofxflowtools-optical-flow-fluid-dynamics-and-particles-in-glsl/15470) and [code](https://github.com/moostrik/ofxFlowTools). 54 | - [`PixelFlow`](https://github.com/diwi/PixelFlow). 55 | - [Thomas DieWald](http://thomasdiewald.com/blog/?p=2766). 56 | - [Adam Ferriss](https://adamferriss.com/gush/). 57 | - [`ofxMIOFlowGLSL`, based on work by Andrew Benson](https://github.com/princemio/ofxMIOFlowGLSL/blob/master/src/FlowShader.cpp). 58 | - [`glslify`](https://github.com/glslify/glslify). 59 | -------------------------------------------------------------------------------- /snap/demo.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keeffEoghan/glsl-optical-flow/336ddaee613a8cf616af01253cd143faf1c5cb89/snap/demo.mp4 -------------------------------------------------------------------------------- /snap/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keeffEoghan/glsl-optical-flow/336ddaee613a8cf616af01253cd143faf1c5cb89/snap/demo.png --------------------------------------------------------------------------------